Merge tag 'sched-urgent-2024-03-24' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 24 Mar 2024 18:11:05 +0000 (11:11 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 24 Mar 2024 18:11:05 +0000 (11:11 -0700)
Pull scheduler doc clarification from Thomas Gleixner:
 "A single update for the documentation of the base_slice_ns tunable to
  clarify that any value which is less than the tick slice has no effect
  because the scheduler tick is not guaranteed to happen within the set
  time slice"

* tag 'sched-urgent-2024-03-24' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  sched/doc: Update documentation for base_slice_ns and CONFIG_HZ relation

1694 files changed:
.gitignore
.mailmap
Documentation/ABI/testing/configfs-usb-gadget-ffs
Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-usb
Documentation/ABI/testing/sysfs-class-usb_role
Documentation/ABI/testing/sysfs-fs-f2fs
Documentation/admin-guide/cifs/introduction.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/reporting-regressions.rst
Documentation/admin-guide/sysctl/kernel.rst
Documentation/admin-guide/verify-bugs-and-bisect-regressions.rst
Documentation/arch/riscv/vm-layout.rst
Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml
Documentation/devicetree/bindings/bus/brcm,gisb-arb.yaml
Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml
Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml
Documentation/devicetree/bindings/iio/adc/adc.yaml
Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml
Documentation/devicetree/bindings/iio/adc/adi,axi-adc.yaml
Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/nxp,imx93-adc.yaml
Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
Documentation/devicetree/bindings/iio/adc/richtek,rtq6056.yaml
Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/afe/voltage-divider.yaml
Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/gyroscope/bosch,bmg160.yaml
Documentation/devicetree/bindings/iio/humidity/ti,hdc2010.yaml
Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml
Documentation/devicetree/bindings/iio/imu/st,lsm6dsx.yaml
Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml
Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml
Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml
Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml
Documentation/devicetree/bindings/interconnect/qcom,sm7150-rpmh.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/layouts/fixed-cell.yaml
Documentation/devicetree/bindings/nvmem/nvmem-provider.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.txt [deleted file]
Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/opencores,pwm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml
Documentation/devicetree/bindings/remoteproc/mtk,scp.yaml
Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml
Documentation/devicetree/bindings/remoteproc/qcom,qcs404-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sc7280-wpss-pil.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sc8180x-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sm6115-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sm6350-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sm6375-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sm8150-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml
Documentation/devicetree/bindings/remoteproc/qcom,wcnss-pil.yaml
Documentation/devicetree/bindings/reset/sophgo,sg2042-reset.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/riscv/cpus.yaml
Documentation/devicetree/bindings/riscv/extensions.yaml
Documentation/devicetree/bindings/rtc/abracon,abx80x.txt [deleted file]
Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/atmel,at91sam9260-rtt.yaml
Documentation/devicetree/bindings/rtc/mediatek,mt2712-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/mediatek,mt7622-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/rtc-mt2712.txt [deleted file]
Documentation/devicetree/bindings/rtc/rtc-mt7622.txt [deleted file]
Documentation/devicetree/bindings/rtc/xlnx,zynqmp-rtc.yaml
Documentation/devicetree/bindings/serial/cdns,uart.yaml
Documentation/devicetree/bindings/serial/fsl-lpuart.yaml
Documentation/devicetree/bindings/serial/renesas,hscif.yaml
Documentation/devicetree/bindings/serial/samsung_uart.yaml
Documentation/devicetree/bindings/serial/serial.yaml
Documentation/devicetree/bindings/serial/st,asc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/serial/st,stm32-uart.yaml
Documentation/devicetree/bindings/serial/st-asc.txt [deleted file]
Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
Documentation/devicetree/bindings/sound/qcom,q6usb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml
Documentation/devicetree/bindings/thermal/qoriq-thermal.yaml
Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.yaml
Documentation/devicetree/bindings/thermal/thermal-zones.yaml
Documentation/devicetree/bindings/timer/cdns,ttc.yaml
Documentation/devicetree/bindings/timer/nxp,sysctr-timer.yaml
Documentation/devicetree/bindings/timer/ralink,cevt-systick.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/timer/renesas,ostm.yaml
Documentation/devicetree/bindings/timer/renesas,tmu.yaml
Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml
Documentation/devicetree/bindings/usb/analogix,anx7411.yaml
Documentation/devicetree/bindings/usb/ci-hdrc-usb2.yaml
Documentation/devicetree/bindings/usb/fcs,fsa4480.yaml
Documentation/devicetree/bindings/usb/generic-ehci.yaml
Documentation/devicetree/bindings/usb/gpio-sbu-mux.yaml
Documentation/devicetree/bindings/usb/hisilicon,hi3798mv200-dwc3.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/ite,it5205.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml
Documentation/devicetree/bindings/usb/microchip,usb5744.yaml
Documentation/devicetree/bindings/usb/nxp,ptn36502.yaml
Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
Documentation/devicetree/bindings/usb/onnn,nb7vpq904m.yaml
Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
Documentation/devicetree/bindings/usb/qcom,pmic-typec.yaml
Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml
Documentation/devicetree/bindings/usb/realtek,rts5411.yaml
Documentation/devicetree/bindings/usb/ti,am62-usb.yaml
Documentation/devicetree/bindings/usb/ti,usb8020b.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb-nop-xceiv.yaml
Documentation/devicetree/bindings/usb/usb-switch.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/devicetree/bindings/w1/w1-uart.yaml [new file with mode: 0644]
Documentation/driver-api/tty/console.rst [new file with mode: 0644]
Documentation/driver-api/tty/index.rst
Documentation/driver-api/usb/callbacks.rst
Documentation/features/sched/membarrier-sync-core/arch-support.txt
Documentation/filesystems/f2fs.rst
Documentation/firmware-guide/acpi/enumeration.rst
Documentation/iio/adis16475.rst [new file with mode: 0644]
Documentation/iio/iio_devbuf.rst [new file with mode: 0644]
Documentation/iio/index.rst
Documentation/kbuild/kconfig-language.rst
Documentation/kbuild/kconfig.rst
Documentation/mm/page_cache.rst
Documentation/networking/device_drivers/ethernet/pensando/ionic.rst
Documentation/networking/multi-pf-netdev.rst
Documentation/networking/net_cachelines/net_device.rst
Documentation/power/suspend-and-interrupts.rst
Documentation/process/handling-regressions.rst
Documentation/scheduler/index.rst
Documentation/scheduler/membarrier.rst [new file with mode: 0644]
Documentation/spi/spi-lm70llp.rst
Documentation/spi/spidev.rst
Documentation/tools/rtla/common_timerlat_options.rst
Documentation/trace/user_events.rst
Documentation/usb/functionfs.rst
Documentation/usb/gadget-testing.rst
Documentation/w1/masters/index.rst
Documentation/w1/masters/w1-uart.rst [new file with mode: 0644]
MAINTAINERS
Makefile
README
arch/Kconfig
arch/alpha/Kconfig
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/boot/dts/ti/omap/am33xx-clocks.dtsi
arch/arm/boot/dts/ti/omap/am35xx-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap3430es1-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap34xx-omap36xx-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap36xx-am35xx-omap3430es2plus-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap36xx-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap36xx-omap3430es2plus-clocks.dtsi
arch/arm/boot/dts/ti/omap/omap3xxx-clocks.dtsi
arch/arm/include/asm/ptrace.h
arch/arm/include/debug/brcmstb.S
arch/arm/kernel/Makefile
arch/arm/kernel/iwmmxt.S
arch/arm/kernel/pj4-cp0.c [deleted file]
arch/arm/kernel/traps.c
arch/arm/kernel/unwind.c
arch/arm/mach-bcm/Kconfig
arch/arm/mm/fault.c
arch/arm/mm/flush.c
arch/arm/mm/init.c
arch/arm64/Kconfig
arch/arm64/boot/dts/broadcom/bcmbca/bcm4908-asus-gt-ac5300.dts
arch/arm64/boot/dts/broadcom/bcmbca/bcm4908.dtsi
arch/arm64/boot/dts/qcom/pm6150.dtsi
arch/arm64/hyperv/hv_core.c
arch/arm64/hyperv/mshyperv.c
arch/arm64/include/asm/hyperv-tlfs.h
arch/arm64/include/asm/mshyperv.h
arch/hexagon/Kconfig
arch/loongarch/Kconfig
arch/loongarch/Kconfig.debug
arch/loongarch/Makefile
arch/loongarch/crypto/crc32-loongarch.c
arch/loongarch/include/asm/Kbuild
arch/loongarch/include/asm/bug.h
arch/loongarch/include/asm/cacheflush.h
arch/loongarch/include/asm/exception.h
arch/loongarch/include/asm/io.h
arch/loongarch/include/asm/module.h
arch/loongarch/include/asm/orc_header.h [new file with mode: 0644]
arch/loongarch/include/asm/orc_lookup.h [new file with mode: 0644]
arch/loongarch/include/asm/orc_types.h [new file with mode: 0644]
arch/loongarch/include/asm/page.h
arch/loongarch/include/asm/percpu.h
arch/loongarch/include/asm/pgtable.h
arch/loongarch/include/asm/qspinlock.h [deleted file]
arch/loongarch/include/asm/stackframe.h
arch/loongarch/include/asm/thread_info.h
arch/loongarch/include/asm/unwind.h
arch/loongarch/include/asm/unwind_hints.h [new file with mode: 0644]
arch/loongarch/kernel/Makefile
arch/loongarch/kernel/entry.S
arch/loongarch/kernel/fpu.S
arch/loongarch/kernel/genex.S
arch/loongarch/kernel/lbt.S
arch/loongarch/kernel/mcount_dyn.S
arch/loongarch/kernel/module.c
arch/loongarch/kernel/relocate_kernel.S
arch/loongarch/kernel/rethook_trampoline.S
arch/loongarch/kernel/setup.c
arch/loongarch/kernel/stacktrace.c
arch/loongarch/kernel/traps.c
arch/loongarch/kernel/unwind_orc.c [new file with mode: 0644]
arch/loongarch/kernel/vmlinux.lds.S
arch/loongarch/kvm/switch.S
arch/loongarch/lib/clear_user.S
arch/loongarch/lib/copy_user.S
arch/loongarch/lib/memcpy.S
arch/loongarch/lib/memset.S
arch/loongarch/mm/tlb.c
arch/loongarch/mm/tlbex.S
arch/loongarch/vdso/Makefile
arch/m68k/amiga/config.c
arch/m68k/hp300/config.c
arch/parisc/Kconfig
arch/powerpc/Kconfig
arch/powerpc/boot/dts/akebono.dts
arch/powerpc/include/asm/kexec.h
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/smp.c
arch/powerpc/kexec/Makefile
arch/powerpc/kexec/core.c
arch/powerpc/kexec/elf_64.c
arch/powerpc/kexec/file_load_64.c
arch/powerpc/mm/book3s32/mmu.c
arch/powerpc/mm/mmu_decl.h
arch/powerpc/mm/nohash/8xx.c
arch/powerpc/mm/nohash/e500.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/platforms/powernv/smp.c
arch/riscv/Kbuild
arch/riscv/Kconfig
arch/riscv/Makefile
arch/riscv/boot/dts/microchip/mpfs.dtsi
arch/riscv/boot/dts/renesas/r9a07g043f.dtsi
arch/riscv/boot/dts/starfive/jh7100-beaglev-starlight.dts
arch/riscv/boot/dts/starfive/jh7100-common.dtsi
arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts
arch/riscv/boot/dts/starfive/jh7100.dtsi
arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
arch/riscv/boot/dts/starfive/jh7110.dtsi
arch/riscv/configs/defconfig
arch/riscv/crypto/Kconfig [new file with mode: 0644]
arch/riscv/crypto/Makefile [new file with mode: 0644]
arch/riscv/crypto/aes-macros.S [new file with mode: 0644]
arch/riscv/crypto/aes-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/aes-riscv64-zvkned-zvbb-zvkg.S [new file with mode: 0644]
arch/riscv/crypto/aes-riscv64-zvkned-zvkb.S [new file with mode: 0644]
arch/riscv/crypto/aes-riscv64-zvkned.S [new file with mode: 0644]
arch/riscv/crypto/chacha-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/chacha-riscv64-zvkb.S [new file with mode: 0644]
arch/riscv/crypto/ghash-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/ghash-riscv64-zvkg.S [new file with mode: 0644]
arch/riscv/crypto/sha256-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/sha256-riscv64-zvknha_or_zvknhb-zvkb.S [new file with mode: 0644]
arch/riscv/crypto/sha512-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/sha512-riscv64-zvknhb-zvkb.S [new file with mode: 0644]
arch/riscv/crypto/sm3-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/sm3-riscv64-zvksh-zvkb.S [new file with mode: 0644]
arch/riscv/crypto/sm4-riscv64-glue.c [new file with mode: 0644]
arch/riscv/crypto/sm4-riscv64-zvksed-zvkb.S [new file with mode: 0644]
arch/riscv/errata/andes/errata.c
arch/riscv/include/asm/asm.h
arch/riscv/include/asm/atomic.h
arch/riscv/include/asm/barrier.h
arch/riscv/include/asm/bitops.h
arch/riscv/include/asm/cmpxchg.h
arch/riscv/include/asm/compat.h
arch/riscv/include/asm/cpufeature.h
arch/riscv/include/asm/elf.h
arch/riscv/include/asm/errata_list.h
arch/riscv/include/asm/fence.h
arch/riscv/include/asm/hwcap.h
arch/riscv/include/asm/io.h
arch/riscv/include/asm/membarrier.h [new file with mode: 0644]
arch/riscv/include/asm/mmio.h
arch/riscv/include/asm/mmiowb.h
arch/riscv/include/asm/pgalloc.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/processor.h
arch/riscv/include/asm/simd.h
arch/riscv/include/asm/suspend.h
arch/riscv/include/asm/sync_core.h [new file with mode: 0644]
arch/riscv/include/asm/syscall_wrapper.h
arch/riscv/include/asm/tlb.h
arch/riscv/include/asm/vector.h
arch/riscv/include/asm/vendorid_list.h
arch/riscv/kernel/Makefile
arch/riscv/kernel/alternative.c
arch/riscv/kernel/cpufeature.c
arch/riscv/kernel/entry.S
arch/riscv/kernel/pi/Makefile
arch/riscv/kernel/ptrace.c
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/suspend.c
arch/riscv/kernel/sys_hwprobe.c
arch/riscv/kernel/tests/Kconfig.debug
arch/riscv/kernel/traps.c
arch/riscv/kernel/traps_misaligned.c
arch/riscv/kernel/unaligned_access_speed.c [new file with mode: 0644]
arch/riscv/lib/csum.c
arch/riscv/lib/uaccess_vector.S
arch/riscv/mm/cacheflush.c
arch/riscv/mm/context.c
arch/riscv/mm/init.c
arch/riscv/mm/pgtable.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/configs/debug_defconfig
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/cio.h
arch/s390/include/asm/dma-types.h [new file with mode: 0644]
arch/s390/include/asm/eadm.h
arch/s390/include/asm/fcx.h
arch/s390/include/asm/idals.h
arch/s390/include/asm/page.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/qdio.h
arch/s390/include/asm/scsw.h
arch/s390/kernel/entry.S
arch/s390/kernel/sysinfo.c
arch/s390/kernel/vtime.c
arch/s390/mm/Makefile
arch/s390/mm/fault.c
arch/s390/mm/physaddr.c [new file with mode: 0644]
arch/sh/cchips/hd6446x/hd64461.c
arch/sh/drivers/dma/dma-sysfs.c
arch/x86/Kconfig
arch/x86/entry/vdso/Makefile
arch/x86/hyperv/hv_init.c
arch/x86/hyperv/hv_spinlock.c
arch/x86/hyperv/hv_vtl.c
arch/x86/include/asm/hyperv-tlfs.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/xen/hypervisor.h
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/platform/pvh/enlighten.c
arch/x86/xen/Kconfig
arch/x86/xen/enlighten.c
arch/x86/xen/enlighten_pvh.c
arch/x86/xen/setup.c
arch/x86/xen/xen-ops.h
block/bdev.c
crypto/Kconfig
drivers/accessibility/speakup/devsynth.c
drivers/accessibility/speakup/synth.c
drivers/acpi/Kconfig
drivers/acpi/dock.c
drivers/acpi/riscv/Makefile
drivers/acpi/riscv/cppc.c [new file with mode: 0644]
drivers/acpi/riscv/cpuidle.c [new file with mode: 0644]
drivers/acpi/sleep.c
drivers/android/binder_alloc.c
drivers/ata/ahci.c
drivers/base/component.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/firmware_loader/main.c
drivers/base/platform-msi.c
drivers/base/property.c
drivers/base/swnode.c
drivers/block/floppy.c
drivers/bluetooth/btmtkuart.c
drivers/bluetooth/btnxpuart.c
drivers/bluetooth/hci_serdev.c
drivers/bus/brcmstb_gisb.c
drivers/bus/mhi/common.h
drivers/bus/mhi/ep/main.c
drivers/bus/mhi/host/boot.c
drivers/bus/mhi/host/init.c
drivers/bus/mhi/host/internal.h
drivers/bus/mhi/host/main.c
drivers/bus/mhi/host/pci_generic.c
drivers/bus/mhi/host/pm.c
drivers/bus/mhi/host/trace.h [new file with mode: 0644]
drivers/bus/ts-nbus.c
drivers/cdx/Makefile
drivers/cdx/cdx.c
drivers/cdx/cdx.h
drivers/cdx/cdx_msi.c [new file with mode: 0644]
drivers/cdx/controller/Kconfig
drivers/cdx/controller/cdx_controller.c
drivers/cdx/controller/mc_cdx_pcol.h
drivers/cdx/controller/mcdi_functions.c
drivers/cdx/controller/mcdi_functions.h
drivers/char/hpet.c
drivers/char/xilinx_hwicap/xilinx_hwicap.c
drivers/char/xillybus/xillybus_of.c
drivers/clk/ti/apll.c
drivers/clk/ti/clk.c
drivers/clk/ti/clock.h
drivers/clk/ti/divider.c
drivers/clk/ti/gate.c
drivers/clk/ti/interface.c
drivers/clk/ti/mux.c
drivers/clocksource/arm_global_timer.c
drivers/clocksource/hyperv_timer.c
drivers/clocksource/timer-clint.c
drivers/clocksource/timer-imx-gpt.c
drivers/clocksource/timer-imx-sysctr.c
drivers/clocksource/timer-riscv.c
drivers/clocksource/timer-stm32.c
drivers/clocksource/timer-ti-32k.c
drivers/comedi/drivers/das08.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/freq_table.c
drivers/cpufreq/scmi-cpufreq.c
drivers/cpuidle/cpuidle-riscv-sbi.c
drivers/cxl/core/trace.h
drivers/dio/dio-driver.c
drivers/firewire/core-device.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/efi/earlycon.c
drivers/firmware/efi/sysfb_efi.c
drivers/firmware/xilinx/zynqmp.c
drivers/fpga/dfl.c
drivers/fpga/fpga-bridge.c
drivers/gnss/serial.c
drivers/gnss/sirf.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfxhub_v2_1.c
drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
drivers/gpu/drm/amd/amdgpu/mmhub_v3_3.c
drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.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/amdgpu/vcn_v3_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_state.c
drivers/gpu/drm/amd/display/dc/dc_types.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h
drivers/gpu/drm/amd/display/dc/dcn201/dcn201_opp.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c
drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c
drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
drivers/gpu/drm/amd/display/dc/inc/link.h
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h
drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h
drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c
drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.c
drivers/gpu/drm/amd/display/modules/power/power_helpers.h
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
drivers/gpu/drm/bridge/lontium-lt8912b.c
drivers/gpu/drm/bridge/lontium-lt9611uxc.c
drivers/gpu/drm/drm_panel.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/exynos/exynos_dp.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/i915/display/intel_display_trace.h
drivers/gpu/drm/imx/ipuv3/parallel-display.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/r535.c
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/xe/xe_exec.c
drivers/gpu/drm/xe/xe_gt_pagefault.c
drivers/gpu/drm/xe/xe_trace.h
drivers/gpu/drm/xe/xe_vm.c
drivers/gpu/drm/xe/xe_vm_types.h
drivers/gpu/drm/xe/xe_vram_freq.c
drivers/greybus/bundle.c
drivers/greybus/control.c
drivers/greybus/core.c
drivers/greybus/es2.c
drivers/greybus/gb-beagleplay.c
drivers/greybus/hd.c
drivers/greybus/interface.c
drivers/greybus/module.c
drivers/greybus/svc.c
drivers/hv/Kconfig
drivers/hv/hv.c
drivers/hv/hv_common.c
drivers/hv/vmbus_drv.c
drivers/hwspinlock/omap_hwspinlock.c
drivers/hwtracing/coresight/Makefile
drivers/hwtracing/coresight/coresight-cfg-afdo.c
drivers/hwtracing/coresight/coresight-core.c
drivers/hwtracing/coresight/coresight-cti-core.c
drivers/hwtracing/coresight/coresight-etb10.c
drivers/hwtracing/coresight/coresight-etm-perf.c
drivers/hwtracing/coresight/coresight-etm.h
drivers/hwtracing/coresight/coresight-etm3x-core.c
drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
drivers/hwtracing/coresight/coresight-etm4x-core.c
drivers/hwtracing/coresight/coresight-etm4x.h
drivers/hwtracing/coresight/coresight-funnel.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-replicator.c
drivers/hwtracing/coresight/coresight-stm.c
drivers/hwtracing/coresight/coresight-sysfs.c
drivers/hwtracing/coresight/coresight-tmc-core.c
drivers/hwtracing/coresight/coresight-tmc-etf.c
drivers/hwtracing/coresight/coresight-tmc-etr.c
drivers/hwtracing/coresight/coresight-tmc.h
drivers/hwtracing/coresight/coresight-tpda.c
drivers/hwtracing/coresight/coresight-tpda.h
drivers/hwtracing/coresight/coresight-tpdm.c
drivers/hwtracing/coresight/coresight-tpdm.h
drivers/hwtracing/coresight/coresight-tpiu.c
drivers/hwtracing/coresight/ultrasoc-smb.c
drivers/hwtracing/coresight/ultrasoc-smb.h
drivers/hwtracing/ptt/hisi_ptt.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/muxes/i2c-mux-pca954x.c
drivers/iio/Kconfig
drivers/iio/Makefile
drivers/iio/accel/Kconfig
drivers/iio/accel/Makefile
drivers/iio/accel/adxl367.c
drivers/iio/accel/adxl372_spi.c
drivers/iio/accel/bma180.c
drivers/iio/accel/bmc150-accel-i2c.c
drivers/iio/accel/bmc150-accel-spi.c
drivers/iio/accel/bmi088-accel-i2c.c [new file with mode: 0644]
drivers/iio/accel/da280.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/kxsd9-spi.c
drivers/iio/accel/mma9551.c
drivers/iio/accel/mma9553.c
drivers/iio/accel/mxc4005.c
drivers/iio/accel/mxc6255.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/stk8ba50.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad4130.c
drivers/iio/adc/ad7091r-base.c
drivers/iio/adc/ad9467.c
drivers/iio/adc/ad_sigma_delta.c
drivers/iio/adc/adi-axi-adc.c
drivers/iio/adc/max1363.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/pac1934.c [new file with mode: 0644]
drivers/iio/adc/qcom-pm8xxx-xoadc.c
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/rtq6056.c
drivers/iio/adc/ti-adc108s102.c
drivers/iio/adc/ti-ads1015.c
drivers/iio/adc/ti-ads1298.c [new file with mode: 0644]
drivers/iio/adc/ti-ads8688.c
drivers/iio/amplifiers/hmc425a.c
drivers/iio/buffer/industrialio-buffer-dmaengine.c
drivers/iio/chemical/pms7003.c
drivers/iio/chemical/scd30_serial.c
drivers/iio/chemical/sps30_serial.c
drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
drivers/iio/dac/mcp4821.c
drivers/iio/dummy/iio_dummy_evgen.c
drivers/iio/dummy/iio_simple_dummy.c
drivers/iio/frequency/Kconfig
drivers/iio/frequency/Makefile
drivers/iio/frequency/admfm2000.c [new file with mode: 0644]
drivers/iio/gyro/bmg160_i2c.c
drivers/iio/health/afe4403.c
drivers/iio/health/afe4404.c
drivers/iio/humidity/hdc3020.c
drivers/iio/humidity/hts221_i2c.c
drivers/iio/imu/adis16475.c
drivers/iio/imu/adis16480.c
drivers/iio/imu/bmi160/bmi160_i2c.c
drivers/iio/imu/bmi323/bmi323_core.c
drivers/iio/imu/bmi323/bmi323_i2c.c
drivers/iio/imu/bno055/bno055_ser_core.c
drivers/iio/imu/fxos8700_i2c.c
drivers/iio/imu/fxos8700_spi.c
drivers/iio/imu/kmx61.c
drivers/iio/imu/st_lsm6dsx/Kconfig
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0.h
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c
drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c
drivers/iio/industrialio-backend.c [new file with mode: 0644]
drivers/iio/industrialio-core.c
drivers/iio/industrialio-gts-helper.c
drivers/iio/light/Kconfig
drivers/iio/light/al3010.c
drivers/iio/light/al3320a.c
drivers/iio/light/as73211.c
drivers/iio/light/hid-sensor-als.c
drivers/iio/light/jsa1212.c
drivers/iio/light/ltr501.c
drivers/iio/light/max44000.c
drivers/iio/light/rpr0521.c
drivers/iio/light/stk3310.c
drivers/iio/light/us5182d.c
drivers/iio/light/vcnl4000.c
drivers/iio/light/vl6180.c
drivers/iio/magnetometer/Kconfig
drivers/iio/magnetometer/Makefile
drivers/iio/magnetometer/af8133j.c [new file with mode: 0644]
drivers/iio/magnetometer/bmc150_magn_i2c.c
drivers/iio/magnetometer/bmc150_magn_spi.c
drivers/iio/magnetometer/mmc35240.c
drivers/iio/potentiometer/max5487.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/Makefile
drivers/iio/pressure/hp206c.c
drivers/iio/pressure/hsc030pa.c
drivers/iio/pressure/hsc030pa.h
drivers/iio/pressure/hsc030pa_i2c.c
drivers/iio/pressure/hsc030pa_spi.c
drivers/iio/pressure/mprls0025pa.c
drivers/iio/pressure/mprls0025pa.h [new file with mode: 0644]
drivers/iio/pressure/mprls0025pa_i2c.c [new file with mode: 0644]
drivers/iio/pressure/mprls0025pa_spi.c [new file with mode: 0644]
drivers/iio/pressure/st_pressure_i2c.c
drivers/iio/proximity/isl29501.c
drivers/iio/proximity/sx9310.c
drivers/iio/proximity/sx9324.c
drivers/iio/proximity/sx9360.c
drivers/iio/temperature/ltc2983.c
drivers/iio/temperature/tmp117.c
drivers/iio/test/Kconfig
drivers/iio/test/Makefile
drivers/iio/test/iio-test-gts.c [new file with mode: 0644]
drivers/infiniband/core/cm.c
drivers/infiniband/core/device.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_ioctl.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/efa/efa.h
drivers/infiniband/hw/efa/efa_main.c
drivers/infiniband/hw/hfi1/tid_rdma.c
drivers/infiniband/hw/hns/hns_roce_cmd.h
drivers/infiniband/hw/hns/hns_roce_cq.c
drivers/infiniband/hw/hns/hns_roce_device.h
drivers/infiniband/hw/hns/hns_roce_hem.c
drivers/infiniband/hw/hns/hns_roce_hem.h
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.h
drivers/infiniband/hw/hns/hns_roce_main.c
drivers/infiniband/hw/hns/hns_roce_mr.c
drivers/infiniband/hw/hns/hns_roce_qp.c
drivers/infiniband/hw/hns/hns_roce_restrack.c
drivers/infiniband/hw/irdma/verbs.c
drivers/infiniband/hw/mana/cq.c
drivers/infiniband/hw/mana/main.c
drivers/infiniband/hw/mana/mana_ib.h
drivers/infiniband/hw/mana/mr.c
drivers/infiniband/hw/mana/qp.c
drivers/infiniband/hw/mana/wq.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/sw/rxe/rxe.c
drivers/infiniband/sw/rxe/rxe.h
drivers/infiniband/sw/rxe/rxe_comp.c
drivers/infiniband/sw/rxe/rxe_cq.c
drivers/infiniband/sw/rxe/rxe_loc.h
drivers/infiniband/sw/rxe/rxe_mr.c
drivers/infiniband/sw/rxe/rxe_mw.c
drivers/infiniband/sw/rxe/rxe_qp.c
drivers/infiniband/sw/rxe/rxe_resp.c
drivers/infiniband/sw/rxe/rxe_task.c
drivers/infiniband/sw/rxe/rxe_verbs.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/keyboard/amikbd.c
drivers/interconnect/core.c
drivers/interconnect/qcom/Kconfig
drivers/interconnect/qcom/Makefile
drivers/interconnect/qcom/icc-common.c
drivers/interconnect/qcom/icc-common.h
drivers/interconnect/qcom/msm8909.c [new file with mode: 0644]
drivers/interconnect/qcom/sa8775p.c
drivers/interconnect/qcom/sm6115.c
drivers/interconnect/qcom/sm7150.c [new file with mode: 0644]
drivers/interconnect/qcom/sm7150.h [new file with mode: 0644]
drivers/interconnect/qcom/sm8250.c
drivers/interconnect/qcom/sm8550.c
drivers/interconnect/qcom/sm8550.h
drivers/interconnect/qcom/x1e80100.c
drivers/interconnect/samsung/exynos.c
drivers/iommu/dma-iommu.c
drivers/iommu/intel/Kconfig
drivers/ipack/ipack.c
drivers/irqchip/irq-renesas-rzg2l.c
drivers/mcb/mcb-core.c
drivers/md/Kconfig
drivers/md/dm-integrity.c
drivers/md/dm-snap.c
drivers/memory/tegra/mc.c
drivers/memory/tegra/tegra124-emc.c
drivers/memory/tegra/tegra124.c
drivers/memory/tegra/tegra186-emc.c
drivers/memory/tegra/tegra20-emc.c
drivers/memory/tegra/tegra20.c
drivers/memory/tegra/tegra30-emc.c
drivers/memory/tegra/tegra30.c
drivers/mfd/rave-sp.c
drivers/misc/atmel-ssc.c
drivers/misc/cxl/of.c
drivers/misc/eeprom/eeprom_93xx46.c
drivers/misc/eeprom/idt_89hpesx.c
drivers/misc/fastrpc.c
drivers/misc/hi6421v600-irq.c
drivers/misc/hisi_hikey_usb.c
drivers/misc/hpilo.c
drivers/misc/lkdtm/bugs.c
drivers/misc/mei/gsc-me.c
drivers/misc/mei/hdcp/Kconfig
drivers/misc/mei/hdcp/mei_hdcp.c
drivers/misc/mei/pci-me.c
drivers/misc/mei/pci-txe.c
drivers/misc/mei/platform-vsc.c
drivers/misc/mei/pxp/Kconfig
drivers/misc/mei/pxp/mei_pxp.c
drivers/misc/mei/vsc-tp.c
drivers/misc/open-dice.c
drivers/misc/sram.c
drivers/misc/ti-st/st_kim.c
drivers/misc/tifm_core.c
drivers/misc/vcpu_stall_detector.c
drivers/misc/xilinx_sdfec.c
drivers/misc/xilinx_tmr_inject.c
drivers/most/core.c
drivers/mtd/ubi/Kconfig
drivers/mtd/ubi/Makefile
drivers/mtd/ubi/block.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/fastmap.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/nvmem.c [new file with mode: 0644]
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/net/can/kvaser_pciefd.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic.h
drivers/net/ethernet/broadcom/cnic_if.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h
drivers/net/ethernet/intel/ice/ice_base.c
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_ddp.c
drivers/net/ethernet/intel/ice/ice_lag.c
drivers/net/ethernet/intel/ice/ice_sched.c
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/mbox.c
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c
drivers/net/ethernet/marvell/octeontx2/af/rvu.c
drivers/net/ethernet/marvell/octeontx2/af/rvu.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_ppe.c
drivers/net/ethernet/qualcomm/qca_uart.c
drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
drivers/net/phy/phy_device.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_xdp.c
drivers/net/wan/fsl_qmc_hdlc.c
drivers/net/wireguard/device.c
drivers/net/wireguard/netlink.c
drivers/net/wireguard/receive.c
drivers/nfc/pn533/uart.c
drivers/nfc/s3fwrn5/uart.c
drivers/nvme/host/apple.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/pci.c
drivers/nvme/host/pr.c
drivers/nvme/host/sysfs.c
drivers/nvme/host/tcp.c
drivers/nvme/host/trace.c
drivers/nvme/target/rdma.c
drivers/nvme/target/tcp.c
drivers/nvme/target/trace.c
drivers/nvmem/core.c
drivers/nvmem/layouts.c
drivers/nvmem/meson-efuse.c
drivers/nvmem/mtk-efuse.c
drivers/nvmem/zynqmp_nvmem.c
drivers/of/property.c
drivers/parport/parport_amiga.c
drivers/parport/parport_sunbpp.c
drivers/perf/Kconfig
drivers/perf/riscv_pmu_sbi.c
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/phy-core.c
drivers/phy/realtek/Kconfig [new file with mode: 0644]
drivers/phy/realtek/Makefile [new file with mode: 0644]
drivers/phy/realtek/phy-rtk-usb2.c [new file with mode: 0644]
drivers/phy/realtek/phy-rtk-usb3.c [new file with mode: 0644]
drivers/phy/tegra/xusb.c
drivers/platform/chrome/cros_ec_typec.c
drivers/platform/chrome/cros_ec_uart.c
drivers/platform/goldfish/Kconfig
drivers/platform/surface/aggregator/core.c
drivers/powercap/intel_rapl_msr.c
drivers/pps/generators/Makefile
drivers/regulator/core.c
drivers/remoteproc/imx_dsp_rproc.c
drivers/remoteproc/imx_rproc.c
drivers/remoteproc/qcom_q6v5_adsp.c
drivers/remoteproc/qcom_q6v5_mss.c
drivers/remoteproc/qcom_q6v5_pas.c
drivers/remoteproc/qcom_q6v5_wcss.c
drivers/remoteproc/qcom_wcnss.c
drivers/remoteproc/remoteproc_core.c
drivers/remoteproc/remoteproc_virtio.c
drivers/remoteproc/st_remoteproc.c
drivers/remoteproc/stm32_rproc.c
drivers/remoteproc/ti_k3_dsp_remoteproc.c
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/core.c
drivers/reset/reset-gpio.c [new file with mode: 0644]
drivers/reset/reset-simple.c
drivers/rpmsg/rpmsg_char.c
drivers/rpmsg/rpmsg_core.c
drivers/rpmsg/rpmsg_ctrl.c
drivers/rtc/Kconfig
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-max31335.c
drivers/rtc/rtc-nct3018y.c
drivers/rtc/rtc-pcf8523.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dcssblk.c
drivers/s390/block/scm_blk.c
drivers/s390/char/con3215.c
drivers/s390/char/fs3270.c
drivers/s390/char/raw3270.c
drivers/s390/char/raw3270.h
drivers/s390/char/tape.h
drivers/s390/char/tape_class.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_id.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/device_pgid.c
drivers/s390/cio/device_status.c
drivers/s390/cio/eadm_sch.c
drivers/s390/cio/fcx.c
drivers/s390/cio/orb.h
drivers/s390/cio/qdio_main.c
drivers/s390/cio/qdio_setup.c
drivers/s390/cio/qdio_thinint.c
drivers/s390/cio/vfio_ccw_cp.c
drivers/s390/cio/vfio_ccw_fsm.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/net/ctcm_fsms.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/ctcm_mpc.c
drivers/s390/net/lcs.c
drivers/s390/net/qeth_core_main.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_qdio.h
drivers/s390/virtio/virtio_ccw.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_proto_test.c [new file with mode: 0644]
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sd.h
drivers/sh/intc/core.c
drivers/sh/intc/internals.h
drivers/siox/siox-bus-gpio.c
drivers/siox/siox-core.c
drivers/siox/siox.h
drivers/slimbus/core.c
drivers/slimbus/qcom-ngd-ctrl.c
drivers/soc/fsl/dpio/dpio-service.c
drivers/soc/fsl/qbman/qman.c
drivers/soc/sunxi/sunxi_sram.c
drivers/spi/spi-fsl-lpspi.c
drivers/spi/spi-imx.c
drivers/spi/spi-lm70llp.c
drivers/spi/spi-mem.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/axis-fifo/axis-fifo.c
drivers/staging/board/Kconfig [deleted file]
drivers/staging/board/Makefile [deleted file]
drivers/staging/board/TODO [deleted file]
drivers/staging/board/armadillo800eva.c [deleted file]
drivers/staging/board/board.c [deleted file]
drivers/staging/board/board.h [deleted file]
drivers/staging/board/kzm9d.c [deleted file]
drivers/staging/emxx_udc/Kconfig [deleted file]
drivers/staging/emxx_udc/Makefile [deleted file]
drivers/staging/emxx_udc/TODO [deleted file]
drivers/staging/emxx_udc/emxx_udc.c [deleted file]
drivers/staging/emxx_udc/emxx_udc.h [deleted file]
drivers/staging/fbtft/fbtft-core.c
drivers/staging/fieldbus/anybuss/arcx-anybus.c
drivers/staging/fieldbus/anybuss/host.c
drivers/staging/fieldbus/dev_core.c
drivers/staging/gdm724x/gdm_lte.c
drivers/staging/greybus/audio_apbridgea.h
drivers/staging/greybus/audio_manager.c
drivers/staging/greybus/audio_topology.c
drivers/staging/greybus/authentication.c
drivers/staging/greybus/bootrom.c
drivers/staging/greybus/fw-download.c
drivers/staging/greybus/fw-management.c
drivers/staging/greybus/gbphy.c
drivers/staging/greybus/greybus_authentication.h
drivers/staging/greybus/greybus_firmware.h
drivers/staging/greybus/light.c
drivers/staging/greybus/loopback.c
drivers/staging/greybus/raw.c
drivers/staging/greybus/vibrator.c
drivers/staging/nvec/TODO
drivers/staging/nvec/nvec.c
drivers/staging/octeon/ethernet-mdio.c
drivers/staging/octeon/octeon-stubs.h
drivers/staging/pi433/pi433_if.c
drivers/staging/pi433/rf69.c
drivers/staging/pi433/rf69.h
drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
drivers/staging/rtl8192e/rtl8192e/rtl_core.c
drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
drivers/staging/rtl8192e/rtl819x_BAProc.c
drivers/staging/rtl8192e/rtl819x_HT.h
drivers/staging/rtl8192e/rtl819x_HTProc.c
drivers/staging/rtl8192e/rtl819x_Qos.h
drivers/staging/rtl8192e/rtl819x_TSProc.c
drivers/staging/rtl8192e/rtllib.h
drivers/staging/rtl8192e/rtllib_rx.c
drivers/staging/rtl8192e/rtllib_softmac.c
drivers/staging/rtl8192e/rtllib_softmac_wx.c
drivers/staging/rtl8192e/rtllib_tx.c
drivers/staging/rtl8192e/rtllib_wx.c
drivers/staging/rtl8723bs/core/rtw_ieee80211.c
drivers/staging/rtl8723bs/core/rtw_mlme.c
drivers/staging/rtl8723bs/core/rtw_sta_mgt.c
drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h
drivers/staging/vme_user/vme.c
drivers/staging/vme_user/vme.h
drivers/staging/vme_user/vme_tsi148.h
drivers/staging/vt6655/card.c
drivers/staging/vt6655/rxtx.h
drivers/thermal/Makefile
drivers/thermal/mediatek/auxadc_thermal.c
drivers/thermal/mediatek/lvts_thermal.c
drivers/thermal/qoriq_thermal.c
drivers/thermal/rcar_gen3_thermal.c
drivers/thermal/st/st_thermal.h
drivers/thermal/st/st_thermal_memmap.c
drivers/thermal/sun8i_thermal.c
drivers/thermal/thermal_of.c
drivers/thunderbolt/Makefile
drivers/thunderbolt/ctl.c
drivers/thunderbolt/ctl.h
drivers/thunderbolt/domain.c
drivers/thunderbolt/icm.c
drivers/thunderbolt/lc.c
drivers/thunderbolt/nhi.c
drivers/thunderbolt/nvm.c
drivers/thunderbolt/path.c
drivers/thunderbolt/quirks.c
drivers/thunderbolt/retimer.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tb.h
drivers/thunderbolt/tb_regs.h
drivers/thunderbolt/trace.h [new file with mode: 0644]
drivers/thunderbolt/tunnel.c
drivers/thunderbolt/tunnel.h
drivers/thunderbolt/usb4.c
drivers/thunderbolt/usb4_port.c
drivers/thunderbolt/xdomain.c
drivers/tty/Kconfig
drivers/tty/amiserial.c
drivers/tty/goldfish.c
drivers/tty/hvc/hvc_iucv.c
drivers/tty/serdev/core.c
drivers/tty/serdev/serdev-ttyport.c
drivers/tty/serial/8250/8250_aspeed_vuart.c
drivers/tty/serial/8250/8250_bcm2835aux.c
drivers/tty/serial/8250/8250_bcm7271.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_exar.c
drivers/tty/serial/8250/8250_ingenic.c
drivers/tty/serial/8250/8250_lpc18xx.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_pci1xxxx.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/8250_pxa.c
drivers/tty/serial/8250/8250_tegra.c
drivers/tty/serial/8250/8250_uniphier.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/ar933x_uart.c
drivers/tty/serial/bcm63xx_uart.c
drivers/tty/serial/fsl_linflexuart.c
drivers/tty/serial/jsm/jsm_cls.c
drivers/tty/serial/lpc32xx_hs.c
drivers/tty/serial/max310x.c
drivers/tty/serial/mcf.c
drivers/tty/serial/meson_uart.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/owl-uart.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/pmac_zilog.c
drivers/tty/serial/pxa.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/rda-uart.c
drivers/tty/serial/samsung_tty.c
drivers/tty/serial/serial_base_bus.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_port.c
drivers/tty/serial/serial_txx9.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sifive.c
drivers/tty/serial/st-asc.c
drivers/tty/serial/stm32-usart.c
drivers/tty/serial/stm32-usart.h
drivers/tty/serial/sunplus-uart.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/tty_buffer.c
drivers/tty/vt/Makefile
drivers/tty/vt/selection.c
drivers/tty/vt/vt.c
drivers/tty/vt/vt_ioctl.c
drivers/uio/uio.c
drivers/uio/uio_dmem_genirq.c
drivers/uio/uio_pruss.c
drivers/usb/cdns3/drd.c
drivers/usb/core/Kconfig
drivers/usb/core/driver.c
drivers/usb/core/endpoint.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/of.c
drivers/usb/core/phy.c
drivers/usb/core/phy.h
drivers/usb/core/port.c
drivers/usb/core/sysfs.c
drivers/usb/core/usb-acpi.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-am62.c
drivers/usb/dwc3/dwc3-of-simple.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/host.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/function/uvc_video.c
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fsl_usb2_udc.h
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/gadget/udc/snps_udc_plat.c
drivers/usb/gadget/udc/tegra-xudc.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/xhci-caps.h [new file with mode: 0644]
drivers/usb/host/xhci-dbgcap.c
drivers/usb/host/xhci-dbgcap.h
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-mtk-sch.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-port.h [new file with mode: 0644]
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci-trace.h
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/image/mdc800.c
drivers/usb/misc/onboard_usb_hub.c
drivers/usb/misc/onboard_usb_hub.h
drivers/usb/mtu3/mtu3_host.c
drivers/usb/musb/musb_gadget.c
drivers/usb/phy/phy-generic.c
drivers/usb/phy/phy.c
drivers/usb/roles/class.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/keyspan.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/storage/freecom.c
drivers/usb/storage/sddr55.c
drivers/usb/typec/altmodes/displayport.c
drivers/usb/typec/bus.c
drivers/usb/typec/class.c
drivers/usb/typec/class.h
drivers/usb/typec/mux.c
drivers/usb/typec/mux/Kconfig
drivers/usb/typec/mux/Makefile
drivers/usb/typec/mux/it5205.c [new file with mode: 0644]
drivers/usb/typec/pd.c
drivers/usb/typec/retimer.c
drivers/usb/typec/tcpm/fusb302.c
drivers/usb/typec/tcpm/qcom/Makefile
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h [new file with mode: 0644]
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c [new file with mode: 0644]
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c
drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h
drivers/usb/typec/tcpm/tcpci.c
drivers/usb/typec/tcpm/tcpci_maxim.h
drivers/usb/typec/tcpm/tcpci_maxim_core.c
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/tcpm/wcove.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h
drivers/usb/typec/ucsi/ucsi_ccg.c
drivers/usb/typec/ucsi/ucsi_glink.c
drivers/vdpa/alibaba/eni_vdpa.c
drivers/vdpa/ifcvf/ifcvf_base.c
drivers/vdpa/ifcvf/ifcvf_base.h
drivers/vdpa/ifcvf/ifcvf_main.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/pds/aux_drv.c
drivers/vdpa/pds/vdpa_dev.c
drivers/vdpa/pds/vdpa_dev.h
drivers/vdpa/vdpa.c
drivers/vdpa/vdpa_sim/vdpa_sim.c
drivers/vdpa/vdpa_user/iova_domain.c
drivers/vdpa/vdpa_user/iova_domain.h
drivers/vdpa/vdpa_user/vduse_dev.c
drivers/vdpa/virtio_pci/vp_vdpa.c
drivers/vhost/net.c
drivers/vhost/vdpa.c
drivers/video/console/dummycon.c
drivers/video/console/mdacon.c
drivers/video/console/newport_con.c
drivers/video/console/sticon.c
drivers/video/console/vgacon.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/arkfb.c
drivers/video/fbdev/core/bitblit.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbcon.h
drivers/video/fbdev/core/fbcon_ccw.c
drivers/video/fbdev/core/fbcon_cw.c
drivers/video/fbdev/core/fbcon_ud.c
drivers/video/fbdev/core/fbmem.c
drivers/video/fbdev/core/fbmon.c
drivers/video/fbdev/core/svgalib.c
drivers/video/fbdev/core/tileblit.c
drivers/video/fbdev/mb862xx/mb862xxfbdrv.c
drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td043mtea1.c
drivers/video/fbdev/s3fb.c
drivers/video/fbdev/tgafb.c
drivers/video/fbdev/uvesafb.c
drivers/video/fbdev/vga16fb.c
drivers/video/fbdev/via/accel.c
drivers/video/fbdev/vt8623fb.c
drivers/video/sticore.c
drivers/virtio/virtio.c
drivers/virtio/virtio_ring.c
drivers/virtio/virtio_vdpa.c
drivers/w1/masters/Kconfig
drivers/w1/masters/Makefile
drivers/w1/masters/mxc_w1.c
drivers/w1/masters/omap_hdq.c
drivers/w1/masters/sgi_w1.c
drivers/w1/masters/w1-gpio.c
drivers/w1/masters/w1-uart.c [new file with mode: 0644]
drivers/w1/w1.c
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/evtchn.c
drivers/xen/grant-dma-iommu.c
fs/afs/dir.c
fs/afs/rotate.c
fs/afs/validation.c
fs/bcachefs/alloc_background.c
fs/bcachefs/alloc_foreground.c
fs/bcachefs/bcachefs.h
fs/bcachefs/btree_gc.c
fs/bcachefs/btree_io.c
fs/bcachefs/btree_key_cache.c
fs/bcachefs/btree_update_interior.c
fs/bcachefs/btree_update_interior.h
fs/bcachefs/btree_write_buffer.c
fs/bcachefs/buckets.c
fs/bcachefs/debug.c
fs/bcachefs/ec.c
fs/bcachefs/error.h
fs/bcachefs/extents.h
fs/bcachefs/fs.c
fs/bcachefs/fsck.c
fs/bcachefs/journal.c
fs/bcachefs/journal_io.c
fs/bcachefs/logged_ops.c
fs/bcachefs/movinggc.c
fs/bcachefs/recovery.c
fs/bcachefs/recovery_types.h
fs/bcachefs/snapshot.c
fs/bcachefs/super-io.c
fs/bcachefs/super.c
fs/bcachefs/util.h
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/file.c
fs/debugfs/inode.c
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/user.c
fs/exfat/dir.c
fs/exfat/exfat_fs.h
fs/exfat/inode.c
fs/exfat/namei.c
fs/f2fs/checkpoint.c
fs/f2fs/compress.c
fs/f2fs/data.c
fs/f2fs/debug.c
fs/f2fs/dir.c
fs/f2fs/extent_cache.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/gc.h
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/node.h
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/sysfs.c
fs/f2fs/verity.c
fs/kernfs/dir.c
fs/kernfs/file.c
fs/kernfs/kernfs-internal.h
fs/netfs/fscache_io.c
fs/nfsd/trace.h
fs/orangefs/orangefs-cache.c
fs/orangefs/orangefs-kernel.h
fs/orangefs/super.c
fs/overlayfs/copy_up.c
fs/smb/client/cached_dir.c
fs/smb/client/cifsfs.c
fs/smb/client/cifsglob.h
fs/smb/client/connect.c
fs/smb/client/file.c
fs/smb/client/inode.c
fs/smb/client/misc.c
fs/smb/client/sess.c
fs/smb/client/smb2ops.c
fs/smb/client/smb2pdu.c
fs/smb/common/smb2pdu.h
fs/smb/server/glob.h
fs/smb/server/ksmbd_netlink.h
fs/smb/server/mgmt/user_session.c
fs/smb/server/mgmt/user_session.h
fs/smb/server/oplock.c
fs/smb/server/oplock.h
fs/smb/server/server.c
fs/smb/server/smb2misc.c
fs/smb/server/smb2ops.c
fs/smb/server/smb2pdu.c
fs/smb/server/smb2pdu.h
fs/smb/server/smb_common.c
fs/smb/server/vfs.c
fs/smb/server/vfs_cache.c
fs/smb/server/vfs_cache.h
fs/super.c
fs/sysfs/group.c
fs/tracefs/event_inode.c
fs/tracefs/internal.h
fs/ubifs/debug.c
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/find.c
fs/ubifs/journal.c
fs/ubifs/lprops.c
fs/ubifs/lpt_commit.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/tnc_misc.c
fs/ubifs/ubifs.h
fs/xfs/xfs_buf_mem.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_trace.h
include/asm-generic/bitops/__ffs.h
include/asm-generic/bitops/__fls.h
include/asm-generic/bitops/ffs.h
include/asm-generic/bitops/fls.h
include/asm-generic/hyperv-tlfs.h
include/asm-generic/mshyperv.h
include/drm/drm_bridge.h
include/drm/drm_fixed.h
include/drm/drm_modeset_helper_vtables.h
include/dt-bindings/interconnect/qcom,msm8909.h [new file with mode: 0644]
include/dt-bindings/interconnect/qcom,sm7150-rpmh.h [new file with mode: 0644]
include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h
include/dt-bindings/reset/sophgo,sg2042-reset.h [new file with mode: 0644]
include/linux/bitmap.h
include/linux/blkdev.h
include/linux/cdx/cdx_bus.h
include/linux/clk/ti.h
include/linux/compiler.h
include/linux/compiler_types.h
include/linux/console.h
include/linux/console_struct.h
include/linux/coresight.h
include/linux/cpu.h
include/linux/cpufreq.h
include/linux/crash_core.h
include/linux/dio.h
include/linux/f2fs_fs.h
include/linux/fb.h
include/linux/find.h
include/linux/firmware.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/font.h
include/linux/ftrace.h
include/linux/fwnode.h
include/linux/greybus.h
include/linux/greybus/greybus_protocols.h
include/linux/hid-sensor-ids.h
include/linux/iio/adc/adi-axi-adc.h [deleted file]
include/linux/iio/backend.h [new file with mode: 0644]
include/linux/iio/buffer-dmaengine.h
include/linux/iio/iio.h
include/linux/interconnect-provider.h
include/linux/kernel.h
include/linux/kernfs.h
include/linux/kobject.h
include/linux/mhi.h
include/linux/mm.h
include/linux/mtd/ubi.h
include/linux/netdevice.h
include/linux/of.h
include/linux/overflow.h
include/linux/phy/phy.h
include/linux/phy/tegra/xusb.h
include/linux/property.h
include/linux/rcupdate.h
include/linux/reset-controller.h
include/linux/rtc.h
include/linux/selection.h
include/linux/serdev.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/slimbus.h
include/linux/soc/qcom/geni-se.h
include/linux/socket.h
include/linux/sync_core.h
include/linux/sysfs.h
include/linux/thunderbolt.h
include/linux/trace_events.h
include/linux/tracepoint.h
include/linux/tty.h
include/linux/uio_driver.h
include/linux/usb/audio-v2.h
include/linux/usb/gadget.h
include/linux/usb/of.h
include/linux/usb/pd.h
include/linux/usb/pd_vdo.h
include/linux/usb/tcpci.h
include/linux/usb/tcpm.h
include/linux/usb/typec.h
include/linux/usb/typec_altmode.h
include/linux/usb/typec_dp.h
include/linux/usb/typec_tbt.h
include/linux/vdpa.h
include/linux/vt_kern.h
include/net/iucv/iucv.h
include/net/request_sock.h
include/rdma/ib_verbs.h
include/rdma/uverbs_ioctl.h
include/scsi/scsi_device.h
include/scsi/scsi_proto.h
include/soc/tegra/mc.h
include/trace/events/sunrpc.h
include/trace/stages/stage2_data_offsets.h
include/trace/stages/stage5_get_offsets.h
include/trace/stages/stage6_event_callback.h
include/uapi/linux/fb.h
include/uapi/linux/usb/ch9.h
include/uapi/linux/usb/functionfs.h
include/uapi/linux/user_events.h
include/uapi/linux/vdpa.h
include/uapi/linux/vesa.h [new file with mode: 0644]
include/uapi/linux/vhost.h
include/uapi/linux/virtio_pci.h
include/uapi/rdma/hns-abi.h
init/Kconfig
io_uring/futex.c
io_uring/io_uring.c
io_uring/kbuf.c
io_uring/kbuf.h
io_uring/net.c
io_uring/poll.c
io_uring/rw.c
io_uring/sqpoll.c
io_uring/waitid.c
ipc/ipc_sysctl.c
kernel/bpf/cpumap.c
kernel/dma/swiotlb.c
kernel/entry/common.c
kernel/ksysfs.c
kernel/module/Kconfig
kernel/power/energy_model.c
kernel/power/suspend_test.c
kernel/printk/printk.c
kernel/sched/core.c
kernel/sched/membarrier.c
kernel/sysctl.c
kernel/time/alarmtimer.c
kernel/time/timer.c
kernel/time/timer_migration.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_benchmark.c
kernel/trace/trace_events_trigger.c
kernel/trace/trace_events_user.c
kernel/trace/trace_sched_switch.c
kernel/trace/trace_selftest.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Kconfig.kgdb
lib/Kconfig.ubsan
lib/fonts/fonts.c
lib/kobject_uevent.c
lib/memcpy_kunit.c
lib/overflow_kunit.c
mm/Kconfig
mm/mmap.c
net/core/dev.c
net/dccp/ccids/Kconfig
net/devlink/netlink.c
net/devlink/port.c
net/hsr/hsr_framereg.c
net/hsr/hsr_main.c
net/ipv4/esp4.c
net/ipv4/inet_hashtables.c
net/ipv4/inet_timewait_sock.c
net/ipv4/ip_output.c
net/ipv4/raw.c
net/ipv4/syncookies.c
net/ipv4/tcp_minisocks.c
net/ipv6/esp6.c
net/ipv6/ip6_output.c
net/ipv6/raw.c
net/ipv6/syncookies.c
net/iucv/af_iucv.c
net/iucv/iucv.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_pipapo.c
net/packet/af_packet.c
net/rds/send.c
net/rxrpc/sendmsg.c
net/rxrpc/txbuf.c
net/sched/sch_fq_pie.c
net/sched/sch_taprio.c
net/socket.c
net/xfrm/xfrm_device.c
rust/Makefile
samples/trace_events/trace-events-sample.h
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.build
scripts/Makefile.dtbinst
scripts/Makefile.extrawarn
scripts/Makefile.lib
scripts/Makefile.package
scripts/check-sysctl-docs
scripts/coccinelle/api/device_attr_show.cocci
scripts/kconfig/array_size.h [new file with mode: 0644]
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/hashtable.h [new file with mode: 0644]
scripts/kconfig/internal.h
scripts/kconfig/lexer.l
scripts/kconfig/list.h
scripts/kconfig/list_types.h [new file with mode: 0644]
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/lxdialog/checklist.c
scripts/kconfig/lxdialog/dialog.h
scripts/kconfig/lxdialog/util.c
scripts/kconfig/mconf.c
scripts/kconfig/menu.c
scripts/kconfig/nconf.c
scripts/kconfig/parser.y
scripts/kconfig/preprocess.c
scripts/kconfig/preprocess.h [new file with mode: 0644]
scripts/kconfig/qconf.cc
scripts/kconfig/symbol.c
scripts/kconfig/tests/choice_randomize/Kconfig [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize/__init__.py [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize/expected_config0 [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize/expected_config1 [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize/expected_config2 [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize2/Kconfig [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize2/__init__.py [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize2/expected_config0 [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize2/expected_config1 [new file with mode: 0644]
scripts/kconfig/tests/choice_randomize2/expected_config2 [new file with mode: 0644]
scripts/kconfig/tests/conftest.py
scripts/kconfig/tests/err_recursive_dep/expected_stderr
scripts/kconfig/util.c
scripts/mod/modpost.c
scripts/package/builddeb
scripts/package/debian/rules
scripts/package/kernel.spec
sound/core/control.c
sound/drivers/serial-generic.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/amd/yc/pci-acp6x.c
sound/soc/codecs/tlv320adc3xxx.c
sound/soc/rockchip/rockchip_i2s_tdm.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/sof/amd/acp-loader.c
sound/soc/sof/amd/acp.c
sound/soc/sof/amd/acp.h
sound/soc/sof/amd/vangogh.c
tools/arch/loongarch/include/asm/inst.h [new file with mode: 0644]
tools/arch/loongarch/include/asm/orc_types.h [new file with mode: 0644]
tools/iio/iio_utils.c
tools/include/linux/bitops.h
tools/lib/bpf/Makefile
tools/net/ynl/Makefile.deps
tools/objtool/Makefile
tools/objtool/arch/loongarch/Build [new file with mode: 0644]
tools/objtool/arch/loongarch/decode.c [new file with mode: 0644]
tools/objtool/arch/loongarch/include/arch/cfi_regs.h [new file with mode: 0644]
tools/objtool/arch/loongarch/include/arch/elf.h [new file with mode: 0644]
tools/objtool/arch/loongarch/include/arch/special.h [new file with mode: 0644]
tools/objtool/arch/loongarch/orc.c [new file with mode: 0644]
tools/objtool/arch/loongarch/special.c [new file with mode: 0644]
tools/objtool/arch/x86/Build
tools/objtool/arch/x86/orc.c [new file with mode: 0644]
tools/objtool/check.c
tools/objtool/include/objtool/elf.h
tools/objtool/include/objtool/orc.h [new file with mode: 0644]
tools/objtool/orc_dump.c
tools/objtool/orc_gen.c
tools/perf/pmu-events/arch/riscv/andes/ax45/firmware.json [new file with mode: 0644]
tools/perf/pmu-events/arch/riscv/andes/ax45/instructions.json [new file with mode: 0644]
tools/perf/pmu-events/arch/riscv/andes/ax45/memory.json [new file with mode: 0644]
tools/perf/pmu-events/arch/riscv/andes/ax45/microarch.json [new file with mode: 0644]
tools/perf/pmu-events/arch/riscv/mapfile.csv
tools/perf/trace/beauty/include/linux/socket.h
tools/testing/ktest/ktest.pl
tools/testing/selftests/Makefile
tools/testing/selftests/devices/Makefile [new file with mode: 0644]
tools/testing/selftests/devices/boards/Dell Inc.,XPS 13 9300.yaml [new file with mode: 0644]
tools/testing/selftests/devices/boards/google,spherion.yaml [new file with mode: 0644]
tools/testing/selftests/devices/ksft.py [new file with mode: 0644]
tools/testing/selftests/devices/test_discoverable_devices.py [new file with mode: 0755]
tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh
tools/testing/selftests/net/forwarding/vxlan_bridge_1q_ipv6.sh
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/veth.sh
tools/testing/selftests/riscv/mm/mmap_bottomup.c
tools/testing/selftests/riscv/mm/mmap_default.c
tools/testing/selftests/riscv/mm/mmap_test.h
tools/testing/selftests/user_events/abi_test.c
tools/testing/selftests/wireguard/qemu/arch/riscv32.config
tools/testing/selftests/wireguard/qemu/arch/riscv64.config
tools/tracing/latency/.gitignore
tools/tracing/latency/Build [new file with mode: 0644]
tools/tracing/latency/Makefile
tools/tracing/latency/Makefile.config [new file with mode: 0644]
tools/tracing/rtla/.gitignore
tools/tracing/rtla/Build [new file with mode: 0644]
tools/tracing/rtla/Makefile
tools/tracing/rtla/Makefile.config [new file with mode: 0644]
tools/tracing/rtla/Makefile.rtla [new file with mode: 0644]
tools/tracing/rtla/Makefile.standalone [new file with mode: 0644]
tools/tracing/rtla/sample/timerlat_load.py [new file with mode: 0644]
tools/tracing/rtla/src/Build [new file with mode: 0644]
tools/tracing/rtla/src/timerlat_hist.c
tools/tracing/rtla/src/timerlat_top.c
tools/verification/rv/.gitignore [new file with mode: 0644]
tools/verification/rv/Build [new file with mode: 0644]
tools/verification/rv/Makefile
tools/verification/rv/Makefile.config [new file with mode: 0644]
tools/verification/rv/Makefile.rv [new file with mode: 0644]
tools/verification/rv/src/Build [new file with mode: 0644]

index 689a4fa3f5477aa0fd46997eca5ee7a29cd78f8a..c59dc60ba62ef082cd027bb0a2f0d74cfebb7d71 100644 (file)
@@ -52,6 +52,7 @@
 *.xz
 *.zst
 Module.symvers
+dtbs-list
 modules.order
 
 #
index e90797de3256a3fc5af06a004b6c28a06ff92ad0..2216b5d5c84e44ccb1ea8d99ec7e4ba4fa059f08 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -439,6 +439,8 @@ Mukesh Ojha <quic_mojha@quicinc.com> <mojha@codeaurora.org>
 Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org>
 Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org>
 Mythri P K <mythripk@ti.com>
+Nadav Amit <nadav.amit@gmail.com> <namit@vmware.com>
+Nadav Amit <nadav.amit@gmail.com> <namit@cs.technion.ac.il>
 Nadia Yvette Chambers <nyc@holomorphy.com> William Lee Irwin III <wli@holomorphy.com>
 Naoya Horiguchi <naoya.horiguchi@nec.com> <n-horiguchi@ah.jp.nec.com>
 Nathan Chancellor <nathan@kernel.org> <natechancellor@gmail.com>
index e39b27653c65c15f4911db846c7ca98859bf0463..bf8936ff6d38c3b27ef055af4cf4bbe0838fb31c 100644 (file)
@@ -4,6 +4,14 @@ KernelVersion: 3.13
 Description:   The purpose of this directory is to create and remove it.
 
                A corresponding USB function instance is created/removed.
-               There are no attributes here.
 
-               All parameters are set through FunctionFS.
+               All attributes are read only:
+
+               =============   ============================================
+               ready           1 if the function is ready to be used, E.G.
+                               if userspace has written descriptors and
+                               strings to ep0, so the gadget can be
+                               enabled - 0 otherwise.
+               =============   ============================================
+
+               All other parameters are set through FunctionFS.
index 4dd49b159543b6a60a0e76170eb9a592c3410b1f..b4d0fc8d319df77bed0ff2ff808fea5970fb5b00 100644 (file)
@@ -170,3 +170,90 @@ Contact:   Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_t
 Description:
                (RW) Set/Get the MSR(mux select register) for the DSB subunit
                TPDM.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_mode
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:   (Write) Set the data collection mode of CMB tpdm. Continuous
+               change creates CMB data set elements on every CMBCLK edge.
+               Trace-on-change creates CMB data set elements only when a new
+               data set element differs in value from the previous element
+               in a CMB data set.
+
+               Accepts only one of the 2 values -  0 or 1.
+               0 : Continuous CMB collection mode.
+               1 : Trace-on-change CMB collection mode.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpr[0:1]
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Set/Get the value of the trigger pattern for the CMB
+               subunit TPDM.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_patt/xpmr[0:1]
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Set/Get the mask of the trigger pattern for the CMB
+               subunit TPDM.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:1]
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Set/Get the value of the pattern for the CMB subunit TPDM.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:1]
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Set/Get the mask of the pattern for the CMB subunit TPDM.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_patt/enable_ts
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (Write) Set the pattern timestamp of CMB tpdm. Read
+               the pattern timestamp of CMB tpdm.
+
+               Accepts only one of the 2 values -  0 or 1.
+               0 : Disable CMB pattern timestamp.
+               1 : Enable CMB pattern timestamp.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_trig_ts
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Set/Get the trigger timestamp of the CMB for tpdm.
+
+               Accepts only one of the 2 values -  0 or 1.
+               0 : Set the CMB trigger type to false
+               1 : Set the CMB trigger type to true
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_ts_all
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Read or write the status of timestamp upon all interface.
+               Only value 0 and 1  can be written to this node. Set this node to 1 to requeset
+               timestamp to all trace packet.
+               Accepts only one of the 2 values -  0 or 1.
+               0 : Disable the timestamp of all trace packets.
+               1 : Enable the timestamp of all trace packets.
+
+What:          /sys/bus/coresight/devices/<tpdm-name>/cmb_msr/msr[0:31]
+Date:          January 2024
+KernelVersion  6.9
+Contact:       Jinlong Mao (QUIC) <quic_jinlmao@quicinc.com>, Tao Zhang (QUIC) <quic_taozha@quicinc.com>
+Description:
+               (RW) Set/Get the MSR(mux select register) for the CMB subunit
+               TPDM.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934 b/Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934
new file mode 100644 (file)
index 0000000..625b7f8
--- /dev/null
@@ -0,0 +1,9 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_shunt_resistorY
+KernelVersion: 6.7
+Contact:       linux-iio@vger.kernel.org
+Description:
+               The value of the shunt resistor may be known only at runtime
+               and set by a client application. This attribute allows to
+               set its value in micro-ohms. X is the IIO index of the device.
+               Y is the channel number. The value is used to calculate
+               current, power and accumulated energy.
index 2b7108e2197756db86cfbd83aa3370457b4f4bf1..af9b653422f169f18b2db09905f3e4a659c9aa6e 100644 (file)
@@ -442,6 +442,16 @@ What:              /sys/bus/usb/devices/usbX/descriptors
 Description:
                Contains the interface descriptors, in binary.
 
+What:          /sys/bus/usb/devices/usbX/bos_descriptors
+Date:          March 2024
+Contact:       Elbert Mai <code@elbertmai.com>
+Description:
+               Binary file containing the cached binary device object store (BOS)
+               of the device. This consists of the BOS descriptor followed by the
+               set of device capability descriptors. All descriptors read from
+               this file are in bus-endian format. Note that the kernel will not
+               request the BOS from a device if its bcdUSB is less than 0x0201.
+
 What:          /sys/bus/usb/devices/usbX/idProduct
 Description:
                Product ID, in hexadecimal.
index 3b810a425a52c8c0d1d30b5af84140779fa3622c..9fab3f06679e297cd334dce5d238d6df2522dc3f 100644 (file)
@@ -19,3 +19,9 @@ Description:
                - none
                - host
                - device
+
+What:          /sys/class/usb_role/<switch>/connector
+Date:          Feb 2024
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Optional symlink to the USB Type-C connector.
index 99fa87a43926e6346aa16d63e03ab0321e4dc29b..1a4d83953379ec902c828af8f359003ff08955f0 100644 (file)
@@ -205,7 +205,7 @@ Description:        Controls the idle timing of system, if there is no FS operation
 What:          /sys/fs/f2fs/<disk>/discard_idle_interval
 Date:          September 2018
 Contact:       "Chao Yu" <yuchao0@huawei.com>
-Contact:       "Sahitya Tummala" <stummala@codeaurora.org>
+Contact:       "Sahitya Tummala" <quic_stummala@quicinc.com>
 Description:   Controls the idle timing of discard thread given
                this time interval.
                Default is 5 secs.
@@ -213,7 +213,7 @@ Description:        Controls the idle timing of discard thread given
 What:          /sys/fs/f2fs/<disk>/gc_idle_interval
 Date:          September 2018
 Contact:       "Chao Yu" <yuchao0@huawei.com>
-Contact:       "Sahitya Tummala" <stummala@codeaurora.org>
+Contact:       "Sahitya Tummala" <quic_stummala@quicinc.com>
 Description:    Controls the idle timing for gc path. Set to 5 seconds by default.
 
 What:          /sys/fs/f2fs/<disk>/iostat_enable
@@ -701,29 +701,31 @@ Description:      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
-               FAULT_PAGE_GET           0x000000008
-               FAULT_ALLOC_BIO          0x000000010 (obsolete)
-               FAULT_ALLOC_NID          0x000000020
-               FAULT_ORPHAN             0x000000040
-               FAULT_BLOCK              0x000000080
-               FAULT_DIR_DEPTH          0x000000100
-               FAULT_EVICT_INODE        0x000000200
-               FAULT_TRUNCATE           0x000000400
-               FAULT_READ_IO            0x000000800
-               FAULT_CHECKPOINT         0x000001000
-               FAULT_DISCARD            0x000002000
-               FAULT_WRITE_IO           0x000004000
-               FAULT_SLAB_ALLOC         0x000008000
-               FAULT_DQUOT_INIT         0x000010000
-               FAULT_LOCK_OP            0x000020000
-               FAULT_BLKADDR            0x000040000
-               ===================      ===========
+               ===========================      ===========
+               Type_Name                        Type_Value
+               ===========================      ===========
+               FAULT_KMALLOC                    0x000000001
+               FAULT_KVMALLOC                   0x000000002
+               FAULT_PAGE_ALLOC                 0x000000004
+               FAULT_PAGE_GET                   0x000000008
+               FAULT_ALLOC_BIO                  0x000000010 (obsolete)
+               FAULT_ALLOC_NID                  0x000000020
+               FAULT_ORPHAN                     0x000000040
+               FAULT_BLOCK                      0x000000080
+               FAULT_DIR_DEPTH                  0x000000100
+               FAULT_EVICT_INODE                0x000000200
+               FAULT_TRUNCATE                   0x000000400
+               FAULT_READ_IO                    0x000000800
+               FAULT_CHECKPOINT                 0x000001000
+               FAULT_DISCARD                    0x000002000
+               FAULT_WRITE_IO                   0x000004000
+               FAULT_SLAB_ALLOC                 0x000008000
+               FAULT_DQUOT_INIT                 0x000010000
+               FAULT_LOCK_OP                    0x000020000
+               FAULT_BLKADDR_VALIDITY           0x000040000
+               FAULT_BLKADDR_CONSISTENCE        0x000080000
+               FAULT_NO_SEGMENT                 0x000100000
+               ===========================      ===========
 
 What:          /sys/fs/f2fs/<disk>/discard_io_aware_gran
 Date:          January 2023
index 53ea62906aa5b127a5fb915eb429aca4900d5a2e..ffc6e2564dd558981dec1113f5751fb64a7a1c10 100644 (file)
@@ -28,7 +28,7 @@ Introduction
   high performance safe distributed caching (leases/oplocks), optional packet
   signing, large files, Unicode support and other internationalization
   improvements. Since both Samba server and this filesystem client support the
-  CIFS Unix extensions, and the Linux client also suppors SMB3 POSIX extensions,
+  CIFS Unix extensions, and the Linux client also supports SMB3 POSIX extensions,
   the combination can provide a reasonable alternative to other network and
   cluster file systems for fileserving in some Linux to Linux environments,
   not just in Linux to Windows (or Linux to Mac) environments.
index 62feb8f31381df4e0784518ca02f2ebba519c6e7..bb884c14b2f679dba3a36ba89755a1eca2fe6db2 100644 (file)
                        The above will cause the "foo" tracing instance to trigger
                        a snapshot at the end of boot up.
 
-       ftrace_dump_on_oops[=orig_cpu]
+       ftrace_dump_on_oops[=2(orig_cpu) | =<instance>][,<instance> |
+                         ,<instance>=2(orig_cpu)]
                        [FTRACE] will dump the trace buffers on oops.
-                       If no parameter is passed, ftrace will dump
-                       buffers of all CPUs, but if you pass orig_cpu, it will
-                       dump only the buffer of the CPU that triggered the
-                       oops.
+                       If no parameter is passed, ftrace will dump global
+                       buffers of all CPUs, if you pass 2 or orig_cpu, it
+                       will dump only the buffer of the CPU that triggered
+                       the oops, or the specific instance will be dumped if
+                       its name is passed. Multiple instance dump is also
+                       supported, and instances are separated by commas. Each
+                       instance supports only dump on CPU that triggered the
+                       oops by passing 2 or orig_cpu to it.
+
+                       ftrace_dump_on_oops=foo=orig_cpu
+
+                       The above will dump only the buffer of "foo" instance
+                       on CPU that triggered the oops.
+
+                       ftrace_dump_on_oops,foo,bar=orig_cpu
+
+                       The above will dump global buffer on all CPUs, the
+                       buffer of "foo" instance on all CPUs and the buffer
+                       of "bar" instance on CPU that triggered the oops.
 
        ftrace_filter=[function-list]
                        [FTRACE] Limit the functions traced by the function
index d8adccdae23f50fa0e72bd6f840979a326cb6740..76b246ecf21b5143417937cafc8e527de3f676fc 100644 (file)
@@ -31,7 +31,7 @@ The important bits (aka "TL;DR")
    Linux kernel regression tracking bot "regzbot" track the issue by specifying
    when the regression started like this::
 
-       #regzbot introduced v5.13..v5.14-rc1
+       #regzbot introduced: v5.13..v5.14-rc1
 
 
 All the details on Linux kernel regressions relevant for users
index a9b71190399d9e355e114706cc2d8424cf7ee076..7fd43947832f8f62206f220880f78767ea9020f1 100644 (file)
@@ -296,12 +296,30 @@ kernel panic). This will output the contents of the ftrace buffers to
 the console.  This is very useful for capturing traces that lead to
 crashes and outputting them to a serial console.
 
-= ===================================================
-0 Disabled (default).
-1 Dump buffers of all CPUs.
-2 Dump the buffer of the CPU that triggered the oops.
-= ===================================================
-
+======================= ===========================================
+0                       Disabled (default).
+1                       Dump buffers of all CPUs.
+2(orig_cpu)             Dump the buffer of the CPU that triggered the
+                        oops.
+<instance>              Dump the specific instance buffer on all CPUs.
+<instance>=2(orig_cpu)  Dump the specific instance buffer on the CPU
+                        that triggered the oops.
+======================= ===========================================
+
+Multiple instance dump is also supported, and instances are separated
+by commas. If global buffer also needs to be dumped, please specify
+the dump mode (1/2/orig_cpu) first for global buffer.
+
+So for example to dump "foo" and "bar" instance buffer on all CPUs,
+user can::
+
+  echo "foo,bar" > /proc/sys/kernel/ftrace_dump_on_oops
+
+To dump global buffer and "foo" instance buffer on all
+CPUs along with the "bar" instance buffer on CPU that triggered the
+oops, user can::
+
+  echo "1,foo,bar=2" > /proc/sys/kernel/ftrace_dump_on_oops
 
 ftrace_enabled, stack_tracer_enabled
 ====================================
index 58211840ac6ffb6f5c0e95eae67bcbd7fea08f26..d3504826f401541e1dd4946c3f6d9f55989bee46 100644 (file)
@@ -39,13 +39,13 @@ aspects, all of which might be essential in your present case.]*
 developers**, execute just the *preparations* and *segment 1*; while doing so,
 consider the newest Linux kernel you regularly use to be the 'working' kernel.
 In the following example that's assumed to be 6.0.13, which is why the sources
-of v6.0 will be used to prepare the .config file.
+of 6.0 will be used to prepare the .config file.
 
 **In case you face a regression**, follow the steps at least till the end of
 *segment 2*. Then you can submit a preliminary report -- or continue with
 *segment 3*, which describes how to perform a bisection needed for a
 full-fledged regression report. In the following example 6.0.13 is assumed to be
-the 'working' kernel and 6.1.5 to be the first 'broken', which is why v6.0
+the 'working' kernel and 6.1.5 to be the first 'broken', which is why 6.0
 will be considered the 'good' release and used to prepare the .config file.
 
 * **Preparations**: set up everything to build your own kernels::
@@ -99,7 +99,8 @@ will be considered the 'good' release and used to prepare the .config file.
        # * Note: on Arch Linux, its derivatives and a few other distributions
        #   the following commands will do nothing at all or only part of the
        #   job. See the step-by-step guide for further details.
-       command -v installkernel && sudo make modules_install install
+       sudo make modules_install
+       command -v installkernel && sudo make install
        # * Check how much space your self-built kernel actually needs, which
        #   enables you to make better estimates later:
        du -ch /boot/*$(make -s kernelrelease)* | tail -n 1
@@ -112,6 +113,7 @@ will be considered the 'good' release and used to prepare the .config file.
        #   checking if the output of the next two commands matches:
        tail -n 1 ~/kernels-built
        uname -r
+       cat /proc/sys/kernel/tainted
 
   c) Check if the problem occurs with this kernel as well.
 
@@ -230,9 +232,10 @@ developers are obliged to act upon.
  :ref:`Supplementary tasks: cleanup during and after following this guide.<introclosure_bissbs>`
 
 The steps in each segment illustrate the important aspects of the process, while
-a comprehensive reference section holds additional details. The latter sometimes
-also outlines alternative approaches, pitfalls, as well as problems that might
-occur at the particular step -- and how to get things rolling again.
+a comprehensive reference section holds additional details for almost all of the
+steps. The reference section sometimes also outlines alternative approaches,
+pitfalls, as well as problems that might occur at the particular step -- and how
+to get things rolling again.
 
 For further details on how to report Linux kernel issues or regressions check
 out Documentation/admin-guide/reporting-issues.rst, which works in conjunction
@@ -283,23 +286,23 @@ Preparations: set up everything to build your own kernels
   Do you follow this guide to verify if a bug is present in the code developers
   care for? Then consider the mainline release your 'working' kernel (the newest
   one you regularly use) is based on to be the 'good' version; if your 'working'
-  kernel for example is '6.0.11', then your 'good' kernel is 'v6.0'.
+  kernel for example is 6.0.11, then your 'good' kernel is 6.0.
 
   In case you face a regression, it depends on the version range where the
   regression was introduced:
 
   * Something which used to work in Linux 6.0 broke when switching to Linux
-    6.1-rc1? Then henceforth regard 'v6.0' as the last known 'good' version
-    and 'v6.1-rc1' as the first 'bad' one.
+    6.1-rc1? Then henceforth regard 6.0 as the last known 'good' version
+    and 6.1-rc1 as the first 'bad' one.
 
   * Some function stopped working when updating from 6.0.11 to 6.1.4? Then for
-    the time being consider 'v6.0' as the last 'good' version and 'v6.1.4' as
+    the time being consider 6.0 as the last 'good' version and 6.1.4 as
     the 'bad' one. Note, at this point it is merely assumed that 6.0 is fine;
     this assumption will be checked in segment 2.
 
   * A feature you used in 6.0.11 does not work at all or worse in 6.1.13? In
     that case you want to bisect within a stable/longterm series: consider
-    'v6.0.11' as the last known 'good' version and 'v6.0.13' as the first 'bad'
+    6.0.11 as the last known 'good' version and 6.0.13 as the first 'bad'
     one. Note, in this case you still want to compile and test a mainline kernel
     as explained in segment 1: the outcome will determine if you need to report
     your issue to the regular developers or the stable team.
@@ -349,7 +352,7 @@ Preparations: set up everything to build your own kernels
   internet connections.*
 
   Execute the following command to retrieve a fresh mainline codebase while
-  preparing things to add stable/longterm branches later::
+  preparing things to add branches for stable/longterm series later::
 
     git clone -o mainline --no-checkout \
       https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ~/linux/
@@ -368,14 +371,19 @@ Preparations: set up everything to build your own kernels
   identifier using ``uname -r``.
 
   Afterwards check out the source code for the version earlier established as
-  'good' (in this example this is assumed to be 6.0) and create a .config file::
+  'good'. In the following example command this is assumed to be 6.0; note that
+  the version number in this and all later Git commands needs to be prefixed
+  with a 'v'::
 
     git checkout --detach v6.0
+
+  Now create a build configuration file::
+
     make olddefconfig
 
-  The second command will try to locate the build configuration file for the
-  running kernel and then adjust it for the needs of the kernel sources you
-  checked out. While doing so, it will print a few lines you need to check.
+  The kernel build scripts then will try to locate the build configuration file
+  for the running kernel and then adjust it for the needs of the kernel sources
+  you checked out. While doing so, it will print a few lines you need to check.
 
   Look out for a line starting with '# using defaults found in'. It should be
   followed by a path to a file in '/boot/' that contains the release identifier
@@ -520,44 +528,32 @@ be a waste of time. [:ref:`details<introlatestcheck_bisref>`]
 
 * Install your newly built kernel.
 
-  Before doing so, consider checking if there is still enough room for it::
+  Before doing so, consider checking if there is still enough space for it::
 
     df -h /boot/ /lib/modules/
 
-  150 MByte in /boot/ and 200 in /lib/modules/ usually suffice. Those are rough
-  estimates assuming the worst case. How much your kernels actually require will
-  be determined later.
-
-  Now install the kernel, which will be saved in parallel to the kernels from
-  your Linux distribution::
-
-    command -v installkernel && sudo make modules_install install
+  For now assume 150 MByte in /boot/ and 200 in /lib/modules/ will suffice; how
+  much your kernels actually require will be determined later during this guide.
 
-  On many commodity Linux distributions this will take care of everything
-  required to boot your kernel. You might want to ensure that's the case by
-  checking if your boot loader's configuration was updated; furthermore ensure
-  an initramfs (also known as initrd) exists, which on many distributions can be
-  achieved by running ``ls -l /boot/init*$(make -s kernelrelease)*``. Those
-  steps are recommended, as there are quite a few Linux distribution where above
-  command is insufficient:
+  Now install the kernel's modules and its image, which will be stored in
+  parallel to the your Linux distribution's kernels::
 
-  * On Arch Linux, its derivatives, many immutable Linux distributions, and a
-    few others the above command does nothing at, as they lack 'installkernel'
-    executable.
+    sudo make modules_install
+    command -v installkernel && sudo make install
 
-  * Some distributions install the kernel, but don't add an entry for your
-    kernel in your boot loader's configuration -- the kernel thus won't show up
-    in the boot menu.
+  The second command ideally will take care of three steps required at this
+  point: copying the kernel's image to /boot/, generating an initramfs, and
+  adding an entry for both to the boot loader's configuration.
 
-  * Some distributions add a boot loader menu entry, but don't create an
-    initramfs on installation -- in that case your kernel most likely will be
-    unable to mount the root partition during bootup.
+  Sadly some distributions (among them Arch Linux, its derivatives, and many
+  immutable Linux distributions) will perform none or only some of those tasks.
+  You therefore want to check if all of them were taken care of and manually
+  perform those that were not. The reference section provides further details on
+  that; your distribution's documentation might help, too.
 
-  If any of that applies to you, see the reference section for further guidance.
-  Once you figured out what to do, consider writing down the necessary
-  installation steps: if you will build more kernels as described in
-  segment 2 and 3, you will have to execute these commands every time that
-  ``command -v installkernel [...]`` comes up again.
+  Once you figured out the steps needed at this point, consider writing them
+  down: if you will build more kernels as described in segment 2 and 3, you will
+  have to perform those again after executing ``command -v installkernel [...]``.
 
   [:ref:`details<install_bisref>`]
 
@@ -583,31 +579,40 @@ be a waste of time. [:ref:`details<introlatestcheck_bisref>`]
   Remember the identifier momentarily, as it will help you pick the right kernel
   from the boot menu upon restarting.
 
-.. _recheckbroken_bissbs:
-
-* Reboot into the kernel you just built and check if the feature that is
-  expected to be broken really is.
-
-  Start by making sure the kernel you booted is the one you just built. When
-  unsure, check if the output of these commands show the exact same release
-  identifier::
+* Reboot into your newly built kernel. To ensure your actually started the one
+  you just built, you might want to verify if the output of these commands
+  matches::
 
     tail -n 1 ~/kernels-built
     uname -r
 
- Now verify if the feature that causes trouble works with your newly built
- kernel. If things work while investigating a regression, check the reference
- section for further details.
+.. _tainted_bissbs:
+
+* Check if the kernel marked itself as 'tainted'::
+
+    cat /proc/sys/kernel/tainted
+
+  If that command does not return '0', check the reference section, as the cause
+  for this might interfere with your testing.
+
+  [:ref:`details<tainted_bisref>`]
+
+.. _recheckbroken_bissbs:
+
+* Verify if your bug occurs with the newly built kernel. If it does not, check
+  out the instructions in the reference section to ensure nothing went sideways
+  during your tests.
 
   [:ref:`details<recheckbroken_bisref>`]
 
 .. _recheckstablebroken_bissbs:
 
-* Are you facing a problem within a stable/longterm release, but failed to
-  reproduce it with the mainline kernel you just built? Then check if the latest
-  codebase for the particular series might already fix the problem. To do so,
-  add the stable series Git branch for your 'good' kernel (again, this here is
-  assumed to be 6.0) and check out the latest version::
+* Are you facing a problem within a stable/longterm series, but failed to
+  reproduce it with the mainline kernel you just built? One that according to
+  the `front page of kernel.org <https://kernel.org/>`_ is still supported? Then
+  check if the latest codebase for the particular series might already fix the
+  problem. To do so, add the stable series Git branch for your 'good' kernel
+  (again, this here is assumed to be 6.0) and check out the latest version::
 
     cd ~/linux/
     git remote set-branches --add stable linux-6.0.y
@@ -622,22 +627,26 @@ be a waste of time. [:ref:`details<introlatestcheck_bisref>`]
     make -j $(nproc --all)
     # * Check if the free space suffices holding another kernel:
     df -h /boot/ /lib/modules/
-    command -v installkernel && sudo make modules_install install
+    sudo make modules_install
+    command -v installkernel && sudo make install
     make -s kernelrelease | tee -a ~/kernels-built
     reboot
 
-  Now verify if you booted the kernel you intended to start, to then check if
-  everything works fine with this kernel::
+  Confirm you booted the kernel you intended to start and check its tainted
+  status::
 
     tail -n 1 ~/kernels-built
     uname -r
+    cat /proc/sys/kernel/tainted
+
+  Now verify if this kernel is showing the problem.
 
   [:ref:`details<recheckstablebroken_bisref>`]
 
 Do you follow this guide to verify if a problem is present in the code
 currently supported by Linux kernel developers? Then you are done at this
 point. If you later want to remove the kernel you just built, check out
-:ref:`Supplementary tasks: cleanup during and after following this guide.<introclosure_bissbs>`.
+:ref:`Supplementary tasks: cleanup during and after following this guide<introclosure_bissbs>`.
 
 In case you face a regression, move on and execute at least the next segment
 as well.
@@ -670,12 +679,13 @@ otherwise would be a waste of time. [:ref:`details<introworkingcheck_bisref>`]
     make -j $(nproc --all)
     # * Check if the free space suffices holding another kernel:
     df -h /boot/ /lib/modules/
-    command -v installkernel && sudo make modules_install install
+    sudo make modules_install
+    command -v installkernel && sudo make install
     make -s kernelrelease | tee -a ~/kernels-built
     reboot
 
   When the system booted, you may want to verify once again that the
-  kernel you started is the one you just built:
+  kernel you started is the one you just built::
 
     tail -n 1 ~/kernels-built
     uname -r
@@ -698,7 +708,7 @@ configuration created earlier this works a lot faster than many people assume:
 overall on average it will often just take about 10 to 15 minutes to compile
 each kernel on commodity x86 machines.
 
-* In case your 'bad' version is a stable/longterm release (say v6.1.5), add its
+* In case your 'bad' version is a stable/longterm release (say 6.1.5), add its
   stable branch, unless you already did so earlier::
 
     cd ~/linux/
@@ -727,7 +737,8 @@ each kernel on commodity x86 machines.
     make -j $(nproc --all)
     # * Check if the free space suffices holding another kernel:
     df -h /boot/ /lib/modules/
-    command -v installkernel && sudo make modules_install install
+    sudo make modules_install
+    command -v installkernel && sudo make install
     make -s kernelrelease | tee -a ~/kernels-built
     reboot
 
@@ -843,7 +854,8 @@ each kernel on commodity x86 machines.
     make -j $(nproc --all) &&
     # * Check if the free space suffices holding another kernel:
     df -h /boot/ /lib/modules/
-    command -v installkernel && sudo make modules_install install
+    sudo make modules_install
+    command -v installkernel && sudo make install
     Make -s kernelrelease | tee -a ~/kernels-built
     reboot
 
@@ -1126,12 +1138,12 @@ Git clone of Linus' mainline repository. There is nothing more to say about
 that -- but there are two alternatives ways to retrieve the sources that might
 work better for you:
 
- * If you have an unreliable internet connection, consider
-   :ref:`using a 'Git bundle'<sources_bundle_bisref>`.
+* If you have an unreliable internet connection, consider
+  :ref:`using a 'Git bundle'<sources_bundle_bisref>`.
 
- * If downloading the complete repository would take too long or requires too
-   much storage space, consider :ref:`using a 'shallow
-   clone'<sources_shallow_bisref>`.
+* If downloading the complete repository would take too long or requires too
+  much storage space, consider :ref:`using a 'shallow
+  clone'<sources_shallow_bisref>`.
 
 .. _sources_bundle_bisref:
 
@@ -1183,23 +1195,23 @@ branches as explained in the step-by-step guide.
 
 Note, shallow clones have a few peculiar characteristics:
 
- * For bisections the history needs to be deepened a few mainline versions
-   farther than it seems necessary, as explained above already. That's because
-   Git otherwise will be unable to revert or describe most of the commits within
-   a range (say v6.1..v6.2), as they are internally based on earlier kernels
-   releases (like v6.0-rc2 or 5.19-rc3).
+* For bisections the history needs to be deepened a few mainline versions
+  farther than it seems necessary, as explained above already. That's because
+  Git otherwise will be unable to revert or describe most of the commits within
+  a range (say 6.1..6.2), as they are internally based on earlier kernels
+  releases (like 6.0-rc2 or 5.19-rc3).
 
- * This document in most places uses ``git fetch`` with ``--shallow-exclude=``
-   to specify the earliest version you care about (or to be precise: its git
-   tag). You alternatively can use the parameter ``--shallow-since=`` to specify
-   an absolute (say ``'2023-07-15'``) or relative (``'12 months'``) date to
-   define the depth of the history you want to download. When using them while
-   bisecting mainline, ensure to deepen the history to at least 7 months before
-   the release of the mainline release your 'good' kernel is based on.
+* This document in most places uses ``git fetch`` with ``--shallow-exclude=``
+  to specify the earliest version you care about (or to be precise: its git
+  tag). You alternatively can use the parameter ``--shallow-since=`` to specify
+  an absolute (say ``'2023-07-15'``) or relative (``'12 months'``) date to
+  define the depth of the history you want to download. When using them while
+  bisecting mainline, ensure to deepen the history to at least 7 months before
+  the release of the mainline release your 'good' kernel is based on.
 
- * Be warned, when deepening your clone you might encounter an error like
-   'fatal: error in object: unshallow cafecaca0c0dacafecaca0c0dacafecaca0c0da'.
-   In that case run ``git repack -d`` and try again.
+* Be warned, when deepening your clone you might encounter an error like
+  'fatal: error in object: unshallow cafecaca0c0dacafecaca0c0dacafecaca0c0da'.
+  In that case run ``git repack -d`` and try again.
 
 [:ref:`back to step-by-step guide <sources_bissbs>`]
 [:ref:`back to section intro <sources_bisref>`]
@@ -1223,23 +1235,23 @@ locate the right build configuration.*
 
 Two things can easily go wrong when creating a .config file as advised:
 
- * The oldconfig target will use a .config file from your build directory, if
-   one is already present there (e.g. '~/linux/.config'). That's totally fine if
-   that's what you intend (see next step), but in all other cases you want to
-   delete it. This for example is important in case you followed this guide
-   further, but due to problems come back here to redo the configuration from
-   scratch.
+* The oldconfig target will use a .config file from your build directory, if
+  one is already present there (e.g. '~/linux/.config'). That's totally fine if
+  that's what you intend (see next step), but in all other cases you want to
+  delete it. This for example is important in case you followed this guide
+  further, but due to problems come back here to redo the configuration from
+  scratch.
 
- * Sometimes olddefconfig is unable to locate the .config file for your running
-   kernel and will use defaults, as briefly outlined in the guide. In that case
-   check if your distribution ships the configuration somewhere and manually put
-   it in the right place (e.g. '~/linux/.config') if it does. On distributions
-   where /proc/config.gz exists this can be achieved using this command::
+* Sometimes olddefconfig is unable to locate the .config file for your running
+  kernel and will use defaults, as briefly outlined in the guide. In that case
+  check if your distribution ships the configuration somewhere and manually put
+  it in the right place (e.g. '~/linux/.config') if it does. On distributions
+  where /proc/config.gz exists this can be achieved using this command::
 
-     zcat /proc/config.gz > .config
+    zcat /proc/config.gz > .config
 
-   Once you put it there, run ``make olddefconfig`` again to adjust it to the
-   needs of the kernel about to be built.
+  Once you put it there, run ``make olddefconfig`` again to adjust it to the
+  needs of the kernel about to be built.
 
 Note, the olddefconfig target will set any undefined build options to their
 default value. If you prefer to set such configuration options manually, use
@@ -1252,7 +1264,7 @@ restrictions).
 
 Occasionally odd things happen when trying to use a config file prepared for one
 kernel (say 6.1) on an older mainline release -- especially if it is much older
-(say v5.15). That's one of the reasons why the previous step in the guide told
+(say 5.15). That's one of the reasons why the previous step in the guide told
 you to boot the kernel where everything works. If you manually add a .config
 file you thus want to ensure it's from the working kernel and not from a one
 that shows the regression.
@@ -1381,16 +1393,16 @@ when following this guide on a few commodity distributions.
 
 **Debian:**
 
- * Remove a stale reference to a certificate file that would cause your build to
-   fail::
+* Remove a stale reference to a certificate file that would cause your build to
+  fail::
 
-    ./scripts/config --set-str SYSTEM_TRUSTED_KEYS ''
+   ./scripts/config --set-str SYSTEM_TRUSTED_KEYS ''
 
-   Alternatively, download the needed certificate and make that configuration
-   option point to it, as `the Debian handbook explains in more detail
-   <https://debian-handbook.info/browse/stable/sect.kernel-compilation.html>`_
-   -- or generate your own, as explained in
-   Documentation/admin-guide/module-signing.rst.
+  Alternatively, download the needed certificate and make that configuration
+  option point to it, as `the Debian handbook explains in more detail
+  <https://debian-handbook.info/browse/stable/sect.kernel-compilation.html>`_
+  -- or generate your own, as explained in
+  Documentation/admin-guide/module-signing.rst.
 
 [:ref:`back to step-by-step guide <configmods_bissbs>`]
 
@@ -1402,12 +1414,12 @@ Individual adjustments
   *If you want to influence the other aspects of the configuration, do so
   now.* [:ref:`... <configmods_bissbs>`]
 
-You at this point can use a command like ``make menuconfig`` to enable or
-disable certain features using a text-based user interface; to use a graphical
-configuration utility, call the make target ``xconfig`` or ``gconfig`` instead.
-All of them require development libraries from toolkits they are based on
-(ncurses, Qt5, Gtk2); an error message will tell you if something required is
-missing.
+At this point you can use a command like ``make menuconfig`` or ``make nconfig``
+to enable or disable certain features using a text-based user interface; to use
+a graphical configuration utility, run ``make xconfig`` instead. Both of them
+require development libraries from toolkits they are rely on (ncurses
+respectively Qt5 or Qt6); an error message will tell you if something required
+is missing.
 
 [:ref:`back to step-by-step guide <configmods_bissbs>`]
 
@@ -1484,10 +1496,10 @@ highly recommended for these reasons:
 
 .. _checkoutmaster_bisref:
 
-Checkout the latest Linux codebase
-----------------------------------
+Check out the latest Linux codebase
+-----------------------------------
 
-  *Checkout the latest Linux codebase.*
+  *Check out the latest Linux codebase.*
   [:ref:`... <introlatestcheck_bissbs>`]
 
 In case you later want to recheck if an ever newer codebase might fix the
@@ -1515,7 +1527,7 @@ When a build error occurs, it might be caused by some aspect of your machine's
 setup that often can be fixed quickly; other times though the problem lies in
 the code and can only be fixed by a developer. A close examination of the
 failure messages coupled with some research on the internet will often tell you
-which of the two it is. To perform such investigation, restart the build
+which of the two it is. To perform such investigation, restart the build
 process like this::
 
   make V=1
@@ -1538,10 +1550,10 @@ often one of the hits will provide a solution for your problem, too. If you
 do not find anything that matches your problem, try again from a different angle
 by modifying your search terms or using another line from the error messages.
 
-In the end, most trouble you are to run into has likely been encountered and
+In the end, most issues you run into have likely been encountered and
 reported by others already. That includes issues where the cause is not your
-system, but lies the code. If you run into one of those, you might thus find a
-solution (e.g. a patch) or workaround for your problem, too.
+system, but lies in the code. If you run into one of those, you might thus find a
+solution (e.g. a patch) or workaround for your issue, too.
 
 Package your kernel up
 ~~~~~~~~~~~~~~~~~~~~~~
@@ -1551,11 +1563,11 @@ The step-by-step guide uses the default make targets (e.g. 'bzImage' and
 steps of the guide then install. You instead can also directly build everything
 and directly package it up by using one of the following targets:
 
- * ``make -j $(nproc --all) bindeb-pkg`` to generate a deb package
+* ``make -j $(nproc --all) bindeb-pkg`` to generate a deb package
 
- * ``make -j $(nproc --all) binrpm-pkg`` to generate a rpm package
+* ``make -j $(nproc --all) binrpm-pkg`` to generate a rpm package
 
- * ``make -j $(nproc --all) tarbz2-pkg`` to generate a bz2 compressed tarball
+* ``make -j $(nproc --all) tarbz2-pkg`` to generate a bz2 compressed tarball
 
 This is just a selection of available make targets for this purpose, see
 ``make help`` for others. You can also use these targets after running
@@ -1580,39 +1592,38 @@ Put the kernel in place
   *Install the kernel you just built.* [:ref:`... <install_bissbs>`]
 
 What you need to do after executing the command in the step-by-step guide
-depends on the existence and the implementation of an ``installkernel``
-executable. Many commodity Linux distributions ship such a kernel installer in
-'/sbin/' that does everything needed, hence there is nothing left for you
-except rebooting. But some distributions contain an installkernel that does
-only part of the job -- and a few lack it completely and leave all the work to
-you.
-
-If ``installkernel`` is found, the kernel's build system will delegate the
-actual installation of your kernel's image and related files to this executable.
-On almost all Linux distributions it will store the image as '/boot/vmlinuz-
-<kernelrelease identifier>' and put a 'System.map-<kernelrelease
-identifier>' alongside it. Your kernel will thus be installed in parallel to any
-existing ones, unless you already have one with exactly the same release name.
-
-Installkernel on many distributions will afterwards generate an 'initramfs'
-(often also called 'initrd'), which commodity distributions rely on for booting;
-hence be sure to keep the order of the two make targets used in the step-by-step
-guide, as things will go sideways if you install your kernel's image before its
-modules. Often installkernel will then add your kernel to the bootloader
-configuration, too. You have to take care of one or both of these tasks
-yourself, if your distributions installkernel doesn't handle them.
-
-A few distributions like Arch Linux and its derivatives totally lack an
-installkernel executable. On those just install the modules using the kernel's
-build system and then install the image and the System.map file manually::
-
-   sudo make modules_install
+depends on the existence and the implementation of ``/sbin/installkernel``
+executable on your distribution.
+
+If installkernel is found, the kernel's build system will delegate the actual
+installation of your kernel image to this executable, which then performs some
+or all of these tasks:
+
+* On almost all Linux distributions installkernel will store your kernel's
+  image in /boot/, usually as '/boot/vmlinuz-<kernelrelease_id>'; often it will
+  put a 'System.map-<kernelrelease_id>' alongside it.
+
+* On most distributions installkernel will then generate an 'initramfs'
+  (sometimes also called 'initrd'), which usually are stored as
+  '/boot/initramfs-<kernelrelease_id>.img' or
+  '/boot/initrd-<kernelrelease_id>'. Commodity distributions rely on this file
+  for booting, hence ensure to execute the make target 'modules_install' first,
+  as your distribution's initramfs generator otherwise will be unable to find
+  the modules that go into the image.
+
+* On some distributions installkernel will then add an entry for your kernel
+  to your bootloader's configuration.
+
+You have to take care of some or all of the tasks yourself, if your
+distribution lacks a installkernel script or does only handle part of them.
+Consult the distribution's documentation for details. If in doubt, install the
+kernel manually::
+
    sudo install -m 0600 $(make -s image_name) /boot/vmlinuz-$(make -s kernelrelease)
    sudo install -m 0600 System.map /boot/System.map-$(make -s kernelrelease)
 
-If your distribution boots with the help of an initramfs, now generate one for
-your kernel using the tools your distribution provides for this process.
-Afterwards add your kernel to your bootloader configuration and reboot.
+Now generate your initramfs using the tools your distribution provides for this
+process. Afterwards add your kernel to your bootloader configuration and reboot.
 
 [:ref:`back to step-by-step guide <install_bissbs>`]
 
@@ -1637,20 +1648,39 @@ need to look in different places.
 
 [:ref:`back to step-by-step guide <storagespace_bissbs>`]
 
+.. _tainted_bisref:
+
+Check if your newly built kernel considers itself 'tainted'
+-----------------------------------------------------------
+
+  *Check if the kernel marked itself as 'tainted'.*
+  [:ref:`... <tainted_bissbs>`]
+
+Linux marks itself as tainted when something happens that potentially leads to
+follow-up errors that look totally unrelated. That is why developers might
+ignore or react scantly to reports from tainted kernels -- unless of course the
+kernel set the flag right when the reported bug occurred.
+
+That's why you want check why a kernel is tainted as explained in
+Documentation/admin-guide/tainted-kernels.rst; doing so is also in your own
+interest, as your testing might be flawed otherwise.
+
+[:ref:`back to step-by-step guide <tainted_bissbs>`]
+
 .. _recheckbroken_bisref:
 
-Check the kernel built from the latest codebase
------------------------------------------------
+Check the kernel built from a recent mainline codebase
+------------------------------------------------------
 
-  *Reboot into the kernel you just built and check if the feature that regressed
-  is really broken there.* [:ref:`... <recheckbroken_bissbs>`]
+  *Verify if your bug occurs with the newly built kernel.*
+  [:ref:`... <recheckbroken_bissbs>`]
 
-There are a couple of reasons why the regression you face might not show up with
-your own kernel built from the latest codebase. These are the most frequent:
+There are a couple of reasons why your bug or regression might not show up with
+the kernel you built from the latest codebase. These are the most frequent:
 
-* The cause for the regression was fixed meanwhile.
+* The bug was fixed meanwhile.
 
-* The regression with the broken kernel was caused by a change in the build
+* What you suspected to be a regression was caused by a change in the build
   configuration the provider of your kernel carried out.
 
 * Your problem might be a race condition that does not show up with your kernel;
@@ -1702,9 +1732,9 @@ it's possible that the thing that regressed might never have worked in vanilla
 builds of the 'good' version in the first place.
 
 There is a third reason for those that noticed a regression between
-stable/longterm kernels of different series (e.g. v6.0.13..v6.1.5): it will
+stable/longterm kernels of different series (e.g. 6.0.13..6.1.5): it will
 ensure the kernel version you assumed to be 'good' earlier in the process (e.g.
-v6.0) actually is working.
+6.0) actually is working.
 
 [:ref:`back to step-by-step guide <introworkingcheck_bissbs>`]
 
@@ -1720,6 +1750,9 @@ In case the feature that broke with newer kernels does not work with your first
 self-built kernel, find and resolve the cause before moving on. There are a
 multitude of reasons why this might happen. Some ideas where to look:
 
+* Check the taint status and the output of ``dmesg``, maybe something unrelated
+  went wrong.
+
 * Maybe localmodconfig did something odd and disabled the module required to
   test the feature? Then you might want to recreate a .config file based on the
   one from the last working kernel and skip trimming it down; manually disabling
@@ -1734,8 +1767,8 @@ multitude of reasons why this might happen. Some ideas where to look:
 
 Note, if you found and fixed problems with the .config file, you want to use it
 to build another kernel from the latest codebase, as your earlier tests with
-mainline and the latest version from an affected stable/longterm series most
-likely has been flawed.
+mainline and the latest version from an affected stable/longterm series were most
+likely flawed.
 
 [:ref:`back to step-by-step guide <recheckworking_bissbs>`]
 
@@ -1748,8 +1781,8 @@ Start the bisection
   'good' and 'bad'.* [:ref:`... <bisectstart_bissbs>`]
 
 This will start the bisection process; the last of the commands will make Git
-checkout a commit round about half-way between the 'good' and the 'bad' changes
-for your to test.
+check out a commit round about half-way between the 'good' and the 'bad' changes
+for you to test.
 
 [:ref:`back to step-by-step guide <bisectstart_bissbs>`]
 
@@ -1774,7 +1807,7 @@ There are two things worth of note here:
 * Those slightly odd looking version identifiers can happen during bisections,
   because the Linux kernel subsystems prepare their changes for a new mainline
   release (say 6.2) before its predecessor (e.g. 6.1) is finished. They thus
-  base them on a somewhat earlier point like v6.1-rc1 or even v6.0 -- and then
+  base them on a somewhat earlier point like 6.1-rc1 or even 6.0 -- and then
   get merged for 6.2 without rebasing nor squashing them once 6.1 is out. This
   leads to those slightly odd looking version identifiers coming up during
   bisections.
@@ -1790,7 +1823,7 @@ Bisection checkpoint
   [:ref:`... <bisecttest_bissbs>`]
 
 Ensure what you tell Git is accurate: getting it wrong just one time will bring
-the rest of the bisection totally of course, hence all testing after that point
+the rest of the bisection totally off course, hence all testing after that point
 will be for nothing.
 
 [:ref:`back to step-by-step guide <bisecttest_bissbs>`]
@@ -1811,7 +1844,7 @@ instead of testing ten or more kernels you might only have to build a few to
 resolve things.
 
 The .config file is put aside, as there is a decent chance that developers might
-ask for it after you reported the regression.
+ask for it after you report the regression.
 
 [:ref:`back to step-by-step guide <bisectlog_bissbs>`]
 
@@ -1861,7 +1894,7 @@ simply remove its modules directory in /lib/modules/.
 
 The other place is /boot/, where typically two up to five files will be placed
 during installation of a kernel. All of them usually contain the release name in
-their file name, but how many files and their exact name depends somewhat on
+their file name, but how many files and their exact names depend somewhat on
 your distribution's installkernel executable and its initramfs generator. On
 some distributions the ``kernel-install remove...`` command mentioned in the
 step-by-step guide will delete all of these files for you while also removing
index 69ff6da1dbf8f3b64898981d811326fdb2391c1d..e476b4386bd9dba3c3f59b501369e169fecc003a 100644 (file)
@@ -144,14 +144,8 @@ passing 0 into the hint address parameter of mmap. On CPUs with an address space
 smaller than sv48, the CPU maximum supported address space will be the default.
 
 Software can "opt-in" to receiving VAs from another VA space by providing
-a hint address to mmap. A hint address passed to mmap will cause the largest
-address space that fits entirely into the hint to be used, unless there is no
-space left in the address space. If there is no space available in the requested
-address space, an address in the next smallest available address space will be
-returned.
-
-For example, in order to obtain 48-bit VA space, a hint address greater than
-:code:`1 << 47` must be provided. Note that this is 47 due to sv48 userspace
-ending at :code:`1 << 47` and the addresses beyond this are reserved for the
-kernel. Similarly, to obtain 57-bit VA space addresses, a hint address greater
-than or equal to :code:`1 << 56` must be provided.
+a hint address to mmap. When a hint address is passed to mmap, the returned
+address will never use more bits than the hint address. For example, if a hint
+address of `1 << 40` is passed to mmap, a valid returned address will never use
+bits 41 through 63. If no mappable addresses are available in that range, mmap
+will return `MAP_FAILED`.
index 61ddc3b5b247b0fcde7fdb320819d1a4da5d6ce9..8eec07d9d45428560c565831ac6a9eeb00987feb 100644 (file)
@@ -44,14 +44,21 @@ properties:
     minItems: 1
     maxItems: 2
 
-  qcom,dsb-element-size:
+  qcom,dsb-element-bits:
     description:
       Specifies the DSB(Discrete Single Bit) element size supported by
       the monitor. The associated aggregator will read this size before it
       is enabled. DSB element size currently only supports 32-bit and 64-bit.
-    $ref: /schemas/types.yaml#/definitions/uint8
     enum: [32, 64]
 
+  qcom,cmb-element-bits:
+    description:
+      Specifies the CMB(Continuous Multi-Bit) element size supported by
+      the monitor. The associated aggregator will read this size before it
+      is enabled. CMB element size currently only supports 8-bit, 32-bit
+      and 64-bit.
+    enum: [8, 32, 64]
+
   qcom,dsb-msrs-num:
     description:
       Specifies the number of DSB(Discrete Single Bit) MSR(mux select register)
@@ -61,6 +68,15 @@ properties:
     minimum: 0
     maximum: 32
 
+  qcom,cmb-msrs-num:
+    description:
+      Specifies the number of CMB MSR(mux select register) registers supported
+      by the monitor. If this property is not configured or set to 0, it means
+      this TPDM doesn't support CMB MSR.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 32
+
   clocks:
     maxItems: 1
 
@@ -94,7 +110,7 @@ examples:
       compatible = "qcom,coresight-tpdm", "arm,primecell";
       reg = <0x0684c000 0x1000>;
 
-      qcom,dsb-element-size = /bits/ 8 <32>;
+      qcom,dsb-element-bits = <32>;
       qcom,dsb-msrs-num = <16>;
 
       clocks = <&aoss_qmp>;
@@ -110,4 +126,22 @@ examples:
       };
     };
 
+    tpdm@6c29000 {
+      compatible = "qcom,coresight-tpdm", "arm,primecell";
+      reg = <0x06c29000 0x1000>;
+
+      qcom,cmb-element-bits = <64>;
+      qcom,cmb-msrs-num = <32>;
+
+      clocks = <&aoss_qmp>;
+      clock-names = "apb_pclk";
+
+      out-ports {
+        port {
+          tpdm_ipcc_out_funnel_center: endpoint {
+            remote-endpoint = <&funnel_center_in_tpdm_ipcc>;
+          };
+        };
+      };
+    };
 ...
index 3aaefdbe361ebe03db169737c2281c0cfe87b76c..9017c5a3f3d20ff5cf8ede3b356b00e16e0d98a3 100644 (file)
@@ -18,6 +18,7 @@ properties:
           - const: brcm,gisb-arb
       - items:
           - enum:
+              - brcm,bcm74165-gisb-arb  # for V7 new style 16nm chips
               - brcm,bcm7278-gisb-arb  # for V7 28nm chips
               - brcm,bcm7435-gisb-arb  # for newer 40nm chips
               - brcm,bcm7400-gisb-arb  # for older 40nm chips and all 65nm chips
index 8386cfe21532e5bba9984fac2b7de37c277aa275..f0eabff863106afdaf8547fceb0126ae1147dc88 100644 (file)
@@ -270,7 +270,7 @@ examples:
 
                 port {
                     ov7251_ep: endpoint {
-                        data-lanes = <0 1>;
+                        data-lanes = <0>;
                         link-frequencies = /bits/ 64 <240000000 319200000>;
                         remote-endpoint = <&csiphy3_ep>;
                     };
index 16024415a4a74085c568c0565c7ac4ef7149a5c2..44c54b162bb10741ec7aac70d165403c28176eba 100644 (file)
@@ -14,9 +14,6 @@ description: The Nomadik I2C host controller began its life in the ST
 maintainers:
   - Linus Walleij <linus.walleij@linaro.org>
 
-allOf:
-  - $ref: /schemas/i2c/i2c-controller.yaml#
-
 # Need a custom select here or 'arm,primecell' will match on lots of nodes
 select:
   properties:
@@ -24,21 +21,23 @@ select:
       contains:
         enum:
           - st,nomadik-i2c
+          - mobileye,eyeq5-i2c
   required:
     - compatible
 
 properties:
   compatible:
     oneOf:
-      # The variant found in STn8815
       - items:
           - const: st,nomadik-i2c
           - const: arm,primecell
-      # The variant found in DB8500
       - items:
           - const: stericsson,db8500-i2c
           - const: st,nomadik-i2c
           - const: arm,primecell
+      - items:
+          - const: mobileye,eyeq5-i2c
+          - const: arm,primecell
 
   reg:
     maxItems: 1
@@ -55,7 +54,7 @@ properties:
       - items:
           - const: mclk
           - const: apb_pclk
-      # Clock name in DB8500
+      # Clock name in DB8500 or EyeQ5
       - items:
           - const: i2cclk
           - const: apb_pclk
@@ -70,6 +69,16 @@ properties:
     minimum: 1
     maximum: 400000
 
+  mobileye,olb:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - items:
+          - description: Phandle to OLB system controller node.
+          - description: Platform-wide controller ID (integer starting from zero).
+    description:
+      The phandle pointing to OLB system controller node, with the I2C
+      controller index.
+
 required:
   - compatible
   - reg
@@ -79,6 +88,20 @@ required:
 
 unevaluatedProperties: false
 
+allOf:
+  - $ref: /schemas/i2c/i2c-controller.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: mobileye,eyeq5-i2c
+    then:
+      required:
+        - mobileye,olb
+    else:
+      properties:
+        mobileye,olb: false
+
 examples:
   - |
     #include <dt-bindings/interrupt-controller/irq.h>
@@ -111,5 +134,19 @@ examples:
       clocks = <&i2c0clk>, <&pclki2c0>;
       clock-names = "mclk", "apb_pclk";
     };
+  - |
+    #include <dt-bindings/interrupt-controller/mips-gic.h>
+    i2c@300000 {
+      compatible = "mobileye,eyeq5-i2c", "arm,primecell";
+      reg = <0x300000 0x1000>;
+      interrupt-parent = <&gic>;
+      interrupts = <GIC_SHARED 1 IRQ_TYPE_LEVEL_HIGH>;
+      clock-frequency = <400000>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      clocks = <&i2c_ser_clk>, <&i2c_clk>;
+      clock-names = "i2cclk", "apb_pclk";
+      mobileye,olb = <&olb 0>;
+    };
 
 ...
index 261601729745693385dfebd2fbbab15049cc6cd8..36775f8f71dfd325fee056bbbd009f59b0376214 100644 (file)
@@ -22,7 +22,6 @@ properties:
     maxItems: 1
 
   label:
-    $ref: /schemas/types.yaml#/definitions/string
     description: Unique name to identify which channel this is.
 
   bipolar:
index 7aa748d6b7a027e4f2950b8a36ba7fde1e180a49..eecd5fbab695810bbfff243852f640f14feda001 100644 (file)
@@ -44,6 +44,9 @@ properties:
       Pin that controls the powerdown mode of the device.
     maxItems: 1
 
+  io-backends:
+    maxItems: 1
+
   reset-gpios:
     description:
       Reset pin for the device.
@@ -68,6 +71,7 @@ examples:
             reg = <0>;
             clocks = <&adc_clk>;
             clock-names = "adc-clk";
+            io-backends = <&iio_backend>;
         };
     };
 ...
index 9996dd93f84b298613880209ebacf879e81a38e4..3d49d21ad33df256f722ad0ec5203ef822910203 100644 (file)
@@ -39,12 +39,15 @@ properties:
     $ref: /schemas/types.yaml#/definitions/phandle
     description:
       A reference to a the actual ADC to which this FPGA ADC interfaces to.
+    deprecated: true
+
+  '#io-backend-cells':
+    const: 0
 
 required:
   - compatible
   - dmas
   - reg
-  - adi,adc-dev
 
 additionalProperties: false
 
@@ -55,7 +58,6 @@ examples:
         reg = <0x44a00000 0x10000>;
         dmas = <&rx_dma 0>;
         dma-names = "rx";
-
-        adi,adc-dev = <&spi_adc>;
+        #io-backend-cells = <0>;
     };
 ...
diff --git a/Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml b/Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
new file mode 100644 (file)
index 0000000..47a11a9
--- /dev/null
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/microchip,pac1934.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip PAC1934 Power Monitors with Accumulator
+
+maintainers:
+  - Marius Cristea <marius.cristea@microchip.com>
+
+description: |
+  This device is part of the Microchip family of Power Monitors with
+  Accumulator.
+  The datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here:
+    https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf
+
+properties:
+  compatible:
+    enum:
+      - microchip,pac1931
+      - microchip,pac1932
+      - microchip,pac1933
+      - microchip,pac1934
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  interrupts:
+    maxItems: 1
+
+  slow-io-gpios:
+    description:
+      A GPIO used to trigger a change is sampling rate (lowering the chip power
+      consumption). If configured in SLOW mode, if this pin is forced high,
+      sampling rate is forced to eight samples/second. When it is forced low,
+      the sampling rate is 1024 samples/second unless a different sample rate
+      has been programmed.
+
+patternProperties:
+  "^channel@[1-4]+$":
+    type: object
+    $ref: adc.yaml
+    description:
+      Represents the external channels which are connected to the ADC.
+
+    properties:
+      reg:
+        items:
+          minimum: 1
+          maximum: 4
+
+      shunt-resistor-micro-ohms:
+        description:
+          Value in micro Ohms of the shunt resistor connected between
+          the SENSE+ and SENSE- inputs, across which the current is measured.
+          Value is needed to compute the scaling of the measured current.
+
+    required:
+      - reg
+      - shunt-resistor-micro-ohms
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        power-monitor@10 {
+            compatible = "microchip,pac1934";
+            reg = <0x10>;
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            channel@1 {
+                reg = <0x1>;
+                shunt-resistor-micro-ohms = <24900000>;
+                label = "CPU";
+            };
+
+            channel@2 {
+                reg = <0x2>;
+                shunt-resistor-micro-ohms = <49900000>;
+                label = "GPU";
+            };
+
+            channel@3 {
+                reg = <0x3>;
+                shunt-resistor-micro-ohms = <75000000>;
+                label = "MEM";
+                bipolar;
+            };
+
+            channel@4 {
+                reg = <0x4>;
+                shunt-resistor-micro-ohms = <100000000>;
+                label = "NET";
+                bipolar;
+            };
+        };
+    };
+
+...
index dacc526dc6953331f08c55948361b5ec042349bd..dfc3f512918f656ee28e0639e99f83d6b6f65591 100644 (file)
@@ -31,7 +31,6 @@ properties:
       - description: normal conversion, include EOC (End of Conversion),
           ECH (End of Chain), JEOC (End of Injected Conversion) and
           JECH (End of injected Chain).
-      - description: Self-testing Interrupts.
 
   clocks:
     maxItems: 1
@@ -70,8 +69,7 @@ examples:
             reg = <0x44530000 0x10000>;
             interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
                          <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+                         <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
             clocks = <&clk IMX93_CLK_ADC1_GATE>;
             clock-names = "ipg";
             vref-supply = <&reg_vref_1v8>;
index 40fa0710f1f0f8f4c9e501e56055f1c33a3b0aed..c28db0d635a0a858072412970f3bec4d9ed73391 100644 (file)
@@ -75,7 +75,6 @@ patternProperties:
           in the PMIC-specific files in include/dt-bindings/iio/.
 
       label:
-        $ref: /schemas/types.yaml#/definitions/string
         description: |
             ADC input of the platform as seen in the schematics.
             For thermistor inputs connected to generic AMUX or GPIO inputs
index 88e008629ea89a494a2d994b5d3a9dbaf7deb71e..af2c3a67f8880e3b04f80064c3c7f83cd939ef0f 100644 (file)
@@ -25,7 +25,14 @@ description: |
 
 properties:
   compatible:
-    const: richtek,rtq6056
+    oneOf:
+      - enum:
+          - richtek,rtq6056
+          - richtek,rtq6059
+      - items:
+          - enum:
+              - richtek,rtq6053
+          - const: richtek,rtq6056
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1298.yaml
new file mode 100644 (file)
index 0000000..bf5a43a
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/ti,ads1298.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments' ads1298 medical ADC chips
+
+description: |
+  Datasheet at: https://www.ti.com/product/ADS1298
+  Bindings for this chip aren't complete.
+
+maintainers:
+  - Mike Looijmans <mike.looijmans@topic.nl>
+
+properties:
+  compatible:
+    enum:
+      - ti,ads1298
+
+  reg:
+    maxItems: 1
+
+  spi-cpha: true
+
+  reset-gpios:
+    maxItems: 1
+
+  avdd-supply:
+    description:
+      Analog power supply, voltage between AVDD and AVSS. When providing a
+      symmetric +/- 2.5V, the regulator should report 5V.
+
+  vref-supply:
+    description:
+      Optional reference voltage. If omitted, internal reference is used,
+      which is 2.4V when analog supply is below 4.4V, 4V otherwise.
+
+  clocks:
+    description: Optional 2.048 MHz external source clock on CLK pin
+    maxItems: 1
+
+  interrupts:
+    description: Interrupt on DRDY pin, triggers on falling edge
+    maxItems: 1
+
+  label: true
+
+required:
+  - compatible
+  - reg
+  - avdd-supply
+  - interrupts
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@1 {
+          reg = <1>;
+          compatible = "ti,ads1298";
+          label = "ads1298-1-ecg";
+          avdd-supply = <&reg_iso_5v_a>;
+          clocks = <&clk_ads1298>;
+          interrupt-parent = <&gpio0>;
+          interrupts = <78 IRQ_TYPE_EDGE_FALLING>;
+          spi-max-frequency = <20000000>;
+          spi-cpha;
+        };
+    };
+...
index dddf97b50549f0012697c60c484c0a2917f49c83..4151f99b42aa79e815d9e593b633a7e8ead0a194 100644 (file)
@@ -39,6 +39,17 @@ properties:
     description: |
       Channel node of a voltage io-channel.
 
+  '#io-channel-cells':
+    description:
+      In addition to consuming the measurement services of a voltage
+      output channel, the voltage divider can act as a provider of
+      measurement services to other devices. This is particularly
+      useful in scenarios wherein an ADC has an analog frontend,
+      such as a voltage divider, and then consuming its raw value
+      isn't interesting. In this case, the voltage before the divider
+      is desired.
+    const: 1
+
   output-ohms:
     description:
       Resistance Rout over which the output voltage is measured. See full-ohms.
index 67de9d4e3a1df6ca9bf90773db3c82d50a67a302..3a470459b9658b294493abaa66ffbd2bfcf00e97 100644 (file)
@@ -21,6 +21,8 @@ description: |
   HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz
     https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf
 
+  LTC6373 is a 3-Bit precision instrumentation amplifier with fully differential outputs
+    https://www.analog.com/media/en/technical-documentation/data-sheets/ltc6373.pdf
 
 properties:
   compatible:
@@ -28,16 +30,55 @@ properties:
       - adi,adrf5740
       - adi,hmc425a
       - adi,hmc540s
+      - adi,ltc6373
 
   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
+      Must contain an array of GPIO specifiers, referring to the GPIO pins
+      connected to the control pins.
+        ADRF5740  - 4 GPIO connected to D2-D5
+        HMC540S   - 4 GPIO connected to V1-V4
+        HMC425A   - 6 GPIO connected to V1-V6
+        LTC6373   - 3 GPIO connected to A0-A2
+    minItems: 1
     maxItems: 6
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: adi,hmc425a
+    then:
+      properties:
+        ctrl-gpios:
+          minItems: 6
+          maxItems: 6
+  - if:
+      properties:
+        compatible:
+          contains:
+            anyOf:
+              - const: adi,adrf5740
+              - const: adi,hmc540s
+    then:
+      properties:
+        ctrl-gpios:
+          minItems: 4
+          maxItems: 4
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: adi,ltc6373
+    then:
+      properties:
+        ctrl-gpios:
+          minItems: 3
+          maxItems: 3
+
 required:
   - compatible
   - ctrl-gpios
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml
new file mode 100644 (file)
index 0000000..2bcf4bb
--- /dev/null
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2024 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adi,admfm2000.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADMFM2000 Dual Microwave Down Converter
+
+maintainers:
+  - Kim Seer Paller <kimseer.paller@analog.com>
+
+description:
+  Dual microwave down converter module with input RF and LO frequency ranges
+  from 0.5 to 32 GHz and an output IF frequency range from 0.1 to 8 GHz.
+  It consists of a LNA, mixer, IF filter, DSA, and IF amplifier for each down
+  conversion path.
+
+properties:
+  compatible:
+    enum:
+      - adi,admfm2000
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+patternProperties:
+  "^channel@[0-1]$":
+    type: object
+    description: Represents a channel of the device.
+
+    additionalProperties: false
+
+    properties:
+      reg:
+        description:
+          The channel number.
+        minimum: 0
+        maximum: 1
+
+      adi,mixer-mode:
+        description:
+          Enable mixer mode for the channel. It downconverts RF between 5 GHz
+          and 32 GHz to IF between 0.5 GHz and 8 GHz. If not present, the channel
+          is in direct IF mode which bypasses the mixer and downconverts RF
+          between 2 GHz and 8 GHz to IF between 0.5 GHz and 8 GHz.
+        type: boolean
+
+      switch-gpios:
+        description: |
+          GPIOs to select the RF path for the channel. The same state of CTRL-A
+          and CTRL-B GPIOs is not permitted.
+          CTRL-A   CTRL-B    CH1 Status        CH2 Status
+          1        0         Direct IF mode    Mixer mode
+          0        1         Mixer mode        Direct IF mode
+
+        items:
+          - description: CTRL-A GPIO
+          - description: CTRL-B GPIO
+
+      attenuation-gpios:
+        description: |
+          Choice of attenuation:
+          DSA-V4  DSA-V3  DSA-V2  DSA-V1  DSA-V0
+          1       1       1       1       1        0 dB
+          1       1       1       1       0        -1 dB
+          1       1       1       0       1        -2 dB
+          1       1       0       1       1        -4 dB
+          1       0       1       1       1        -8 dB
+          0       1       1       1       1        -16 dB
+          0       0       0       0       0        -31 dB
+
+        items:
+          - description: DSA-V0 GPIO
+          - description: DSA-V1 GPIO
+          - description: DSA-V2 GPIO
+          - description: DSA-V3 GPIO
+          - description: DSA-V4 GPIO
+
+    required:
+      - reg
+      - switch-gpios
+      - attenuation-gpios
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    converter {
+      compatible = "adi,admfm2000";
+
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      channel@0 {
+        reg = <0>;
+        switch-gpios = <&gpio 1 GPIO_ACTIVE_LOW>,
+                       <&gpio 2 GPIO_ACTIVE_HIGH>;
+
+        attenuation-gpios = <&gpio 17 GPIO_ACTIVE_LOW>,
+                            <&gpio 22 GPIO_ACTIVE_LOW>,
+                            <&gpio 23 GPIO_ACTIVE_LOW>,
+                            <&gpio 24 GPIO_ACTIVE_LOW>,
+                            <&gpio 25 GPIO_ACTIVE_LOW>;
+      };
+
+      channel@1 {
+        reg = <1>;
+        adi,mixer-mode;
+        switch-gpios = <&gpio 3 GPIO_ACTIVE_LOW>,
+                       <&gpio 4 GPIO_ACTIVE_HIGH>;
+
+        attenuation-gpios = <&gpio 0 GPIO_ACTIVE_LOW>,
+                            <&gpio 5 GPIO_ACTIVE_LOW>,
+                            <&gpio 6 GPIO_ACTIVE_LOW>,
+                            <&gpio 16 GPIO_ACTIVE_LOW>,
+                            <&gpio 26 GPIO_ACTIVE_LOW>;
+      };
+    };
+...
index 1414ba9977c1634a8636f93d965a0852942acaac..3c6fe74af0b8357985af7cf37b930df52b19eec4 100644 (file)
@@ -22,6 +22,9 @@ properties:
   vdd-supply: true
   vddio-supply: true
 
+  spi-max-frequency:
+    maximum: 10000000
+
   interrupts:
     minItems: 1
     maxItems: 2
@@ -33,7 +36,10 @@ required:
   - compatible
   - reg
 
-additionalProperties: false
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
index 79e75a8675cba3a8f33d09f3079aa88e3a15335a..e3eca89175175437d203807370e5fb2ddee25adc 100644 (file)
@@ -27,6 +27,9 @@ properties:
   reg:
     maxItems: 1
 
+  interrupts:
+    maxItems: 1
+
 required:
   - compatible
   - reg
index 7f6d0f9edc75e3985d5c71fcc1be09bfb62e4acb..8b5dedd1a598cfb300c97e453da1765e582c3478 100644 (file)
@@ -43,6 +43,7 @@ additionalProperties: false
 
 examples:
   - |
+    #include <dt-bindings/interrupt-controller/irq.h>
     i2c {
         #address-cells = <1>;
         #size-cells = <0>;
@@ -51,5 +52,7 @@ examples:
             compatible = "ti,hdc3021", "ti,hdc3020";
             reg = <0x47>;
             vdd-supply = <&vcc_3v3>;
+            interrupt-parent = <&gpio3>;
+            interrupts = <23 IRQ_TYPE_EDGE_RISING>;
         };
     };
index 28b667a9cb76b6643df074b77861e34da8d7726c..c48a96d17f511f9f5321e3aa3099f82dad874554 100644 (file)
@@ -35,7 +35,9 @@ properties:
           - st,lsm6dsv
           - st,lsm6dso16is
       - items:
-          - const: st,asm330lhhx
+          - enum:
+              - st,asm330lhhx
+              - st,asm330lhhxg1
           - const: st,lsm6dsr
       - items:
           - const: st,lsm6dstx
index 0e8cd02759b368dfea99cca10130a9ea00044603..062a038aa0ff5256d6b95d4e58a6cae920fc4868 100644 (file)
@@ -4,19 +4,22 @@
 $id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
+title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 UV Sensor
 
 maintainers:
   - Christian Eggers <ceggers@arri.de>
 
 description: |
-  XYZ True Color Sensor with I2C Interface
+  AMS AS73211 XYZ True Color Sensor with I2C Interface
   https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df
+  AMS AS7331 UVA, UVB and UVC Sensor with I2C Interface
+  https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf
 
 properties:
   compatible:
     enum:
       - ams,as73211
+      - ams,as7331
 
   reg:
     description:
index abee04cd126e416823791ad7836aac7f002767f9..91c318746bf30aceeb79f0497169d092ea5e622f 100644 (file)
@@ -21,6 +21,7 @@ properties:
 required:
   - compatible
   - reg
+  - vdd-supply
 
 additionalProperties: false
 
diff --git a/Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml b/Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml
new file mode 100644 (file)
index 0000000..b6ab01a
--- /dev/null
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/magnetometer/voltafield,af8133j.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Voltafield AF8133J magnetometer sensor
+
+maintainers:
+  - Ondřej Jirman <megi@xff.cz>
+
+properties:
+  compatible:
+    const: voltafield,af8133j
+
+  reg:
+    maxItems: 1
+
+  reset-gpios:
+    description:
+      A signal for active low reset input of the sensor. (optional; if not
+      used, software reset over I2C will be used instead)
+
+  avdd-supply:
+    description:
+      A regulator that provides AVDD power (Working power, usually 3.3V) to
+      the sensor.
+
+  dvdd-supply:
+    description:
+      A regulator that provides DVDD power (Digital IO power, 1.8V - AVDD)
+      to the sensor.
+
+  mount-matrix:
+    description: An optional 3x3 mounting rotation matrix.
+
+required:
+  - compatible
+  - reg
+  - avdd-supply
+  - dvdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/gpio/gpio.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        magnetometer@1c {
+            compatible = "voltafield,af8133j";
+            reg = <0x1c>;
+            avdd-supply = <&reg_dldo1>;
+            dvdd-supply = <&reg_dldo1>;
+            reset-gpios = <&pio 1 1 GPIO_ACTIVE_LOW>;
+        };
+    };
index 65a24ed67b3ccd115502371db4f1deee1960bdf5..89977b9f01cfe1ef4dade090793d7058143130e6 100644 (file)
@@ -99,6 +99,9 @@ required:
   - honeywell,transfer-function
   - honeywell,pressure-triplet
 
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml
+
 additionalProperties: false
 
 dependentSchemas:
index d9e903fbfd99ea3c7666f22b3d87851a04cc1d89..6994b30015bdb69ac8e8d8cc847f93593bd029da 100644 (file)
@@ -8,25 +8,28 @@ title: Honeywell mprls0025pa pressure sensor
 
 maintainers:
   - Andreas Klinger <ak@it-klinger.de>
+  - Petre Rodan <petre.rodan@subdimension.ro>
 
 description: |
   Honeywell pressure sensor of model mprls0025pa.
 
-  This sensor has an I2C and SPI interface. Only the I2C interface is
-  implemented.
+  This sensor has an I2C and SPI interface.
 
   There are many models with different pressure ranges available. The vendor
   calls them "mpr series". All of them have the identical programming model and
   differ in the pressure range, unit and transfer function.
 
-  To support different models one need to specify the pressure range as well as
-  the transfer function. Pressure range needs to be converted from its unit to
-  pascal.
+  To support different models one need to specify its pressure triplet as well
+  as the transfer function.
+
+  For custom silicon chips not covered by the Honeywell MPR series datasheet,
+  the pressure values can be specified manually via honeywell,pmin-pascal and
+  honeywell,pmax-pascal.
+  The minimal range value stands for the minimum pressure and the maximum value
+  also for the maximum pressure with linear relation inside the range.
 
   The transfer function defines the ranges of numerical values delivered by the
-  sensor. The minimal range value stands for the minimum pressure and the
-  maximum value also for the maximum pressure with linear relation inside the
-  range.
+  sensor.
 
   Specifications about the devices can be found at:
     https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/
@@ -42,6 +45,10 @@ properties:
     maxItems: 1
 
   interrupts:
+    description:
+      Optional interrupt for indicating End-of-conversion.
+      If not present, the driver loops for a while until the received status
+      byte indicates correct measurement.
     maxItems: 1
 
   reset-gpios:
@@ -50,14 +57,6 @@ properties:
       If not present the device is not reset during the probe.
     maxItems: 1
 
-  honeywell,pmin-pascal:
-    description:
-      Minimum pressure value the sensor can measure in pascal.
-
-  honeywell,pmax-pascal:
-    description:
-      Maximum pressure value the sensor can measure in pascal.
-
   honeywell,transfer-function:
     description: |
       Transfer function which defines the range of valid values delivered by the
@@ -65,19 +64,57 @@ properties:
       1 - A, 10% to 90% of 2^24 (1677722 .. 15099494)
       2 - B, 2.5% to 22.5% of 2^24 (419430 .. 3774874)
       3 - C, 20% to 80% of 2^24 (3355443 .. 13421773)
+    enum: [1, 2, 3]
     $ref: /schemas/types.yaml#/definitions/uint32
 
+  honeywell,pressure-triplet:
+    description: |
+      Case-sensitive five character string that defines pressure range, unit
+      and type as part of the device nomenclature. In the unlikely case of a
+      custom chip, unset and provide pmin-pascal and pmax-pascal instead.
+    enum: [0001BA, 01.6BA, 02.5BA, 0060MG, 0100MG, 0160MG, 0250MG, 0400MG,
+           0600MG, 0001BG, 01.6BG, 02.5BG, 0100KA, 0160KA, 0250KA, 0006KG,
+           0010KG, 0016KG, 0025KG, 0040KG, 0060KG, 0100KG, 0160KG, 0250KG,
+           0015PA, 0025PA, 0030PA, 0001PG, 0005PG, 0015PG, 0030PG, 0300YG]
+    $ref: /schemas/types.yaml#/definitions/string
+
+  honeywell,pmin-pascal:
+    description:
+      Minimum pressure value the sensor can measure in pascal.
+
+  honeywell,pmax-pascal:
+    description:
+      Maximum pressure value the sensor can measure in pascal.
+
+  spi-max-frequency:
+    maximum: 800000
+
   vdd-supply:
     description: provide VDD power to the sensor.
 
 required:
   - compatible
   - reg
-  - honeywell,pmin-pascal
-  - honeywell,pmax-pascal
   - honeywell,transfer-function
   - vdd-supply
 
+oneOf:
+  - required:
+      - honeywell,pressure-triplet
+  - required:
+      - honeywell,pmin-pascal
+      - honeywell,pmax-pascal
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml
+  - if:
+      required:
+        - honeywell,pressure-triplet
+    then:
+      properties:
+        honeywell,pmin-pascal: false
+        honeywell,pmax-pascal: false
+
 additionalProperties: false
 
 examples:
@@ -93,10 +130,29 @@ examples:
             reg = <0x18>;
             reset-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
             interrupt-parent = <&gpio3>;
-            interrupts = <21 IRQ_TYPE_EDGE_FALLING>;
-            honeywell,pmin-pascal = <0>;
-            honeywell,pmax-pascal = <172369>;
+            interrupts = <21 IRQ_TYPE_EDGE_RISING>;
+
+            honeywell,pressure-triplet = "0025PA";
+            honeywell,transfer-function = <1>;
+            vdd-supply = <&vcc_3v3>;
+        };
+    };
+  - |
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pressure@0 {
+            compatible = "honeywell,mprls0025pa";
+            reg = <0>;
+            spi-max-frequency = <800000>;
+            reset-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+            interrupt-parent = <&gpio0>;
+            interrupts = <30 IRQ_TYPE_EDGE_RISING>;
+
+            honeywell,pressure-triplet = "0015PA";
             honeywell,transfer-function = <1>;
             vdd-supply = <&vcc_3v3>;
         };
     };
+...
index 8c6d7735e87502ec4bacd1b814fa2b9a5b0fe1db..58aa1542776b51cf08db928c7ffa6e73b18358c0 100644 (file)
@@ -24,9 +24,16 @@ properties:
   reg:
     maxItems: 1
 
+  vcc-supply:
+    description: provide VCC power to the sensor.
+
+  label:
+    description: Unique name to identify which device this is.
+
 required:
   - compatible
   - reg
+  - vcc-supply
 
 additionalProperties: false
 
@@ -39,5 +46,6 @@ examples:
         tmp117@48 {
              compatible = "ti,tmp117";
              reg = <0x48>;
+             vcc-supply = <&pmic_reg_3v3>;
         };
     };
index 08c1c6b9d7cf8dd13db5c9bc857f7a7e218f58fe..5aaa92a7cef7c2789a66ab7e97c35658441eeb63 100644 (file)
@@ -23,6 +23,9 @@ properties:
 
   compatible:
     enum:
+      - qcom,msm8909-bimc
+      - qcom,msm8909-pcnoc
+      - qcom,msm8909-snoc
       - qcom,msm8916-bimc
       - qcom,msm8916-pcnoc
       - qcom,msm8916-snoc
index 74ab080249ff893106ab8051c74c31db07595e54..9318b845ec359bda726df0280ae338605a06f2cf 100644 (file)
@@ -8,7 +8,7 @@ title: Qualcomm RPMh Network-On-Chip Interconnect
 
 maintainers:
   - Georgi Djakov <georgi.djakov@linaro.org>
-  - Odelu Kukatla <okukatla@codeaurora.org>
+  - Odelu Kukatla <quic_okukatla@quicinc.com>
 
 description: |
    RPMh interconnect providers support system bandwidth requirements through
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm7150-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm7150-rpmh.yaml
new file mode 100644 (file)
index 0000000..b565d1a
--- /dev/null
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interconnect/qcom,sm7150-rpmh.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm RPMh Network-On-Chip Interconnect on SM7150
+
+maintainers:
+  - Danila Tikhonov <danila@jiaxyga.com>
+
+description: |
+  RPMh interconnect providers support system bandwidth requirements through
+  RPMh hardware accelerators known as Bus Clock Manager (BCM).
+
+  See also:: include/dt-bindings/interconnect/qcom,sm7150-rpmh.h
+
+allOf:
+  - $ref: qcom,rpmh-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - qcom,sm7150-aggre1-noc
+      - qcom,sm7150-aggre2-noc
+      - qcom,sm7150-compute-noc
+      - qcom,sm7150-config-noc
+      - qcom,sm7150-dc-noc
+      - qcom,sm7150-gem-noc
+      - qcom,sm7150-mc-virt
+      - qcom,sm7150-mmss-noc
+      - qcom,sm7150-system-noc
+
+  reg:
+    maxItems: 1
+
+# Child node's properties
+patternProperties:
+  '^interconnect-[0-9]+$':
+    type: object
+    description:
+      The interconnect providers do not have a separate QoS register space,
+      but share parent's space.
+
+    allOf:
+      - $ref: qcom,rpmh-common.yaml#
+
+    properties:
+      compatible:
+        enum:
+          - qcom,sm7150-camnoc-virt
+
+    required:
+      - compatible
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    mc_virt: interconnect@1380000 {
+        compatible = "qcom,sm7150-mc-virt";
+        reg = <0x01380000 0x40000>;
+        #interconnect-cells = <2>;
+        qcom,bcm-voters = <&apps_bcm_voter>;
+    };
+
+    system_noc: interconnect@1620000 {
+        compatible = "qcom,sm7150-system-noc";
+        reg = <0x01620000 0x40000>;
+        #interconnect-cells = <2>;
+        qcom,bcm-voters = <&apps_bcm_voter>;
+
+        camnoc_virt: interconnect-0 {
+            compatible = "qcom,sm7150-camnoc-virt";
+            #interconnect-cells = <2>;
+            qcom,bcm-voters = <&apps_bcm_voter>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml b/Documentation/devicetree/bindings/mtd/partitions/linux,ubi.yaml
new file mode 100644 (file)
index 0000000..27e1ac1
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/linux,ubi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Unsorted Block Images
+
+description: |
+  UBI ("Unsorted Block Images") is a volume management system for raw
+  flash devices which manages multiple logical volumes on a single
+  physical flash device and spreads the I/O load (i.e wear-leveling)
+  across the whole flash chip.
+
+maintainers:
+  - Daniel Golle <daniel@makrotopia.org>
+
+allOf:
+  - $ref: partition.yaml#
+
+properties:
+  compatible:
+    const: linux,ubi
+
+  volumes:
+    type: object
+    description: UBI Volumes
+
+    patternProperties:
+      "^ubi-volume-.*$":
+        $ref: /schemas/mtd/partitions/ubi-volume.yaml#
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    partitions {
+        compatible = "fixed-partitions";
+        #address-cells = <1>;
+        #size-cells = <1>;
+
+        partition@0 {
+            reg = <0x0 0x100000>;
+            label = "bootloader";
+            read-only;
+        };
+
+        partition@100000 {
+            reg = <0x100000 0x1ff00000>;
+            label = "ubi";
+            compatible = "linux,ubi";
+
+            volumes {
+                ubi-volume-caldata {
+                    volid = <2>;
+                    volname = "rf";
+
+                    nvmem-layout {
+                        compatible = "fixed-layout";
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+
+                        eeprom@0 {
+                            reg = <0x0 0x1000>;
+                        };
+                    };
+                };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml b/Documentation/devicetree/bindings/mtd/partitions/ubi-volume.yaml
new file mode 100644 (file)
index 0000000..19736b2
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mtd/partitions/ubi-volume.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UBI volume
+
+description: |
+  This binding describes a single UBI volume. Volumes can be matches either
+  by their ID or their name, or both.
+
+maintainers:
+  - Daniel Golle <daniel@makrotopia.org>
+
+properties:
+  volid:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Match UBI volume ID
+
+  volname:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      Match UBI volume ID
+
+  nvmem-layout:
+    $ref: /schemas/nvmem/layouts/nvmem-layout.yaml#
+    description:
+      This container may reference an NVMEM layout parser.
+
+anyOf:
+  - required:
+      - volid
+
+  - required:
+      - volname
+
+# This is a generic file other binding inherit from and extend
+additionalProperties: true
index ac2381e6602790b2bc66ef159da72c58231f83c8..8b3826243dddfcf9c9bea531541c55d3fc04a3bf 100644 (file)
@@ -36,20 +36,18 @@ properties:
 
 allOf:
   - if:
+      properties:
+        compatible:
+          contains:
+            const: mac-base
       required: [ compatible ]
     then:
-      if:
-        properties:
-          compatible:
-            contains:
-              const: mac-base
-      then:
-        properties:
-          "#nvmem-cell-cells":
-            description: The first argument is a MAC address offset.
-            const: 1
-        required:
-          - "#nvmem-cell-cells"
+      properties:
+        "#nvmem-cell-cells":
+          description: The first argument is a MAC address offset.
+          const: 1
+      required:
+        - "#nvmem-cell-cells"
 
 required:
   - reg
diff --git a/Documentation/devicetree/bindings/nvmem/nvmem-provider.yaml b/Documentation/devicetree/bindings/nvmem/nvmem-provider.yaml
new file mode 100644 (file)
index 0000000..4009a9a
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/nvmem-provider.yaml#
+$schema: http://devicetree.org/meta-schemas/base.yaml#
+
+title: NVMEM (Non Volatile Memory) Provider
+
+maintainers:
+  - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+select: true
+
+properties:
+  '#nvmem-cell-cells':
+    enum: [0, 1]
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.txt b/Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.txt
deleted file mode 100644 (file)
index 4881561..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
---------------------------------------------------------------------------
-=  Zynq UltraScale+ MPSoC nvmem firmware driver binding =
---------------------------------------------------------------------------
-The nvmem_firmware node provides access to the hardware related data
-like soc revision, IDCODE... etc, By using the firmware interface.
-
-Required properties:
-- compatible: should be "xlnx,zynqmp-nvmem-fw"
-
-= Data cells =
-Are child nodes of silicon id, bindings of which as described in
-bindings/nvmem/nvmem.txt
-
--------
- Example
--------
-firmware {
-       zynqmp_firmware: zynqmp-firmware {
-               compatible = "xlnx,zynqmp-firmware";
-               method = "smc";
-
-               nvmem_firmware {
-                       compatible = "xlnx,zynqmp-nvmem-fw";
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-
-                       /* Data cells */
-                       soc_revision: soc_revision {
-                               reg = <0x0 0x4>;
-                       };
-               };
-       };
-};
-
-= Data consumers =
-Are device nodes which consume nvmem data cells.
-
-For example:
-       pcap {
-               ...
-
-               nvmem-cells = <&soc_revision>;
-               nvmem-cell-names = "soc_revision";
-
-               ...
-       };
diff --git a/Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.yaml b/Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.yaml
new file mode 100644 (file)
index 0000000..917c40d
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/xlnx,zynqmp-nvmem.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Zynq UltraScale+ MPSoC Non Volatile Memory interface
+
+description: |
+    The ZynqMP MPSoC provides access to the hardware related data
+    like SOC revision, IDCODE and specific purpose efuses.
+
+maintainers:
+  - Kalyani Akula <kalyani.akula@amd.com>
+  - Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
+
+allOf:
+  - $ref: nvmem.yaml#
+
+properties:
+  compatible:
+    const: xlnx,zynqmp-nvmem-fw
+
+required:
+  - compatible
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    nvmem {
+        compatible = "xlnx,zynqmp-nvmem-fw";
+        nvmem-layout {
+            compatible = "fixed-layout";
+            #address-cells = <1>;
+            #size-cells = <1>;
+
+            soc_revision: soc-revision@0 {
+                reg = <0x0 0x4>;
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml b/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
new file mode 100644 (file)
index 0000000..52a59d2
--- /dev/null
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/opencores,pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OpenCores PWM controller
+
+maintainers:
+  - William Qiu <william.qiu@starfivetech.com>
+
+description:
+  The OpenCores PTC ip core contains a PWM controller. When operating in PWM
+  mode, the PTC core generates binary signal with user-programmable low and
+  high periods. All PTC counters and registers are 32-bit.
+
+allOf:
+  - $ref: pwm.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - starfive,jh7100-pwm
+          - starfive,jh7110-pwm
+          - starfive,jh8100-pwm
+      - const: opencores,pwm-v1
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  "#pwm-cells":
+    const: 3
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    pwm@12490000 {
+        compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+        reg = <0x12490000 0x10000>;
+        clocks = <&clkgen 181>;
+        resets = <&rstgen 109>;
+        #pwm-cells = <3>;
+    };
index 8afb40c67af31ae5fc6bee22ab5272364858b31d..33ae1f786802eca931721f3c3feff5bdb2ce0f97 100644 (file)
@@ -26,6 +26,7 @@ properties:
           - enum:
               - qcom,pm4125-vbus-reg
               - qcom,pm6150-vbus-reg
+              - qcom,pmi632-vbus-reg
           - const: qcom,pm8150b-vbus-reg
 
   reg:
index 09102dda4942c14121191c455e8edb6b3a6e3d42..507f98f73d235449cff58334cd9b07da2a0cdf3a 100644 (file)
@@ -47,7 +47,7 @@ properties:
     maxItems: 1
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description:
       If present, name (or relative path) of the file within the
       firmware search path containing the firmware image used when
@@ -115,7 +115,7 @@ patternProperties:
         maxItems: 1
 
       firmware-name:
-        $ref: /schemas/types.yaml#/definitions/string
+        maxItems: 1
         description:
           If present, name (or relative path) of the file within the
           firmware search path containing the firmware image used when
index 884158bccd50740edf5e2004289db4de752dfede..3766d4513b379010141c1d81f1f4b4df39e13b63 100644 (file)
@@ -18,7 +18,6 @@ properties:
     const: qcom,glink-rpm
 
   label:
-    $ref: /schemas/types.yaml#/definitions/string
     description:
       Name of the edge, used for debugging and identification purposes. The
       node name will be used if this is not present.
index eb868a7ff4cd819a3d09178e812481022436fe77..ad45fd00ae346e4a4a42659f466589718f6a6dff 100644 (file)
@@ -46,7 +46,7 @@ properties:
     description: Reference to the reserved-memory for the Hexagon core
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index c054b84fdcd5c51a31a628327bf2e99b851ff4d6..66b455d0a8e3271307028a23596d5d460f8b5d44 100644 (file)
@@ -45,7 +45,7 @@ properties:
   smd-edge: false
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index b6bd3343858450db5da8aa9ba51f6f01c97fd411..9381c7022ff499b99dc4179c93bce4960f78222c 100644 (file)
@@ -80,7 +80,7 @@ properties:
     description: Reference to the reserved-memory for the Hexagon core
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description:
       The name of the firmware which should be loaded for this remote
       processor.
index 4744a37b2b5d75b6ea5197414720cd9a465b631e..45ee9fbe09664ac93ab697d73d84ea55127a219b 100644 (file)
@@ -42,7 +42,7 @@ properties:
     description: Reference to the reserved-memory for the Hexagon core
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index 02828723591220abf50da6509b60d249dad9c59e..758adb06c8ddd915f52d8032537b90e23d9db72b 100644 (file)
@@ -47,7 +47,7 @@ properties:
   smd-edge: false
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index f7e40fb166da1f5bea65c6241ebfab2118510f4e..c1a3cc308bdb2d9ab73358d557c98442b9ac6a2a 100644 (file)
@@ -42,7 +42,7 @@ properties:
   smd-edge: false
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index 3e4a03eb4532b8f6eef7d5ce2ee5059691d4c6d1..7286b2baa19f2a8a41fbf193bd946a9cbe6b8fe1 100644 (file)
@@ -36,7 +36,7 @@ properties:
     description: Reference to the reserved-memory for the Hexagon core
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
   smd-edge: false
index 238c6e5e67c5698baeaa2effad3e69ef37debf93..d67386c50fa4d6e4f9b844b36e17ffa1db613adb 100644 (file)
@@ -46,7 +46,7 @@ properties:
   smd-edge: false
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index 53cea8e53a311ebc9a8f6491b7b786acaa433af5..4b9fb74fb9e966b61d51fe578b636f967e4c6af8 100644 (file)
@@ -47,7 +47,7 @@ properties:
     description: Reference to the reserved-memory for the Hexagon core
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description: Firmware name for the Hexagon core
 
 required:
index 58120829fb06f5646f2c1af060bce326f2eec21b..73fda7565cd12fdc649baa1d406170096c4df7dd 100644 (file)
@@ -19,6 +19,11 @@ properties:
       - qcom,sm8550-adsp-pas
       - qcom,sm8550-cdsp-pas
       - qcom,sm8550-mpss-pas
+      - qcom,sm8650-adsp-pas
+      - qcom,sm8650-cdsp-pas
+      - qcom,sm8650-mpss-pas
+      - qcom,x1e80100-adsp-pas
+      - qcom,x1e80100-cdsp-pas
 
   reg:
     maxItems: 1
@@ -49,6 +54,8 @@ properties:
       - description: Memory region for main Firmware authentication
       - description: Memory region for Devicetree Firmware authentication
       - description: DSM Memory region
+      - description: DSM Memory region 2
+      - description: Memory region for Qlink Logging
 
 required:
   - compatible
@@ -63,6 +70,9 @@ allOf:
           enum:
             - qcom,sm8550-adsp-pas
             - qcom,sm8550-cdsp-pas
+            - qcom,sm8650-adsp-pas
+            - qcom,x1e80100-adsp-pas
+            - qcom,x1e80100-cdsp-pas
     then:
       properties:
         interrupts:
@@ -71,7 +81,26 @@ allOf:
           maxItems: 5
         memory-region:
           maxItems: 2
-    else:
+  - if:
+      properties:
+        compatible:
+          enum:
+            - qcom,sm8650-cdsp-pas
+    then:
+      properties:
+        interrupts:
+          maxItems: 5
+        interrupt-names:
+          maxItems: 5
+        memory-region:
+          minItems: 3
+          maxItems: 3
+  - if:
+      properties:
+        compatible:
+          enum:
+            - qcom,sm8550-mpss-pas
+    then:
       properties:
         interrupts:
           minItems: 6
@@ -79,12 +108,29 @@ allOf:
           minItems: 6
         memory-region:
           minItems: 3
+          maxItems: 3
+  - if:
+      properties:
+        compatible:
+          enum:
+            - qcom,sm8650-mpss-pas
+    then:
+      properties:
+        interrupts:
+          minItems: 6
+        interrupt-names:
+          minItems: 6
+        memory-region:
+          minItems: 5
+          maxItems: 5
 
   - if:
       properties:
         compatible:
           enum:
             - qcom,sm8550-adsp-pas
+            - qcom,sm8650-adsp-pas
+            - qcom,x1e80100-adsp-pas
     then:
       properties:
         power-domains:
@@ -101,6 +147,7 @@ allOf:
         compatible:
           enum:
             - qcom,sm8550-mpss-pas
+            - qcom,sm8650-mpss-pas
     then:
       properties:
         power-domains:
@@ -116,6 +163,8 @@ allOf:
         compatible:
           enum:
             - qcom,sm8550-cdsp-pas
+            - qcom,sm8650-cdsp-pas
+            - qcom,x1e80100-cdsp-pas
     then:
       properties:
         power-domains:
index 45eb42bd3c2cd8a061e7b7221bfffee1e28553ef..8e033b22d28cfa8203234f744b3b408e976e20c3 100644 (file)
@@ -51,7 +51,7 @@ properties:
       - const: stop-ack
 
   firmware-name:
-    $ref: /schemas/types.yaml#/definitions/string
+    maxItems: 1
     description:
       Relative firmware image path for the WCNSS core. Defaults to
       "wcnss.mdt".
diff --git a/Documentation/devicetree/bindings/reset/sophgo,sg2042-reset.yaml b/Documentation/devicetree/bindings/reset/sophgo,sg2042-reset.yaml
new file mode 100644 (file)
index 0000000..76e1931
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reset/sophgo,sg2042-reset.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo SG2042 SoC Reset Controller
+
+maintainers:
+  - Chen Wang <unicorn_wang@outlook.com>
+
+properties:
+  compatible:
+    const: sophgo,sg2042-reset
+
+  reg:
+    maxItems: 1
+
+  "#reset-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - "#reset-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    rstgen: reset-controller@c00 {
+        compatible = "sophgo,sg2042-reset";
+        reg = <0xc00 0xc>;
+        #reset-cells = <1>;
+    };
index 9d8670c00e3b3bdea5d2196b98538d97465abf0d..d87dd50f1a4b577f525353660cb5fe82493b52f4 100644 (file)
@@ -75,6 +75,10 @@ properties:
       - riscv,sv57
       - riscv,none
 
+  reg:
+    description:
+      The hart ID of this CPU node.
+
   riscv,cbom-block-size:
     $ref: /schemas/types.yaml#/definitions/uint32
     description:
@@ -106,7 +110,11 @@ properties:
         const: 1
 
       compatible:
-        const: riscv,cpu-intc
+        oneOf:
+          - items:
+              - const: andestech,cpu-intc
+              - const: riscv,cpu-intc
+          - const: riscv,cpu-intc
 
       interrupt-controller: true
 
index 63d81dc895e5ce4c08715ce1d6bf0958a757ca86..468c646247aa5cebbea5cbe839c01cfacbaecf7e 100644 (file)
@@ -477,5 +477,12 @@ properties:
             latency, as ratified in commit 56ed795 ("Update
             riscv-crypto-spec-vector.adoc") of riscv-crypto.
 
+        - const: xandespmu
+          description:
+            The Andes Technology performance monitor extension for counter overflow
+            and privilege mode filtering. For more details, see Counter Related
+            Registers in the AX45MP datasheet.
+            https://www.andestech.com/wp-content/uploads/AX45MP-1C-Rev.-5.0.0-Datasheet.pdf
+
 additionalProperties: true
 ...
diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt
deleted file mode 100644 (file)
index 2405e35..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Abracon ABX80X I2C ultra low power RTC/Alarm chip
-
-The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801,
-ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805
-is the superset of ab180x.
-
-Required properties:
-
- - "compatible": should one of:
-        "abracon,abx80x"
-        "abracon,ab0801"
-        "abracon,ab0803"
-        "abracon,ab0804"
-        "abracon,ab0805"
-        "abracon,ab1801"
-        "abracon,ab1803"
-        "abracon,ab1804"
-        "abracon,ab1805"
-        "microcrystal,rv1805"
-       Using "abracon,abx80x" will enable chip autodetection.
- - "reg": I2C bus address of the device
-
-Optional properties:
-
-The abx804 and abx805 have a trickle charger that is able to charge the
-connected battery or supercap. Both the following properties have to be defined
-and valid to enable charging:
-
- - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
- - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
-                          resistor, the other values are in kOhm.
diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml b/Documentation/devicetree/bindings/rtc/abracon,abx80x.yaml
new file mode 100644 (file)
index 0000000..355b059
--- /dev/null
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/abracon,abx80x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Abracon ABX80X I2C ultra low power RTC/Alarm chip
+
+maintainers:
+  - linux-rtc@vger.kernel.org
+
+properties:
+  compatible:
+    description:
+      The wildcard 'abracon,abx80x' may be used to support a mix
+      of different abracon rtc`s. In this case the driver
+      must perform auto-detection from ID register.
+    enum:
+      - abracon,abx80x
+      - abracon,ab0801
+      - abracon,ab0803
+      - abracon,ab0804
+      - abracon,ab0805
+      - abracon,ab1801
+      - abracon,ab1803
+      - abracon,ab1804
+      - abracon,ab1805
+      - microcrystal,rv1805
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  abracon,tc-diode:
+    description:
+      Trickle-charge diode type.
+      Required to enable charging backup battery.
+
+      Supported are 'standard' diodes with a 0.6V drop
+      and 'schottky' diodes with a 0.3V drop.
+    $ref: /schemas/types.yaml#/definitions/string
+    enum:
+      - standard
+      - schottky
+
+  abracon,tc-resistor:
+    description:
+      Trickle-charge resistor value in kOhm.
+      Required to enable charging backup battery.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 3, 6, 11]
+
+dependentRequired:
+  abracon,tc-diode: ["abracon,tc-resistor"]
+  abracon,tc-resistor: ["abracon,tc-diode"]
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: rtc.yaml#
+  - if:
+      properties:
+        compatible:
+          not:
+            contains:
+              enum:
+                - abracon,abx80x
+                - abracon,ab0804
+                - abracon,ab1804
+                - abracon,ab0805
+                - abracon,ab1805
+    then:
+      properties:
+        abracon,tc-diode: false
+        abracon,tc-resistor: false
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        rtc@69 {
+            compatible = "abracon,abx80x";
+            reg = <0x69>;
+            abracon,tc-diode = "schottky";
+            abracon,tc-resistor = <3>;
+            interrupts = <44 IRQ_TYPE_EDGE_FALLING>;
+        };
+    };
index b80b85c394ac5cd5281e86f4bac400865e41292d..a7f6c1d1a08ab910c4295385de68dfcb010e160d 100644 (file)
@@ -19,7 +19,9 @@ properties:
       - items:
           - const: atmel,at91sam9260-rtt
       - items:
-          - const: microchip,sam9x60-rtt
+          - enum:
+              - microchip,sam9x60-rtt
+              - microchip,sam9x7-rtt
           - const: atmel,at91sam9260-rtt
       - items:
           - const: microchip,sama7g5-rtt
diff --git a/Documentation/devicetree/bindings/rtc/mediatek,mt2712-rtc.yaml b/Documentation/devicetree/bindings/rtc/mediatek,mt2712-rtc.yaml
new file mode 100644 (file)
index 0000000..75624dd
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/mediatek,mt2712-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT2712 on-SoC RTC
+
+allOf:
+  - $ref: rtc.yaml#
+
+maintainers:
+  - Ran Bi <ran.bi@mediatek.com>
+
+properties:
+  compatible:
+    const: mediatek,mt2712-rtc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - reg
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    rtc@10011000 {
+        compatible = "mediatek,mt2712-rtc";
+        reg = <0x10011000 0x1000>;
+        interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_LOW>;
+    };
diff --git a/Documentation/devicetree/bindings/rtc/mediatek,mt7622-rtc.yaml b/Documentation/devicetree/bindings/rtc/mediatek,mt7622-rtc.yaml
new file mode 100644 (file)
index 0000000..e74dfc1
--- /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/rtc/mediatek,mt7622-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT7622 on-SoC RTC
+
+allOf:
+  - $ref: rtc.yaml#
+
+maintainers:
+  - Sean Wang <sean.wang@mediatek.com>
+
+properties:
+  compatible:
+    items:
+      - const: mediatek,mt7622-rtc
+      - const: mediatek,soc-rtc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: rtc
+
+required:
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/mt7622-clk.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    rtc@10212800 {
+        compatible = "mediatek,mt7622-rtc", "mediatek,soc-rtc";
+        reg = <0x10212800 0x200>;
+        interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
+        clocks = <&topckgen CLK_TOP_RTC>;
+        clock-names = "rtc";
+    };
diff --git a/Documentation/devicetree/bindings/rtc/rtc-mt2712.txt b/Documentation/devicetree/bindings/rtc/rtc-mt2712.txt
deleted file mode 100644 (file)
index c33d87e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-Device-Tree bindings for MediaTek SoC based RTC
-
-Required properties:
-- compatible       : Should be "mediatek,mt2712-rtc" : for MT2712 SoC
-- reg              : Specifies base physical address and size of the registers;
-- interrupts       : Should contain the interrupt for RTC alarm;
-
-Example:
-
-rtc: rtc@10011000 {
-       compatible = "mediatek,mt2712-rtc";
-       reg = <0 0x10011000 0 0x1000>;
-       interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_LOW>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt b/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
deleted file mode 100644 (file)
index 09fe8f5..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Device-Tree bindings for MediaTek SoC based RTC
-
-Required properties:
-- compatible       : Should be
-                       "mediatek,mt7622-rtc", "mediatek,soc-rtc" : for MT7622 SoC
-- reg              : Specifies base physical address and size of the registers;
-- interrupts       : Should contain the interrupt for RTC alarm;
-- clocks           : Specifies list of clock specifiers, corresponding to
-                     entries in clock-names property;
-- clock-names      : Should contain "rtc" entries
-
-Example:
-
-rtc: rtc@10212800 {
-       compatible = "mediatek,mt7622-rtc",
-                    "mediatek,soc-rtc";
-       reg = <0 0x10212800 0 0x200>;
-       interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
-       clocks = <&topckgen CLK_TOP_RTC>;
-       clock-names = "rtc";
-};
index d1f5eb996dba06d177fa5dfdcca389344497f3fb..01cc90fee81e5e88eda793d658e5c9aa43cf8554 100644 (file)
@@ -18,7 +18,13 @@ allOf:
 
 properties:
   compatible:
-    const: xlnx,zynqmp-rtc
+    oneOf:
+      - const: xlnx,zynqmp-rtc
+      - items:
+          - enum:
+              - xlnx,versal-rtc
+              - xlnx,versal-net-rtc
+          - const: xlnx,zynqmp-rtc
 
   reg:
     maxItems: 1
@@ -48,6 +54,9 @@ properties:
     default: 0x198233
     deprecated: true
 
+  power-domains:
+    maxItems: 1
+
 required:
   - compatible
   - reg
index e35ad1109efc8b7b13211e5795c5668111e3f5c1..2129247d7c816d5b33e600af41b633aef7efa295 100644 (file)
@@ -55,6 +55,7 @@ required:
 
 allOf:
   - $ref: serial.yaml#
+  - $ref: rs485.yaml#
   - if:
       properties:
         compatible:
index 3a5b59f5d3e35de921e9a0907700e8b4db063850..3f9ace89dee902011d593c19a6d6f46424b1c832 100644 (file)
@@ -30,6 +30,7 @@ properties:
       - items:
           - enum:
               - fsl,imx93-lpuart
+              - fsl,imx95-lpuart
           - const: fsl,imx8ulp-lpuart
           - const: fsl,imx7ulp-lpuart
       - items:
index 2046e2dc0a3d190e932ee052411ec5e04bb66ab6..9480ed30915c9c4ec1ecb3445d013ed5dcef6098 100644 (file)
@@ -59,6 +59,7 @@ properties:
               - renesas,hscif-r8a779a0     # R-Car V3U
               - renesas,hscif-r8a779f0     # R-Car S4-8
               - renesas,hscif-r8a779g0     # R-Car V4H
+              - renesas,hscif-r8a779h0     # R-Car V4M
           - const: renesas,rcar-gen4-hscif # R-Car Gen4
           - const: renesas,hscif           # generic HSCIF compatible UART
 
index 133259ed3a34c577ee86e58f36bdf2a4937afcf4..0f0131026911cd0e07071cf38f0e9b41de9a7237 100644 (file)
@@ -143,6 +143,8 @@ allOf:
     then:
       required:
         - samsung,uart-fifosize
+      properties:
+        reg-io-width: false
 
 unevaluatedProperties: false
 
index 65804ca274ae75e2bfdbbc80a030335c99fd821d..ffc9198ae21469de249c87da75e27521bc2a419f 100644 (file)
@@ -88,7 +88,7 @@ properties:
       TX FIFO threshold configuration (in bytes).
 
 patternProperties:
-  "^(bluetooth|bluetooth-gnss|gnss|gps|mcu)$":
+  "^(bluetooth|bluetooth-gnss|gnss|gps|mcu|onewire)$":
     if:
       type: object
     then:
diff --git a/Documentation/devicetree/bindings/serial/st,asc.yaml b/Documentation/devicetree/bindings/serial/st,asc.yaml
new file mode 100644 (file)
index 0000000..f208338
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/st,asc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STi SoCs Serial Port
+
+maintainers:
+  - Patrice Chotard <patrice.chotard@foss.st.com>
+
+allOf:
+  - $ref: serial.yaml#
+
+properties:
+  compatible:
+    const: st,asc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  st,hw-flow-ctrl:
+    description: When set, enable hardware flow control.
+    type: boolean
+
+  st,force-m1:
+    description: When set, force asc to be in Mode-1. This is recommended for
+      high bit rates above 19.2K.
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/stih407-clks.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    serial@9830000 {
+        compatible = "st,asc";
+        reg = <0x9830000 0x2c>;
+        interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+    };
+...
index 1df8ffe95fc615b058e43300876c6e357990d77f..62f97da1b2fd7c944442c17127897d154d6c4acb 100644 (file)
@@ -58,6 +58,9 @@ properties:
 
   wakeup-source: true
 
+  power-domains:
+    maxItems: 1
+
   rx-threshold:
     description:
       If value is set to 1, RX FIFO threshold is disabled.
diff --git a/Documentation/devicetree/bindings/serial/st-asc.txt b/Documentation/devicetree/bindings/serial/st-asc.txt
deleted file mode 100644 (file)
index a1b9b6f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-*st-asc(Serial Port)
-
-Required properties:
-- compatible : Should be "st,asc".
-- reg, reg-names, interrupts, interrupt-names  : Standard way to define device
-                       resources with names. look in
-                       Documentation/devicetree/bindings/resource-names.txt
-
-Optional properties:
-- st,hw-flow-ctrl      bool flag to enable hardware flow control.
-- st,force-m1          bool flat to force asc to be in Mode-1 recommended
-                       for high bit rates (above 19.2K)
-Example:
-serial@fe440000{
-    compatible    = "st,asc";
-    reg         = <0xfe440000 0x2c>;
-    interrupts     =  <0 209 0>;
-};
index d3f3259ef77d5c8ef1ae9abe1cbd0620b462d715..4310bae6c58ef320a3af1abf01a86c64719a6afa 100644 (file)
@@ -23,6 +23,7 @@ properties:
     oneOf:
       - items:
           - enum:
+              - qcom,qcm6490-pmic-glink
               - qcom,sc8180x-pmic-glink
               - qcom,sc8280xp-pmic-glink
               - qcom,sm8350-pmic-glink
index 7f9d8c7a635a6ffc1cb4ad3a7987929d28391488..99a536601cc7e67e2d3fe735749ff3dda5f16175 100644 (file)
@@ -185,11 +185,12 @@ properties:
 
       gpio-ranges:
         items:
-          - description: A phandle to the CODEC pinctrl node
-            minimum: 0
-          - const: 0
-          - const: 0
-          - const: 3
+          - items:
+              - description: A phandle to the CODEC pinctrl node
+                minimum: 0
+              - const: 0
+              - const: 0
+              - const: 3
 
     patternProperties:
       "-state$":
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6usb.yaml b/Documentation/devicetree/bindings/sound/qcom,q6usb.yaml
new file mode 100644 (file)
index 0000000..37161d2
--- /dev/null
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,q6usb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm ASoC DPCM USB backend DAI
+
+maintainers:
+  - Wesley Cheng <quic_wcheng@quicinc.com>
+
+description:
+  The USB port is a supported AFE path on the Q6 DSP.  This ASoC DPCM
+  backend DAI will communicate the required settings to initialize the
+  XHCI host controller properly for enabling the offloaded audio stream.
+  Parameters defined under this node will carry settings, which will be
+  passed along during the QMI stream enable request and configuration of
+  the XHCI host controller.
+
+allOf:
+  - $ref: dai-common.yaml#
+
+properties:
+  compatible:
+    enum:
+      - qcom,q6usb
+
+  iommus:
+    maxItems: 1
+
+  "#sound-dai-cells":
+    const: 1
+
+  qcom,usb-audio-intr-idx:
+    description:
+      Desired XHCI interrupter number to use.  Depending on the audio DSP
+      on the platform, it will operate on a specific XHCI interrupter.
+    $ref: /schemas/types.yaml#/definitions/uint16
+    maximum: 8
+
+required:
+  - compatible
+  - "#sound-dai-cells"
+  - qcom,usb-audio-intr-idx
+
+additionalProperties: false
+
+examples:
+  - |
+    dais {
+      compatible = "qcom,q6usb";
+      #sound-dai-cells = <1>;
+      iommus = <&apps_smmu 0x180f 0x0>;
+      qcom,usb-audio-intr-idx = /bits/ 16 <2>;
+    };
index 9b2272a9ec15d89122c3540b7088c91198a81e5d..6b3aea6d73b077ba537eeaf456840f61fb1cca6a 100644 (file)
@@ -21,6 +21,7 @@ properties:
       - allwinner,sun50i-a100-ths
       - allwinner,sun50i-h5-ths
       - allwinner,sun50i-h6-ths
+      - allwinner,sun50i-h616-ths
 
   clocks:
     minItems: 1
@@ -50,6 +51,10 @@ properties:
   nvmem-cell-names:
     const: calibration
 
+  allwinner,sram:
+    maxItems: 1
+    description: phandle to device controlling temperate offset SYS_CFG register
+
   # See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for details
   "#thermal-sensor-cells":
     enum:
@@ -65,6 +70,7 @@ allOf:
               - allwinner,sun20i-d1-ths
               - allwinner,sun50i-a100-ths
               - allwinner,sun50i-h6-ths
+              - allwinner,sun50i-h616-ths
 
     then:
       properties:
@@ -82,6 +88,17 @@ allOf:
         clock-names:
           minItems: 2
 
+  - if:
+      not:
+        properties:
+          compatible:
+            contains:
+              const: allwinner,sun50i-h616-ths
+
+    then:
+      properties:
+        allwinner,sram: false
+
   - if:
       properties:
         compatible:
@@ -101,17 +118,12 @@ allOf:
           const: 1
 
   - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - allwinner,sun8i-h3-ths
-              - allwinner,sun8i-r40-ths
-              - allwinner,sun20i-d1-ths
-              - allwinner,sun50i-a64-ths
-              - allwinner,sun50i-a100-ths
-              - allwinner,sun50i-h5-ths
-              - allwinner,sun50i-h6-ths
+      not:
+        properties:
+          compatible:
+            contains:
+              enum:
+                - allwinner,sun8i-a83t-ths
 
     then:
       required:
index 145744027234bf82a46aabfb46ff74cc605288f5..d155d6799da6fcf1744d3fbeb635f6f4d1542b25 100644 (file)
@@ -33,7 +33,8 @@ properties:
     description: |
       The values to be programmed into TTRnCR, as specified by the SoC
       reference manual. The first cell is TTR0CR, the second is TTR1CR, etc.
-    maxItems: 4
+    minItems: 2
+    maxItems: 7
 
   fsl,tmu-calibration:
     $ref: /schemas/types.yaml#/definitions/uint32-matrix
index ecf276fd155cfb2730ac5d9a91e9feecb72fd46b..6a81cb6e11bc1e149af6152977239ac9c6a5b883 100644 (file)
@@ -29,6 +29,7 @@ properties:
       - renesas,r8a779a0-thermal # R-Car V3U
       - renesas,r8a779f0-thermal # R-Car S4-8
       - renesas,r8a779g0-thermal # R-Car V4H
+      - renesas,r8a779h0-thermal # R-Car V4M
 
   reg: true
 
@@ -90,6 +91,7 @@ else:
             enum:
               - renesas,r8a779f0-thermal
               - renesas,r8a779g0-thermal
+              - renesas,r8a779h0-thermal
   then:
     required:
       - interrupts
index dbd52620d293060f59432ac5e3df2b6d8d23a542..68398e7e8655657f77eb7b186137af522d675fd6 100644 (file)
@@ -228,8 +228,6 @@ patternProperties:
             additionalProperties: false
 
     required:
-      - polling-delay
-      - polling-delay-passive
       - thermal-sensors
       - trips
 
index dbba780c9b0213ee08bb9ed7568431bce200aeef..da342464d32ed2ff5c2b9ee29a36931edb989996 100644 (file)
@@ -32,12 +32,23 @@ properties:
     description: |
       Bit width of the timer, necessary if not 16.
 
+  "#pwm-cells":
+    const: 3
+
 required:
   - compatible
   - reg
-  - interrupts
   - clocks
 
+allOf:
+  - if:
+      not:
+        required:
+          - "#pwm-cells"
+    then:
+      required:
+        - interrupts
+
 additionalProperties: false
 
 examples:
@@ -50,3 +61,12 @@ examples:
         clocks = <&cpu_clk 3>;
         timer-width = <32>;
     };
+
+  - |
+    pwm: pwm@f8002000 {
+        compatible = "cdns,ttc";
+        reg = <0xf8002000 0x1000>;
+        clocks = <&cpu_clk 3>;
+        timer-width = <32>;
+        #pwm-cells = <3>;
+    };
index 2b9653dafab8f3380d60f942ef04f29a14e34bb8..891cca00952815b000aeaf41660354960e4233e4 100644 (file)
@@ -18,7 +18,9 @@ description: |
 
 properties:
   compatible:
-    const: nxp,sysctr-timer
+    enum:
+      - nxp,imx95-sysctr-timer
+      - nxp,sysctr-timer
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/timer/ralink,cevt-systick.yaml b/Documentation/devicetree/bindings/timer/ralink,cevt-systick.yaml
new file mode 100644 (file)
index 0000000..59d97fe
--- /dev/null
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/ralink,cevt-systick.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: System tick counter present in Ralink family SoCs
+
+maintainers:
+  - Sergio Paracuellos <sergio.paracuellos@gmail.com>
+
+properties:
+  compatible:
+    const: ralink,cevt-systick
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    systick@d00 {
+        compatible = "ralink,cevt-systick";
+        reg = <0xd00 0x10>;
+
+        interrupt-parent = <&cpuintc>;
+        interrupts = <7>;
+    };
+...
index 7207929e5cd6a7a2db7e0146acfd61979ce734f1..8b06a681764e3b5dfedf7b41d7e87b12f5d083a9 100644 (file)
@@ -23,7 +23,7 @@ properties:
       - enum:
           - renesas,r7s72100-ostm  # RZ/A1H
           - renesas,r7s9210-ostm   # RZ/A2M
-          - renesas,r9a07g043-ostm # RZ/G2UL
+          - renesas,r9a07g043-ostm # RZ/G2UL and RZ/Five
           - renesas,r9a07g044-ostm # RZ/G2{L,LC}
           - renesas,r9a07g054-ostm # RZ/V2L
       - const: renesas,ostm        # Generic
index a67e427a9e7e22aa81d2efe987fec304d6feb41e..84bbe15028a1de941e38f4510500a43d4be88d68 100644 (file)
@@ -46,7 +46,19 @@ properties:
 
   interrupts:
     minItems: 2
-    maxItems: 3
+    items:
+      - description: Underflow interrupt, channel 0
+      - description: Underflow interrupt, channel 1
+      - description: Underflow interrupt, channel 2
+      - description: Input capture interrupt, channel 2
+
+  interrupt-names:
+    minItems: 2
+    items:
+      - const: tuni0
+      - const: tuni1
+      - const: tuni2
+      - const: ticpi2
 
   clocks:
     maxItems: 1
@@ -100,7 +112,9 @@ examples:
             reg = <0xffd80000 0x30>;
             interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
                          <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
-                         <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                         <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
+                         <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+            interrupt-names = "tuni0", "tuni1", "tuni2", "ticpi2";
             clocks = <&mstp0_clks R8A7779_CLK_TMU0>;
             clock-names = "fck";
             power-domains = <&sysc R8A7779_PD_ALWAYS_ON>;
index 829bd2227f7c9c64a86417af3dc5c6057bba9234..774b7992a0cafca8222220d6982726fa6ca217d7 100644 (file)
@@ -26,6 +26,7 @@ properties:
       - items:
           - enum:
               - axis,artpec8-mct
+              - google,gs101-mct
               - samsung,exynos3250-mct
               - samsung,exynos5250-mct
               - samsung,exynos5260-mct
@@ -127,6 +128,7 @@ allOf:
           contains:
             enum:
               - axis,artpec8-mct
+              - google,gs101-mct
               - samsung,exynos5260-mct
               - samsung,exynos5420-mct
               - samsung,exynos5433-mct
index e4d893369d57bffc913114ce8310e7d249e6f3fd..3f5857aee3b0e968f0c4cb51888c1f1a3539e56a 100644 (file)
@@ -23,24 +23,11 @@ properties:
   connector:
     type: object
     $ref: ../connector/usb-connector.yaml
-    unevaluatedProperties: false
-
-    description:
-      Properties for usb c connector.
 
     properties:
       compatible:
         const: usb-c-connector
 
-      power-role: true
-
-      data-role: true
-
-      try-power-role: true
-
-    required:
-      - compatible
-
 required:
   - compatible
   - reg
index b7e664f7395b33405bff1cb181e79fe38aeb378a..3b56e0edb1c676cbcad7a6e74dd650ea7e96a490 100644 (file)
@@ -313,7 +313,7 @@ properties:
 
   usb-phy:
     description: phandle for the PHY device. Use "phys" instead.
-    $ref: /schemas/types.yaml#/definitions/phandle
+    maxItems: 1
     deprecated: true
 
   fsl,usbphy:
index f9410eb76a621a2e6d1d98ab44f7bad3c37eb123..8b25b9a01ced358f446270695b9686c94484a5df 100644 (file)
@@ -27,13 +27,8 @@ properties:
   vcc-supply:
     description: power supply (2.7V-5.5V)
 
-  mode-switch:
-    description: Flag the port as possible handle of altmode switching
-    type: boolean
-
-  orientation-switch:
-    description: Flag the port as possible handler of orientation switching
-    type: boolean
+  mode-switch: true
+  orientation-switch: true
 
   port:
     $ref: /schemas/graph.yaml#/$defs/port-base
@@ -79,6 +74,9 @@ required:
   - reg
   - port
 
+allOf:
+  - $ref: usb-switch.yaml#
+
 additionalProperties: false
 
 examples:
index 87986c45be88efdcc1953022da688f929ddb6797..2ed178f16a7822e2bc61b41823364c714aef1c55 100644 (file)
@@ -77,6 +77,7 @@ properties:
           - const: usb-ehci
       - enum:
           - generic-ehci
+          - marvell,ac5-ehci
           - marvell,armada-3700-ehci
           - marvell,orion-ehci
           - nuvoton,npcm750-ehci
index d3b2b666ec2a4c694e2b5dcce15a03fd1adff191..88e1607cf053ac11ae7bf76ea13f09ad4b15c7da 100644 (file)
@@ -33,13 +33,8 @@ properties:
   vcc-supply:
     description: power supply
 
-  mode-switch:
-    description: Flag the port as possible handle of altmode switching
-    type: boolean
-
-  orientation-switch:
-    description: Flag the port as possible handler of orientation switching
-    type: boolean
+  mode-switch: true
+  orientation-switch: true
 
   port:
     $ref: /schemas/graph.yaml#/properties/port
@@ -54,6 +49,9 @@ required:
   - orientation-switch
   - port
 
+allOf:
+  - $ref: usb-switch.yaml#
+
 additionalProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/usb/hisilicon,hi3798mv200-dwc3.yaml b/Documentation/devicetree/bindings/usb/hisilicon,hi3798mv200-dwc3.yaml
new file mode 100644 (file)
index 0000000..f301169
--- /dev/null
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/hisilicon,hi3798mv200-dwc3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HiSilicon Hi3798MV200 DWC3 USB SoC controller
+
+maintainers:
+  - Yang Xiwen <forbidden405@foxmail.com>
+
+properties:
+  compatible:
+    const: hisilicon,hi3798mv200-dwc3
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 1
+
+  ranges: true
+
+  clocks:
+    items:
+      - description: Controller bus clock
+      - description: Controller suspend clock
+      - description: Controller reference clock
+      - description: Controller gm clock
+      - description: Controller gs clock
+      - description: Controller utmi clock
+      - description: Controller pipe clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: suspend
+      - const: ref
+      - const: gm
+      - const: gs
+      - const: utmi
+      - const: pipe
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    const: soft
+
+patternProperties:
+  '^usb@[0-9a-f]+$':
+    $ref: snps,dwc3.yaml#
+
+required:
+  - compatible
+  - ranges
+  - '#address-cells'
+  - '#size-cells'
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    usb {
+        compatible = "hisilicon,hi3798mv200-dwc3";
+        ranges;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        clocks = <&clk_bus>,
+                 <&clk_suspend>,
+                 <&clk_ref>,
+                 <&clk_gm>,
+                 <&clk_gs>,
+                 <&clk_utmi>,
+                 <&clk_pipe>;
+        clock-names = "bus", "suspend", "ref", "gm", "gs", "utmi", "pipe";
+        resets = <&crg 0xb0 12>;
+        reset-names = "soft";
+
+        usb@98a0000 {
+            compatible = "snps,dwc3";
+            reg = <0x98a0000 0x10000>;
+            interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&clk_bus>,
+                     <&clk_suspend>,
+                     <&clk_ref>;
+            clock-names = "bus_early", "suspend", "ref";
+            phys = <&usb2_phy1_port2>, <&combphy0 0>;
+            phy-names = "usb2-phy", "usb3-phy";
+            maximum-speed = "super-speed";
+            dr_mode = "host";
+        };
+    };
diff --git a/Documentation/devicetree/bindings/usb/ite,it5205.yaml b/Documentation/devicetree/bindings/usb/ite,it5205.yaml
new file mode 100644 (file)
index 0000000..36ec425
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ite,it5205.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ITE IT5202 Type-C USB Alternate Mode Passive MUX
+
+maintainers:
+  - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+  - Tianping Fang <tianping.fang@mediatek.com>
+
+properties:
+  compatible:
+    const: ite,it5205
+
+  reg:
+    maxItems: 1
+
+  vcc-supply:
+    description: Power supply for VCC pin (3.3V)
+
+  mode-switch:
+    description: Flag the port as possible handle of altmode switching
+    type: boolean
+
+  orientation-switch:
+    description: Flag the port as possible handler of orientation switching
+    type: boolean
+
+  ite,ovp-enable:
+    description: Enable Over Voltage Protection functionality
+    type: boolean
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      A port node to link the IT5205 to a TypeC controller for the purpose of
+      handling altmode muxing and orientation switching.
+
+required:
+  - compatible
+  - reg
+  - orientation-switch
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c2 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        typec-mux@48 {
+          compatible = "ite,it5205";
+          reg = <0x48>;
+
+          mode-switch;
+          orientation-switch;
+
+          vcc-supply = <&mt6359_vibr_ldo_reg>;
+
+          port {
+            it5205_usbss_sbu: endpoint {
+              remote-endpoint = <&typec_controller>;
+            };
+          };
+        };
+    };
+...
index a59d91243ac836a94c0f990f487fab747ff4708b..d4e187c78a0b525717b776d41a0c6b0421f8b9c7 100644 (file)
@@ -185,7 +185,10 @@ properties:
             2 - used by mt2712 etc, revision 2 with following IPM rule;
             101 - used by mt8183, specific 1.01;
             102 - used by mt8192, specific 1.02;
-          enum: [1, 2, 101, 102]
+            103 - used by mt8195, IP0, specific 1.03;
+            105 - used by mt8195, IP2, specific 1.05;
+            106 - used by mt8195, IP3, specific 1.06;
+          enum: [1, 2, 101, 102, 103, 105, 106]
 
   mediatek,u3p-dis-msk:
     $ref: /schemas/types.yaml#/definitions/uint32
index 445183d9d6db1adaa1ab9d04cb4271eadbe22ffc..e2a72deae7760195d27fc450750d84144b1c3372 100644 (file)
@@ -72,8 +72,6 @@ allOf:
         i2c-bus: false
     else:
       $ref: /schemas/usb/usb-device.yaml
-      required:
-        - peer-hub
 
 additionalProperties: false
 
index eee548ac1abea377dc019ed646f835eb9b95bb9b..d805dde80796f31a066cf52ba2f226ce2e9e9cc2 100644 (file)
@@ -20,13 +20,8 @@ properties:
   vdd18-supply:
     description: Power supply for VDD18 pin
 
-  retimer-switch:
-    description: Flag the port as possible handle of SuperSpeed signals retiming
-    type: boolean
-
-  orientation-switch:
-    description: Flag the port as possible handler of orientation switching
-    type: boolean
+  orientation-switch: true
+  retimer-switch: true
 
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
@@ -49,6 +44,9 @@ required:
   - compatible
   - reg
 
+allOf:
+  - $ref: usb-switch.yaml#
+
 additionalProperties: false
 
 examples:
index eaedb4cc6b6cceae8af44c7507086c4b36fc402c..65a8632b4d9ed8f7f27b994df88adb903c051de6 100644 (file)
@@ -11,7 +11,9 @@ maintainers:
 
 properties:
   compatible:
-    const: nxp,ptn5110
+    items:
+      - const: nxp,ptn5110
+      - const: tcpci
 
   reg:
     maxItems: 1
@@ -41,7 +43,7 @@ examples:
         #size-cells = <0>;
 
         tcpci@50 {
-            compatible = "nxp,ptn5110";
+            compatible = "nxp,ptn5110", "tcpci";
             reg = <0x50>;
             interrupt-parent = <&gpio3>;
             interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
index c0201da002f62917aaeb2a90c3f6d4e0c1bcf5ae..589914d22bf250ff94c98ed22b32616d2c0cca1c 100644 (file)
@@ -21,14 +21,8 @@ properties:
     description: power supply (1.8V)
 
   enable-gpios: true
-
-  retimer-switch:
-    description: Flag the port as possible handle of SuperSpeed signals retiming
-    type: boolean
-
-  orientation-switch:
-    description: Flag the port as possible handler of orientation switching
-    type: boolean
+  orientation-switch: true
+  retimer-switch: true
 
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
@@ -95,6 +89,9 @@ required:
   - compatible
   - reg
 
+allOf:
+  - $ref: usb-switch.yaml#
+
 additionalProperties: false
 
 examples:
index 63d150b216c52873248ac478d840a713135dd576..38a3404ec71bbb8a2438b2dc61b161f5bc82a3a2 100644 (file)
@@ -102,7 +102,7 @@ properties:
     description: |
       Different types of interrupts are used based on HS PHY used on target:
         - pwr_event: Used for wakeup based on other power events.
-        - hs_phY_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is
+        - hs_phy_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is
                        hs_phy_irq which is not triggered by default and its
                        functionality is mutually exclusive to that of
                        {dp/dm}_hs_phy_irq and qusb2_phy_irq.
index 55df3129a0bc73afe855373655b9daf8d39bf37f..d9694570c419e8cc43119d63990262b7dcf00a05 100644 (file)
@@ -14,8 +14,19 @@ description:
 
 properties:
   compatible:
-    enum:
-      - qcom,pm8150b-typec
+    oneOf:
+      - enum:
+          - qcom,pmi632-typec
+          - qcom,pm8150b-typec
+      - items:
+          - enum:
+              - qcom,pm6150-typec
+          - const: qcom,pm8150b-typec
+      - items:
+          - enum:
+              - qcom,pm4125-typec
+          - const: qcom,pmi632-typec
+
 
   connector:
     type: object
@@ -24,9 +35,11 @@ properties:
 
   reg:
     description: Type-C port and pdphy SPMI register base offsets
+    minItems: 1
     maxItems: 2
 
   interrupts:
+    minItems: 8
     items:
       - description: Type-C CC attach notification, VBUS error, tCCDebounce done
       - description: Type-C VCONN powered
@@ -46,6 +59,7 @@ properties:
       - description: Power Domain Fast Role Swap event
 
   interrupt-names:
+    minItems: 8
     items:
       - const: or-rid-detect-change
       - const: vpd-detect
@@ -81,7 +95,33 @@ required:
   - interrupts
   - interrupt-names
   - vdd-vbus-supply
-  - vdd-pdphy-supply
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,pmi632-typec
+    then:
+      properties:
+        reg:
+          maxItems: 1
+        interrupts:
+          maxItems: 8
+        interrupt-names:
+          maxItems: 8
+        vdd-pdphy-supply: false
+    else:
+      properties:
+        reg:
+          maxItems: 2
+        interrupts:
+          minItems: 16
+        interrupt-names:
+          maxItems: 16
+      required:
+        - vdd-pdphy-supply
 
 additionalProperties: false
 
index 7ddfd3313a185875e1be376eed84918857034ac0..96346723f3e9c92c32325c7395eff49336cbcaf8 100644 (file)
@@ -35,13 +35,8 @@ properties:
   vdd-supply:
     description: USBSS VDD power supply
 
-  mode-switch:
-    description: Flag the port as possible handle of altmode switching
-    type: boolean
-
-  orientation-switch:
-    description: Flag the port as possible handler of orientation switching
-    type: boolean
+  mode-switch: true
+  orientation-switch: true
 
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
@@ -63,6 +58,9 @@ required:
   - reg
   - ports
 
+allOf:
+  - $ref: usb-switch.yaml#
+
 additionalProperties: false
 
 examples:
index f0784d2e86dae0b6a8d1c6b526a54e9bfcafc826..0874fc21f66fbba36548774b40d5712aa190c7c5 100644 (file)
@@ -21,6 +21,12 @@ properties:
 
   reg: true
 
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
   vdd-supply:
     description:
       phandle to the regulator that provides power to the hub.
@@ -30,6 +36,36 @@ properties:
     description:
       phandle to the peer hub on the controller.
 
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          1st downstream facing USB port
+
+      port@2:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          2nd downstream facing USB port
+
+      port@3:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          3rd downstream facing USB port
+
+      port@4:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          4th downstream facing USB port
+
+patternProperties:
+  '^.*@[1-4]$':
+    description: The hard wired USB devices
+    type: object
+    $ref: /schemas/usb/usb-device.yaml
+
 required:
   - peer-hub
   - compatible
@@ -50,6 +86,13 @@ examples:
             reg = <1>;
             vdd-supply = <&pp3300_hub>;
             peer-hub = <&hub_3_0>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+            /* USB 2.0 device on port 2 */
+            device@2 {
+                compatible = "usb123,4567";
+                reg = <2>;
+            };
         };
 
         /* 3.0 hub on port 2 */
@@ -58,5 +101,17 @@ examples:
             reg = <2>;
             vdd-supply = <&pp3300_hub>;
             peer-hub = <&hub_2_0>;
+
+            ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                /* Type-A connector on port 4 */
+                port@4 {
+                    reg = <4>;
+                    endpoint {
+                      remote-endpoint = <&usb_a0_ss>;
+                    };
+                };
+            };
         };
     };
index fec5651f560296828052866e1e8efd621fd33522..f6e6d084d1c5a786ad8f68a0e46658a60dc2c8f6 100644 (file)
@@ -14,7 +14,10 @@ properties:
     const: ti,am62-usb
 
   reg:
-    maxItems: 1
+    minItems: 1
+    items:
+      - description: USB CFG register space
+      - description: USB PHY2 register space
 
   ranges: true
 
@@ -82,7 +85,8 @@ examples:
 
       usbss1: usb@f910000 {
         compatible = "ti,am62-usb";
-        reg = <0x00 0x0f910000 0x00 0x800>;
+        reg = <0x00 0x0f910000 0x00 0x800>,
+              <0x00 0x0f918000 0x00 0x400>;
         clocks = <&k3_clks 162 3>;
         clock-names = "ref";
         ti,syscon-phy-pll-refclk = <&wkup_conf 0x4018>;
diff --git a/Documentation/devicetree/bindings/usb/ti,usb8020b.yaml b/Documentation/devicetree/bindings/usb/ti,usb8020b.yaml
new file mode 100644 (file)
index 0000000..8ef1177
--- /dev/null
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ti,usb8020b.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI USB8020B USB 3.0 hub controller
+
+maintainers:
+  - Macpaul Lin <macpaul.lin@mediatek.com>
+
+allOf:
+  - $ref: usb-device.yaml#
+
+properties:
+  compatible:
+    enum:
+      - usb451,8025
+      - usb451,8027
+
+  reg: true
+
+  reset-gpios:
+    items:
+      - description: GPIO specifier for GRST# pin.
+
+  vdd-supply:
+    description:
+      VDD power supply to the hub
+
+  peer-hub:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      phandle to the peer hub on the controller.
+
+required:
+  - compatible
+  - reg
+  - peer-hub
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    usb {
+        dr_mode = "host";
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        /* 2.0 hub on port 1 */
+        hub_2_0: hub@1 {
+          compatible = "usb451,8027";
+          reg = <1>;
+          peer-hub = <&hub_3_0>;
+          reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+          vdd-supply = <&usb_hub_fixed_3v3>;
+        };
+
+        /* 3.0 hub on port 2 */
+        hub_3_0: hub@2 {
+          compatible = "usb451,8025";
+          reg = <2>;
+          peer-hub = <&hub_2_0>;
+          reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>;
+          vdd-supply = <&usb_hub_fixed_3v3>;
+        };
+    };
index 6734f4d3aa789f829ed8bbb8c7cf5f7e8b03f7eb..9b3ea23654af6e2f2c9eadce1d8c5e3cffb938b1 100644 (file)
@@ -37,10 +37,11 @@ properties:
     description: Should specify the GPIO detecting a VBus insertion
     maxItems: 1
 
-  vbus-regulator:
-    description: Should specify the regulator supplying current drawn from
-      the VBus line.
-    $ref: /schemas/types.yaml#/definitions/phandle
+  vbus-supply:
+    description: regulator supplying VBUS. It will be enabled and disabled
+                 dynamically in OTG mode. If the regulator is controlled by a
+                 GPIO line, this should be modeled as a regulator-fixed and
+                 referenced by this supply.
 
   wakeup-source:
     description:
@@ -65,7 +66,7 @@ examples:
         vcc-supply = <&hsusb1_vcc_regulator>;
         reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
         vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>;
-        vbus-regulator = <&vbus_regulator>;
+        vbus-supply = <&vbus_regulator>;
         #phy-cells = <0>;
     };
 
diff --git a/Documentation/devicetree/bindings/usb/usb-switch.yaml b/Documentation/devicetree/bindings/usb/usb-switch.yaml
new file mode 100644 (file)
index 0000000..da76118
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/usb-switch.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: USB Orientation and Mode Switches Common Properties
+
+maintainers:
+  - Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+description:
+  Common properties for devices handling USB mode and orientation switching.
+
+properties:
+  mode-switch:
+    description: Possible handler of altmode switching
+    type: boolean
+
+  orientation-switch:
+    description: Possible handler of orientation switching
+    type: boolean
+
+  retimer-switch:
+    description: Possible handler of SuperSpeed signals retiming
+    type: boolean
+
+  port:
+    $ref: /schemas/graph.yaml#/properties/port
+    description:
+      A port node to link the device to a TypeC controller for the purpose of
+      handling altmode muxing and orientation switching.
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Super Speed (SS) Output endpoint to the Type-C connector
+
+      port@1:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        description:
+          Super Speed (SS) Input endpoint from the Super-Speed PHY
+        unevaluatedProperties: false
+
+        properties:
+          endpoint:
+            $ref: /schemas/graph.yaml#/$defs/endpoint-base
+            unevaluatedProperties: false
+            properties:
+              data-lanes:
+                $ref: /schemas/types.yaml#/definitions/uint32-array
+                minItems: 1
+                maxItems: 8
+                uniqueItems: true
+                items:
+                  maximum: 8
+
+oneOf:
+  - required:
+      - port
+  - required:
+      - ports
+
+additionalProperties: true
index 326b14f05d1c419dc39bb5d95de5150c99c135f3..1761b7aa92f052496a5ec1081fda7a90dc072c2b 100644 (file)
@@ -25,6 +25,8 @@ properties:
 
   usb-phy:
     $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      maxItems: 1
     description:
       List of all the USB PHYs on this HCD to be accepted by the legacy USB
       Physical Layer subsystem.
index 04505cb0b640f1b996606ea85c3d84206d649db8..b97d298b3eb695ba016d98b0715d692c23bb6ce1 100644 (file)
@@ -1573,6 +1573,8 @@ patternProperties:
     description: VoCore Studio
   "^voipac,.*":
     description: Voipac Technologies s.r.o.
+  "^voltafield,.*":
+    description: Voltafield Technology Corp.
   "^vot,.*":
     description: Vision Optical Technology Co., Ltd.
   "^vscom,.*":
diff --git a/Documentation/devicetree/bindings/w1/w1-uart.yaml b/Documentation/devicetree/bindings/w1/w1-uart.yaml
new file mode 100644 (file)
index 0000000..bd7c62d
--- /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/w1/w1-uart.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UART 1-Wire Bus
+
+maintainers:
+  - Christoph Winklhofer <cj.winklhofer@gmail.com>
+
+description: |
+  UART 1-wire bus. Utilizes the UART interface via the Serial Device Bus
+  to create the 1-Wire timing patterns.
+
+  The UART peripheral must support full-duplex and operate in open-drain
+  mode. The timing patterns are generated by a specific combination of
+  baud-rate and transmitted byte, which corresponds to a 1-Wire read bit,
+  write bit or reset pulse.
+
+  The default baud-rate for reset and presence detection is 9600 and for
+  a 1-Wire read or write operation 115200. In case the actual baud-rate
+  is different from the requested one, the transmitted byte is adapted
+  to generate the 1-Wire timing patterns.
+
+  https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html
+
+properties:
+  compatible:
+    const: w1-uart
+
+  reset-bps:
+    default: 9600
+    description:
+      The baud rate for the 1-Wire reset and presence detect.
+
+  write-0-bps:
+    default: 115200
+    description:
+      The baud rate for the 1-Wire write-0 cycle.
+
+  write-1-bps:
+    default: 115200
+    description:
+      The baud rate for the 1-Wire write-1 and read cycle.
+
+required:
+  - compatible
+
+additionalProperties:
+  type: object
+
+examples:
+  - |
+    serial {
+        onewire {
+            compatible = "w1-uart";
+        };
+    };
diff --git a/Documentation/driver-api/tty/console.rst b/Documentation/driver-api/tty/console.rst
new file mode 100644 (file)
index 0000000..4348e36
--- /dev/null
@@ -0,0 +1,45 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======
+Console
+=======
+
+.. contents:: :local:
+
+Struct Console
+==============
+
+.. kernel-doc:: include/linux/console.h
+   :identifiers: console cons_flags
+
+Internals
+---------
+
+.. kernel-doc:: include/linux/console.h
+   :identifiers: nbcon_state nbcon_prio nbcon_context nbcon_write_context
+
+Struct Consw
+============
+
+.. kernel-doc:: include/linux/console.h
+   :identifiers: consw
+
+Console functions
+=================
+
+.. kernel-doc:: include/linux/console.h
+   :identifiers: console_srcu_read_flags console_srcu_write_flags
+        console_is_registered for_each_console_srcu for_each_console
+
+.. kernel-doc:: drivers/tty/vt/selection.c
+   :export:
+.. kernel-doc:: drivers/tty/vt/vt.c
+   :export:
+
+Internals
+---------
+
+.. kernel-doc:: drivers/tty/vt/selection.c
+   :internal:
+.. kernel-doc:: drivers/tty/vt/vt.c
+   :internal:
index b490da11f257fce6c5469c781bd4fb1556153f67..c1ffe3d1ec46999d8767b66df5b274c075315580 100644 (file)
@@ -38,6 +38,7 @@ In-detail description of the named TTY structures is in separate documents:
    tty_buffer
    tty_ioctl
    tty_internals
+   console
 
 Writing TTY Driver
 ==================
index 2b80cf54bcc3118b956a8292aeae8e3af80acf7a..927da49b8f002f53cfcb93a6ef6dc9d72703fcd0 100644 (file)
@@ -99,8 +99,10 @@ The disconnect() callback
 This callback is a signal to break any connection with an interface.
 You are not allowed any IO to a device after returning from this
 callback. You also may not do any other operation that may interfere
-with another driver bound the interface, eg. a power management
-operation.
+with another driver bound to the interface, eg. a power management
+operation. Outstanding operations on the device must be completed or
+aborted before this callback may return.
+
 If you are called due to a physical disconnection, all your URBs will be
 killed by usbcore. Note that in this case disconnect will be called some
 time after the physical disconnection. Thus your driver must be prepared
index d96b778b87ed8e8c19b457340a3386ef186f19bc..7425d2b994a3997447a42a43bf924c7be401a6d7 100644 (file)
 # Rely on implicit context synchronization as a result of exception return
 # when returning from IPI handler, and when returning to user-space.
 #
+# * riscv
+#
+# riscv uses xRET as return from interrupt and to return to user-space.
+#
+# Given that xRET is not core serializing, we rely on FENCE.I for providing
+# core serialization:
+#
+#  - by calling sync_core_before_usermode() on return from interrupt (cf.
+#    ipi_sync_core()),
+#
+#  - via switch_mm() and sync_core_before_usermode() (respectively, for
+#    uthread->uthread and kthread->uthread transitions) before returning
+#    to user-space.
+#
+#  The serialization in switch_mm() is activated by prepare_sync_core_cmd().
+#
 # * x86
 #
 # x86-32 uses IRET as return from interrupt, which takes care of the IPI.
@@ -43,7 +59,7 @@
     |    openrisc: | TODO |
     |      parisc: | TODO |
     |     powerpc: |  ok  |
-    |       riscv: | TODO |
+    |       riscv: |  ok  |
     |        s390: |  ok  |
     |          sh: | TODO |
     |       sparc: | TODO |
index d32c6209685d64bae996ed110ea9cfe7543fa14c..efc3493fd6f84b92b986da63c44e8629bd042f02 100644 (file)
@@ -126,9 +126,7 @@ norecovery           Disable the roll-forward recovery routine, mounted read-
 discard/nodiscard       Enable/disable real-time discard in f2fs, if discard is
                         enabled, f2fs will issue discard/TRIM commands when a
                         segment is cleaned.
-no_heap                         Disable heap-style segment allocation which finds free
-                        segments for data from the beginning of main area, while
-                        for node from the end of main area.
+heap/no_heap            Deprecated.
 nouser_xattr            Disable Extended User Attributes. Note: xattr is enabled
                         by default if CONFIG_F2FS_FS_XATTR is selected.
 noacl                   Disable POSIX Access Control List. Note: acl is enabled
@@ -184,29 +182,31 @@ 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
-                        FAULT_PAGE_GET           0x000000008
-                        FAULT_ALLOC_BIO          0x000000010 (obsolete)
-                        FAULT_ALLOC_NID          0x000000020
-                        FAULT_ORPHAN             0x000000040
-                        FAULT_BLOCK              0x000000080
-                        FAULT_DIR_DEPTH          0x000000100
-                        FAULT_EVICT_INODE        0x000000200
-                        FAULT_TRUNCATE           0x000000400
-                        FAULT_READ_IO            0x000000800
-                        FAULT_CHECKPOINT         0x000001000
-                        FAULT_DISCARD            0x000002000
-                        FAULT_WRITE_IO           0x000004000
-                        FAULT_SLAB_ALLOC         0x000008000
-                        FAULT_DQUOT_INIT         0x000010000
-                        FAULT_LOCK_OP            0x000020000
-                        FAULT_BLKADDR            0x000040000
-                        ===================      ===========
+                        ===========================      ===========
+                        Type_Name                        Type_Value
+                        ===========================      ===========
+                        FAULT_KMALLOC                    0x000000001
+                        FAULT_KVMALLOC                   0x000000002
+                        FAULT_PAGE_ALLOC                 0x000000004
+                        FAULT_PAGE_GET                   0x000000008
+                        FAULT_ALLOC_BIO                  0x000000010 (obsolete)
+                        FAULT_ALLOC_NID                  0x000000020
+                        FAULT_ORPHAN                     0x000000040
+                        FAULT_BLOCK                      0x000000080
+                        FAULT_DIR_DEPTH                  0x000000100
+                        FAULT_EVICT_INODE                0x000000200
+                        FAULT_TRUNCATE                   0x000000400
+                        FAULT_READ_IO                    0x000000800
+                        FAULT_CHECKPOINT                 0x000001000
+                        FAULT_DISCARD                    0x000002000
+                        FAULT_WRITE_IO                   0x000004000
+                        FAULT_SLAB_ALLOC                 0x000008000
+                        FAULT_DQUOT_INIT                 0x000010000
+                        FAULT_LOCK_OP                    0x000020000
+                        FAULT_BLKADDR_VALIDITY           0x000040000
+                        FAULT_BLKADDR_CONSISTENCE        0x000080000
+                        FAULT_NO_SEGMENT                 0x000100000
+                        ===========================      ===========
 mode=%s                         Control block allocation mode which supports "adaptive"
                         and "lfs". In "lfs" mode, there should be no random
                         writes towards main area.
@@ -228,8 +228,6 @@ mode=%s                      Control block allocation mode which supports "adaptive"
                         option for more randomness.
                         Please, use these options for your experiments and we strongly
                         recommend to re-format the filesystem after using these options.
-io_bits=%u              Set the bit size of write IO requests. It should be set
-                        with "mode=lfs".
 usrquota                Enable plain user disk quota accounting.
 grpquota                Enable plain group disk quota accounting.
 prjquota                Enable plain project quota accounting.
index d79f693909913b97069b162649f99ad8c24d3fbd..0165b09c0957f5010e32271c4e371458de8fa2ea 100644 (file)
@@ -595,7 +595,7 @@ bridges/switches of the board.
 
 For example, let's assume we have a system with a PCIe serial port, an
 Exar XR17V3521, soldered on the main board. This UART chip also includes
-16 GPIOs and we want to add the property ``gpio-line-names`` [1] to these pins.
+16 GPIOs and we want to add the property ``gpio-line-names`` [1]_ to these pins.
 In this case, the ``lspci`` output for this component is::
 
        07:00.0 Serial controller: Exar Corp. XR17V3521 Dual PCIe UART (rev 03)
@@ -637,7 +637,7 @@ of the chipset bridge (also called "root port") with address::
        Bus: 0 - Device: 14 - Function: 1
 
 To find this information, it is necessary to disassemble the BIOS ACPI tables,
-in particular the DSDT (see also [2])::
+in particular the DSDT (see also [2]_)::
 
        mkdir ~/tables/
        cd ~/tables/
@@ -667,7 +667,7 @@ device::
                        }
        ... other definitions follow ...
 
-and the _ADR method [3] returns exactly the device/function couple that
+and the _ADR method [3]_ returns exactly the device/function couple that
 we are looking for. With this information and analyzing the above ``lspci``
 output (both the devices list and the devices tree), we can write the following
 ACPI description for the Exar PCIe UART, also adding the list of its GPIO line
@@ -724,10 +724,10 @@ created analyzing the position of the Exar UART in the PCI bus topology.
 References
 ==========
 
-[1] Documentation/firmware-guide/acpi/gpio-properties.rst
+.. [1] Documentation/firmware-guide/acpi/gpio-properties.rst
 
-[2] Documentation/admin-guide/acpi/initrd_table_override.rst
+.. [2] Documentation/admin-guide/acpi/initrd_table_override.rst
 
-[3] ACPI Specifications, Version 6.3 - Paragraph 6.1.1 _ADR Address)
+.. [3] ACPI Specifications, Version 6.3 - Paragraph 6.1.1 _ADR Address)
     https://uefi.org/sites/default/files/resources/ACPI_6_3_May16.pdf,
     referenced 2020-11-18
diff --git a/Documentation/iio/adis16475.rst b/Documentation/iio/adis16475.rst
new file mode 100644 (file)
index 0000000..91cabb7
--- /dev/null
@@ -0,0 +1,407 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+ADIS16475 driver
+================
+
+This driver supports Analog Device's IMUs on SPI bus.
+
+1. Supported devices
+====================
+
+* `ADIS16465 <https://www.analog.com/ADIS16465>`_
+* `ADIS16467 <https://www.analog.com/ADIS16467>`_
+* `ADIS16470 <https://www.analog.com/ADIS16470>`_
+* `ADIS16475 <https://www.analog.com/ADIS16475>`_
+* `ADIS16477 <https://www.analog.com/ADIS16477>`_
+* `ADIS16500 <https://www.analog.com/ADIS16500>`_
+* `ADIS16505 <https://www.analog.com/ADIS16505>`_
+* `ADIS16507 <https://www.analog.com/ADIS16507>`_
+
+Each supported device is a precision, miniature microelectromechanical system
+(MEMS) inertial measurement unit (IMU) that includes a triaxial gyroscope and a
+triaxial accelerometer. Each inertial sensor in the IMU device combines with
+signal conditioning that optimizes dynamic performance. The factory calibration
+characterizes each sensor for sensitivity, bias, alignment, linear acceleration
+(gyroscope bias), and point of percussion (accelerometer location). As a result,
+each sensor has dynamic compensation formulas that provide accurate sensor
+measurements over a broad set of conditions.
+
+2. Device attributes
+====================
+
+Accelerometer, gyroscope measurements are always provided. Furthermore, the
+driver offers the capability to retrieve the delta angle and the delta velocity
+measurements computed by the device.
+
+The delta angle measurements represent a calculation of angular displacement
+between each sample update, while the delta velocity measurements represent a
+calculation of linear velocity change between each sample update.
+
+Finally, temperature data are provided which show a coarse measurement of
+the temperature inside of the IMU device. This data is most useful for
+monitoring relative changes in the thermal environment.
+
+The signal chain of each inertial sensor (accelerometers and gyroscopes)
+includes the application of unique correction formulas, which are derived from
+extensive characterization of bias, sensitivity, alignment, response to linear
+acceleration (gyroscopes), and point of percussion (accelerometer location)
+over a temperature range of −40°C to +85°C, for each ADIS device. These
+correction formulas are not accessible, but users do have the opportunity to
+adjust the bias for each sensor individually through the calibbias attribute.
+
+Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
+where X is the IIO index of the device. Under these folders reside a set of
+device files, depending on the characteristics and features of the hardware
+device in questions. These files are consistently generalized and documented in
+the IIO ABI documentation.
+
+The following tables show the adis16475 related device files, found in the
+specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
+
++-------------------------------------------+----------------------------------------------------------+
+| 3-Axis Accelerometer related device files | Description                                              |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_scale                            | Scale for the accelerometer channels.                    |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_x_calibbias                      | Calibration offset for the X-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_calibbias_x                      | x-axis acceleration offset correction                    |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_x_raw                            | Raw X-axis accelerometer channel value.                  |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_calibbias_y                      | y-axis acceleration offset correction                    |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_y_raw                            | Raw Y-axis accelerometer channel value.                  |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_z_calibbias                      | Calibration offset for the Z-axis accelerometer channel. |
++-------------------------------------------+----------------------------------------------------------+
+| in_accel_z_raw                            | Raw Z-axis accelerometer channel value.                  |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_scale                    | Scale for delta velocity channels.                       |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_x_raw                    | Raw X-axis delta velocity channel value.                 |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_y_raw                    | Raw Y-axis delta velocity channel value.                 |
++-------------------------------------------+----------------------------------------------------------+
+| in_deltavelocity_z_raw                    | Raw Z-axis delta velocity channel value.                 |
++-------------------------------------------+----------------------------------------------------------+
+
++---------------------------------------+------------------------------------------------------+
+| 3-Axis Gyroscope related device files | Description                                          |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_scale                      | Scale for the gyroscope channels.                    |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_x_calibbias                | Calibration offset for the X-axis gyroscope channel. |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_calibbias_x                | x-axis gyroscope offset correction                   |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_x_raw                      | Raw X-axis gyroscope channel value.                  |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_calibbias_y                | y-axis gyroscope offset correction                   |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_y_raw                      | Raw Y-axis gyroscope channel value.                  |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_z_calibbias                | Calibration offset for the Z-axis gyroscope channel. |
++---------------------------------------+------------------------------------------------------+
+| in_anglvel_z_raw                      | Raw Z-axis gyroscope channel value.                  |
++---------------------------------------+------------------------------------------------------+
+| in_deltaangl_scale                    | Scale for delta angle channels.                      |
++---------------------------------------+------------------------------------------------------+
+| in_deltaangl_x_raw                    | Raw X-axis delta angle channel value.                |
++---------------------------------------+------------------------------------------------------+
+| in_deltaangl_y_raw                    | Raw Y-axis delta angle channel value.                |
++---------------------------------------+------------------------------------------------------+
+| in_deltaangl_z_raw                    | Raw Z-axis delta angle channel value.                |
++---------------------------------------+------------------------------------------------------+
+
++----------------------------------+-------------------------------------------+
+| Temperature sensor related files | Description                               |
++----------------------------------+-------------------------------------------+
+| in_temp0_raw                     | Raw temperature channel value.            |
++----------------------------------+-------------------------------------------+
+| in_temp0_scale                   | Scale for the temperature sensor channel. |
++----------------------------------+-------------------------------------------+
+
++-------------------------------+---------------------------------------------------------+
+| Miscellaneous device files    | Description                                             |
++-------------------------------+---------------------------------------------------------+
+| name                          | Name of the IIO device.                                 |
++-------------------------------+---------------------------------------------------------+
+| sampling_frequency            | Currently selected sample rate.                         |
++-------------------------------+---------------------------------------------------------+
+| filter_low_pass_3db_frequency | Bandwidth for the accelerometer and gyroscope channels. |
++-------------------------------+---------------------------------------------------------+
+
+The following table shows the adis16475 related device debug files, found in the
+specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``.
+
++----------------------+-------------------------------------------------------------------------+
+| Debugfs device files | Description                                                             |
++----------------------+-------------------------------------------------------------------------+
+| serial_number        | The serial number of the chip in hexadecimal format.                    |
++----------------------+-------------------------------------------------------------------------+
+| product_id           | Chip specific product id (e.g. 16475, 16500, 16505, etc.).              |
++----------------------+-------------------------------------------------------------------------+
+| flash_count          | The number of flash writes performed on the device.                     |
++----------------------+-------------------------------------------------------------------------+
+| firmware_revision    | String containing the firmware revision in the following format ##.##.  |
++----------------------+-------------------------------------------------------------------------+
+| firmware_date        | String containing the firmware date in the following format mm-dd-yyyy. |
++----------------------+-------------------------------------------------------------------------+
+
+Channels processed values
+-------------------------
+
+A channel value can be read from its _raw attribute. The value returned is the
+raw value as reported by the devices. To get the processed value of the channel,
+apply the following formula:
+
+.. code-block:: bash
+
+        processed value = (_raw + _offset) * _scale
+
+Where _offset and _scale are device attributes. If no _offset attribute is
+present, simply assume its value is 0.
+
+The adis16475 driver offers data for 5 types of channels, the table below shows
+the measurement units for the processed value, which are defined by the IIO
+framework:
+
++-------------------------------------+---------------------------+
+| Channel type                        | Measurement unit          |
++-------------------------------------+---------------------------+
+| Acceleration on X, Y, and Z axis    | Meters per Second squared |
++-------------------------------------+---------------------------+
+| Angular velocity on X, Y and Z axis | Radians per second        |
++-------------------------------------+---------------------------+
+| Delta velocity on X. Y, and Z axis  | Meters per Second         |
++-------------------------------------+---------------------------+
+| Delta angle on X, Y, and Z axis     | Radians                   |
++-------------------------------------+---------------------------+
+| Temperature                         | Millidegrees Celsius      |
++-------------------------------------+---------------------------+
+
+Usage examples
+--------------
+
+Show device name:
+
+.. code-block:: bash
+
+       root:/sys/bus/iio/devices/iio:device0> cat name
+        adis16505-2
+
+Show accelerometer channels value:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw
+        -275924
+        root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw
+        -30142222
+        root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw
+        261265769
+        root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale
+        0.000000037
+
+- X-axis acceleration = in_accel_x_raw * in_accel_scale = −0.010209188 m/s^2
+- Y-axis acceleration = in_accel_y_raw * in_accel_scale = −1.115262214 m/s^2
+- Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.666833453 m/s^2
+
+Show gyroscope channels value:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw
+        -3324626
+        root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw
+        1336980
+        root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw
+        -602983
+        root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale
+        0.000000006
+
+- X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = −0.019947756 rad/s
+- Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = 0.00802188 rad/s
+- Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = −0.003617898 rad/s
+
+Set calibration offset for accelerometer channels:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
+        0
+
+        root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias
+        root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
+        5000
+
+Set calibration offset for gyroscope channels:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
+        0
+
+        root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias
+        root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
+        -5000
+
+Set sampling frequency:
+
+.. code-block:: bash
+
+       root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency
+        2000.000000
+
+        root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency
+        1000.000000
+
+Set bandwidth for accelerometer and gyroscope:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency
+        720
+
+        root:/sys/bus/iio/devices/iio:device0> echo 360 > filter_low_pass_3db_frequency
+        root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency
+        360
+
+Show serial number:
+
+.. code-block:: bash
+
+        root:/sys/kernel/debug/iio/iio:device0> cat serial_number
+        0x04f9
+
+Show product id:
+
+.. code-block:: bash
+
+        root:/sys/kernel/debug/iio/iio:device0> cat product_id
+        16505
+
+Show flash count:
+
+.. code-block:: bash
+
+        root:/sys/kernel/debug/iio/iio:device0> cat flash_count
+        150
+
+Show firmware revision:
+
+.. code-block:: bash
+
+        root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision
+        1.6
+
+Show firmware date:
+
+.. code-block:: bash
+
+        root:/sys/kernel/debug/iio/iio:device0> cat firmware_date
+        06-27-2019
+
+3. Device buffers
+=================
+
+This driver supports IIO buffers.
+
+All devices support retrieving the raw acceleration, gyroscope and temperature
+measurements using buffers.
+
+The following device families also support retrieving the delta velocity, delta
+angle and temperature measurements using buffers:
+
+- ADIS16477
+- ADIS16500
+- ADIS16505
+- ADIS16507
+
+However, when retrieving acceleration or gyroscope data using buffers, delta
+readings will not be available and vice versa.
+
+Usage examples
+--------------
+
+Set device trigger in current_trigger, if not already set:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
+
+        root:/sys/bus/iio/devices/iio:device0> echo adis16505-2-dev0 > trigger/current_trigger
+        root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
+        adis16505-2-dev0
+
+Select channels for buffer read:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en
+        root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en
+        root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en
+        root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en
+
+Set the number of samples to be stored in the buffer:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length
+
+Enable buffer readings:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable
+
+Obtain buffered data:
+
+.. code-block:: bash
+
+        root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0
+        ...
+        00001680  01 1f 00 00 ff ff fe ef  00 00 47 bf 00 03 35 55  |..........G...5U|
+        00001690  01 1f 00 00 ff ff ff d9  00 00 46 f1 00 03 35 35  |..........F...55|
+        000016a0  01 1f 00 00 ff ff fe fc  00 00 46 cb 00 03 35 7b  |..........F...5{|
+        000016b0  01 1f 00 00 ff ff fe 41  00 00 47 0d 00 03 35 8b  |.......A..G...5.|
+        000016c0  01 1f 00 00 ff ff fe 37  00 00 46 b4 00 03 35 90  |.......7..F...5.|
+        000016d0  01 1d 00 00 ff ff fe 5a  00 00 45 d7 00 03 36 08  |.......Z..E...6.|
+        000016e0  01 1b 00 00 ff ff fe fb  00 00 45 e7 00 03 36 60  |..........E...6`|
+        000016f0  01 1a 00 00 ff ff ff 17  00 00 46 bc 00 03 36 de  |..........F...6.|
+        00001700  01 1a 00 00 ff ff fe 59  00 00 46 d7 00 03 37 b8  |.......Y..F...7.|
+        00001710  01 1a 00 00 ff ff fe ae  00 00 46 95 00 03 37 ba  |..........F...7.|
+        00001720  01 1a 00 00 ff ff fe c5  00 00 46 63 00 03 37 9f  |..........Fc..7.|
+        00001730  01 1a 00 00 ff ff fe 55  00 00 46 89 00 03 37 c1  |.......U..F...7.|
+        00001740  01 1a 00 00 ff ff fe 31  00 00 46 aa 00 03 37 f7  |.......1..F...7.|
+        ...
+
+See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
+data is structured.
+
+4. IIO Interfacing Tools
+========================
+
+Linux Kernel Tools
+------------------
+
+Linux Kernel provides some userspace tools that can be used to retrieve data
+from IIO sysfs:
+
+* lsiio: example application that provides a list of IIO devices and triggers
+* iio_event_monitor: example application that reads events from an IIO device
+  and prints them
+* iio_generic_buffer: example application that reads data from buffer
+* iio_utils: set of APIs, typically used to access sysfs files.
+
+LibIIO
+------
+
+LibIIO is a C/C++ library that provides generic access to IIO devices. The
+library abstracts the low-level details of the hardware, and provides a simple
+yet complete programming interface that can be used for advanced projects.
+
+For more information about LibIIO, please see:
+https://github.com/analogdevicesinc/libiio
diff --git a/Documentation/iio/iio_devbuf.rst b/Documentation/iio/iio_devbuf.rst
new file mode 100644 (file)
index 0000000..9919e47
--- /dev/null
@@ -0,0 +1,152 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================
+Industrial IIO device buffers
+=============================
+
+1. Overview
+===========
+
+The Industrial I/O core offers a way for continuous data capture based on a
+trigger source. Multiple data channels can be read at once from
+``/dev/iio:deviceX`` character device node, thus reducing the CPU load.
+
+Devices with buffer support feature an additional sub-directory in the
+``/sys/bus/iio/devices/iio:deviceX/`` directory hierarchy, called bufferY, where
+Y defaults to 0, for devices with a single buffer.
+
+2. Buffer attributes
+====================
+
+An IIO buffer has an associated attributes directory under
+``/sys/bus/iio/iio:deviceX/bufferY/``. The attributes are described below.
+
+``length``
+----------
+
+Read / Write attribute which states the total number of data samples (capacity)
+that can be stored by the buffer.
+
+``enable``
+----------
+
+Read / Write attribute which starts / stops the buffer capture. This file should
+be written last, after length and selection of scan elements. Writing a non-zero
+value may result in an error, such as EINVAL, if, for example, an unsupported
+combination of channels is given.
+
+``watermark``
+-------------
+
+Read / Write positive integer attribute specifying the maximum number of scan
+elements to wait for.
+
+Poll will block until the watermark is reached.
+
+Blocking read will wait until the minimum between the requested read amount or
+the low watermark is available.
+
+Non-blocking read will retrieve the available samples from the buffer even if
+there are less samples than the watermark level. This allows the application to
+block on poll with a timeout and read the available samples after the timeout
+expires and thus have a maximum delay guarantee.
+
+Data available
+--------------
+
+Read-only attribute indicating the bytes of data available in the buffer. In the
+case of an output buffer, this indicates the amount of empty space available to
+write data to. In the case of an input buffer, this indicates the amount of data
+available for reading.
+
+Scan elements
+-------------
+
+The meta information associated with a channel data placed in a buffer is called
+a scan element. The scan elements attributes are presented below.
+
+**_en**
+
+Read / Write attribute used for enabling a channel. If and only if its value
+is non-zero, then a triggered capture will contain data samples for this
+channel.
+
+**_index**
+
+Read-only unsigned integer attribute specifying the position of the channel in
+the buffer. Note these are not dependent on what is enabled and may not be
+contiguous. Thus for userspace to establish the full layout these must be used
+in conjunction with all _en attributes to establish which channels are present,
+and the relevant _type attributes to establish the data storage format.
+
+**_type**
+
+Read-only attribute containing the description of the scan element data storage
+within the buffer and hence the form in which it is read from userspace. Format
+is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift], where:
+
+- **be** or **le** specifies big or little-endian.
+- **s** or **u** specifies if signed (2's complement) or unsigned.
+- **bits** is the number of valid data bits.
+- **storagebits** is the number of bits (after padding) that it occupies in the
+  buffer.
+- **repeat** specifies the number of bits/storagebits repetitions. When the
+  repeat element is 0 or 1, then the repeat value is omitted.
+- **shift** if specified, is the shift that needs to be applied prior to
+  masking out unused bits.
+
+For example, a driver for a 3-axis accelerometer with 12-bit resolution where
+data is stored in two 8-bit registers is as follows::
+
+          7   6   5   4   3   2   1   0
+        +---+---+---+---+---+---+---+---+
+        |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06)
+        +---+---+---+---+---+---+---+---+
+
+          7   6   5   4   3   2   1   0
+        +---+---+---+---+---+---+---+---+
+        |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07)
+        +---+---+---+---+---+---+---+---+
+
+will have the following scan element type for each axis:
+
+.. code-block:: bash
+
+        $ cat /sys/bus/iio/devices/iio:device0/buffer0/in_accel_y_type
+        le:s12/16>>4
+
+A userspace application will interpret data samples read from the buffer as
+two-byte little-endian signed data, that needs a 4 bits right shift before
+masking out the 12 valid bits of data.
+
+It is also worth mentioning that the data in the buffer will be naturally
+aligned, so the userspace application has to handle the buffers accordingly.
+
+Take for example, a driver with four channels with the following description:
+- channel0: index: 0, type: be:u16/16>>0
+- channel1: index: 1, type: be:u32/32>>0
+- channel2: index: 2, type: be:u32/32>>0
+- channel3: index: 3, type: be:u64/64>>0
+
+If all channels are enabled, the data will be aligned in the buffer as follows::
+
+          0-1   2   3   4-7  8-11  12  13  14  15  16-23   -> buffer byte number
+        +-----+---+---+-----+-----+---+---+---+---+-----+
+        |CHN_0|PAD|PAD|CHN_1|CHN_2|PAD|PAD|PAD|PAD|CHN_3|  -> buffer content
+        +-----+---+---+-----+-----+---+---+---+---+-----+
+
+If only channel0 and channel3 are enabled, the data will be aligned in the
+buffer as follows::
+
+          0-1   2   3   4   5   6   7  8-15    -> buffer byte number
+        +-----+---+---+---+---+---+---+-----+
+        |CHN_0|PAD|PAD|PAD|PAD|PAD|PAD|CHN_3|  -> buffer content
+        +-----+---+---+---+---+---+---+-----+
+
+Typically the buffered data is found in raw format (unscaled with no offset
+applied), however there are corner cases in which the buffered data may be found
+in a processed form. Please note that these corner cases are not addressed by
+this documentation.
+
+Please see ``Documentation/ABI/testing/sysfs-bus-iio`` for a complete
+description of the attributes.
index 1b7292c58cd07a4cd33a897377335bb24af8703d..30b09eefe75edf6c5aad2c522a72ee08ba40c5ca 100644 (file)
@@ -8,7 +8,14 @@ Industrial I/O
    :maxdepth: 1
 
    iio_configfs
+   iio_devbuf
 
-   ep93xx_adc
+Industrial I/O Kernel Drivers
+=============================
 
+.. toctree::
+   :maxdepth: 1
+
+   adis16475
    bno055
+   ep93xx_adc
index 0135905c0aa352f2d83747cc407080d0973d9bd8..79ac2e8184f6f0da6de66eb082ae69b44a85f951 100644 (file)
@@ -393,7 +393,7 @@ of C0, which doesn't depend on M::
 
 choices::
 
-       "choice" [symbol]
+       "choice"
        <choice options>
        <choice block>
        "endchoice"
@@ -412,10 +412,6 @@ the kernel, but all drivers can be compiled as modules.
 
 A choice accepts another option "optional", which allows to set the
 choice to 'n' and no entry needs to be selected.
-If no [symbol] is associated with a choice, then you can not have multiple
-definitions of that choice. If a [symbol] is associated to the choice,
-then you may define the same choice (i.e. with the same entries) in another
-place.
 
 comment::
 
index c946eb44bd138e9784c94b3a1eacf242c7dc06e5..fc4e845bc249ba87b5ce045186683848f424bced 100644 (file)
@@ -1,10 +1,10 @@
-===================
-Kconfig make config
-===================
+=================================
+Configuration targets and editors
+=================================
 
-This file contains some assistance for using `make *config`.
+This file contains some assistance for using ``make *config``.
 
-Use "make help" to list all of the possible configuration targets.
+Use ``make help`` to list all of the possible configuration targets.
 
 The xconfig ('qconf'), menuconfig ('mconf'), and nconfig ('nconf')
 programs also have embedded help text.  Be sure to check that for
@@ -12,8 +12,9 @@ navigation, search, and other general help text.
 
 The gconfig ('gconf') program has limited help text.
 
+
 General
--------
+=======
 
 New kernel releases often introduce new config symbols.  Often more
 important, new kernel releases may rename config symbols.  When
@@ -24,118 +25,102 @@ symbols have been introduced.
 
 To see a list of new config symbols, use::
 
-       cp user/some/old.config .config
-       make listnewconfig
+    cp user/some/old.config .config
+    make listnewconfig
 
 and the config program will list any new symbols, one per line.
 
 Alternatively, you can use the brute force method::
 
-       make oldconfig
-       scripts/diffconfig .config.old .config | less
-
-----------------------------------------------------------------------
-
-Environment variables for `*config`
+    make oldconfig
+    scripts/diffconfig .config.old .config | less
 
-KCONFIG_CONFIG
---------------
-This environment variable can be used to specify a default kernel config
-file name to override the default name of ".config".
 
-KCONFIG_DEFCONFIG_LIST
-----------------------
+Environment variables
+=====================
 
-This environment variable specifies a list of config files which can be used
-as a base configuration in case the .config does not exist yet. Entries in
-the list are separated with whitespaces to each other, and the first one
-that exists is used.
+Environment variables for ``*config``:
 
-KCONFIG_OVERWRITECONFIG
------------------------
-If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
-break symlinks when .config is a symlink to somewhere else.
+``KCONFIG_CONFIG``
+    This environment variable can be used to specify a default kernel config
+    file name to override the default name of ".config".
 
-KCONFIG_WARN_UNKNOWN_SYMBOLS
-----------------------------
-This environment variable makes Kconfig warn about all unrecognized
-symbols in the config input.
+``KCONFIG_DEFCONFIG_LIST``
+    This environment variable specifies a list of config files which can be
+    used as a base configuration in case the .config does not exist yet.
+    Entries in the list are separated with whitespaces to each other, and
+    the first one that exists is used.
 
-KCONFIG_WERROR
---------------
-If set, Kconfig treats warnings as errors.
+``KCONFIG_OVERWRITECONFIG``
+    If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
+    break symlinks when .config is a symlink to somewhere else.
 
-`CONFIG_`
----------
-If you set `CONFIG_` in the environment, Kconfig will prefix all symbols
-with its value when saving the configuration, instead of using the default,
-`CONFIG_`.
+``KCONFIG_WARN_UNKNOWN_SYMBOLS``
+    This environment variable makes Kconfig warn about all unrecognized
+    symbols in the config input.
 
-----------------------------------------------------------------------
+``KCONFIG_WERROR``
+    If set, Kconfig treats warnings as errors.
 
-Environment variables for '{allyes/allmod/allno/rand}config'
+``CONFIG_``
+    If you set ``CONFIG_`` in the environment, Kconfig will prefix all symbols
+    with its value when saving the configuration, instead of using the
+    default, ``CONFIG_``.
 
-KCONFIG_ALLCONFIG
------------------
-(partially based on lkml email from/by Rob Landley, re: miniconfig)
+Environment variables for ``{allyes/allmod/allno/rand}config``:
 
---------------------------------------------------
+``KCONFIG_ALLCONFIG``
+    The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also
+    use the environment variable KCONFIG_ALLCONFIG as a flag or a filename
+    that contains config symbols that the user requires to be set to a
+    specific value.  If KCONFIG_ALLCONFIG is used without a filename where
+    KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", ``make *config``
+    checks for a file named "all{yes/mod/no/def/random}.config"
+    (corresponding to the ``*config`` command that was used) for symbol values
+    that are to be forced.  If this file is not found, it checks for a
+    file named "all.config" to contain forced values.
 
-The allyesconfig/allmodconfig/allnoconfig/randconfig variants can also
-use the environment variable KCONFIG_ALLCONFIG as a flag or a filename
-that contains config symbols that the user requires to be set to a
-specific value.  If KCONFIG_ALLCONFIG is used without a filename where
-KCONFIG_ALLCONFIG == "" or KCONFIG_ALLCONFIG == "1", `make *config`
-checks for a file named "all{yes/mod/no/def/random}.config"
-(corresponding to the `*config` command that was used) for symbol values
-that are to be forced.  If this file is not found, it checks for a
-file named "all.config" to contain forced values.
+    This enables you to create "miniature" config (miniconfig) or custom
+    config files containing just the config symbols that you are interested
+    in.  Then the kernel config system generates the full .config file,
+    including symbols of your miniconfig file.
 
-This enables you to create "miniature" config (miniconfig) or custom
-config files containing just the config symbols that you are interested
-in.  Then the kernel config system generates the full .config file,
-including symbols of your miniconfig file.
-
-This 'KCONFIG_ALLCONFIG' file is a config file which contains
-(usually a subset of all) preset config symbols.  These variable
-settings are still subject to normal dependency checks.
-
-Examples::
+    This ``KCONFIG_ALLCONFIG`` file is a config file which contains
+    (usually a subset of all) preset config symbols.  These variable
+    settings are still subject to normal dependency checks.
 
-       KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig
+    Examples::
 
-or::
+        KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig
 
-       KCONFIG_ALLCONFIG=mini.config make allnoconfig
+    or::
 
-or::
+        KCONFIG_ALLCONFIG=mini.config make allnoconfig
 
-       make KCONFIG_ALLCONFIG=mini.config allnoconfig
+    or::
 
-These examples will disable most options (allnoconfig) but enable or
-disable the options that are explicitly listed in the specified
-mini-config files.
+        make KCONFIG_ALLCONFIG=mini.config allnoconfig
 
-----------------------------------------------------------------------
+    These examples will disable most options (allnoconfig) but enable or
+    disable the options that are explicitly listed in the specified
+    mini-config files.
 
-Environment variables for 'randconfig'
+Environment variables for ``randconfig``:
 
-KCONFIG_SEED
-------------
-You can set this to the integer value used to seed the RNG, if you want
-to somehow debug the behaviour of the kconfig parser/frontends.
-If not set, the current time will be used.
+``KCONFIG_SEED``
+    You can set this to the integer value used to seed the RNG, if you want
+    to somehow debug the behaviour of the kconfig parser/frontends.
+    If not set, the current time will be used.
 
-KCONFIG_PROBABILITY
--------------------
-This variable can be used to skew the probabilities. This variable can
-be unset or empty, or set to three different formats:
+``KCONFIG_PROBABILITY``
+    This variable can be used to skew the probabilities. This variable can
+    be unset or empty, or set to three different formats:
 
     =======================     ==================  =====================
-       KCONFIG_PROBABILITY     y:n split           y:m:n split
+    KCONFIG_PROBABILITY         y:n split           y:m:n split
     =======================     ==================  =====================
-       unset or empty          50  : 50            33  : 33  : 34
-       N                        N  : 100-N         N/2 : N/2 : 100-N
+    unset or empty              50  : 50            33  : 33  : 34
+    N                            N  : 100-N         N/2 : N/2 : 100-N
     [1] N:M                     N+M : 100-(N+M)      N  :  M  : 100-(N+M)
     [2] N:M:L                    N  : 100-N          M  :  L  : 100-(M+L)
     =======================     ==================  =====================
@@ -149,112 +134,98 @@ that:
 
 Examples::
 
-       KCONFIG_PROBABILITY=10
-               10% of booleans will be set to 'y', 90% to 'n'
-               5% of tristates will be set to 'y', 5% to 'm', 90% to 'n'
-       KCONFIG_PROBABILITY=15:25
-               40% of booleans will be set to 'y', 60% to 'n'
-               15% of tristates will be set to 'y', 25% to 'm', 60% to 'n'
-       KCONFIG_PROBABILITY=10:15:15
-               10% of booleans will be set to 'y', 90% to 'n'
-               15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
+    KCONFIG_PROBABILITY=10
+        10% of booleans will be set to 'y', 90% to 'n'
+        5% of tristates will be set to 'y', 5% to 'm', 90% to 'n'
+    KCONFIG_PROBABILITY=15:25
+        40% of booleans will be set to 'y', 60% to 'n'
+        15% of tristates will be set to 'y', 25% to 'm', 60% to 'n'
+    KCONFIG_PROBABILITY=10:15:15
+        10% of booleans will be set to 'y', 90% to 'n'
+        15% of tristates will be set to 'y', 15% to 'm', 70% to 'n'
 
-----------------------------------------------------------------------
+Environment variables for ``syncconfig``:
 
-Environment variables for 'syncconfig'
+``KCONFIG_NOSILENTUPDATE``
+    If this variable has a non-blank value, it prevents silent kernel
+    config updates (requires explicit updates).
 
-KCONFIG_NOSILENTUPDATE
-----------------------
-If this variable has a non-blank value, it prevents silent kernel
-config updates (requires explicit updates).
+``KCONFIG_AUTOCONFIG``
+    This environment variable can be set to specify the path & name of the
+    "auto.conf" file.  Its default value is "include/config/auto.conf".
 
-KCONFIG_AUTOCONFIG
-------------------
-This environment variable can be set to specify the path & name of the
-"auto.conf" file.  Its default value is "include/config/auto.conf".
+``KCONFIG_AUTOHEADER``
+    This environment variable can be set to specify the path & name of the
+    "autoconf.h" (header) file.
+    Its default value is "include/generated/autoconf.h".
 
-KCONFIG_AUTOHEADER
-------------------
-This environment variable can be set to specify the path & name of the
-"autoconf.h" (header) file.
-Its default value is "include/generated/autoconf.h".
-
-
-----------------------------------------------------------------------
 
 menuconfig
-----------
-
-SEARCHING for CONFIG symbols
+==========
 
 Searching in menuconfig:
 
-       The Search function searches for kernel configuration symbol
-       names, so you have to know something close to what you are
-       looking for.
+    The Search function searches for kernel configuration symbol
+    names, so you have to know something close to what you are
+    looking for.
 
-       Example::
+    Example::
 
-               /hotplug
-               This lists all config symbols that contain "hotplug",
-               e.g., HOTPLUG_CPU, MEMORY_HOTPLUG.
+        /hotplug
+        This lists all config symbols that contain "hotplug",
+        e.g., HOTPLUG_CPU, MEMORY_HOTPLUG.
 
-       For search help, enter / followed by TAB-TAB (to highlight
-       <Help>) and Enter.  This will tell you that you can also use
-       regular expressions (regexes) in the search string, so if you
-       are not interested in MEMORY_HOTPLUG, you could try::
+    For search help, enter / followed by TAB-TAB (to highlight
+    <Help>) and Enter.  This will tell you that you can also use
+    regular expressions (regexes) in the search string, so if you
+    are not interested in MEMORY_HOTPLUG, you could try::
 
-               /^hotplug
+        /^hotplug
 
-       When searching, symbols are sorted thus:
+    When searching, symbols are sorted thus:
 
-         - first, exact matches, sorted alphabetically (an exact match
-           is when the search matches the complete symbol name);
-         - then, other matches, sorted alphabetically.
+    - first, exact matches, sorted alphabetically (an exact match
+      is when the search matches the complete symbol name);
+    - then, other matches, sorted alphabetically.
 
-       For example: ^ATH.K matches:
+    For example, ^ATH.K matches:
 
-           ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
-           [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
+        ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
+        [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
 
-       of which only ATH5K and ATH9K match exactly and so are sorted
-       first (and in alphabetical order), then come all other symbols,
-       sorted in alphabetical order.
+    of which only ATH5K and ATH9K match exactly and so are sorted
+    first (and in alphabetical order), then come all other symbols,
+    sorted in alphabetical order.
 
-       In this menu, pressing the key in the (#) prefix will jump
-       directly to that location. You will be returned to the current
-       search results after exiting this new menu.
+    In this menu, pressing the key in the (#) prefix will jump
+    directly to that location. You will be returned to the current
+    search results after exiting this new menu.
 
-----------------------------------------------------------------------
+User interface options for 'menuconfig':
 
-User interface options for 'menuconfig'
+``MENUCONFIG_COLOR``
+    It is possible to select different color themes using the variable
+    MENUCONFIG_COLOR.  To select a theme use::
 
-MENUCONFIG_COLOR
-----------------
-It is possible to select different color themes using the variable
-MENUCONFIG_COLOR.  To select a theme use::
+        make MENUCONFIG_COLOR=<theme> menuconfig
 
-       make MENUCONFIG_COLOR=<theme> menuconfig
+    Available themes are::
 
-Available themes are::
+      - mono       => selects colors suitable for monochrome displays
+      - blackbg    => selects a color scheme with black background
+      - classic    => theme with blue background. The classic look
+      - bluetitle  => a LCD friendly version of classic. (default)
 
-  - mono       => selects colors suitable for monochrome displays
-  - blackbg    => selects a color scheme with black background
-  - classic    => theme with blue background. The classic look
-  - bluetitle  => a LCD friendly version of classic. (default)
+``MENUCONFIG_MODE``
+    This mode shows all sub-menus in one large tree.
 
-MENUCONFIG_MODE
----------------
-This mode shows all sub-menus in one large tree.
+    Example::
 
-Example::
+        make MENUCONFIG_MODE=single_menu menuconfig
 
-       make MENUCONFIG_MODE=single_menu menuconfig
-
-----------------------------------------------------------------------
 
 nconfig
--------
+=======
 
 nconfig is an alternate text-based configurator.  It lists function
 keys across the bottom of the terminal (window) that execute commands.
@@ -266,61 +237,59 @@ Use F1 for Global help or F3 for the Short help menu.
 
 Searching in nconfig:
 
-       You can search either in the menu entry "prompt" strings
-       or in the configuration symbols.
+    You can search either in the menu entry "prompt" strings
+    or in the configuration symbols.
+
+    Use / to begin a search through the menu entries.  This does
+    not support regular expressions.  Use <Down> or <Up> for
+    Next hit and Previous hit, respectively.  Use <Esc> to
+    terminate the search mode.
 
-       Use / to begin a search through the menu entries.  This does
-       not support regular expressions.  Use <Down> or <Up> for
-       Next hit and Previous hit, respectively.  Use <Esc> to
-       terminate the search mode.
+    F8 (SymSearch) searches the configuration symbols for the
+    given string or regular expression (regex).
 
-       F8 (SymSearch) searches the configuration symbols for the
-       given string or regular expression (regex).
+    In the SymSearch, pressing the key in the (#) prefix will
+    jump directly to that location. You will be returned to the
+    current search results after exiting this new menu.
 
-       In the SymSearch, pressing the key in the (#) prefix will
-       jump directly to that location. You will be returned to the
-       current search results after exiting this new menu.
+Environment variables:
 
-NCONFIG_MODE
-------------
-This mode shows all sub-menus in one large tree.
+``NCONFIG_MODE``
+    This mode shows all sub-menus in one large tree.
 
-Example::
+    Example::
 
-       make NCONFIG_MODE=single_menu nconfig
+        make NCONFIG_MODE=single_menu nconfig
 
-----------------------------------------------------------------------
 
 xconfig
--------
+=======
 
 Searching in xconfig:
 
-       The Search function searches for kernel configuration symbol
-       names, so you have to know something close to what you are
-       looking for.
-
-       Example::
+    The Search function searches for kernel configuration symbol
+    names, so you have to know something close to what you are
+    looking for.
 
-               Ctrl-F hotplug
+    Example::
 
-       or::
+        Ctrl-F hotplug
 
-               Menu: File, Search, hotplug
+    or::
 
-       lists all config symbol entries that contain "hotplug" in
-       the symbol name.  In this Search dialog, you may change the
-       config setting for any of the entries that are not grayed out.
-       You can also enter a different search string without having
-       to return to the main menu.
+        Menu: File, Search, hotplug
 
+    lists all config symbol entries that contain "hotplug" in
+    the symbol name.  In this Search dialog, you may change the
+    config setting for any of the entries that are not grayed out.
+    You can also enter a different search string without having
+    to return to the main menu.
 
-----------------------------------------------------------------------
 
 gconfig
--------
+=======
 
 Searching in gconfig:
 
-       There is no search command in gconfig.  However, gconfig does
-       have several different viewing choices, modes, and options.
+    There is no search command in gconfig.  However, gconfig does
+    have several different viewing choices, modes, and options.
index 75eba7c431b2f136e55507dab3c597ac8dd5441c..138d61f869df09524dc3d8aa9c7af69543726898 100644 (file)
@@ -3,3 +3,13 @@
 ==========
 Page Cache
 ==========
+
+The page cache is the primary way that the user and the rest of the kernel
+interact with filesystems.  It can be bypassed (e.g. with O_DIRECT),
+but normal reads, writes and mmaps go through the page cache.
+
+Folios
+======
+
+The folio is the unit of memory management within the page cache.
+Operations 
index 6ec7d686efab04546045a3ccfe0a2d096a2d89b5..05fe2b11bb18834cade782b1426f7c2991de42b8 100644 (file)
@@ -99,6 +99,12 @@ Minimal SR-IOV support is currently offered and can be enabled by setting
 the sysfs 'sriov_numvfs' value, if supported by your particular firmware
 configuration.
 
+XDP
+---
+
+Support for XDP includes the basics, plus Jumbo frames, Redirect and
+ndo_xmit.  There is no current support for zero-copy sockets or HW offload.
+
 Statistics
 ==========
 
@@ -138,6 +144,12 @@ Driver port specific::
      rx_csum_none: 0
      rx_csum_complete: 3
      rx_csum_error: 0
+     xdp_drop: 0
+     xdp_aborted: 0
+     xdp_pass: 0
+     xdp_tx: 0
+     xdp_redirect: 0
+     xdp_frames: 0
 
 Driver queue specific::
 
@@ -149,9 +161,12 @@ Driver queue specific::
      tx_0_frags: 0
      tx_0_tso: 0
      tx_0_tso_bytes: 0
+     tx_0_hwstamp_valid: 0
+     tx_0_hwstamp_invalid: 0
      tx_0_csum_none: 3
      tx_0_csum: 0
      tx_0_vlan_inserted: 0
+     tx_0_xdp_frames: 0
      rx_0_pkts: 2
      rx_0_bytes: 120
      rx_0_dma_map_err: 0
@@ -159,8 +174,15 @@ Driver queue specific::
      rx_0_csum_none: 0
      rx_0_csum_complete: 0
      rx_0_csum_error: 0
+     rx_0_hwstamp_valid: 0
+     rx_0_hwstamp_invalid: 0
      rx_0_dropped: 0
      rx_0_vlan_stripped: 0
+     rx_0_xdp_drop: 0
+     rx_0_xdp_aborted: 0
+     rx_0_xdp_pass: 0
+     rx_0_xdp_tx: 0
+     rx_0_xdp_redirect: 0
 
 Firmware port specific::
 
index be8e4bcadf119021496fc98db04c5c77cd24b39f..268819225866cb1a023470ad3017026394ac7f89 100644 (file)
@@ -87,35 +87,35 @@ all using the same instance under "priv->mdev".
 
 Observability
 =============
-The relation between PF, irq, napi, and queue can be observed via netlink spec:
-
-$ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump queue-get --json='{"ifindex": 13}'
-[{'id': 0, 'ifindex': 13, 'napi-id': 539, 'type': 'rx'},
- {'id': 1, 'ifindex': 13, 'napi-id': 540, 'type': 'rx'},
- {'id': 2, 'ifindex': 13, 'napi-id': 541, 'type': 'rx'},
- {'id': 3, 'ifindex': 13, 'napi-id': 542, 'type': 'rx'},
- {'id': 4, 'ifindex': 13, 'napi-id': 543, 'type': 'rx'},
- {'id': 0, 'ifindex': 13, 'napi-id': 539, 'type': 'tx'},
- {'id': 1, 'ifindex': 13, 'napi-id': 540, 'type': 'tx'},
- {'id': 2, 'ifindex': 13, 'napi-id': 541, 'type': 'tx'},
- {'id': 3, 'ifindex': 13, 'napi-id': 542, 'type': 'tx'},
- {'id': 4, 'ifindex': 13, 'napi-id': 543, 'type': 'tx'}]
-
-$ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump napi-get --json='{"ifindex": 13}'
-[{'id': 543, 'ifindex': 13, 'irq': 42},
- {'id': 542, 'ifindex': 13, 'irq': 41},
- {'id': 541, 'ifindex': 13, 'irq': 40},
- {'id': 540, 'ifindex': 13, 'irq': 39},
- {'id': 539, 'ifindex': 13, 'irq': 36}]
-
-Here you can clearly observe our channels distribution policy:
-
-$ ls /proc/irq/{36,39,40,41,42}/mlx5* -d -1
-/proc/irq/36/mlx5_comp1@pci:0000:08:00.0
-/proc/irq/39/mlx5_comp1@pci:0000:09:00.0
-/proc/irq/40/mlx5_comp2@pci:0000:08:00.0
-/proc/irq/41/mlx5_comp2@pci:0000:09:00.0
-/proc/irq/42/mlx5_comp3@pci:0000:08:00.0
+The relation between PF, irq, napi, and queue can be observed via netlink spec::
+
+  $ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump queue-get --json='{"ifindex": 13}'
+  [{'id': 0, 'ifindex': 13, 'napi-id': 539, 'type': 'rx'},
  {'id': 1, 'ifindex': 13, 'napi-id': 540, 'type': 'rx'},
  {'id': 2, 'ifindex': 13, 'napi-id': 541, 'type': 'rx'},
  {'id': 3, 'ifindex': 13, 'napi-id': 542, 'type': 'rx'},
  {'id': 4, 'ifindex': 13, 'napi-id': 543, 'type': 'rx'},
  {'id': 0, 'ifindex': 13, 'napi-id': 539, 'type': 'tx'},
  {'id': 1, 'ifindex': 13, 'napi-id': 540, 'type': 'tx'},
  {'id': 2, 'ifindex': 13, 'napi-id': 541, 'type': 'tx'},
  {'id': 3, 'ifindex': 13, 'napi-id': 542, 'type': 'tx'},
  {'id': 4, 'ifindex': 13, 'napi-id': 543, 'type': 'tx'}]
+
+  $ ./tools/net/ynl/cli.py --spec Documentation/netlink/specs/netdev.yaml --dump napi-get --json='{"ifindex": 13}'
+  [{'id': 543, 'ifindex': 13, 'irq': 42},
  {'id': 542, 'ifindex': 13, 'irq': 41},
  {'id': 541, 'ifindex': 13, 'irq': 40},
  {'id': 540, 'ifindex': 13, 'irq': 39},
  {'id': 539, 'ifindex': 13, 'irq': 36}]
+
+Here you can clearly observe our channels distribution policy::
+
+  $ ls /proc/irq/{36,39,40,41,42}/mlx5* -d -1
+  /proc/irq/36/mlx5_comp1@pci:0000:08:00.0
+  /proc/irq/39/mlx5_comp1@pci:0000:09:00.0
+  /proc/irq/40/mlx5_comp2@pci:0000:08:00.0
+  /proc/irq/41/mlx5_comp2@pci:0000:09:00.0
+  /proc/irq/42/mlx5_comp3@pci:0000:08:00.0
 
 Steering
 ========
index dceb49d56a91158232543e920c7ed23bed74106e..70c4fb9d4e5ce0feb0d82578b878da3dbd00a7fb 100644 (file)
@@ -13,7 +13,7 @@ struct_dev_ifalias*                 ifalias
 unsigned_long                       mem_end                                                         
 unsigned_long                       mem_start                                                       
 unsigned_long                       base_addr                                                       
-unsigned_long                       state                                                           
+unsigned_long                       state                   read_mostly         read_mostly         netif_running(dev)
 struct_list_head                    dev_list                                                        
 struct_list_head                    napi_list                                                       
 struct_list_head                    unreg_list                                                      
index dfbace2f4600c8dbbdaa58a748e6377577685f8c..f588feeecad0fccb7d8f6a169cb93d24a273960a 100644 (file)
@@ -78,7 +78,7 @@ handling the given IRQ as a system wakeup interrupt line and disable_irq_wake()
 turns that logic off.
 
 Calling enable_irq_wake() causes suspend_device_irqs() to treat the given IRQ
-in a special way.  Namely, the IRQ remains enabled, by on the first interrupt
+in a special way.  Namely, the IRQ remains enabled, but on the first interrupt
 it will be disabled, marked as pending and "suspended" so that it will be
 re-enabled by resume_device_irqs() during the subsequent system resume.  Also
 the PM core is notified about the event which causes the system suspend in
index 5d3c3de3f4ecbd8953f0b7791e4fabe107a4f57c..ce6753a674f336b59785f105b2e419547724bd75 100644 (file)
@@ -27,11 +27,11 @@ The important bits (aka "The TL;DR")
    is optional, but recommended):
 
     * For mailed reports, check if the reporter included a line like ``#regzbot
-      introduced v5.13..v5.14-rc1``. If not, send a reply (with the regressions
+      introduced: v5.13..v5.14-rc1``. If not, send a reply (with the regressions
       list in CC) containing a paragraph like the following, which tells regzbot
       when the issue started to happen::
 
-       #regzbot ^introduced 1f2e3d4c5b6a
+       #regzbot ^introduced: 1f2e3d4c5b6a
 
     * When forwarding reports from a bug tracker to the regressions list (see
       above), include a paragraph like the following::
@@ -79,7 +79,7 @@ When doing either, consider making the Linux kernel regression tracking bot
 "regzbot" immediately start tracking the issue:
 
  * For mailed reports, check if the reporter included a "regzbot command" like
-   ``#regzbot introduced 1f2e3d4c5b6a``. If not, send a reply (with the
+   ``#regzbot introduced: 1f2e3d4c5b6a``. If not, send a reply (with the
    regressions list in CC) with a paragraph like the following:::
 
        #regzbot ^introduced: v5.13..v5.14-rc1
@@ -398,9 +398,9 @@ By using a 'regzbot command' in a direct or indirect reply to the mail with the
 regression report. These commands need to be in their own paragraph (IOW: they
 need to be separated from the rest of the mail using blank lines).
 
-One such command is ``#regzbot introduced <version or commit>``, which makes
+One such command is ``#regzbot introduced: <version or commit>``, which makes
 regzbot consider your mail as a regressions report added to the tracking, as
-already described above; ``#regzbot ^introduced <version or commit>`` is another
+already described above; ``#regzbot ^introduced: <version or commit>`` is another
 such command, which makes regzbot consider the parent mail as a report for a
 regression which it starts to track.
 
@@ -432,7 +432,7 @@ or itself is a reply to that mail:
  * Mark a regression as fixed by a commit that is heading upstream or already
    landed::
 
-       #regzbot fixed-by: 1f2e3d4c5d
+       #regzbot fix: 1f2e3d4c5d
 
  * Mark a regression as a duplicate of another one already tracked by regzbot::
 
index 3170747226f6da7f828223f6504704391fe47314..43bd8a145b7a9b380e4706b751e40ab7fe05138a 100644 (file)
@@ -7,6 +7,7 @@ Scheduler
 
 
     completion
+    membarrier
     sched-arch
     sched-bwc
     sched-deadline
diff --git a/Documentation/scheduler/membarrier.rst b/Documentation/scheduler/membarrier.rst
new file mode 100644 (file)
index 0000000..2387804
--- /dev/null
@@ -0,0 +1,39 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================
+membarrier() System Call
+========================
+
+MEMBARRIER_CMD_{PRIVATE,GLOBAL}_EXPEDITED - Architecture requirements
+=====================================================================
+
+Memory barriers before updating rq->curr
+----------------------------------------
+
+The commands MEMBARRIER_CMD_PRIVATE_EXPEDITED and MEMBARRIER_CMD_GLOBAL_EXPEDITED
+require each architecture to have a full memory barrier after coming from
+user-space, before updating rq->curr.  This barrier is implied by the sequence
+rq_lock(); smp_mb__after_spinlock() in __schedule().  The barrier matches a full
+barrier in the proximity of the membarrier system call exit, cf.
+membarrier_{private,global}_expedited().
+
+Memory barriers after updating rq->curr
+---------------------------------------
+
+The commands MEMBARRIER_CMD_PRIVATE_EXPEDITED and MEMBARRIER_CMD_GLOBAL_EXPEDITED
+require each architecture to have a full memory barrier after updating rq->curr,
+before returning to user-space.  The schemes providing this barrier on the various
+architectures are as follows.
+
+ - alpha, arc, arm, hexagon, mips rely on the full barrier implied by
+   spin_unlock() in finish_lock_switch().
+
+ - arm64 relies on the full barrier implied by switch_to().
+
+ - powerpc, riscv, s390, sparc, x86 rely on the full barrier implied by
+   switch_mm(), if mm is not NULL; they rely on the full barrier implied
+   by mmdrop(), otherwise.  On powerpc and riscv, switch_mm() relies on
+   membarrier_arch_switch_mm().
+
+The barrier matches a full barrier in the proximity of the membarrier system call
+entry, cf. membarrier_{private,global}_expedited().
index 2f20e5b405e66afba0ff50b233abf659884fe2a4..ff98ddc76a7478efbd9faccafb8e46f672952e8d 100644 (file)
@@ -6,7 +6,7 @@ Supported board/chip:
 
   * National Semiconductor LM70 LLP evaluation board
 
-    Datasheet: http://www.national.com/pf/LM/LM70.html
+    Datasheet: https://www.ti.com/lit/gpn/lm70
 
 Author:
         Kaiwan N Billimoria <kaiwan@designergraphix.com>
@@ -28,7 +28,7 @@ Hardware Interfacing
 The schematic for this particular board (the LM70EVAL-LLP) is
 available (on page 4) here:
 
-  http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
+  https://download.datasheets.com/pdfs/documentation/nat/kit&board/lm70llpevalmanual.pdf
 
 The hardware interfacing on the LM70 LLP eval board is as follows:
 
index 369c657ba4358bd6164dc85ea0c5b7c5ebba0dad..e08b301ad24ac649293ad7c4b7b911dde80d877d 100644 (file)
@@ -61,7 +61,7 @@ the spidev driver failing to probe.
 
 Sysfs also supports userspace driven binding/unbinding of drivers to
 devices that do not bind automatically using one of the tables above.
-To make the spidev driver bind to such a device, use the following:
+To make the spidev driver bind to such a device, use the following::
 
     echo spidev > /sys/bus/spi/devices/spiB.C/driver_override
     echo spiB.C > /sys/bus/spi/drivers/spidev/bind
index 88506b397c2dd6d0ce6009881b932016c85f1c48..d3255ed70195faafe9c9affaef7e751e3049b002 100644 (file)
@@ -33,3 +33,9 @@
         to wait on the timerlat_fd. Once the workload is awakes, it goes to sleep again
         adding so the measurement for the kernel-to-user and user-to-kernel to the tracer
         output.
+
+**-U**, **--user-load**
+
+        Set timerlat to run without workload, waiting for the user to dispatch a per-cpu
+        task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd.
+        See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code.
index d8f12442aaa6bdaa85012e8cda49b881837fedb2..1d5a7626e6a6c93cc46bd963b6d5979931344a5c 100644 (file)
@@ -92,6 +92,24 @@ The following flags are currently supported.
   process closes or unregisters the event. Requires CAP_PERFMON otherwise
   -EPERM is returned.
 
++ USER_EVENT_REG_MULTI_FORMAT: The event can contain multiple formats. This
+  allows programs to prevent themselves from being blocked when their event
+  format changes and they wish to use the same name. When this flag is used the
+  tracepoint name will be in the new format of "name.unique_id" vs the older
+  format of "name". A tracepoint will be created for each unique pair of name
+  and format. This means if several processes use the same name and format,
+  they will use the same tracepoint. If yet another process uses the same name,
+  but a different format than the other processes, it will use a different
+  tracepoint with a new unique id. Recording programs need to scan tracefs for
+  the various different formats of the event name they are interested in
+  recording. The system name of the tracepoint will also use "user_events_multi"
+  instead of "user_events". This prevents single-format event names conflicting
+  with any multi-format event names within tracefs. The unique_id is output as
+  a hex string. Recording programs should ensure the tracepoint name starts with
+  the event name they registered and has a suffix that starts with . and only
+  has hex characters. For example to find all versions of the event "test" you
+  can use the regex "^test\.[0-9a-fA-F]+$".
+
 Upon successful registration the following is set.
 
 + write_index: The index to use for this file descriptor that represents this
@@ -106,6 +124,9 @@ or perf record -e user_events:[name] when attaching/recording.
 **NOTE:** The event subsystem name by default is "user_events". Callers should
 not assume it will always be "user_events". Operators reserve the right in the
 future to change the subsystem name per-process to accommodate event isolation.
+In addition if the USER_EVENT_REG_MULTI_FORMAT flag is used the tracepoint name
+will have a unique id appended to it and the system name will be
+"user_events_multi" as described above.
 
 Command Format
 ^^^^^^^^^^^^^^
@@ -156,7 +177,11 @@ to request deletes than the one used for registration due to this.
 to the event. If programs do not want auto-delete, they must use the
 USER_EVENT_REG_PERSIST flag when registering the event. Once that flag is used
 the event exists until DIAG_IOCSDEL is invoked. Both register and delete of an
-event that persists requires CAP_PERFMON, otherwise -EPERM is returned.
+event that persists requires CAP_PERFMON, otherwise -EPERM is returned. When
+there are multiple formats of the same event name, all events with the same
+name will be attempted to be deleted. If only a specific version is wanted to
+be deleted then the /sys/kernel/tracing/dynamic_events file should be used for
+that specific format of the event.
 
 Unregistering
 -------------
index a3054bea38f3cd48dc02d82cd578f35072263ab0..d05a775bc45bc032cc583bee7162f79c5848b784 100644 (file)
@@ -2,6 +2,9 @@
 How FunctionFS works
 ====================
 
+Overview
+========
+
 From kernel point of view it is just a composite function with some
 unique behaviour.  It may be added to an USB configuration only after
 the user space driver has registered by writing descriptors and
@@ -66,3 +69,36 @@ have been written to their ep0's.
 
 Conversely, the gadget is unregistered after the first USB function
 closes its endpoints.
+
+DMABUF interface
+================
+
+FunctionFS additionally supports a DMABUF based interface, where the
+userspace can attach DMABUF objects (externally created) to an endpoint,
+and subsequently use them for data transfers.
+
+A userspace application can then use this interface to share DMABUF
+objects between several interfaces, allowing it to transfer data in a
+zero-copy fashion, for instance between IIO and the USB stack.
+
+As part of this interface, three new IOCTLs have been added. These three
+IOCTLs have to be performed on a data endpoint (ie. not ep0). They are:
+
+  ``FUNCTIONFS_DMABUF_ATTACH(int)``
+    Attach the DMABUF object, identified by its file descriptor, to the
+    data endpoint. Returns zero on success, and a negative errno value
+    on error.
+
+  ``FUNCTIONFS_DMABUF_DETACH(int)``
+    Detach the given DMABUF object, identified by its file descriptor,
+    from the data endpoint. Returns zero on success, and a negative
+    errno value on error. Note that closing the endpoint's file
+    descriptor will automatically detach all attached DMABUFs.
+
+  ``FUNCTIONFS_DMABUF_TRANSFER(struct usb_ffs_dmabuf_transfer_req *)``
+    Enqueue the previously attached DMABUF to the transfer queue.
+    The argument is a structure that packs the DMABUF's file descriptor,
+    the size in bytes to transfer (which should generally correspond to
+    the size of the DMABUF), and a 'flags' field which is unused
+    for now. Returns zero on success, and a negative errno value on
+    error.
index 077dfac7ed98f7911d731312eb09631e41c63772..b086c7ab72f065a2881bd290d637706b5bf0adf1 100644 (file)
@@ -206,6 +206,14 @@ the standard procedure for using FunctionFS (mount it, run the userspace
 process which implements the function proper). The gadget should be enabled
 by writing a suitable string to usb_gadget/<gadget>/UDC.
 
+The FFS function provides just one attribute in its function directory:
+
+       ready
+
+The attribute is read-only and signals if the function is ready (1) to be
+used, E.G. if userspace has written descriptors and strings to ep0, so
+the gadget can be enabled.
+
 Testing the FFS function
 ------------------------
 
index 4442a98850adf3b8297058fde80dc65ff98a7600..cc40189909fd17098d2a3763a0e1d401de92b889 100644 (file)
@@ -12,3 +12,4 @@
    mxc-w1
    omap-hdq
    w1-gpio
+   w1-uart
diff --git a/Documentation/w1/masters/w1-uart.rst b/Documentation/w1/masters/w1-uart.rst
new file mode 100644 (file)
index 0000000..8d0f122
--- /dev/null
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+=====================
+Kernel driver w1-uart
+=====================
+
+Author: Christoph Winklhofer <cj.winklhofer@gmail.com>
+
+
+Description
+-----------
+
+UART 1-Wire bus driver. The driver utilizes the UART interface via the
+Serial Device Bus to create the 1-Wire timing patterns as described in
+the document `"Using a UART to Implement a 1-Wire Bus Master"`_.
+
+.. _"Using a UART to Implement a 1-Wire Bus Master": https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html
+
+In short, the UART peripheral must support full-duplex and operate in
+open-drain mode. The timing patterns are generated by a specific
+combination of baud-rate and transmitted byte, which corresponds to a
+1-Wire read bit, write bit or reset pulse.
+
+For instance the timing pattern for a 1-Wire reset and presence detect uses
+the baud-rate 9600, i.e. 104.2 us per bit. The transmitted byte 0xf0 over
+UART (least significant bit first, start-bit low) sets the reset low time
+for 1-Wire to 521 us. A present 1-Wire device changes the received byte by
+pulling the line low, which is used by the driver to evaluate the result of
+the 1-Wire operation.
+
+Similar for a 1-Wire read bit or write bit, which uses the baud-rate
+115200, i.e. 8.7 us per bit. The transmitted byte 0x80 is used for a
+Write-0 operation (low time 69.6us) and the byte 0xff for Read-0, Read-1
+and Write-1 (low time 8.7us).
+
+The default baud-rate for reset and presence detection is 9600 and for
+a 1-Wire read or write operation 115200. In case the actual baud-rate
+is different from the requested one, the transmitted byte is adapted
+to generate the 1-Wire timing patterns.
+
+
+Usage
+-----
+
+Specify the UART 1-wire bus in the device tree by adding the single child
+onewire to the serial node (e.g. uart0). For example:
+::
+
+  @uart0 {
+    ...
+    onewire {
+      compatible = "w1-uart";
+    };
+  };
index d4300cab7062440dfbccd6b6a0b4e7c65d39236e..aa3b947fb0801dc9de9365c1d61ca4a0733431d2 100644 (file)
@@ -579,6 +579,12 @@ F: drivers/iio/accel/adxl372.c
 F:     drivers/iio/accel/adxl372_i2c.c
 F:     drivers/iio/accel/adxl372_spi.c
 
+AF8133J THREE-AXIS MAGNETOMETER DRIVER
+M:     Ondřej Jirman <megi@xff.cz>
+S:     Maintained
+F:     Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml
+F:     drivers/iio/magnetometer/af8133j.c
+
 AF9013 MEDIA DRIVER
 L:     linux-media@vger.kernel.org
 S:     Orphan
@@ -1158,7 +1164,7 @@ L:        linux-iio@vger.kernel.org
 S:     Supported
 W:     http://ez.analog.com/community/linux-device-drivers
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7091r*
-F:     drivers/iio/adc/drivers/iio/adc/ad7091r*
+F:     drivers/iio/adc/ad7091r*
 
 ANALOG DEVICES INC AD7192 DRIVER
 M:     Alexandru Tachici <alexandru.tachici@analog.com>
@@ -1281,6 +1287,14 @@ W:       https://ez.analog.com/linux-software-drivers
 F:     Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml
 F:     drivers/hwmon/adm1177.c
 
+ANALOG DEVICES INC ADMFM2000 DRIVER
+M:     Kim Seer Paller <kimseer.paller@analog.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+W:     https://ez.analog.com/linux-software-drivers
+F:     Documentation/devicetree/bindings/iio/frequency/adi,admfm2000.yaml
+F:     drivers/iio/frequency/admfm2000.c
+
 ANALOG DEVICES INC ADMV1013 DRIVER
 M:     Antoniu Miclaus <antoniu.miclaus@analog.com>
 L:     linux-iio@vger.kernel.org
@@ -2363,8 +2377,8 @@ M:        Sean Wang <sean.wang@mediatek.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     Documentation/devicetree/bindings/rtc/rtc-mt2712.txt
-F:     Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
+F:     Documentation/devicetree/bindings/rtc/mediatek,mt2712-rtc.yaml
+F:     Documentation/devicetree/bindings/rtc/mediatek,mt7622-rtc.yaml
 F:     drivers/rtc/rtc-mt2712.c
 F:     drivers/rtc/rtc-mt6397.c
 F:     drivers/rtc/rtc-mt7622.c
@@ -2603,6 +2617,7 @@ F:        drivers/pci/controller/dwc/pcie-qcom.c
 F:     drivers/phy/qualcomm/
 F:     drivers/power/*/msm*
 F:     drivers/reset/reset-qcom-*
+F:     drivers/rtc/rtc-pm8xxx.c
 F:     drivers/spi/spi-geni-qcom.c
 F:     drivers/spi/spi-qcom-qspi.c
 F:     drivers/spi/spi-qup.c
@@ -3598,7 +3613,6 @@ F:        include/uapi/linux/bfs_fs.h
 
 BITMAP API
 M:     Yury Norov <yury.norov@gmail.com>
-R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 R:     Rasmus Villemoes <linux@rasmusvillemoes.dk>
 S:     Maintained
 F:     include/linux/bitfield.h
@@ -8987,6 +9001,11 @@ F:       Documentation/i2c/muxes/i2c-mux-gpio.rst
 F:     drivers/i2c/muxes/i2c-mux-gpio.c
 F:     include/linux/platform_data/i2c-mux-gpio.h
 
+GENERIC GPIO RESET DRIVER
+M:     Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+S:     Maintained
+F:     drivers/reset/reset-gpio.c
+
 GENERIC HDLC (WAN) DRIVERS
 M:     Krzysztof Halasa <khc@pm.waw.pl>
 S:     Maintained
@@ -9505,7 +9524,7 @@ T:        git git://linuxtv.org/media_tree.git
 F:     drivers/media/usb/hdpvr/
 
 HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER
-M:     Matt Hsiao <matt.hsiao@hpe.com>
+M:     Keng-Yu Lin <keng-yu.lin@hpe.com>
 S:     Supported
 F:     drivers/misc/hpilo.[ch]
 
@@ -9875,10 +9894,11 @@ F:      drivers/iio/pressure/hsc030pa*
 
 HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER
 M:     Andreas Klinger <ak@it-klinger.de>
+M:     Petre Rodan <petre.rodan@subdimension.ro>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
-F:     drivers/iio/pressure/mprls0025pa.c
+F:     drivers/iio/pressure/mprls0025pa*
 
 HP BIOSCFG DRIVER
 M:     Jorge Lopez <jorge.lopez2@hp.com>
@@ -10471,6 +10491,14 @@ L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/rc/iguanair.c
 
+IIO BACKEND FRAMEWORK
+M:     Nuno Sa <nuno.sa@analog.com>
+R:     Olivier Moysan <olivier.moysan@foss.st.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     drivers/iio/industrialio-backend.c
+F:     include/linux/iio/backend.h
+
 IIO DIGITAL POTENTIOMETER DAC
 M:     Peter Rosin <peda@axentia.se>
 L:     linux-iio@vger.kernel.org
@@ -10493,6 +10521,7 @@ L:      linux-iio@vger.kernel.org
 S:     Maintained
 F:     drivers/iio/industrialio-gts-helper.c
 F:     include/linux/iio/iio-gts-helper.h
+F:     drivers/iio/test/iio-test-gts.c
 
 IIO MULTIPLEXER
 M:     Peter Rosin <peda@axentia.se>
@@ -14105,7 +14134,9 @@ M:      Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 M:     "Paul E. McKenney" <paulmck@kernel.org>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     arch/powerpc/include/asm/membarrier.h
+F:     Documentation/scheduler/membarrier.rst
+F:     arch/*/include/asm/membarrier.h
+F:     arch/*/include/asm/sync_core.h
 F:     include/uapi/linux/membarrier.h
 F:     kernel/sched/membarrier.c
 
@@ -14483,6 +14514,13 @@ F:     Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
 F:     drivers/nvmem/microchip-otpc.c
 F:     include/dt-bindings/nvmem/microchip,sama7g5-otpc.h
 
+MICROCHIP PAC1934 POWER/ENERGY MONITOR DRIVER
+M:     Marius Cristea <marius.cristea@microchip.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
+F:     drivers/iio/adc/pac1934.c
+
 MICROCHIP PCI1XXXX GP DRIVER
 M:     Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com>
 M:     Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
@@ -15202,7 +15240,6 @@ F:      drivers/net/ethernet/neterion/
 NETFILTER
 M:     Pablo Neira Ayuso <pablo@netfilter.org>
 M:     Jozsef Kadlecsik <kadlec@netfilter.org>
-M:     Florian Westphal <fw@strlen.de>
 L:     netfilter-devel@vger.kernel.org
 L:     coreteam@netfilter.org
 S:     Maintained
@@ -16588,7 +16625,7 @@ M:      Miklos Szeredi <miklos@szeredi.hu>
 M:     Amir Goldstein <amir73il@gmail.com>
 L:     linux-unionfs@vger.kernel.org
 S:     Supported
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git
 F:     Documentation/filesystems/overlayfs.rst
 F:     fs/overlayfs/
 
@@ -17689,7 +17726,7 @@ M:      Joel Granados <j.granados@samsung.com>
 L:     linux-kernel@vger.kernel.org
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git sysctl-next
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl.git sysctl-next
 F:     fs/proc/proc_sysctl.c
 F:     include/linux/sysctl.h
 F:     kernel/sysctl-test.c
@@ -22539,6 +22576,7 @@ F:      include/uapi/misc/uacce/
 
 UBI FILE SYSTEM (UBIFS)
 M:     Richard Weinberger <richard@nod.at>
+R:     Zhihao Cheng <chengzhihao1@huawei.com>
 L:     linux-mtd@lists.infradead.org
 S:     Supported
 W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
@@ -22684,6 +22722,7 @@ F:      drivers/ufs/host/ufs-renesas.c
 
 UNSORTED BLOCK IMAGES (UBI)
 M:     Richard Weinberger <richard@nod.at>
+R:     Zhihao Cheng <chengzhihao1@huawei.com>
 L:     linux-mtd@lists.infradead.org
 S:     Supported
 W:     http://www.linux-mtd.infradead.org/
@@ -23562,8 +23601,8 @@ F:      Documentation/driver-api/vme.rst
 F:     drivers/staging/vme_user/
 
 VMWARE BALLOON DRIVER
-M:     Nadav Amit <namit@vmware.com>
-R:     VMware PV-Drivers Reviewers <pv-drivers@vmware.com>
+M:     Jerrin Shaji George <jerrin.shaji-george@broadcom.com>
+R:     Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/misc/vmw_balloon.c
@@ -24340,6 +24379,14 @@ M:     Harsha <harsha.harsha@amd.com>
 S:     Maintained
 F:     drivers/crypto/xilinx/zynqmp-sha.c
 
+XILINX ZYNQMP NVMEM DRIVER
+M:     Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
+M:     Kalyani Akula <kalyani.akula@amd.com>
+R:     Michal Simek <michal.simek@amd.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/nvmem/xlnx,zynqmp-nvmem.yaml
+F:     drivers/nvmem/zynqmp_nvmem.c
+
 XILLYBUS DRIVER
 M:     Eli Billauer <eli.billauer@gmail.com>
 L:     linux-kernel@vger.kernel.org
index 6fe2ae1a6d9214a8ff31253b7ac575fb7ef78f22..5e09b53b485016d3b6a4ba2f1ded15ae84496371 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,8 +39,8 @@ __all:
 # prepare rule.
 
 this-makefile := $(lastword $(MAKEFILE_LIST))
-export abs_srctree := $(realpath $(dir $(this-makefile)))
-export abs_objtree := $(CURDIR)
+abs_srctree := $(realpath $(dir $(this-makefile)))
+abs_objtree := $(CURDIR)
 
 ifneq ($(sub_make_done),1)
 
@@ -295,51 +295,51 @@ single-build      :=
 
 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
     ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
-               need-config :=
+        need-config :=
     endif
 endif
 
 ifneq ($(filter $(no-sync-config-targets), $(MAKECMDGOALS)),)
     ifeq ($(filter-out $(no-sync-config-targets), $(MAKECMDGOALS)),)
-               may-sync-config :=
+        may-sync-config :=
     endif
 endif
 
 need-compiler := $(may-sync-config)
 
 ifneq ($(KBUILD_EXTMOD),)
-       may-sync-config :=
+    may-sync-config :=
 endif
 
 ifeq ($(KBUILD_EXTMOD),)
-        ifneq ($(filter %config,$(MAKECMDGOALS)),)
-               config-build := 1
-                ifneq ($(words $(MAKECMDGOALS)),1)
-                       mixed-build := 1
-                endif
+    ifneq ($(filter %config,$(MAKECMDGOALS)),)
+        config-build := 1
+        ifneq ($(words $(MAKECMDGOALS)),1)
+            mixed-build := 1
         endif
+    endif
 endif
 
 # We cannot build single targets and the others at the same time
 ifneq ($(filter $(single-targets), $(MAKECMDGOALS)),)
-       single-build := 1
+    single-build := 1
     ifneq ($(filter-out $(single-targets), $(MAKECMDGOALS)),)
-               mixed-build := 1
+        mixed-build := 1
     endif
 endif
 
 # For "make -j clean all", "make -j mrproper defconfig all", etc.
 ifneq ($(filter $(clean-targets),$(MAKECMDGOALS)),)
-        ifneq ($(filter-out $(clean-targets),$(MAKECMDGOALS)),)
-               mixed-build := 1
-        endif
+    ifneq ($(filter-out $(clean-targets),$(MAKECMDGOALS)),)
+        mixed-build := 1
+    endif
 endif
 
 # install and modules_install need also be processed one by one
 ifneq ($(filter install,$(MAKECMDGOALS)),)
-        ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
-               mixed-build := 1
-        endif
+    ifneq ($(filter modules_install,$(MAKECMDGOALS)),)
+        mixed-build := 1
+    endif
 endif
 
 ifdef mixed-build
@@ -965,8 +965,15 @@ export CC_FLAGS_CFI
 endif
 
 ifneq ($(CONFIG_FUNCTION_ALIGNMENT),0)
+# Set the minimal function alignment. Use the newer GCC option
+# -fmin-function-alignment if it is available, or fall back to -falign-funtions.
+# See also CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT.
+ifdef CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT
+KBUILD_CFLAGS += -fmin-function-alignment=$(CONFIG_FUNCTION_ALIGNMENT)
+else
 KBUILD_CFLAGS += -falign-functions=$(CONFIG_FUNCTION_ALIGNMENT)
 endif
+endif
 
 # arch Makefile may override CC so keep this after arch Makefile is included
 NOSTDINC_FLAGS += -nostdinc
@@ -1384,7 +1391,7 @@ ifneq ($(dtstree),)
 
 PHONY += dtbs dtbs_prepare dtbs_install dtbs_check
 dtbs: dtbs_prepare
-       $(Q)$(MAKE) $(build)=$(dtstree)
+       $(Q)$(MAKE) $(build)=$(dtstree) need-dtbslist=1
 
 # include/config/kernel.release is actually needed when installing DTBs because
 # INSTALL_DTBS_PATH contains $(KERNELRELEASE). However, we do not want to make
@@ -1402,7 +1409,7 @@ endif
 dtbs_check: dtbs
 
 dtbs_install:
-       $(Q)$(MAKE) $(dtbinst)=$(dtstree) dst=$(INSTALL_DTBS_PATH)
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.dtbinst obj=$(dtstree)
 
 ifdef CONFIG_OF_EARLY_FLATTREE
 all: dtbs
@@ -1923,7 +1930,7 @@ clean: $(clean-dirs)
                -o -name '*.ko.*' \
                -o -name '*.dtb' -o -name '*.dtbo' \
                -o -name '*.dtb.S' -o -name '*.dtbo.S' \
-               -o -name '*.dt.yaml' \
+               -o -name '*.dt.yaml' -o -name 'dtbs-list' \
                -o -name '*.dwo' -o -name '*.lst' \
                -o -name '*.su' -o -name '*.mod' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
diff --git a/README b/README
index 026eff0b8e0657350289ebc9cceb2057809e8677..fd903645e6de0628ed3274423355426ec0347bab 100644 (file)
--- a/README
+++ b/README
@@ -11,7 +11,7 @@ In order to build the documentation, use ``make htmldocs`` or
     https://www.kernel.org/doc/html/latest/
 
 There are various text files in the Documentation/ subdirectory,
-several of them using the ReStructured Text markup notation.
+several of them using the reStructuredText markup notation.
 
 Please read the Documentation/process/changes.rst file, as it contains the
 requirements for building and running the kernel, and information about
index fd18b7db2c777bb1223ffd0a4bcf0d5b11633330..9f066785bb71d93ca5da01a22d15ed2effba5901 100644 (file)
@@ -799,7 +799,7 @@ config CFI_CLANG
        depends on ARCH_SUPPORTS_CFI_CLANG
        depends on $(cc-option,-fsanitize=kcfi)
        help
-         This option enables Clangs forward-edge Control Flow Integrity
+         This option enables Clang's forward-edge Control Flow Integrity
          (CFI) checking, where the compiler injects a runtime check to each
          indirect function call to ensure the target is a valid function with
          the correct static type. This restricts possible call targets and
@@ -1597,4 +1597,16 @@ config FUNCTION_ALIGNMENT
        default 4 if FUNCTION_ALIGNMENT_4B
        default 0
 
+config CC_HAS_MIN_FUNCTION_ALIGNMENT
+       # Detect availability of the GCC option -fmin-function-alignment which
+       # guarantees minimal alignment for all functions, unlike
+       # -falign-functions which the compiler ignores for cold functions.
+       def_bool $(cc-option, -fmin-function-alignment=8)
+
+config CC_HAS_SANE_FUNCTION_ALIGNMENT
+       # Set if the guaranteed alignment with -fmin-function-alignment is
+       # available or extra care is required in the kernel. Clang provides
+       # strict alignment always, even with -falign-functions.
+       def_bool CC_HAS_MIN_FUNCTION_ALIGNMENT || CC_IS_CLANG
+
 endmenu
index 4f490250d32302087a6decd3a70e0f21b9611035..3afd042150f8aff71a1709e9ab3e704a829c3a45 100644 (file)
@@ -339,6 +339,7 @@ config ALPHA_EV4
        bool
        depends on ALPHA_JENSEN || (ALPHA_SABLE && !ALPHA_GAMMA) || ALPHA_LYNX || ALPHA_NORITAKE && !ALPHA_PRIMO || ALPHA_MIKASA && !ALPHA_PRIMO || ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P_CH || ALPHA_XL || ALPHA_NONAME || ALPHA_EB66 || ALPHA_EB66P || ALPHA_P2K
        default y if !ALPHA_LYNX
+       default y if !ALPHA_EV5
 
 config ALPHA_LCA
        bool
@@ -366,10 +367,6 @@ config ALPHA_EV5
        bool "EV5 CPU(s) (model 5/xxx)?" if ALPHA_LYNX
        default y if ALPHA_RX164 || ALPHA_RAWHIDE || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_SABLE && ALPHA_GAMMA || ALPHA_NORITAKE && ALPHA_PRIMO || ALPHA_MIKASA && ALPHA_PRIMO || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR
 
-config ALPHA_EV4
-       bool
-       default y if ALPHA_LYNX && !ALPHA_EV5
-
 config ALPHA_CIA
        bool
        depends on ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_RUFFIAN || ALPHA_NORITAKE && ALPHA_PRIMO || ALPHA_MIKASA && ALPHA_PRIMO || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR
@@ -394,16 +391,12 @@ config ALPHA_PRIMO
          Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx.
 
 config ALPHA_GAMMA
-       bool "EV5 CPU(s) (model 5/xxx)?"
-       depends on ALPHA_SABLE
+       bool "EV5 CPU(s) (model 5/xxx)?" if ALPHA_SABLE
+       depends on ALPHA_SABLE || ALPHA_LYNX
+       default ALPHA_LYNX
        help
          Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
 
-config ALPHA_GAMMA
-       bool
-       depends on ALPHA_LYNX
-       default y
-
 config ALPHA_T2
        bool
        depends on ALPHA_SABLE || ALPHA_LYNX
index 702d97a9c30471a59dc6d2d3bfaf8436621d63df..b14aed3a17abb6732e0b87d3ba1b4edc260e7f0e 100644 (file)
@@ -505,8 +505,8 @@ source "arch/arm/mm/Kconfig"
 
 config IWMMXT
        bool "Enable iWMMXt support"
-       depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4 || CPU_PJ4B
-       default y if PXA27x || PXA3xx || ARCH_MMP || CPU_PJ4 || CPU_PJ4B
+       depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK
+       default y if PXA27x || PXA3xx || ARCH_MMP
        help
          Enable support for iWMMXt context switching at run time if
          running on a CPU that supports it.
index f1fc278081d0354d1cf027f3c73179f2654b32c4..7f47b4f335c3d2cfe459d15a83322625b8fa6edc 100644 (file)
@@ -90,9 +90,6 @@ config BACKTRACE_VERBOSE
          In most cases, say N here, unless you are intending to debug the
          kernel and have access to the kernel binary image.
 
-config FRAME_POINTER
-       bool
-
 config DEBUG_USER
        bool "Verbose user fault messages"
        help
index d34483ae1778e509fadab5607e7f698e3289374a..99b62c6b4ce8eb79e5ca1a9d4e8c32f608cf5d76 100644 (file)
                compatible = "ti,clksel";
                reg = <0x664>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               ehrpwm0_tbclk: clock-ehrpwm0-tbclk {
+               ehrpwm0_tbclk: clock-ehrpwm0-tbclk@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "ehrpwm0_tbclk";
                        clocks = <&l4ls_gclk>;
-                       ti,bit-shift = <0>;
                };
 
-               ehrpwm1_tbclk: clock-ehrpwm1-tbclk {
+               ehrpwm1_tbclk: clock-ehrpwm1-tbclk@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "ehrpwm1_tbclk";
                        clocks = <&l4ls_gclk>;
-                       ti,bit-shift = <1>;
                };
 
-               ehrpwm2_tbclk: clock-ehrpwm2-tbclk {
+               ehrpwm2_tbclk: clock-ehrpwm2-tbclk@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "ehrpwm2_tbclk";
                        clocks = <&l4ls_gclk>;
-                       ti,bit-shift = <2>;
                };
        };
 };
                compatible = "ti,clksel";
                reg = <0x52c>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               gfx_fclk_clksel_ck: clock-gfx-fclk-clksel {
+               gfx_fclk_clksel_ck: clock-gfx-fclk-clksel@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "gfx_fclk_clksel_ck";
                        clocks = <&dpll_core_m4_ck>, <&dpll_per_m2_ck>;
-                       ti,bit-shift = <1>;
                };
 
-               gfx_fck_div_ck: clock-gfx-fck-div {
+               gfx_fck_div_ck: clock-gfx-fck-div@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "gfx_fck_div_ck";
                compatible = "ti,clksel";
                reg = <0x700>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               sysclkout_pre_ck: clock-sysclkout-pre {
+               sysclkout_pre_ck: clock-sysclkout-pre@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "sysclkout_pre_ck";
                        clocks = <&clk_32768_ck>, <&l3_gclk>, <&dpll_ddr_m2_ck>, <&dpll_per_m2_ck>, <&lcd_gclk>;
                };
 
-               clkout2_div_ck: clock-clkout2-div {
+               clkout2_div_ck: clock-clkout2-div@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "clkout2_div_ck";
                        clocks = <&sysclkout_pre_ck>;
-                       ti,bit-shift = <3>;
                        ti,max-div = <8>;
                };
 
-               clkout2_ck: clock-clkout2 {
+               clkout2_ck: clock-clkout2@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "clkout2_ck";
                        clocks = <&clkout2_div_ck>;
-                       ti,bit-shift = <7>;
                };
        };
 };
index 0ee7afaa0e8e2064820219db605e0c504864ba13..b521139e6f5178fdfe40a2ea0c20320fd50bea58 100644 (file)
                compatible = "ti,clksel";
                reg = <0xa10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               ipss_ick: clock-ipss-ick {
+               ipss_ick: clock-ipss-ick@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,am35xx-interface-clock";
                        clock-output-names = "ipss_ick";
                        clocks = <&core_l3_ick>;
-                       ti,bit-shift = <4>;
                };
 
-               uart4_ick_am35xx: clock-uart4-ick-am35xx {
+               uart4_ick_am35xx: clock-uart4-ick-am35xx@23 {
+                       reg = <23>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "uart4_ick_am35xx";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <23>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               uart4_fck_am35xx: clock-uart4-fck-am35xx {
+               uart4_fck_am35xx: clock-uart4-fck-am35xx@23 {
+                       reg = <23>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "uart4_fck_am35xx";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <23>;
                };
        };
 };
index 24adfac26be04af05aab0e4f00aebf73cc20453f..6e754d265f18924fcafdbb52d9b1995da9e56def 100644 (file)
                compatible = "ti,clksel";
                reg = <0xa00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               d2d_26m_fck: clock-d2d-26m-fck {
+               d2d_26m_fck: clock-d2d-26m-fck@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "d2d_26m_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <3>;
                };
 
-               fshostusb_fck: clock-fshostusb-fck {
+               fshostusb_fck: clock-fshostusb-fck@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "fshostusb_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <5>;
                };
 
-               ssi_ssr_gate_fck_3430es1: clock-ssi-ssr-gate-fck-3430es1 {
+               ssi_ssr_gate_fck_3430es1: clock-ssi-ssr-gate-fck-3430es1@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-no-wait-gate-clock";
                        clock-output-names = "ssi_ssr_gate_fck_3430es1";
                        clocks = <&corex2_fck>;
-                       ti,bit-shift = <0>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               ssi_ssr_div_fck_3430es1: clock-ssi-ssr-div-fck-3430es1 {
+               ssi_ssr_div_fck_3430es1: clock-ssi-ssr-div-fck-3430es1@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-divider-clock";
                        clock-output-names = "ssi_ssr_div_fck_3430es1";
                        clocks = <&corex2_fck>;
-                       ti,bit-shift = <8>;
                        ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
                };
 
-               usb_l4_div_ick: clock-usb-l4-div-ick {
+               usb_l4_div_ick: clock-usb-l4-div-ick@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-divider-clock";
                        clock-output-names = "usb_l4_div_ick";
                        clocks = <&l4_ick>;
-                       ti,bit-shift = <4>;
                        ti,max-div = <1>;
                        ti,index-starts-at-one;
                };
                compatible = "ti,clksel";
                reg = <0xa10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               hsotgusb_ick_3430es1: clock-hsotgusb-ick-3430es1 {
+               hsotgusb_ick_3430es1: clock-hsotgusb-ick-3430es1@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-no-wait-interface-clock";
                        clock-output-names = "hsotgusb_ick_3430es1";
                        clocks = <&core_l3_ick>;
-                       ti,bit-shift = <4>;
                };
 
-               fac_ick: clock-fac-ick {
+               fac_ick: clock-fac-ick@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "fac_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <8>;
                };
 
-               ssi_ick: clock-ssi-ick-3430es1 {
+               ssi_ick: clock-ssi-ick-3430es1@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-no-wait-interface-clock";
                        clock-output-names = "ssi_ick_3430es1";
                        clocks = <&ssi_l4_ick>;
-                       ti,bit-shift = <0>;
                };
 
-               usb_l4_gate_ick: clock-usb-l4-gate-ick {
+               usb_l4_gate_ick: clock-usb-l4-gate-ick@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-interface-clock";
                        clock-output-names = "usb_l4_gate_ick";
                        clocks = <&l4_ick>;
-                       ti,bit-shift = <5>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xe00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               dss1_alwon_fck: clock-dss1-alwon-fck-3430es1 {
+               dss1_alwon_fck: clock-dss1-alwon-fck-3430es1@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "dss1_alwon_fck_3430es1";
                        clocks = <&dpll4_m4x2_ck>;
-                       ti,bit-shift = <0>;
                        ti,set-rate-parent;
                };
        };
index 8374532f20e2b752dfee16ee9f1740619c92b6fe..ca6372711bafd86ff06efe33f4aff16bcc8fb90c 100644 (file)
                compatible = "ti,clksel";
                reg = <0xa14>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               aes1_ick: clock-aes1-ick {
+               aes1_ick: clock-aes1-ick@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "aes1_ick";
                        clocks = <&security_l4_ick2>;
-                       ti,bit-shift = <3>;
                };
 
-               rng_ick: clock-rng-ick {
+               rng_ick: clock-rng-ick@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "rng_ick";
                        clocks = <&security_l4_ick2>;
-                       ti,bit-shift = <2>;
                };
 
-               sha11_ick: clock-sha11-ick {
+               sha11_ick: clock-sha11-ick@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "sha11_ick";
                        clocks = <&security_l4_ick2>;
-                       ti,bit-shift = <1>;
                };
 
-               des1_ick: clock-des1-ick {
+               des1_ick: clock-des1-ick@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "des1_ick";
                        clocks = <&security_l4_ick2>;
-                       ti,bit-shift = <0>;
                };
 
-               pka_ick: clock-pka-ick {
+               pka_ick: clock-pka-ick@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "pka_ick";
                        clocks = <&security_l3_ick>;
-                       ti,bit-shift = <4>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xf00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               cam_mclk: clock-cam-mclk {
+               cam_mclk: clock-cam-mclk@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "cam_mclk";
                        clocks = <&dpll4_m5x2_ck>;
-                       ti,bit-shift = <0>;
                        ti,set-rate-parent;
                };
 
-               csi2_96m_fck: clock-csi2-96m-fck {
+               csi2_96m_fck: clock-csi2-96m-fck@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "csi2_96m_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <1>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               icr_ick: clock-icr-ick {
+               icr_ick: clock-icr-ick@29 {
+                       reg = <29>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "icr_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <29>;
                };
 
-               des2_ick: clock-des2-ick {
+               des2_ick: clock-des2-ick@26 {
+                       reg = <26>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "des2_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <26>;
                };
 
-               mspro_ick: clock-mspro-ick {
+               mspro_ick: clock-mspro-ick@23 {
+                       reg = <23>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mspro_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <23>;
                };
 
-               mailboxes_ick: clock-mailboxes-ick {
+               mailboxes_ick: clock-mailboxes-ick@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mailboxes_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <7>;
                };
 
-               sad2d_ick: clock-sad2d-ick {
+               sad2d_ick: clock-sad2d-ick@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "sad2d_ick";
                        clocks = <&l3_ick>;
-                       ti,bit-shift = <3>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xc00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               sr1_fck: clock-sr1-fck {
+               sr1_fck: clock-sr1-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "sr1_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <6>;
                };
 
-               sr2_fck: clock-sr2-fck {
+               sr2_fck: clock-sr2-fck@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "sr2_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <7>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               modem_fck: clock-modem-fck {
+               modem_fck: clock-modem-fck@31 {
+                       reg = <31>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "modem_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <31>;
                };
 
-               mspro_fck: clock-mspro-fck {
+               mspro_fck: clock-mspro-fck@23 {
+                       reg = <23>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mspro_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <23>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa18>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #ssize-cells = <0>;
 
-               mad2d_ick: clock-mad2d-ick {
+               mad2d_ick: clock-mad2d-ick@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mad2d_ick";
                        clocks = <&l3_ick>;
-                       ti,bit-shift = <3>;
                };
        };
 
index dcc5cfcd1fe66c7f9600248c4dfcf68bbd374c4f..656cf80f878a846c42936f19eb7433622608099b 100644 (file)
                compatible = "ti,clksel";
                reg = <0xa18>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               usbtll_ick: clock-usbtll-ick {
+               usbtll_ick: clock-usbtll-ick@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "usbtll_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <2>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               mmchs3_ick: clock-mmchs3-ick {
+               mmchs3_ick: clock-mmchs3-ick@30 {
+                       reg = <30>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mmchs3_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <30>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               mmchs3_fck: clock-mmchs3-fck {
+               mmchs3_fck: clock-mmchs3-fck@30 {
+                       reg = <30>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mmchs3_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <30>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xe00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               dss1_alwon_fck: clock-dss1-alwon-fck-3430es2 {
+               dss1_alwon_fck: clock-dss1-alwon-fck-3430es2@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,dss-gate-clock";
                        clock-output-names = "dss1_alwon_fck_3430es2";
                        clocks = <&dpll4_m4x2_ck>;
-                       ti,bit-shift = <0>;
                        ti,set-rate-parent;
                };
        };
index c5fdb2bd765d0afb0de63cecaf09d06259adde7f..1e90f2b1ef8b3585a30a4cb10249fae5bafddf64 100644 (file)
                compatible = "ti,clksel";
                reg = <0x1000>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               uart4_fck: clock-uart4-fck {
+               uart4_fck: clock-uart4-fck@18 {
+                       reg = <18>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "uart4_fck";
                        clocks = <&per_48m_fck>;
-                       ti,bit-shift = <18>;
                };
        };
 };
index c94eb86d3da75663751f54598896d199c3d8aba6..798acb839db4707f2391aef8037901da7b826c8f 100644 (file)
@@ -9,14 +9,15 @@
                compatible = "ti,clksel";
                reg = <0xa00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               ssi_ssr_gate_fck_3430es2: clock-ssi-ssr-gate-fck-3430es2 {
+               ssi_ssr_gate_fck_3430es2: clock-ssi-ssr-gate-fck-3430es2@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-no-wait-gate-clock";
                        clock-output-names = "ssi_ssr_gate_fck_3430es2";
                        clocks = <&corex2_fck>;
-                       ti,bit-shift = <0>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               ssi_ssr_div_fck_3430es2: clock-ssi-ssr-div-fck-3430es2 {
+               ssi_ssr_div_fck_3430es2: clock-ssi-ssr-div-fck-3430es2@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-divider-clock";
                        clock-output-names = "ssi_ssr_div_fck_3430es2";
                        clocks = <&corex2_fck>;
-                       ti,bit-shift = <8>;
                        ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
                };
        };
                compatible = "ti,clksel";
                reg = <0xa10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               hsotgusb_ick_3430es2: clock-hsotgusb-ick-3430es2 {
+               hsotgusb_ick_3430es2: clock-hsotgusb-ick-3430es2@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-hsotgusb-interface-clock";
                        clock-output-names = "hsotgusb_ick_3430es2";
                        clocks = <&core_l3_ick>;
-                       ti,bit-shift = <4>;
                };
 
-               ssi_ick: clock-ssi-ick-3430es2 {
+               ssi_ick: clock-ssi-ick-3430es2@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-ssi-interface-clock";
                        clock-output-names = "ssi_ick_3430es2";
                        clocks = <&ssi_l4_ick>;
-                       ti,bit-shift = <0>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xc00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               usim_gate_fck: clock-usim-gate-fck {
+               usim_gate_fck: clock-usim-gate-fck@9 {
+                       reg = <9>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "usim_gate_fck";
                        clocks = <&omap_96m_fck>;
-                       ti,bit-shift = <9>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xc40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               usim_mux_fck: clock-usim-mux-fck {
+               usim_mux_fck: clock-usim-mux-fck@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "usim_mux_fck";
                        clocks = <&sys_ck>, <&sys_d2_ck>, <&omap_96m_d2_fck>, <&omap_96m_d4_fck>, <&omap_96m_d8_fck>, <&omap_96m_d10_fck>, <&dpll5_m2_d4_ck>, <&dpll5_m2_d8_ck>, <&dpll5_m2_d16_ck>, <&dpll5_m2_d20_ck>;
-                       ti,bit-shift = <3>;
                        ti,index-starts-at-one;
                };
        };
                compatible = "ti,clksel";
                reg = <0xc10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               usim_ick: clock-usim-ick {
+               usim_ick: clock-usim-ick@9 {
+                       reg = <9>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "usim_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <9>;
                };
        };
 };
index 2e13ca11ceeaff24680d8740c26cc9f71a93091e..901ee79a66f10b5d134e72264627c3bf94d1d1f0 100644 (file)
                compatible = "ti,clksel";
                reg = <0x68>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               mcbsp5_mux_fck: clock-mcbsp5-mux-fck {
+               mcbsp5_mux_fck: clock-mcbsp5-mux-fck@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "mcbsp5_mux_fck";
                        clocks = <&core_96m_fck>, <&mcbsp_clks>;
-                       ti,bit-shift = <4>;
                };
 
-               mcbsp3_mux_fck: clock-mcbsp3-mux-fck {
+               mcbsp3_mux_fck: clock-mcbsp3-mux-fck@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "mcbsp3_mux_fck";
                        clocks = <&per_96m_fck>, <&mcbsp_clks>;
                };
 
-               mcbsp4_mux_fck: clock-mcbsp4-mux-fck {
+               mcbsp4_mux_fck: clock-mcbsp4-mux-fck@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "mcbsp4_mux_fck";
                        clocks = <&per_96m_fck>, <&mcbsp_clks>;
-                       ti,bit-shift = <2>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0x4>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               mcbsp1_mux_fck: clock-mcbsp1-mux-fck {
+               mcbsp1_mux_fck: clock-mcbsp1-mux-fck@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "mcbsp1_mux_fck";
                        clocks = <&core_96m_fck>, <&mcbsp_clks>;
-                       ti,bit-shift = <2>;
                };
 
-               mcbsp2_mux_fck: clock-mcbsp2-mux-fck {
+               mcbsp2_mux_fck: clock-mcbsp2-mux-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "mcbsp2_mux_fck";
                        clocks = <&per_96m_fck>, <&mcbsp_clks>;
-                       ti,bit-shift = <6>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0x1140>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               dpll3_m3_ck: clock-dpll3-m3 {
+               dpll3_m3_ck: clock-dpll3-m3@16 {
+                       reg = <16>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "dpll3_m3_ck";
                        clocks = <&dpll3_ck>;
-                       ti,bit-shift = <16>;
                        ti,max-div = <31>;
                        ti,index-starts-at-one;
                };
 
-               dpll4_m6_ck: clock-dpll4-m6 {
+               dpll4_m6_ck: clock-dpll4-m6@24 {
+                       reg = <24>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "dpll4_m6_ck";
                        clocks = <&dpll4_ck>;
-                       ti,bit-shift = <24>;
                        ti,max-div = <63>;
                        ti,index-starts-at-one;
                };
 
-               emu_src_mux_ck: clock-emu-src-mux {
+               emu_src_mux_ck: clock-emu-src-mux@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "emu_src_mux_ck";
                        clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>;
                };
 
-               pclk_fck: clock-pclk-fck {
+               pclk_fck: clock-pclk-fck@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "pclk_fck";
                        clocks = <&emu_src_ck>;
-                       ti,bit-shift = <8>;
                        ti,max-div = <7>;
                        ti,index-starts-at-one;
                };
 
-               pclkx2_fck: clock-pclkx2-fck {
+               pclkx2_fck: clock-pclkx2-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "pclkx2_fck";
                        clocks = <&emu_src_ck>;
-                       ti,bit-shift = <6>;
                        ti,max-div = <3>;
                        ti,index-starts-at-one;
                };
 
-               atclk_fck: clock-atclk-fck {
+               atclk_fck: clock-atclk-fck@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "atclk_fck";
                        clocks = <&emu_src_ck>;
-                       ti,bit-shift = <4>;
                        ti,max-div = <3>;
                        ti,index-starts-at-one;
                };
 
-               traceclk_src_fck: clock-traceclk-src-fck {
+               traceclk_src_fck: clock-traceclk-src-fck@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "traceclk_src_fck";
                        clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>;
-                       ti,bit-shift = <2>;
                };
 
-               traceclk_fck: clock-traceclk-fck {
+               traceclk_fck: clock-traceclk-fck@11 {
+                       reg = <11>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "traceclk_fck";
                        clocks = <&traceclk_src_fck>;
-                       ti,bit-shift = <11>;
                        ti,max-div = <7>;
                        ti,index-starts-at-one;
                };
                compatible = "ti,clksel";
                reg = <0xd40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               dpll3_m2_ck: clock-dpll3-m2 {
+               dpll3_m2_ck: clock-dpll3-m2@27 {
+                       reg = <27>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "dpll3_m2_ck";
                        clocks = <&dpll3_ck>;
-                       ti,bit-shift = <27>;
                        ti,max-div = <31>;
                        ti,index-starts-at-one;
                };
 
-               omap_96m_fck: clock-omap-96m-fck {
+               omap_96m_fck: clock-omap-96m-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "omap_96m_fck";
                        clocks = <&cm_96m_fck>, <&sys_ck>;
-                       ti,bit-shift = <6>;
                };
 
-               omap_54m_fck: clock-omap-54m-fck {
+               omap_54m_fck: clock-omap-54m-fck@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "omap_54m_fck";
                        clocks = <&dpll4_m3x2_ck>, <&sys_altclk>;
-                       ti,bit-shift = <5>;
                };
 
-               omap_48m_fck: clock-omap-48m-fck {
+               omap_48m_fck: clock-omap-48m-fck@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,mux-clock";
                        clock-output-names = "omap_48m_fck";
                        clocks = <&cm_96m_d2_fck>, <&sys_altclk>;
-                       ti,bit-shift = <3>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xe40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               dpll4_m3_ck: clock-dpll4-m3 {
+               dpll4_m3_ck: clock-dpll4-m3@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "dpll4_m3_ck";
                        clocks = <&dpll4_ck>;
-                       ti,bit-shift = <8>;
                        ti,max-div = <32>;
                        ti,index-starts-at-one;
                };
 
-               dpll4_m4_ck: clock-dpll4-m4 {
+               dpll4_m4_ck: clock-dpll4-m4@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "dpll4_m4_ck";
                compatible = "ti,clksel";
                reg = <0xd70>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               clkout2_src_gate_ck: clock-clkout2-src-gate {
+               clkout2_src_gate_ck: clock-clkout2-src-gate@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-no-wait-gate-clock";
                        clock-output-names = "clkout2_src_gate_ck";
                        clocks = <&core_ck>;
-                       ti,bit-shift = <7>;
                };
 
-               clkout2_src_mux_ck: clock-clkout2-src-mux {
+               clkout2_src_mux_ck: clock-clkout2-src-mux@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "clkout2_src_mux_ck";
                        clocks = <&core_ck>, <&sys_ck>, <&cm_96m_fck>, <&omap_54m_fck>;
                };
 
-               sys_clkout2: clock-sys-clkout2 {
+               sys_clkout2: clock-sys-clkout2@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "sys_clkout2";
                        clocks = <&clkout2_src_ck>;
-                       ti,bit-shift = <3>;
                        ti,max-div = <64>;
                        ti,index-power-of-two;
                };
                compatible = "ti,clksel";
                reg = <0xa40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               l3_ick: clock-l3-ick {
+               l3_ick: clock-l3-ick@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "l3_ick";
                        ti,index-starts-at-one;
                };
 
-               l4_ick: clock-l4-ick {
+               l4_ick: clock-l4-ick@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "l4_ick";
                        clocks = <&l3_ick>;
-                       ti,bit-shift = <2>;
                        ti,max-div = <3>;
                        ti,index-starts-at-one;
                };
 
-               gpt10_mux_fck: clock-gpt10-mux-fck {
+               gpt10_mux_fck: clock-gpt10-mux-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt10_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <6>;
                };
 
-               gpt11_mux_fck: clock-gpt11-mux-fck {
+               gpt11_mux_fck: clock-gpt11-mux-fck@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt11_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <7>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xc40>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               rm_ick: clock-rm-ick {
+               rm_ick: clock-rm-ick@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,divider-clock";
                        clock-output-names = "rm_ick";
                        clocks = <&l4_ick>;
-                       ti,bit-shift = <1>;
                        ti,max-div = <3>;
                        ti,index-starts-at-one;
                };
 
-               gpt1_mux_fck: clock-gpt1-mux-fck {
+               gpt1_mux_fck: clock-gpt1-mux-fck@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt1_mux_fck";
                compatible = "ti,clksel";
                reg = <0xa00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               gpt10_gate_fck: clock-gpt10-gate-fck {
+               gpt10_gate_fck: clock-gpt10-gate-fck@11 {
+                       reg = <11>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt10_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <11>;
                };
 
-               gpt11_gate_fck: clock-gpt11-gate-fck {
+               gpt11_gate_fck: clock-gpt11-gate-fck@12 {
+                       reg = <12>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt11_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <12>;
                };
 
-               mmchs2_fck: clock-mmchs2-fck {
+               mmchs2_fck: clock-mmchs2-fck@25 {
+                       reg = <25>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mmchs2_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <25>;
                };
 
-               mmchs1_fck: clock-mmchs1-fck {
+               mmchs1_fck: clock-mmchs1-fck@24 {
+                       reg = <24>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mmchs1_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <24>;
                };
 
-               i2c3_fck: clock-i2c3-fck {
+               i2c3_fck: clock-i2c3-fck@17 {
+                       reg = <17>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "i2c3_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <17>;
                };
 
-               i2c2_fck: clock-i2c2-fck {
+               i2c2_fck: clock-i2c2-fck@16 {
+                       reg = <16>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "i2c2_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <16>;
                };
 
-               i2c1_fck: clock-i2c1-fck {
+               i2c1_fck: clock-i2c1-fck@15 {
+                       reg = <15>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "i2c1_fck";
                        clocks = <&core_96m_fck>;
-                       ti,bit-shift = <15>;
                };
 
-               mcbsp5_gate_fck: clock-mcbsp5-gate-fck {
+               mcbsp5_gate_fck: clock-mcbsp5-gate-fck@10 {
+                       reg = <10>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "mcbsp5_gate_fck";
                        clocks = <&mcbsp_clks>;
-                       ti,bit-shift = <10>;
                };
 
-               mcbsp1_gate_fck: clock-mcbsp1-gate-fck {
+               mcbsp1_gate_fck: clock-mcbsp1-gate-fck@9 {
+                       reg = <9>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "mcbsp1_gate_fck";
                        clocks = <&mcbsp_clks>;
-                       ti,bit-shift = <9>;
                };
 
-               mcspi4_fck: clock-mcspi4-fck {
+               mcspi4_fck: clock-mcspi4-fck@21 {
+                       reg = <21>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mcspi4_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <21>;
                };
 
-               mcspi3_fck: clock-mcspi3-fck {
+               mcspi3_fck: clock-mcspi3-fck@20 {
+                       reg = <20>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mcspi3_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <20>;
                };
 
-               mcspi2_fck: clock-mcspi2-fck {
+               mcspi2_fck: clock-mcspi2-fck@19 {
+                       reg = <19>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mcspi2_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <19>;
                };
 
-               mcspi1_fck: clock-mcspi1-fck {
+               mcspi1_fck: clock-mcspi1-fck@18 {
+                       reg = <18>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "mcspi1_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <18>;
                };
 
-               uart2_fck: clock-uart2-fck {
+               uart2_fck: clock-uart2-fck@14 {
+                       reg = <14>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "uart2_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <14>;
                };
 
-               uart1_fck: clock-uart1-fck {
+               uart1_fck: clock-uart1-fck@13 {
+                       reg = <13>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "uart1_fck";
                        clocks = <&core_48m_fck>;
-                       ti,bit-shift = <13>;
                };
 
-               hdq_fck: clock-hdq-fck {
+               hdq_fck: clock-hdq-fck@22 {
+                       reg = <22>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "hdq_fck";
                        clocks = <&core_12m_fck>;
-                       ti,bit-shift = <22>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xa10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               sdrc_ick: clock-sdrc-ick {
+               sdrc_ick: clock-sdrc-ick@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "sdrc_ick";
                        clocks = <&core_l3_ick>;
-                       ti,bit-shift = <1>;
                };
 
-               mmchs2_ick: clock-mmchs2-ick {
+               mmchs2_ick: clock-mmchs2-ick@25 {
+                       reg = <25>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mmchs2_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <25>;
                };
 
-               mmchs1_ick: clock-mmchs1-ick {
+               mmchs1_ick: clock-mmchs1-ick@24 {
+                       reg = <24>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mmchs1_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <24>;
                };
 
-               hdq_ick: clock-hdq-ick {
+               hdq_ick: clock-hdq-ick@22 {
+                       reg = <22>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "hdq_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <22>;
                };
 
-               mcspi4_ick: clock-mcspi4-ick {
+               mcspi4_ick: clock-mcspi4-ick@21 {
+                       reg = <21>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcspi4_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <21>;
                };
 
-               mcspi3_ick: clock-mcspi3-ick {
+               mcspi3_ick: clock-mcspi3-ick@20 {
+                       reg = <20>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcspi3_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <20>;
                };
 
-               mcspi2_ick: clock-mcspi2-ick {
+               mcspi2_ick: clock-mcspi2-ick@19 {
+                       reg = <19>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcspi2_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <19>;
                };
 
-               mcspi1_ick: clock-mcspi1-ick {
+               mcspi1_ick: clock-mcspi1-ick@18 {
+                       reg = <18>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcspi1_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <18>;
                };
 
-               i2c3_ick: clock-i2c3-ick {
+               i2c3_ick: clock-i2c3-ick@17 {
+                       reg = <17>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "i2c3_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <17>;
                };
 
-               i2c2_ick: clock-i2c2-ick {
+               i2c2_ick: clock-i2c2-ick@16 {
+                       reg = <16>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "i2c2_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <16>;
                };
 
-               i2c1_ick: clock-i2c1-ick {
+               i2c1_ick: clock-i2c1-ick@15 {
+                       reg = <15>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "i2c1_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <15>;
                };
 
-               uart2_ick: clock-uart2-ick {
+               uart2_ick: clock-uart2-ick@14 {
+                       reg = <14>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "uart2_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <14>;
                };
 
-               uart1_ick: clock-uart1-ick {
+               uart1_ick: clock-uart1-ick@13 {
+                       reg = <13>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "uart1_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <13>;
                };
 
-               gpt11_ick: clock-gpt11-ick {
+               gpt11_ick: clock-gpt11-ick@12 {
+                       reg = <12>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt11_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <12>;
                };
 
-               gpt10_ick: clock-gpt10-ick {
+               gpt10_ick: clock-gpt10-ick@11 {
+                       reg = <11>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt10_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <11>;
                };
 
-               mcbsp5_ick: clock-mcbsp5-ick {
+               mcbsp5_ick: clock-mcbsp5-ick@10 {
+                       reg = <10>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcbsp5_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <10>;
                };
 
-               mcbsp1_ick: clock-mcbsp1-ick {
+               mcbsp1_ick: clock-mcbsp1-ick@9 {
+                       reg = <9>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcbsp1_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <9>;
                };
 
-               omapctrl_ick: clock-omapctrl-ick {
+               omapctrl_ick: clock-omapctrl-ick@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "omapctrl_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <6>;
                };
 
-               aes2_ick: clock-aes2-ick {
+               aes2_ick: clock-aes2-ick@28 {
+                       reg = <28>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "aes2_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <28>;
                };
 
-               sha12_ick: clock-sha12-ick {
+               sha12_ick: clock-sha12-ick@27 {
+                       reg = <27>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "sha12_ick";
                        clocks = <&core_l4_ick>;
-                       ti,bit-shift = <27>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xc00>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               gpt1_gate_fck: clock-gpt1-gate-fck {
+               gpt1_gate_fck: clock-gpt1-gate-fck@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt1_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <0>;
                };
 
-               gpio1_dbck: clock-gpio1-dbck {
+               gpio1_dbck: clock-gpio1-dbck@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "gpio1_dbck";
                        clocks = <&wkup_32k_fck>;
-                       ti,bit-shift = <3>;
                };
 
-               wdt2_fck: clock-wdt2-fck {
+               wdt2_fck: clock-wdt2-fck@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "wdt2_fck";
                        clocks = <&wkup_32k_fck>;
-                       ti,bit-shift = <5>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0xc10>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               wdt2_ick: clock-wdt2-ick {
+               wdt2_ick: clock-wdt2-ick@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "wdt2_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <5>;
                };
 
-               wdt1_ick: clock-wdt1-ick {
+               wdt1_ick: clock-wdt1-ick@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "wdt1_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <4>;
                };
 
-               gpio1_ick: clock-gpio1-ick {
+               gpio1_ick: clock-gpio1-ick@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpio1_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <3>;
                };
 
-               omap_32ksync_ick: clock-omap-32ksync-ick {
+               omap_32ksync_ick: clock-omap-32ksync-ick@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "omap_32ksync_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <2>;
                };
 
-               gpt12_ick: clock-gpt12-ick {
+               gpt12_ick: clock-gpt12-ick@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt12_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <1>;
                };
 
-               gpt1_ick: clock-gpt1-ick {
+               gpt1_ick: clock-gpt1-ick@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt1_ick";
                        clocks = <&wkup_l4_ick>;
-                       ti,bit-shift = <0>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0x1000>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               uart3_fck: clock-uart3-fck {
+               uart3_fck: clock-uart3-fck@11 {
+                       reg = <11>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "uart3_fck";
                        clocks = <&per_48m_fck>;
-                       ti,bit-shift = <11>;
                };
 
-               gpt2_gate_fck: clock-gpt2-gate-fck {
+               gpt2_gate_fck: clock-gpt2-gate-fck@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt2_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <3>;
                };
 
-               gpt3_gate_fck: clock-gpt3-gate-fck {
+               gpt3_gate_fck: clock-gpt3-gate-fck@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt3_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <4>;
                };
 
-               gpt4_gate_fck: clock-gpt4-gate-fck {
+               gpt4_gate_fck: clock-gpt4-gate-fck@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt4_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <5>;
                };
 
-               gpt5_gate_fck: clock-gpt5-gate-fck {
+               gpt5_gate_fck: clock-gpt5-gate-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt5_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <6>;
                };
 
-               gpt6_gate_fck: clock-gpt6-gate-fck {
+               gpt6_gate_fck: clock-gpt6-gate-fck@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt6_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <7>;
                };
 
-               gpt7_gate_fck: clock-gpt7-gate-fck {
+               gpt7_gate_fck: clock-gpt7-gate-fck@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt7_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <8>;
                };
 
-               gpt8_gate_fck: clock-gpt8-gate-fck {
+               gpt8_gate_fck: clock-gpt8-gate-fck@9 {
+                       reg = <9>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt8_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <9>;
                };
 
-               gpt9_gate_fck: clock-gpt9-gate-fck {
+               gpt9_gate_fck: clock-gpt9-gate-fck@10 {
+                       reg = <10>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "gpt9_gate_fck";
                        clocks = <&sys_ck>;
-                       ti,bit-shift = <10>;
                };
 
-               gpio6_dbck: clock-gpio6-dbck {
+               gpio6_dbck: clock-gpio6-dbck@17 {
+                       reg = <17>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "gpio6_dbck";
                        clocks = <&per_32k_alwon_fck>;
-                       ti,bit-shift = <17>;
                };
 
-               gpio5_dbck: clock-gpio5-dbck {
+               gpio5_dbck: clock-gpio5-dbck@16 {
+                       reg = <16>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "gpio5_dbck";
                        clocks = <&per_32k_alwon_fck>;
-                       ti,bit-shift = <16>;
                };
 
-               gpio4_dbck: clock-gpio4-dbck {
+               gpio4_dbck: clock-gpio4-dbck@15 {
+                       reg = <15>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "gpio4_dbck";
                        clocks = <&per_32k_alwon_fck>;
-                       ti,bit-shift = <15>;
                };
 
-               gpio3_dbck: clock-gpio3-dbck {
+               gpio3_dbck: clock-gpio3-dbck@14 {
+                       reg = <14>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "gpio3_dbck";
                        clocks = <&per_32k_alwon_fck>;
-                       ti,bit-shift = <14>;
                };
 
-               gpio2_dbck: clock-gpio2-dbck {
+               gpio2_dbck: clock-gpio2-dbck@13 {
+                       reg = <13>;
                        #clock-cells = <0>;
                        compatible = "ti,gate-clock";
                        clock-output-names = "gpio2_dbck";
                        clocks = <&per_32k_alwon_fck>;
-                       ti,bit-shift = <13>;
                };
 
-               wdt3_fck: clock-wdt3-fck {
+               wdt3_fck: clock-wdt3-fck@12 {
+                       reg = <12>;
                        #clock-cells = <0>;
                        compatible = "ti,wait-gate-clock";
                        clock-output-names = "wdt3_fck";
                        clocks = <&per_32k_alwon_fck>;
-                       ti,bit-shift = <12>;
                };
 
-               mcbsp2_gate_fck: clock-mcbsp2-gate-fck {
+               mcbsp2_gate_fck: clock-mcbsp2-gate-fck@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "mcbsp2_gate_fck";
                        clocks = <&mcbsp_clks>;
-                       ti,bit-shift = <0>;
                };
 
-               mcbsp3_gate_fck: clock-mcbsp3-gate-fck {
+               mcbsp3_gate_fck: clock-mcbsp3-gate-fck@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "mcbsp3_gate_fck";
                        clocks = <&mcbsp_clks>;
-                       ti,bit-shift = <1>;
                };
 
-               mcbsp4_gate_fck: clock-mcbsp4-gate-fck {
+               mcbsp4_gate_fck: clock-mcbsp4-gate-fck@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-gate-clock";
                        clock-output-names = "mcbsp4_gate_fck";
                        clocks = <&mcbsp_clks>;
-                       ti,bit-shift = <2>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0x1040>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               gpt2_mux_fck: clock-gpt2-mux-fck {
+               gpt2_mux_fck: clock-gpt2-mux-fck@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt2_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
                };
 
-               gpt3_mux_fck: clock-gpt3-mux-fck {
+               gpt3_mux_fck: clock-gpt3-mux-fck@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt3_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <1>;
                };
 
-               gpt4_mux_fck: clock-gpt4-mux-fck {
+               gpt4_mux_fck: clock-gpt4-mux-fck@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt4_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <2>;
                };
 
-               gpt5_mux_fck: clock-gpt5-mux-fck {
+               gpt5_mux_fck: clock-gpt5-mux-fck@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt5_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <3>;
                };
 
-               gpt6_mux_fck: clock-gpt6-mux-fck {
+               gpt6_mux_fck: clock-gpt6-mux-fck@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt6_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <4>;
                };
 
-               gpt7_mux_fck: clock-gpt7-mux-fck {
+               gpt7_mux_fck: clock-gpt7-mux-fck@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt7_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <5>;
                };
 
-               gpt8_mux_fck: clock-gpt8-mux-fck {
+               gpt8_mux_fck: clock-gpt8-mux-fck@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt8_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <6>;
                };
 
-               gpt9_mux_fck: clock-gpt9-mux-fck {
+               gpt9_mux_fck: clock-gpt9-mux-fck@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,composite-mux-clock";
                        clock-output-names = "gpt9_mux_fck";
                        clocks = <&omap_32k_fck>, <&sys_ck>;
-                       ti,bit-shift = <7>;
                };
        };
 
                compatible = "ti,clksel";
                reg = <0x1010>;
                #clock-cells = <2>;
-               #address-cells = <0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
 
-               gpio6_ick: clock-gpio6-ick {
+               gpio6_ick: clock-gpio6-ick@17 {
+                       reg = <17>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpio6_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <17>;
                };
 
-               gpio5_ick: clock-gpio5-ick {
+               gpio5_ick: clock-gpio5-ick@16 {
+                       reg = <16>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpio5_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <16>;
                };
 
-               gpio4_ick: clock-gpio4-ick {
+               gpio4_ick: clock-gpio4-ick@15 {
+                       reg = <15>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpio4_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <15>;
                };
 
-               gpio3_ick: clock-gpio3-ick {
+               gpio3_ick: clock-gpio3-ick@14 {
+                       reg = <14>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpio3_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <14>;
                };
 
-               gpio2_ick: clock-gpio2-ick {
+               gpio2_ick: clock-gpio2-ick@13 {
+                       reg = <13>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpio2_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <13>;
                };
 
-               wdt3_ick: clock-wdt3-ick {
+               wdt3_ick: clock-wdt3-ick@12 {
+                       reg = <12>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "wdt3_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <12>;
                };
 
-               uart3_ick: clock-uart3-ick {
+               uart3_ick: clock-uart3-ick@11 {
+                       reg = <11>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "uart3_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <11>;
                };
 
-               uart4_ick: clock-uart4-ick {
+               uart4_ick: clock-uart4-ick@18 {
+                       reg = <18>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "uart4_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <18>;
                };
 
-               gpt9_ick: clock-gpt9-ick {
+               gpt9_ick: clock-gpt9-ick@10 {
+                       reg = <10>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt9_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <10>;
                };
 
-               gpt8_ick: clock-gpt8-ick {
+               gpt8_ick: clock-gpt8-ick@9 {
+                       reg = <9>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt8_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <9>;
                };
 
-               gpt7_ick: clock-gpt7-ick {
+               gpt7_ick: clock-gpt7-ick@8 {
+                       reg = <8>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt7_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <8>;
                };
 
-               gpt6_ick: clock-gpt6-ick {
+               gpt6_ick: clock-gpt6-ick@7 {
+                       reg = <7>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt6_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <7>;
                };
 
-               gpt5_ick: clock-gpt5-ick {
+               gpt5_ick: clock-gpt5-ick@6 {
+                       reg = <6>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt5_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <6>;
                };
 
-               gpt4_ick: clock-gpt4-ick {
+               gpt4_ick: clock-gpt4-ick@5 {
+                       reg = <5>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt4_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <5>;
                };
 
-               gpt3_ick: clock-gpt3-ick {
+               gpt3_ick: clock-gpt3-ick@4 {
+                       reg = <4>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt3_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <4>;
                };
 
-               gpt2_ick: clock-gpt2-ick {
+               gpt2_ick: clock-gpt2-ick@3 {
+                       reg = <3>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "gpt2_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <3>;
                };
 
-               mcbsp2_ick: clock-mcbsp2-ick {
+               mcbsp2_ick: clock-mcbsp2-ick@0 {
+                       reg = <0>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcbsp2_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <0>;
                };
 
-               mcbsp3_ick: clock-mcbsp3-ick {
+               mcbsp3_ick: clock-mcbsp3-ick@1 {
+                       reg = <1>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcbsp3_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <1>;
                };
 
-               mcbsp4_ick: clock-mcbsp4-ick {
+               mcbsp4_ick: clock-mcbsp4-ick@2 {
+                       reg = <2>;
                        #clock-cells = <0>;
                        compatible = "ti,omap3-interface-clock";
                        clock-output-names = "mcbsp4_ick";
                        clocks = <&per_l4_ick>;
-                       ti,bit-shift = <2>;
                };
        };
 
index 7f44e88d1f25bcc57891701af2339f57054b3f14..14a38cc67e0bc966891af77d23a8897873ea46a3 100644 (file)
@@ -10,6 +10,7 @@
 #include <uapi/asm/ptrace.h>
 
 #ifndef __ASSEMBLY__
+#include <linux/bitfield.h>
 #include <linux/types.h>
 
 struct pt_regs {
@@ -35,8 +36,8 @@ struct svc_pt_regs {
 
 #ifndef CONFIG_CPU_V7M
 #define isa_mode(regs) \
-       ((((regs)->ARM_cpsr & PSR_J_BIT) >> (__ffs(PSR_J_BIT) - 1)) | \
-        (((regs)->ARM_cpsr & PSR_T_BIT) >> (__ffs(PSR_T_BIT))))
+       (FIELD_GET(PSR_J_BIT, (regs)->ARM_cpsr) << 1 | \
+        FIELD_GET(PSR_T_BIT, (regs)->ARM_cpsr))
 #else
 #define isa_mode(regs) 1 /* Thumb */
 #endif
index f6175e6e28cd2206371671de341d1bc53028a54e..3f7d68740ed4c9982875e13d6fe05e410bc612a4 100644 (file)
@@ -27,6 +27,7 @@
 #define UARTA_72165            UARTA_7278
 #define UARTA_7364             REG_PHYS_ADDR(0x40b000)
 #define UARTA_7366             UARTA_7364
+#define UARTA_74165            UARTA_7278
 #define UARTA_74371            REG_PHYS_ADDR(0x406b00)
 #define UARTA_7439             REG_PHYS_ADDR(0x40a900)
 #define UARTA_7445             REG_PHYS_ADDR(0x40ab00)
@@ -88,9 +89,10 @@ ARM_BE8(     rev     \rv, \rv )
 30:            checkuart(\rp, \rv, 0x72780000, 7278)
 31:            checkuart(\rp, \rv, 0x73640000, 7364)
 32:            checkuart(\rp, \rv, 0x73660000, 7366)
-33:            checkuart(\rp, \rv, 0x07437100, 74371)
-34:            checkuart(\rp, \rv, 0x74390000, 7439)
-35:            checkuart(\rp, \rv, 0x74450000, 7445)
+33:            checkuart(\rp, \rv, 0x07416500, 74165)
+34:            checkuart(\rp, \rv, 0x07437100, 74371)
+35:            checkuart(\rp, \rv, 0x74390000, 7439)
+36:            checkuart(\rp, \rv, 0x74450000, 7445)
 
                /* No valid UART found */
 90:            mov     \rp, #0
index 6a9de826ffd3c035d938b8177d06ab1476cbf951..89a77e3f51d20a09a2136a872fef5ab347f23acf 100644 (file)
@@ -76,8 +76,6 @@ obj-$(CONFIG_HAVE_HW_BREAKPOINT)      += hw_breakpoint.o
 obj-$(CONFIG_CPU_XSCALE)       += xscale-cp0.o
 obj-$(CONFIG_CPU_XSC3)         += xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)       += xscale-cp0.o
-obj-$(CONFIG_CPU_PJ4)          += pj4-cp0.o
-obj-$(CONFIG_CPU_PJ4B)         += pj4-cp0.o
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_regs.o perf_callchain.o
 obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event_xscale.o perf_event_v6.o \
index a0218c4867b9b6054fbd8b809a8311b8e259aa55..4a335d3c59690bdc37ce14629751e08afdb41806 100644 (file)
 #include <asm/assembler.h>
 #include "iwmmxt.h"
 
-#if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B)
-#define PJ4(code...)           code
-#define XSC(code...)
-#elif defined(CONFIG_CPU_MOHAWK) || \
-       defined(CONFIG_CPU_XSC3) || \
-       defined(CONFIG_CPU_XSCALE)
-#define PJ4(code...)
-#define XSC(code...)           code
-#else
-#error "Unsupported iWMMXt architecture"
-#endif
-
 #define MMX_WR0                        (0x00)
 #define MMX_WR1                        (0x08)
 #define MMX_WR2                        (0x10)
@@ -81,17 +69,13 @@ ENDPROC(iwmmxt_undef_handler)
 ENTRY(iwmmxt_task_enable)
        inc_preempt_count r10, r3
 
-       XSC(mrc p15, 0, r2, c15, c1, 0)
-       PJ4(mrc p15, 0, r2, c1, c0, 2)
+       mrc     p15, 0, r2, c15, c1, 0
        @ CP0 and CP1 accessible?
-       XSC(tst r2, #0x3)
-       PJ4(tst r2, #0xf)
+       tst     r2, #0x3
        bne     4f                              @ if so no business here
        @ enable access to CP0 and CP1
-       XSC(orr r2, r2, #0x3)
-       XSC(mcr p15, 0, r2, c15, c1, 0)
-       PJ4(orr r2, r2, #0xf)
-       PJ4(mcr p15, 0, r2, c1, c0, 2)
+       orr     r2, r2, #0x3
+       mcr     p15, 0, r2, c15, c1, 0
 
        ldr     r3, =concan_owner
        ldr     r2, [r0, #S_PC]                 @ current task pc value
@@ -218,12 +202,9 @@ ENTRY(iwmmxt_task_disable)
        bne     1f                              @ no: quit
 
        @ enable access to CP0 and CP1
-       XSC(mrc p15, 0, r4, c15, c1, 0)
-       XSC(orr r4, r4, #0x3)
-       XSC(mcr p15, 0, r4, c15, c1, 0)
-       PJ4(mrc p15, 0, r4, c1, c0, 2)
-       PJ4(orr r4, r4, #0xf)
-       PJ4(mcr p15, 0, r4, c1, c0, 2)
+       mrc     p15, 0, r4, c15, c1, 0
+       orr     r4, r4, #0x3
+       mcr     p15, 0, r4, c15, c1, 0
 
        mov     r0, #0                          @ nothing to load
        str     r0, [r3]                        @ no more current owner
@@ -232,10 +213,8 @@ ENTRY(iwmmxt_task_disable)
        bl      concan_save
 
        @ disable access to CP0 and CP1
-       XSC(bic r4, r4, #0x3)
-       XSC(mcr p15, 0, r4, c15, c1, 0)
-       PJ4(bic r4, r4, #0xf)
-       PJ4(mcr p15, 0, r4, c1, c0, 2)
+       bic     r4, r4, #0x3
+       mcr     p15, 0, r4, c15, c1, 0
 
        mrc     p15, 0, r2, c2, c0, 0
        mov     r2, r2                          @ cpwait
@@ -330,11 +309,9 @@ ENDPROC(iwmmxt_task_restore)
  */
 ENTRY(iwmmxt_task_switch)
 
-       XSC(mrc p15, 0, r1, c15, c1, 0)
-       PJ4(mrc p15, 0, r1, c1, c0, 2)
+       mrc     p15, 0, r1, c15, c1, 0
        @ CP0 and CP1 accessible?
-       XSC(tst r1, #0x3)
-       PJ4(tst r1, #0xf)
+       tst     r1, #0x3
        bne     1f                              @ yes: block them for next task
 
        ldr     r2, =concan_owner
@@ -344,10 +321,8 @@ ENTRY(iwmmxt_task_switch)
        retne   lr                              @ no: leave Concan disabled
 
 1:     @ flip Concan access
-       XSC(eor r1, r1, #0x3)
-       XSC(mcr p15, 0, r1, c15, c1, 0)
-       PJ4(eor r1, r1, #0xf)
-       PJ4(mcr p15, 0, r1, c1, c0, 2)
+       eor     r1, r1, #0x3
+       mcr     p15, 0, r1, c15, c1, 0
 
        mrc     p15, 0, r1, c2, c0, 0
        sub     pc, lr, r1, lsr #32             @ cpwait and return
diff --git a/arch/arm/kernel/pj4-cp0.c b/arch/arm/kernel/pj4-cp0.c
deleted file mode 100644 (file)
index 4bca809..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * linux/arch/arm/kernel/pj4-cp0.c
- *
- * PJ4 iWMMXt coprocessor context switching and handling
- *
- * Copyright (c) 2010 Marvell International Inc.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <asm/thread_notify.h>
-#include <asm/cputype.h>
-
-static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
-{
-       struct thread_info *thread = t;
-
-       switch (cmd) {
-       case THREAD_NOTIFY_FLUSH:
-               /*
-                * flush_thread() zeroes thread->fpstate, so no need
-                * to do anything here.
-                *
-                * FALLTHROUGH: Ensure we don't try to overwrite our newly
-                * initialised state information on the first fault.
-                */
-
-       case THREAD_NOTIFY_EXIT:
-               iwmmxt_task_release(thread);
-               break;
-
-       case THREAD_NOTIFY_SWITCH:
-               iwmmxt_task_switch(thread);
-               break;
-       }
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block __maybe_unused iwmmxt_notifier_block = {
-       .notifier_call  = iwmmxt_do,
-};
-
-
-static u32 __init pj4_cp_access_read(void)
-{
-       u32 value;
-
-       __asm__ __volatile__ (
-               "mrc    p15, 0, %0, c1, c0, 2\n\t"
-               : "=r" (value));
-       return value;
-}
-
-static void __init pj4_cp_access_write(u32 value)
-{
-       u32 temp;
-
-       __asm__ __volatile__ (
-               "mcr    p15, 0, %1, c1, c0, 2\n\t"
-#ifdef CONFIG_THUMB2_KERNEL
-               "isb\n\t"
-#else
-               "mrc    p15, 0, %0, c1, c0, 2\n\t"
-               "mov    %0, %0\n\t"
-               "sub    pc, pc, #4\n\t"
-#endif
-               : "=r" (temp) : "r" (value));
-}
-
-static int __init pj4_get_iwmmxt_version(void)
-{
-       u32 cp_access, wcid;
-
-       cp_access = pj4_cp_access_read();
-       pj4_cp_access_write(cp_access | 0xf);
-
-       /* check if coprocessor 0 and 1 are available */
-       if ((pj4_cp_access_read() & 0xf) != 0xf) {
-               pj4_cp_access_write(cp_access);
-               return -ENODEV;
-       }
-
-       /* read iWMMXt coprocessor id register p1, c0 */
-       __asm__ __volatile__ ("mrc    p1, 0, %0, c0, c0, 0\n" : "=r" (wcid));
-
-       pj4_cp_access_write(cp_access);
-
-       /* iWMMXt v1 */
-       if ((wcid & 0xffffff00) == 0x56051000)
-               return 1;
-       /* iWMMXt v2 */
-       if ((wcid & 0xffffff00) == 0x56052000)
-               return 2;
-
-       return -EINVAL;
-}
-
-/*
- * Disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
- * switch code handle iWMMXt context switching.
- */
-static int __init pj4_cp0_init(void)
-{
-       u32 __maybe_unused cp_access;
-       int vers;
-
-       if (!cpu_is_pj4())
-               return 0;
-
-       vers = pj4_get_iwmmxt_version();
-       if (vers < 0)
-               return 0;
-
-#ifndef CONFIG_IWMMXT
-       pr_info("PJ4 iWMMXt coprocessor detected, but kernel support is missing.\n");
-#else
-       cp_access = pj4_cp_access_read() & ~0xf;
-       pj4_cp_access_write(cp_access);
-
-       pr_info("PJ4 iWMMXt v%d coprocessor enabled.\n", vers);
-       elf_hwcap |= HWCAP_IWMMXT;
-       thread_register_notifier(&iwmmxt_notifier_block);
-       register_iwmmxt_undef_handler();
-#endif
-
-       return 0;
-}
-
-late_initcall(pj4_cp0_init);
index 3bad79db5d6e8095214d39d89853ff85d46d5eed..72c82a4d63ac206b5d4f96f7504a111abd688b09 100644 (file)
@@ -220,7 +220,7 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
        unsigned int fp, mode;
        int ok = 1;
 
-       printk("%sBacktrace: ", loglvl);
+       printk("%sCall trace: ", loglvl);
 
        if (!tsk)
                tsk = current;
index 9d2192156087be4727d909a5190e682c99efa02a..f60547dadc93987aff61abb09f558482c57eca8a 100644 (file)
@@ -524,6 +524,8 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk,
 {
        struct stackframe frame;
 
+       printk("%sCall trace: ", loglvl);
+
        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
        if (!tsk)
index 8789d93a7c04b3929452ceed8063c024a794e815..7318d8789e2486900bb9d63d20a56d3675bc03e7 100644 (file)
@@ -93,7 +93,6 @@ config ARCH_BCM_MOBILE
        select ARM_ERRATA_775420
        select ARM_GIC
        select GPIO_BCM_KONA
-       select TICK_ONESHOT
        select HAVE_ARM_ARCH_TIMER
        select PINCTRL
        select ARCH_BCM_MOBILE_SMP if SMP
index 07565b593ed681b0f1675f8ef7a934c1ae53dc51..439dc6a26bb982ba7b085ca924ba4fc862ac61cc 100644 (file)
 
 #include "fault.h"
 
+bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
+{
+       unsigned long addr = (unsigned long)unsafe_src;
+
+       return addr >= TASK_SIZE && ULONG_MAX - addr >= size;
+}
+
 #ifdef CONFIG_MMU
 
 /*
@@ -588,6 +595,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
        if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
                return;
 
+       pr_alert("8<--- cut here ---\n");
        pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
                inf->name, ifsr, addr);
 
index d19d140a10c7d56621342fe98c756ec5d2af36a0..0749cf8a66371bb608f8bbd793c2e8302d56d989 100644 (file)
@@ -296,6 +296,9 @@ void __sync_icache_dcache(pte_t pteval)
                return;
 
        folio = page_folio(pfn_to_page(pfn));
+       if (folio_test_reserved(folio))
+               return;
+
        if (cache_is_vipt_aliasing())
                mapping = folio_flush_mapping(folio);
        else
index 4c3d78691279d3e4022bce8b2e8dde8df916a19f..e8c6f4be0ce1987b66208d0da1d2b942d56dacff 100644 (file)
@@ -418,7 +418,7 @@ static void set_section_perms(struct section_perm *perms, int n, bool set,
 
 }
 
-/**
+/*
  * update_sections_early intended to be called only through stop_machine
  * framework and executed by only one CPU while all other CPUs will spin and
  * wait, so no locking is required in this function.
index 77e05d4959f289313488dc5b03d9254db571e50f..7b11c98b3e84bf76bcd6a33b34af257a9b7f48d7 100644 (file)
@@ -120,6 +120,7 @@ config ARM64
        select CLONE_BACKWARDS
        select COMMON_CLK
        select CPU_PM if (SUSPEND || CPU_IDLE)
+       select CPUMASK_OFFSTACK if NR_CPUS > 256
        select CRC32
        select DCACHE_WORD_ACCESS
        select DYNAMIC_FTRACE if FUNCTION_TRACER
@@ -1425,7 +1426,7 @@ config SCHED_SMT
 config NR_CPUS
        int "Maximum number of CPUs (2-4096)"
        range 2 4096
-       default "256"
+       default "512"
 
 config HOTPLUG_CPU
        bool "Support for hot-pluggable CPUs"
index 52f928dbfa3cd7a878ace893b2d56a95b3f74ef3..2a0d4ee3bd796157dd7532f886cebea77036d14c 100644 (file)
                #size-cells = <1>;
 
                partition@0 {
-                       compatible = "nvmem-cells";
                        label = "cferom";
                        reg = <0x0 0x100000>;
 
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <0 0x0 0x100000>;
+                       nvmem-layout {
+                               compatible = "fixed-layout";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
 
-                       base_mac_addr: mac@106a0 {
-                               reg = <0x106a0 0x6>;
+                               base_mac_addr: mac@106a0 {
+                                       reg = <0x106a0 0x6>;
+                               };
                        };
                };
 
index 336016e334d9374741ad2d18989d7922efed6082..e01cf4f540770cc24b92c0aa6051ced0e473206d 100644 (file)
                                brcm,num-gphy = <5>;
                                brcm,num-rgmii-ports = <2>;
 
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
                                ports: ports {
                                        #address-cells = <1>;
                                        #size-cells = <0>;
index ddbaf7280b03075aca5d9b5c984108e7d6cb2fdb..11158c2bd5241661da0efb8019952d0b91db05ba 100644 (file)
                        };
                };
 
+               pm6150_vbus: usb-vbus-regulator@1100 {
+                       compatible = "qcom,pm6150-vbus-reg,
+                                     qcom,pm8150b-vbus-reg";
+                       reg = <0x1100>;
+                       status = "disabled";
+               };
+
+               pm6150_typec: typec@1500 {
+                       compatible = "qcom,pm6150-typec,
+                                     qcom,pm8150b-typec";
+                       reg = <0x1500>, <0x1700>;
+                       interrupts = <0x0 0x15 0x00 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x01 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x0 0x15 0x02 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x03 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x0 0x15 0x04 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x05 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x15 0x06 IRQ_TYPE_EDGE_BOTH>,
+                                    <0x0 0x15 0x07 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x00 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x01 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x02 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x03 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x04 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x05 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x06 IRQ_TYPE_EDGE_RISING>,
+                                    <0x0 0x17 0x07 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "or-rid-detect-change",
+                                         "vpd-detect",
+                                         "cc-state-change",
+                                         "vconn-oc",
+                                         "vbus-change",
+                                         "attach-detach",
+                                         "legacy-cable-detect",
+                                         "try-snk-src-detect",
+                                         "sig-tx",
+                                         "sig-rx",
+                                         "msg-tx",
+                                         "msg-rx",
+                                         "msg-tx-failed",
+                                         "msg-tx-discarded",
+                                         "msg-rx-discarded",
+                                         "fr-swap";
+                       status = "disabled";
+               };
+
                pm6150_temp: temp-alarm@2400 {
                        compatible = "qcom,spmi-temp-alarm";
                        reg = <0x2400>;
index b54c3479370120bc3826876a105f45500fb6ec69..f1ebc025e1df765af9b02d77cbf415273d121793 100644 (file)
@@ -160,22 +160,22 @@ void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
                return;
        panic_reported = true;
 
-       guest_id = hv_get_vpreg(HV_REGISTER_GUEST_OSID);
+       guest_id = hv_get_vpreg(HV_REGISTER_GUEST_OS_ID);
 
        /*
         * Hyper-V provides the ability to store only 5 values.
         * Pick the passed in error value, the guest_id, the PC,
         * and the SP.
         */
-       hv_set_vpreg(HV_REGISTER_CRASH_P0, err);
-       hv_set_vpreg(HV_REGISTER_CRASH_P1, guest_id);
-       hv_set_vpreg(HV_REGISTER_CRASH_P2, regs->pc);
-       hv_set_vpreg(HV_REGISTER_CRASH_P3, regs->sp);
-       hv_set_vpreg(HV_REGISTER_CRASH_P4, 0);
+       hv_set_vpreg(HV_REGISTER_GUEST_CRASH_P0, err);
+       hv_set_vpreg(HV_REGISTER_GUEST_CRASH_P1, guest_id);
+       hv_set_vpreg(HV_REGISTER_GUEST_CRASH_P2, regs->pc);
+       hv_set_vpreg(HV_REGISTER_GUEST_CRASH_P3, regs->sp);
+       hv_set_vpreg(HV_REGISTER_GUEST_CRASH_P4, 0);
 
        /*
         * Let Hyper-V know there is crash data available
         */
-       hv_set_vpreg(HV_REGISTER_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
+       hv_set_vpreg(HV_REGISTER_GUEST_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
 }
 EXPORT_SYMBOL_GPL(hyperv_report_panic);
index f1b8a04ee9f26364bdebe33510cd135781d3f63b..b1a4de4eee2930f622409b7e68a7c82d50e27496 100644 (file)
 
 static bool hyperv_initialized;
 
+int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
+{
+       hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION,
+                        (struct hv_get_vp_registers_output *)info);
+
+       return 0;
+}
+
 static int __init hyperv_init(void)
 {
        struct hv_get_vp_registers_output       result;
-       u32     a, b, c, d;
        u64     guest_id;
        int     ret;
 
@@ -39,7 +46,7 @@ static int __init hyperv_init(void)
 
        /* Setup the guest ID */
        guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
-       hv_set_vpreg(HV_REGISTER_GUEST_OSID, guest_id);
+       hv_set_vpreg(HV_REGISTER_GUEST_OS_ID, guest_id);
 
        /* Get the features and hints from Hyper-V */
        hv_get_vpreg_128(HV_REGISTER_FEATURES, &result);
@@ -54,15 +61,6 @@ static int __init hyperv_init(void)
                ms_hyperv.features, ms_hyperv.priv_high, ms_hyperv.hints,
                ms_hyperv.misc_features);
 
-       /* Get information about the Hyper-V host version */
-       hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION, &result);
-       a = result.as32.a;
-       b = result.as32.b;
-       c = result.as32.c;
-       d = result.as32.d;
-       pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
-               b >> 16, b & 0xFFFF, a, d & 0xFFFFFF, c, d >> 24);
-
        ret = hv_common_init();
        if (ret)
                return ret;
@@ -74,6 +72,8 @@ static int __init hyperv_init(void)
                return ret;
        }
 
+       ms_hyperv_late_init();
+
        hyperv_initialized = true;
        return 0;
 }
index bc6c7ac934a1a124d93dfd6cf6c7e20eb3af0c1c..bc30aadedfe9d223fea7675f32f410f7ba7b1c2e 100644 (file)
  * byte ordering of Linux running on ARM64, so no special handling is required.
  */
 
-/*
- * These Hyper-V registers provide information equivalent to the CPUID
- * instruction on x86/x64.
- */
-#define HV_REGISTER_HYPERVISOR_VERSION         0x00000100 /*CPUID 0x40000002 */
-#define HV_REGISTER_FEATURES                   0x00000200 /*CPUID 0x40000003 */
-#define HV_REGISTER_ENLIGHTENMENTS             0x00000201 /*CPUID 0x40000004 */
-
 /*
  * Group C Features. See the asm-generic version of hyperv-tlfs.h
  * for a description of Feature Groups.
 #define HV_STIMER_DIRECT_MODE_AVAILABLE                BIT(13)
 
 /*
- * Synthetic register definitions equivalent to MSRs on x86/x64
+ * To support arch-generic code calling hv_set/get_register:
+ * - On x86, HV_MSR_ indicates an MSR accessed via rdmsrl/wrmsrl
+ * - On ARM, HV_MSR_ indicates a VP register accessed via hypercall
  */
-#define HV_REGISTER_CRASH_P0           0x00000210
-#define HV_REGISTER_CRASH_P1           0x00000211
-#define HV_REGISTER_CRASH_P2           0x00000212
-#define HV_REGISTER_CRASH_P3           0x00000213
-#define HV_REGISTER_CRASH_P4           0x00000214
-#define HV_REGISTER_CRASH_CTL          0x00000215
+#define HV_MSR_CRASH_P0                (HV_REGISTER_GUEST_CRASH_P0)
+#define HV_MSR_CRASH_P1                (HV_REGISTER_GUEST_CRASH_P1)
+#define HV_MSR_CRASH_P2                (HV_REGISTER_GUEST_CRASH_P2)
+#define HV_MSR_CRASH_P3                (HV_REGISTER_GUEST_CRASH_P3)
+#define HV_MSR_CRASH_P4                (HV_REGISTER_GUEST_CRASH_P4)
+#define HV_MSR_CRASH_CTL       (HV_REGISTER_GUEST_CRASH_CTL)
 
-#define HV_REGISTER_GUEST_OSID         0x00090002
-#define HV_REGISTER_VP_INDEX           0x00090003
-#define HV_REGISTER_TIME_REF_COUNT     0x00090004
-#define HV_REGISTER_REFERENCE_TSC      0x00090017
+#define HV_MSR_VP_INDEX                (HV_REGISTER_VP_INDEX)
+#define HV_MSR_TIME_REF_COUNT  (HV_REGISTER_TIME_REF_COUNT)
+#define HV_MSR_REFERENCE_TSC   (HV_REGISTER_REFERENCE_TSC)
 
-#define HV_REGISTER_SINT0              0x000A0000
-#define HV_REGISTER_SCONTROL           0x000A0010
-#define HV_REGISTER_SIEFP              0x000A0012
-#define HV_REGISTER_SIMP               0x000A0013
-#define HV_REGISTER_EOM                        0x000A0014
+#define HV_MSR_SINT0           (HV_REGISTER_SINT0)
+#define HV_MSR_SCONTROL                (HV_REGISTER_SCONTROL)
+#define HV_MSR_SIEFP           (HV_REGISTER_SIEFP)
+#define HV_MSR_SIMP            (HV_REGISTER_SIMP)
+#define HV_MSR_EOM             (HV_REGISTER_EOM)
 
-#define HV_REGISTER_STIMER0_CONFIG     0x000B0000
-#define HV_REGISTER_STIMER0_COUNT      0x000B0001
+#define HV_MSR_STIMER0_CONFIG  (HV_REGISTER_STIMER0_CONFIG)
+#define HV_MSR_STIMER0_COUNT   (HV_REGISTER_STIMER0_COUNT)
 
 union hv_msi_entry {
        u64 as_uint64[2];
index 20070a847304cf85739ff62b6fc64e42e9bec0ae..a975e1a689ddba3cb7e2cccde2b0fe7f1efb534b 100644 (file)
@@ -31,12 +31,12 @@ void hv_set_vpreg(u32 reg, u64 value);
 u64 hv_get_vpreg(u32 reg);
 void hv_get_vpreg_128(u32 reg, struct hv_get_vp_registers_output *result);
 
-static inline void hv_set_register(unsigned int reg, u64 value)
+static inline void hv_set_msr(unsigned int reg, u64 value)
 {
        hv_set_vpreg(reg, value);
 }
 
-static inline u64 hv_get_register(unsigned int reg)
+static inline u64 hv_get_msr(unsigned int reg)
 {
        return hv_get_vpreg(reg);
 }
index 1414052e7d6b2ad5c22975d1cb5b002f558ebc1e..e233b5efa2761e35c416cbc147f6b6422a7c5b8f 100644 (file)
@@ -7,11 +7,13 @@ config HEXAGON
        select ARCH_32BIT_OFF_T
        select ARCH_HAS_SYNC_DMA_FOR_DEVICE
        select ARCH_NO_PREEMPT
+       select ARCH_WANT_FRAME_POINTERS
        select DMA_GLOBAL_POOL
        select HAVE_PAGE_SIZE_4KB
        select HAVE_PAGE_SIZE_16KB
        select HAVE_PAGE_SIZE_64KB
        select HAVE_PAGE_SIZE_256KB
+       select FRAME_POINTER
        # Other pending projects/to-do items.
        # select HAVE_REGS_AND_STACK_ACCESS_API
        # select HAVE_HW_BREAKPOINT if PERF_EVENTS
@@ -23,6 +25,7 @@ config HEXAGON
        select HAVE_PERF_EVENTS
        # GENERIC_ALLOCATOR is used by dma_alloc_coherent()
        select GENERIC_ALLOCATOR
+       select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
@@ -47,9 +50,6 @@ config HEXAGON_PHYS_OFFSET
        help
          Platforms that don't load the kernel at zero set this.
 
-config FRAME_POINTER
-       def_bool y
-
 config LOCKDEP_SUPPORT
        def_bool y
 
@@ -62,12 +62,6 @@ config MMU
 config GENERIC_CSUM
        def_bool y
 
-#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_IRQ_PROBE
-       def_bool y
-
 config GENERIC_HWEIGHT
        def_bool y
 
index c139d0d728029e200899c857c9cbb50e45c9d7c2..a5f300ec6f2808b8890ebc27d0de8a918eaa8636 100644 (file)
@@ -15,6 +15,7 @@ config LOONGARCH
        select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
        select ARCH_HAS_ACPI_TABLE_UPGRADE      if ACPI
        select ARCH_HAS_CPU_FINALIZE_INIT
+       select ARCH_HAS_CURRENT_STACK_POINTER
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_KCOV
        select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
@@ -104,6 +105,7 @@ config LOONGARCH
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
+       select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD
        select HAVE_ASM_MODVERSIONS
        select HAVE_CONTEXT_TRACKING_USER
        select HAVE_C_RECORDMCOUNT
@@ -133,20 +135,24 @@ config LOONGARCH
        select HAVE_KPROBES
        select HAVE_KPROBES_ON_FTRACE
        select HAVE_KRETPROBES
+       select HAVE_LIVEPATCH
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
+       select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS
        select HAVE_PCI
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
        select HAVE_PERF_USER_STACK_DUMP
        select HAVE_PREEMPT_DYNAMIC_KEY
        select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC
        select HAVE_RETHOOK
        select HAVE_RSEQ
        select HAVE_RUST
        select HAVE_SAMPLE_FTRACE_DIRECT
        select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
        select HAVE_SETUP_PER_CPU_AREA if NUMA
+       select HAVE_STACK_VALIDATION if HAVE_OBJTOOL
        select HAVE_STACKPROTECTOR
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_TIF_NOHZ
@@ -624,6 +630,8 @@ config RANDOMIZE_BASE_MAX_OFFSET
 
          This is limited by the size of the lower address memory, 256MB.
 
+source "kernel/livepatch/Kconfig"
+
 endmenu
 
 config ARCH_SELECT_MEMORY_MODEL
index 8d36aab530083b9c57355ea0dd96f69e23a64765..98d60630c3d4b4771d7fe5570e15b7f5e0ab2071 100644 (file)
@@ -26,4 +26,15 @@ config UNWINDER_PROLOGUE
          Some of the addresses it reports may be incorrect (but better than the
          Guess unwinder).
 
+config UNWINDER_ORC
+       bool "ORC unwinder"
+       select OBJTOOL
+       help
+         This option enables the ORC (Oops Rewind Capability) unwinder for
+         unwinding kernel stack traces.  It uses a custom data format which is
+         a simplified version of the DWARF Call Frame Information standard.
+
+         Enabling this option will increase the kernel's runtime memory usage
+         by roughly 2-4MB, depending on your kernel config.
+
 endchoice
index fa4fb09909aeb1c7ebe640329936cd095e8224c8..df6caf79537a9d884aa97161a32840782147460e 100644 (file)
@@ -26,6 +26,18 @@ endif
 32bit-emul             = elf32loongarch
 64bit-emul             = elf64loongarch
 
+ifdef CONFIG_UNWINDER_ORC
+orc_hash_h := arch/$(SRCARCH)/include/generated/asm/orc_hash.h
+orc_hash_sh := $(srctree)/scripts/orc_hash.sh
+targets += $(orc_hash_h)
+quiet_cmd_orc_hash = GEN     $@
+      cmd_orc_hash = mkdir -p $(dir $@); \
+                    $(CONFIG_SHELL) $(orc_hash_sh) < $< > $@
+$(orc_hash_h): $(srctree)/arch/loongarch/include/asm/orc_types.h $(orc_hash_sh) FORCE
+       $(call if_changed,orc_hash)
+archprepare: $(orc_hash_h)
+endif
+
 ifdef CONFIG_DYNAMIC_FTRACE
 KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
 CC_FLAGS_FTRACE := -fpatchable-function-entry=2
@@ -72,8 +84,6 @@ KBUILD_CFLAGS_KERNEL          += $(call cc-option,-mdirect-extern-access)
 KBUILD_CFLAGS_KERNEL           += $(call cc-option,-fdirect-access-external-data)
 KBUILD_AFLAGS_MODULE           += $(call cc-option,-fno-direct-access-external-data)
 KBUILD_CFLAGS_MODULE           += $(call cc-option,-fno-direct-access-external-data)
-KBUILD_AFLAGS_MODULE           += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
-KBUILD_CFLAGS_MODULE           += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
 else
 cflags-y                       += $(call cc-option,-mno-explicit-relocs)
 KBUILD_AFLAGS_KERNEL           += -Wa,-mla-global-with-pcrel
@@ -82,6 +92,15 @@ KBUILD_AFLAGS_MODULE         += -Wa,-mla-global-with-abs
 KBUILD_CFLAGS_MODULE           += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
 endif
 
+KBUILD_AFLAGS                  += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
+KBUILD_CFLAGS                  += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
+KBUILD_AFLAGS                  += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
+KBUILD_CFLAGS                  += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
+
+ifdef CONFIG_OBJTOOL
+KBUILD_CFLAGS                  += -fno-jump-tables
+endif
+
 KBUILD_RUSTFLAGS                       += --target=$(objtree)/scripts/target.json
 KBUILD_RUSTFLAGS_MODULE                += -Crelocation-model=pic
 
index a49e507af38c0e667092bfe7839da5391a7734e1..3eebea3a7b478d0b2e78ac02ac5d2005a3b1a171 100644 (file)
@@ -44,7 +44,6 @@ static u32 crc32_loongarch_hw(u32 crc_, const u8 *p, unsigned int len)
 
                CRC32(crc, value, w);
                p += sizeof(u32);
-               len -= sizeof(u32);
        }
 
        if (len & sizeof(u16)) {
@@ -80,7 +79,6 @@ static u32 crc32c_loongarch_hw(u32 crc_, const u8 *p, unsigned int len)
 
                CRC32C(crc, value, w);
                p += sizeof(u32);
-               len -= sizeof(u32);
        }
 
        if (len & sizeof(u16)) {
index 93783fa24f6e9b634be44a3634346524eaec3811..2dbec7853ae864868fd4fe0ff7b73b957a3d0462 100644 (file)
@@ -1,9 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
+generated-y += orc_hash.h
+
 generic-y += dma-contiguous.h
 generic-y += mcs_spinlock.h
 generic-y += parport.h
 generic-y += early_ioremap.h
 generic-y += qrwlock.h
+generic-y += qspinlock.h
 generic-y += rwsem.h
 generic-y += segment.h
 generic-y += user.h
index d4ca3ba2541885c0a7d28229b1adacadad9ec0a5..08388876ade4ce11d60d7ab0c7658a1aacffda1d 100644 (file)
@@ -44,6 +44,7 @@
 do {                                                           \
        instrumentation_begin();                                \
        __BUG_FLAGS(BUGFLAG_WARNING|(flags));                   \
+       annotate_reachable();                                   \
        instrumentation_end();                                  \
 } while (0)
 
index 80bd74106985a97d7b246447a7d0482e047b2274..f8754d08a31ab07490717c31b9253871668b9a76 100644 (file)
@@ -37,8 +37,6 @@ void local_flush_icache_range(unsigned long start, unsigned long end);
 #define flush_icache_range     local_flush_icache_range
 #define flush_icache_user_range        local_flush_icache_range
 
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-
 #define flush_cache_all()                              do { } while (0)
 #define flush_cache_mm(mm)                             do { } while (0)
 #define flush_cache_dup_mm(mm)                         do { } while (0)
@@ -47,7 +45,6 @@ void local_flush_icache_range(unsigned long start, unsigned long end);
 #define flush_cache_vmap(start, end)                   do { } while (0)
 #define flush_cache_vunmap(start, end)                 do { } while (0)
 #define flush_icache_user_page(vma, page, addr, len)   do { } while (0)
-#define flush_dcache_page(page)                                do { } while (0)
 #define flush_dcache_mmap_lock(mapping)                        do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)              do { } while (0)
 
index af74a3fdcad179f7582d0234c5cfd4cdca6d5d65..c6d20736fd9270605b57c7ad9a30110bb4b47f02 100644 (file)
@@ -6,6 +6,8 @@
 #include <asm/ptrace.h>
 #include <linux/kprobes.h>
 
+extern void *exception_table[];
+
 void show_registers(struct pt_regs *regs);
 
 asmlinkage void cache_parity_error(void);
index c486c2341b6623020073bb8827eced93601ff900..4a8adcca329b81e4f289dd7825fb15dbf2f4f7a9 100644 (file)
@@ -71,6 +71,8 @@ extern void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t
 #define memcpy_fromio(a, c, l) __memcpy_fromio((a), (c), (l))
 #define memcpy_toio(c, a, l)   __memcpy_toio((c), (a), (l))
 
+#define __io_aw() mmiowb()
+
 #include <asm-generic/io.h>
 
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
index 2ecd82bb64e1322cec7666cfaded4d6da2421185..f33f3fd32ecc2cf3c5cf66e8c29d0f61a7b750f9 100644 (file)
@@ -6,6 +6,7 @@
 #define _ASM_MODULE_H
 
 #include <asm/inst.h>
+#include <asm/orc_types.h>
 #include <asm-generic/module.h>
 
 #define RELA_STACK_DEPTH 16
@@ -21,6 +22,12 @@ struct mod_arch_specific {
        struct mod_section plt;
        struct mod_section plt_idx;
 
+#ifdef CONFIG_UNWINDER_ORC
+       unsigned int num_orcs;
+       int *orc_unwind_ip;
+       struct orc_entry *orc_unwind;
+#endif
+
        /* For CONFIG_DYNAMIC_FTRACE */
        struct plt_entry *ftrace_trampolines;
 };
diff --git a/arch/loongarch/include/asm/orc_header.h b/arch/loongarch/include/asm/orc_header.h
new file mode 100644 (file)
index 0000000..f9d509c
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _ORC_HEADER_H
+#define _ORC_HEADER_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <asm/orc_hash.h>
+
+/*
+ * The header is currently a 20-byte hash of the ORC entry definition; see
+ * scripts/orc_hash.sh.
+ */
+#define ORC_HEADER                                     \
+       __used __section(".orc_header") __aligned(4)    \
+       static const u8 orc_header[] = { ORC_HASH }
+
+#endif /* _ORC_HEADER_H */
diff --git a/arch/loongarch/include/asm/orc_lookup.h b/arch/loongarch/include/asm/orc_lookup.h
new file mode 100644 (file)
index 0000000..b02e635
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _ORC_LOOKUP_H
+#define _ORC_LOOKUP_H
+
+/*
+ * This is a lookup table for speeding up access to the .orc_unwind table.
+ * Given an input address offset, the corresponding lookup table entry
+ * specifies a subset of the .orc_unwind table to search.
+ *
+ * Each block represents the end of the previous range and the start of the
+ * next range.  An extra block is added to give the last range an end.
+ *
+ * The block size should be a power of 2 to avoid a costly 'div' instruction.
+ *
+ * A block size of 256 was chosen because it roughly doubles unwinder
+ * performance while only adding ~5% to the ORC data footprint.
+ */
+#define LOOKUP_BLOCK_ORDER     8
+#define LOOKUP_BLOCK_SIZE      (1 << LOOKUP_BLOCK_ORDER)
+
+#ifndef LINKER_SCRIPT
+
+extern unsigned int orc_lookup[];
+extern unsigned int orc_lookup_end[];
+
+#define LOOKUP_START_IP                (unsigned long)_stext
+#define LOOKUP_STOP_IP         (unsigned long)_etext
+
+#endif /* LINKER_SCRIPT */
+
+#endif /* _ORC_LOOKUP_H */
diff --git a/arch/loongarch/include/asm/orc_types.h b/arch/loongarch/include/asm/orc_types.h
new file mode 100644 (file)
index 0000000..caf1f71
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _ORC_TYPES_H
+#define _ORC_TYPES_H
+
+#include <linux/types.h>
+
+/*
+ * The ORC_REG_* registers are base registers which are used to find other
+ * registers on the stack.
+ *
+ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the
+ * address of the previous frame: the caller's SP before it called the current
+ * function.
+ *
+ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in
+ * the current frame.
+ *
+ * The most commonly used base registers are SP and FP -- which the previous SP
+ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous FP is
+ * usually based on.
+ *
+ * The rest of the base registers are needed for special cases like entry code
+ * and GCC realigned stacks.
+ */
+#define ORC_REG_UNDEFINED              0
+#define ORC_REG_PREV_SP                        1
+#define ORC_REG_SP                     2
+#define ORC_REG_FP                     3
+#define ORC_REG_MAX                    4
+
+#define ORC_TYPE_UNDEFINED             0
+#define ORC_TYPE_END_OF_STACK          1
+#define ORC_TYPE_CALL                  2
+#define ORC_TYPE_REGS                  3
+#define ORC_TYPE_REGS_PARTIAL          4
+
+#ifndef __ASSEMBLY__
+/*
+ * This struct is more or less a vastly simplified version of the DWARF Call
+ * Frame Information standard.  It contains only the necessary parts of DWARF
+ * CFI, simplified for ease of access by the in-kernel unwinder.  It tells the
+ * unwinder how to find the previous SP and FP (and sometimes entry regs) on
+ * the stack for a given code address.  Each instance of the struct corresponds
+ * to one or more code locations.
+ */
+struct orc_entry {
+       s16             sp_offset;
+       s16             fp_offset;
+       s16             ra_offset;
+       unsigned int    sp_reg:4;
+       unsigned int    fp_reg:4;
+       unsigned int    ra_reg:4;
+       unsigned int    type:3;
+       unsigned int    signal:1;
+};
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ORC_TYPES_H */
index afb6fa16b82636caed29820a118a895f7446ad72..44027060c54a28bd34a80f538135491e3ebc758a 100644 (file)
@@ -75,6 +75,9 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 #define sym_to_pfn(x)          __phys_to_pfn(__pa_symbol(x))
 
+struct page *dmw_virt_to_page(unsigned long kaddr);
+struct page *tlb_virt_to_page(unsigned long kaddr);
+
 #define virt_to_pfn(kaddr)     PFN_DOWN(PHYSADDR(kaddr))
 
 #define virt_to_page(kaddr)                                                            \
index 9b36ac003f8907ed06a279c94bb49ede82b213b2..8f290e5546cf720f64893807faadd7fedc6acd4e 100644 (file)
@@ -29,7 +29,12 @@ static inline void set_my_cpu_offset(unsigned long off)
        __my_cpu_offset = off;
        csr_write64(off, PERCPU_BASE_KS);
 }
-#define __my_cpu_offset __my_cpu_offset
+
+#define __my_cpu_offset                                        \
+({                                                     \
+       __asm__ __volatile__("":"+r"(__my_cpu_offset)); \
+       __my_cpu_offset;                                \
+})
 
 #define PERCPU_OP(op, asm_op, c_op)                                    \
 static __always_inline unsigned long __percpu_##op(void *ptr,          \
index 8b5df1bbf9e9c21b09c04639c7ac5c4f3c8d4a4d..af3acdf3481a6a74cb4583a42c12362d44204bf2 100644 (file)
@@ -363,9 +363,6 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
 extern pgd_t swapper_pg_dir[];
 extern pgd_t invalid_pg_dir[];
 
-struct page *dmw_virt_to_page(unsigned long kaddr);
-struct page *tlb_virt_to_page(unsigned long kaddr);
-
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
diff --git a/arch/loongarch/include/asm/qspinlock.h b/arch/loongarch/include/asm/qspinlock.h
deleted file mode 100644 (file)
index 34f43f8..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_QSPINLOCK_H
-#define _ASM_QSPINLOCK_H
-
-#include <asm-generic/qspinlock_types.h>
-
-#define queued_spin_unlock queued_spin_unlock
-
-static inline void queued_spin_unlock(struct qspinlock *lock)
-{
-       compiletime_assert_atomic_type(lock->locked);
-       c_sync();
-       WRITE_ONCE(lock->locked, 0);
-}
-
-#include <asm-generic/qspinlock.h>
-
-#endif /* _ASM_QSPINLOCK_H */
index 4fb1e6408b982aec130c75413e04bb6d2fb6c52c..45b507a7b06fca8af6e16b36a2a1c3f538368eb2 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/loongarch.h>
 #include <asm/thread_info.h>
+#include <asm/unwind_hints.h>
 
 /* Make the addition of cfi info a little easier. */
        .macro cfi_rel_offset reg offset=0 docfi=0
        li.w    t0, CSR_CRMD_WE
        csrxchg t0, t0, LOONGARCH_CSR_CRMD
 #endif
+       UNWIND_HINT_REGS
        .endm
 
        .macro  SAVE_ALL docfi=0
 
        .macro  RESTORE_SP_AND_RET docfi=0
        cfi_ld  sp, PT_R3, \docfi
+       UNWIND_HINT_FUNC
        ertn
        .endm
 
index 8cb653d49a54343ebfa26814e037ddf844c98351..8bf0e6f5154668e7ea477e5182d68705ab4a4f32 100644 (file)
@@ -86,6 +86,7 @@ register unsigned long current_stack_pointer __asm__("$sp");
 #define TIF_LASX_CTX_LIVE      18      /* LASX context must be preserved */
 #define TIF_USEDLBT            19      /* LBT was used by this task this quantum (SMP) */
 #define TIF_LBT_CTX_LIVE       20      /* LBT context must be preserved */
+#define TIF_PATCH_PENDING      21      /* pending live patching update */
 
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
@@ -105,6 +106,7 @@ register unsigned long current_stack_pointer __asm__("$sp");
 #define _TIF_LASX_CTX_LIVE     (1<<TIF_LASX_CTX_LIVE)
 #define _TIF_USEDLBT           (1<<TIF_USEDLBT)
 #define _TIF_LBT_CTX_LIVE      (1<<TIF_LBT_CTX_LIVE)
+#define _TIF_PATCH_PENDING     (1<<TIF_PATCH_PENDING)
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_THREAD_INFO_H */
index b9dce87afd2e058a3dd786ccbb513a3bbbff637c..40a6763c5aecd5abeb77601063b376af87c68d31 100644 (file)
@@ -16,6 +16,7 @@
 enum unwinder_type {
        UNWINDER_GUESS,
        UNWINDER_PROLOGUE,
+       UNWINDER_ORC,
 };
 
 struct unwind_state {
@@ -24,7 +25,7 @@ struct unwind_state {
        struct task_struct *task;
        bool first, error, reset;
        int graph_idx;
-       unsigned long sp, pc, ra;
+       unsigned long sp, fp, pc, ra;
 };
 
 bool default_next_frame(struct unwind_state *state);
@@ -61,14 +62,17 @@ static __always_inline void __unwind_start(struct unwind_state *state,
                state->sp = regs->regs[3];
                state->pc = regs->csr_era;
                state->ra = regs->regs[1];
+               state->fp = regs->regs[22];
        } else if (task && task != current) {
                state->sp = thread_saved_fp(task);
                state->pc = thread_saved_ra(task);
                state->ra = 0;
+               state->fp = 0;
        } else {
                state->sp = (unsigned long)__builtin_frame_address(0);
                state->pc = (unsigned long)__builtin_return_address(0);
                state->ra = 0;
+               state->fp = 0;
        }
        state->task = task;
        get_stack_info(state->sp, state->task, &state->stack_info);
@@ -77,6 +81,18 @@ static __always_inline void __unwind_start(struct unwind_state *state,
 
 static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
 {
-       return unwind_done(state) ? 0 : state->pc;
+       if (unwind_done(state))
+               return 0;
+
+       return __kernel_text_address(state->pc) ? state->pc : 0;
 }
+
+#ifdef CONFIG_UNWINDER_ORC
+void unwind_init(void);
+void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size);
+#else
+static inline void unwind_init(void) {}
+static inline void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size) {}
+#endif
+
 #endif /* _ASM_UNWIND_H */
diff --git a/arch/loongarch/include/asm/unwind_hints.h b/arch/loongarch/include/asm/unwind_hints.h
new file mode 100644 (file)
index 0000000..a01086a
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_LOONGARCH_UNWIND_HINTS_H
+#define _ASM_LOONGARCH_UNWIND_HINTS_H
+
+#include <linux/objtool.h>
+#include <asm/orc_types.h>
+
+#ifdef __ASSEMBLY__
+
+.macro UNWIND_HINT_UNDEFINED
+       UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED
+.endm
+
+.macro UNWIND_HINT_END_OF_STACK
+       UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK
+.endm
+
+.macro UNWIND_HINT_REGS
+       UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_REGS
+.endm
+
+.macro UNWIND_HINT_FUNC
+       UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
index 3c808c6803703c931d5bb52b6eefd71464da726c..3a7620b66bc6c0a53347decd98b73977059484e5 100644 (file)
@@ -3,6 +3,8 @@
 # Makefile for the Linux/LoongArch kernel.
 #
 
+OBJECT_FILES_NON_STANDARD_head.o := y
+
 extra-y                := vmlinux.lds
 
 obj-y          += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
@@ -21,6 +23,7 @@ obj-$(CONFIG_ARCH_STRICT_ALIGN)       += unaligned.o
 
 CFLAGS_module.o                += $(call cc-option,-Wno-override-init,)
 CFLAGS_syscall.o       += $(call cc-option,-Wno-override-init,)
+CFLAGS_traps.o         += $(call cc-option,-Wno-override-init,)
 CFLAGS_perf_event.o    += $(call cc-option,-Wno-override-init,)
 
 ifdef CONFIG_FUNCTION_TRACER
@@ -62,6 +65,7 @@ obj-$(CONFIG_CRASH_DUMP)      += crash_dump.o
 
 obj-$(CONFIG_UNWINDER_GUESS)   += unwind_guess.o
 obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o
+obj-$(CONFIG_UNWINDER_ORC)     += unwind_orc.o
 
 obj-$(CONFIG_PERF_EVENTS)      += perf_event.o perf_regs.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
index 1ec8e4c4cc2bd89d5af2492b0b31158ce8b53f9e..48e7e34e355e83eae8165957ba2eac05a8bf17df 100644 (file)
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 #include <asm/thread_info.h>
+#include <asm/unwind_hints.h>
 
        .text
        .cfi_sections   .debug_frame
        .align  5
 SYM_CODE_START(handle_syscall)
+       UNWIND_HINT_UNDEFINED
        csrrd           t0, PERCPU_BASE_KS
        la.pcrel        t1, kernelsp
        add.d           t1, t1, t0
@@ -57,6 +59,7 @@ SYM_CODE_START(handle_syscall)
        cfi_st          fp, PT_R22
 
        SAVE_STATIC
+       UNWIND_HINT_REGS
 
 #ifdef CONFIG_KGDB
        li.w            t1, CSR_CRMD_WE
@@ -75,6 +78,7 @@ SYM_CODE_END(handle_syscall)
 _ASM_NOKPROBE(handle_syscall)
 
 SYM_CODE_START(ret_from_fork)
+       UNWIND_HINT_REGS
        bl              schedule_tail           # a0 = struct task_struct *prev
        move            a0, sp
        bl              syscall_exit_to_user_mode
@@ -84,6 +88,7 @@ SYM_CODE_START(ret_from_fork)
 SYM_CODE_END(ret_from_fork)
 
 SYM_CODE_START(ret_from_kernel_thread)
+       UNWIND_HINT_REGS
        bl              schedule_tail           # a0 = struct task_struct *prev
        move            a0, s1
        jirl            ra, s0, 0
index 4382e36ae3d44466663aefaa5af1f23717876f35..69a85f2479fba1b34a0f56cd5618be707993d438 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/fpregdef.h>
 #include <asm/loongarch.h>
 #include <asm/regdef.h>
+#include <asm/unwind_hints.h>
 
 #define FPU_REG_WIDTH          8
 #define LSX_REG_WIDTH          16
@@ -526,3 +527,9 @@ SYM_FUNC_END(_restore_lasx_context)
 .L_fpu_fault:
        li.w    a0, -EFAULT                             # failure
        jr      ra
+
+#ifdef CONFIG_CPU_HAS_LBT
+STACK_FRAME_NON_STANDARD _restore_fp
+STACK_FRAME_NON_STANDARD _restore_lsx
+STACK_FRAME_NON_STANDARD _restore_lasx
+#endif
index 2bb3aa2dcfcb2e67935389d76585e813c7a6e169..86d5d90ebefe5b704aaeae79f529ec3f323dcd34 100644 (file)
@@ -32,6 +32,7 @@ SYM_FUNC_START(__arch_cpu_idle)
 SYM_FUNC_END(__arch_cpu_idle)
 
 SYM_CODE_START(handle_vint)
+       UNWIND_HINT_UNDEFINED
        BACKUP_T0T1
        SAVE_ALL
        la_abs  t1, __arch_cpu_idle
@@ -49,6 +50,7 @@ SYM_CODE_START(handle_vint)
 SYM_CODE_END(handle_vint)
 
 SYM_CODE_START(except_vec_cex)
+       UNWIND_HINT_UNDEFINED
        b       cache_parity_error
 SYM_CODE_END(except_vec_cex)
 
@@ -67,6 +69,7 @@ SYM_CODE_END(except_vec_cex)
        .macro  BUILD_HANDLER exception handler prep
        .align  5
        SYM_CODE_START(handle_\exception)
+       UNWIND_HINT_UNDEFINED
        666:
        BACKUP_T0T1
        SAVE_ALL
@@ -77,7 +80,9 @@ SYM_CODE_END(except_vec_cex)
        668:
        RESTORE_ALL_AND_RET
        SYM_CODE_END(handle_\exception)
+       .pushsection    ".data", "aw", %progbits
        SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
+       .popsection
        .endm
 
        BUILD_HANDLER ade ade badv
@@ -94,6 +99,7 @@ SYM_CODE_END(except_vec_cex)
        BUILD_HANDLER reserved reserved none    /* others */
 
 SYM_CODE_START(handle_sys)
+       UNWIND_HINT_UNDEFINED
        la_abs  t0, handle_syscall
        jr      t0
 SYM_CODE_END(handle_sys)
index 9c75120a26d836d75d3bb08c2b5a0022a8c5d58d..001f061d226ab52818aaa79cca57e94c0b4d3f9d 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/errno.h>
 #include <asm/regdef.h>
+#include <asm/unwind_hints.h>
 
 #define SCR_REG_WIDTH 8
 
@@ -153,3 +154,5 @@ SYM_FUNC_END(_restore_ftop_context)
 .L_lbt_fault:
        li.w            a0, -EFAULT             # failure
        jr              ra
+
+STACK_FRAME_NON_STANDARD _restore_ftop_context
index 482aa553aa2d5eb54a460ffa1822d0524e56046b..0c65cf09110cd4cbab6ed06917c52532c3526e1f 100644 (file)
@@ -73,6 +73,7 @@ SYM_FUNC_START(ftrace_stub)
 SYM_FUNC_END(ftrace_stub)
 
 SYM_CODE_START(ftrace_common)
+       UNWIND_HINT_UNDEFINED
        PTR_ADDI        a0, ra, -8      /* arg0: ip */
        move            a1, t0          /* arg1: parent_ip */
        la.pcrel        t1, function_trace_op
@@ -113,12 +114,14 @@ ftrace_common_return:
 SYM_CODE_END(ftrace_common)
 
 SYM_CODE_START(ftrace_caller)
+       UNWIND_HINT_UNDEFINED
        ftrace_regs_entry allregs=0
        b               ftrace_common
 SYM_CODE_END(ftrace_caller)
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 SYM_CODE_START(ftrace_regs_caller)
+       UNWIND_HINT_UNDEFINED
        ftrace_regs_entry allregs=1
        b               ftrace_common
 SYM_CODE_END(ftrace_regs_caller)
@@ -126,6 +129,7 @@ SYM_CODE_END(ftrace_regs_caller)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 SYM_CODE_START(ftrace_graph_caller)
+       UNWIND_HINT_UNDEFINED
        PTR_L           a0, sp, PT_ERA
        PTR_ADDI        a0, a0, -8      /* arg0: self_addr */
        PTR_ADDI        a1, sp, PT_R1   /* arg1: parent */
@@ -134,6 +138,7 @@ SYM_CODE_START(ftrace_graph_caller)
 SYM_CODE_END(ftrace_graph_caller)
 
 SYM_CODE_START(return_to_handler)
+       UNWIND_HINT_UNDEFINED
        /* Save return value regs */
        PTR_ADDI        sp, sp, -FGRET_REGS_SIZE
        PTR_S           a0, sp, FGRET_REGS_A0
@@ -155,6 +160,7 @@ SYM_CODE_END(return_to_handler)
 
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 SYM_CODE_START(ftrace_stub_direct_tramp)
+       UNWIND_HINT_UNDEFINED
        jr              t0
 SYM_CODE_END(ftrace_stub_direct_tramp)
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
index b13b2858fe392398823cb8f261665a964250a836..c7d0338d12c15bc15634f69191eb20a44a1d42c5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <asm/alternative.h>
 #include <asm/inst.h>
+#include <asm/unwind.h>
 
 static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)
 {
@@ -515,15 +516,28 @@ static void module_init_ftrace_plt(const Elf_Ehdr *hdr,
 int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs, struct module *mod)
 {
-       const Elf_Shdr *s, *se;
        const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+       const Elf_Shdr *s, *alt = NULL, *orc = NULL, *orc_ip = NULL, *ftrace = NULL;
 
-       for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
+       for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
                if (!strcmp(".altinstructions", secstrs + s->sh_name))
-                       apply_alternatives((void *)s->sh_addr, (void *)s->sh_addr + s->sh_size);
+                       alt = s;
+               if (!strcmp(".orc_unwind", secstrs + s->sh_name))
+                       orc = s;
+               if (!strcmp(".orc_unwind_ip", secstrs + s->sh_name))
+                       orc_ip = s;
                if (!strcmp(".ftrace_trampoline", secstrs + s->sh_name))
-                       module_init_ftrace_plt(hdr, s, mod);
+                       ftrace = s;
        }
 
+       if (alt)
+               apply_alternatives((void *)alt->sh_addr, (void *)alt->sh_addr + alt->sh_size);
+
+       if (orc && orc_ip)
+               unwind_module_init(mod, (void *)orc_ip->sh_addr, orc_ip->sh_size, (void *)orc->sh_addr, orc->sh_size);
+
+       if (ftrace)
+               module_init_ftrace_plt(hdr, ftrace, mod);
+
        return 0;
 }
index f49f6b053763d1e729b68b870b1b64ffe09d4504..84e6de2fd97354376740f52407834d108fda5fb1 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/addrspace.h>
 
 SYM_CODE_START(relocate_new_kernel)
+       UNWIND_HINT_UNDEFINED
        /*
         * a0: EFI boot flag for the new kernel
         * a1: Command line pointer for the new kernel
@@ -90,6 +91,7 @@ SYM_CODE_END(relocate_new_kernel)
  * then start at the entry point from LOONGARCH_IOCSR_MBUF0.
  */
 SYM_CODE_START(kexec_smp_wait)
+       UNWIND_HINT_UNDEFINED
 1:     li.w            t0, 0x100                       /* wait for init loop */
 2:     addi.w          t0, t0, -1                      /* limit mailbox access */
        bnez            t0, 2b
@@ -106,6 +108,5 @@ SYM_CODE_END(kexec_smp_wait)
 
 relocate_new_kernel_end:
 
-SYM_DATA_START(relocate_new_kernel_size)
-       PTR             relocate_new_kernel_end - relocate_new_kernel
-SYM_DATA_END(relocate_new_kernel_size)
+       .section ".data"
+SYM_DATA(relocate_new_kernel_size, .long relocate_new_kernel_end - relocate_new_kernel)
index bd5772c963382f7bc475c142d4af9ca985357f65..d4ceb2fa2a5ce46372539126da4b3a777b621802 100644 (file)
@@ -76,6 +76,7 @@
        .endm
 
 SYM_CODE_START(arch_rethook_trampoline)
+       UNWIND_HINT_UNDEFINED
        addi.d  sp, sp, -PT_SIZE
        save_all_base_regs
 
index 2b72eb326b44288a7ee4aba76e69c25bd75789d4..60e0fe97f61a31604b095044395c40ba6fd5efc8 100644 (file)
@@ -47,6 +47,7 @@
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/time.h>
+#include <asm/unwind.h>
 
 #define SMBIOS_BIOSSIZE_OFFSET         0x09
 #define SMBIOS_BIOSEXTERN_OFFSET       0x13
@@ -587,6 +588,7 @@ static void __init prefill_possible_map(void)
 void __init setup_arch(char **cmdline_p)
 {
        cpu_probe();
+       unwind_init();
 
        init_environ();
        efi_init();
index f623feb2129f12829b623d77c84d2ba6f677a689..9a038d1070d73b1efcf195ea7ba02e574bca104a 100644 (file)
@@ -29,6 +29,7 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
                        regs->csr_era = thread_saved_ra(task);
                }
                regs->regs[1] = 0;
+               regs->regs[22] = 0;
        }
 
        for (unwind_start(&state, task, regs);
@@ -39,6 +40,46 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
        }
 }
 
+int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
+                            void *cookie, struct task_struct *task)
+{
+       unsigned long addr;
+       struct pt_regs dummyregs;
+       struct pt_regs *regs = &dummyregs;
+       struct unwind_state state;
+
+       if (task == current) {
+               regs->regs[3] = (unsigned long)__builtin_frame_address(0);
+               regs->csr_era = (unsigned long)__builtin_return_address(0);
+       } else {
+               regs->regs[3] = thread_saved_fp(task);
+               regs->csr_era = thread_saved_ra(task);
+       }
+       regs->regs[1] = 0;
+       regs->regs[22] = 0;
+
+       for (unwind_start(&state, task, regs);
+            !unwind_done(&state) && !unwind_error(&state); unwind_next_frame(&state)) {
+               addr = unwind_get_return_address(&state);
+
+               /*
+                * A NULL or invalid return address probably means there's some
+                * generated code which __kernel_text_address() doesn't know about.
+                */
+               if (!addr)
+                       return -EINVAL;
+
+               if (!consume_entry(cookie, addr))
+                       return -EINVAL;
+       }
+
+       /* Check for stack corruption */
+       if (unwind_error(&state))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int
 copy_stack_frame(unsigned long fp, struct stack_frame *frame)
 {
index aebfc3733a760713836fb5255045e1e9948ca5f4..f9f4eb00c92ef586c3350049b0b9d55ac6aac1ff 100644 (file)
 
 #include "access-helper.h"
 
+void *exception_table[EXCCODE_INT_START] = {
+       [0 ... EXCCODE_INT_START - 1] = handle_reserved,
+
+       [EXCCODE_TLBI]          = handle_tlb_load,
+       [EXCCODE_TLBL]          = handle_tlb_load,
+       [EXCCODE_TLBS]          = handle_tlb_store,
+       [EXCCODE_TLBM]          = handle_tlb_modify,
+       [EXCCODE_TLBNR]         = handle_tlb_protect,
+       [EXCCODE_TLBNX]         = handle_tlb_protect,
+       [EXCCODE_TLBPE]         = handle_tlb_protect,
+       [EXCCODE_ADE]           = handle_ade,
+       [EXCCODE_ALE]           = handle_ale,
+       [EXCCODE_BCE]           = handle_bce,
+       [EXCCODE_SYS]           = handle_sys,
+       [EXCCODE_BP]            = handle_bp,
+       [EXCCODE_INE]           = handle_ri,
+       [EXCCODE_IPE]           = handle_ri,
+       [EXCCODE_FPDIS]         = handle_fpu,
+       [EXCCODE_LSXDIS]        = handle_lsx,
+       [EXCCODE_LASXDIS]       = handle_lasx,
+       [EXCCODE_FPE]           = handle_fpe,
+       [EXCCODE_WATCH]         = handle_watch,
+       [EXCCODE_BTDIS]         = handle_lbt,
+};
+EXPORT_SYMBOL_GPL(exception_table);
+
 static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
                           const char *loglvl, bool user)
 {
@@ -1150,19 +1176,9 @@ void __init trap_init(void)
        for (i = EXCCODE_INT_START; i <= EXCCODE_INT_END; i++)
                set_handler(i * VECSIZE, handle_vint, VECSIZE);
 
-       set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE);
-       set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE);
-       set_handler(EXCCODE_BCE * VECSIZE, handle_bce, VECSIZE);
-       set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE);
-       set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE);
-       set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE);
-       set_handler(EXCCODE_IPE * VECSIZE, handle_ri, VECSIZE);
-       set_handler(EXCCODE_FPDIS * VECSIZE, handle_fpu, VECSIZE);
-       set_handler(EXCCODE_LSXDIS * VECSIZE, handle_lsx, VECSIZE);
-       set_handler(EXCCODE_LASXDIS * VECSIZE, handle_lasx, VECSIZE);
-       set_handler(EXCCODE_FPE * VECSIZE, handle_fpe, VECSIZE);
-       set_handler(EXCCODE_BTDIS * VECSIZE, handle_lbt, VECSIZE);
-       set_handler(EXCCODE_WATCH * VECSIZE, handle_watch, VECSIZE);
+       /* Set exception vector handler */
+       for (i = EXCCODE_ADE; i <= EXCCODE_BTDIS; i++)
+               set_handler(i * VECSIZE, exception_table[i], VECSIZE);
 
        cache_error_setup();
 
diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c
new file mode 100644 (file)
index 0000000..b257228
--- /dev/null
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/objtool.h>
+#include <linux/module.h>
+#include <linux/sort.h>
+#include <asm/exception.h>
+#include <asm/orc_header.h>
+#include <asm/orc_lookup.h>
+#include <asm/orc_types.h>
+#include <asm/ptrace.h>
+#include <asm/setup.h>
+#include <asm/stacktrace.h>
+#include <asm/tlb.h>
+#include <asm/unwind.h>
+
+ORC_HEADER;
+
+#define orc_warn(fmt, ...) \
+       printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
+
+extern int __start_orc_unwind_ip[];
+extern int __stop_orc_unwind_ip[];
+extern struct orc_entry __start_orc_unwind[];
+extern struct orc_entry __stop_orc_unwind[];
+
+static bool orc_init __ro_after_init;
+static unsigned int lookup_num_blocks __ro_after_init;
+
+/* Fake frame pointer entry -- used as a fallback for generated code */
+static struct orc_entry orc_fp_entry = {
+       .sp_reg         = ORC_REG_FP,
+       .sp_offset      = 16,
+       .fp_reg         = ORC_REG_PREV_SP,
+       .fp_offset      = -16,
+       .ra_reg         = ORC_REG_PREV_SP,
+       .ra_offset      = -8,
+       .type           = ORC_TYPE_CALL
+};
+
+/*
+ * If we crash with IP==0, the last successfully executed instruction
+ * was probably an indirect function call with a NULL function pointer,
+ * and we don't have unwind information for NULL.
+ * This hardcoded ORC entry for IP==0 allows us to unwind from a NULL function
+ * pointer into its parent and then continue normally from there.
+ */
+static struct orc_entry orc_null_entry = {
+       .sp_reg         = ORC_REG_SP,
+       .sp_offset      = sizeof(long),
+       .fp_reg         = ORC_REG_UNDEFINED,
+       .type           = ORC_TYPE_CALL
+};
+
+static inline unsigned long orc_ip(const int *ip)
+{
+       return (unsigned long)ip + *ip;
+}
+
+static struct orc_entry *__orc_find(int *ip_table, struct orc_entry *u_table,
+                                   unsigned int num_entries, unsigned long ip)
+{
+       int *first = ip_table;
+       int *mid = first, *found = first;
+       int *last = ip_table + num_entries - 1;
+
+       if (!num_entries)
+               return NULL;
+
+       /*
+        * Do a binary range search to find the rightmost duplicate of a given
+        * starting address.  Some entries are section terminators which are
+        * "weak" entries for ensuring there are no gaps.  They should be
+        * ignored when they conflict with a real entry.
+        */
+       while (first <= last) {
+               mid = first + ((last - first) / 2);
+
+               if (orc_ip(mid) <= ip) {
+                       found = mid;
+                       first = mid + 1;
+               } else
+                       last = mid - 1;
+       }
+
+       return u_table + (found - ip_table);
+}
+
+#ifdef CONFIG_MODULES
+static struct orc_entry *orc_module_find(unsigned long ip)
+{
+       struct module *mod;
+
+       mod = __module_address(ip);
+       if (!mod || !mod->arch.orc_unwind || !mod->arch.orc_unwind_ip)
+               return NULL;
+
+       return __orc_find(mod->arch.orc_unwind_ip, mod->arch.orc_unwind, mod->arch.num_orcs, ip);
+}
+#else
+static struct orc_entry *orc_module_find(unsigned long ip)
+{
+       return NULL;
+}
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+static struct orc_entry *orc_find(unsigned long ip);
+
+/*
+ * Ftrace dynamic trampolines do not have orc entries of their own.
+ * But they are copies of the ftrace entries that are static and
+ * defined in ftrace_*.S, which do have orc entries.
+ *
+ * If the unwinder comes across a ftrace trampoline, then find the
+ * ftrace function that was used to create it, and use that ftrace
+ * function's orc entry, as the placement of the return code in
+ * the stack will be identical.
+ */
+static struct orc_entry *orc_ftrace_find(unsigned long ip)
+{
+       struct ftrace_ops *ops;
+       unsigned long tramp_addr, offset;
+
+       ops = ftrace_ops_trampoline(ip);
+       if (!ops)
+               return NULL;
+
+       /* Set tramp_addr to the start of the code copied by the trampoline */
+       if (ops->flags & FTRACE_OPS_FL_SAVE_REGS)
+               tramp_addr = (unsigned long)ftrace_regs_caller;
+       else
+               tramp_addr = (unsigned long)ftrace_caller;
+
+       /* Now place tramp_addr to the location within the trampoline ip is at */
+       offset = ip - ops->trampoline;
+       tramp_addr += offset;
+
+       /* Prevent unlikely recursion */
+       if (ip == tramp_addr)
+               return NULL;
+
+       return orc_find(tramp_addr);
+}
+#else
+static struct orc_entry *orc_ftrace_find(unsigned long ip)
+{
+       return NULL;
+}
+#endif
+
+static struct orc_entry *orc_find(unsigned long ip)
+{
+       static struct orc_entry *orc;
+
+       if (ip == 0)
+               return &orc_null_entry;
+
+       /* For non-init vmlinux addresses, use the fast lookup table: */
+       if (ip >= LOOKUP_START_IP && ip < LOOKUP_STOP_IP) {
+               unsigned int idx, start, stop;
+
+               idx = (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE;
+
+               if (unlikely((idx >= lookup_num_blocks-1))) {
+                       orc_warn("WARNING: bad lookup idx: idx=%u num=%u ip=%pB\n",
+                                idx, lookup_num_blocks, (void *)ip);
+                       return NULL;
+               }
+
+               start = orc_lookup[idx];
+               stop = orc_lookup[idx + 1] + 1;
+
+               if (unlikely((__start_orc_unwind + start >= __stop_orc_unwind) ||
+                            (__start_orc_unwind + stop > __stop_orc_unwind))) {
+                       orc_warn("WARNING: bad lookup value: idx=%u num=%u start=%u stop=%u ip=%pB\n",
+                                idx, lookup_num_blocks, start, stop, (void *)ip);
+                       return NULL;
+               }
+
+               return __orc_find(__start_orc_unwind_ip + start,
+                                 __start_orc_unwind + start, stop - start, ip);
+       }
+
+       /* vmlinux .init slow lookup: */
+       if (is_kernel_inittext(ip))
+               return __orc_find(__start_orc_unwind_ip, __start_orc_unwind,
+                                 __stop_orc_unwind_ip - __start_orc_unwind_ip, ip);
+
+       /* Module lookup: */
+       orc = orc_module_find(ip);
+       if (orc)
+               return orc;
+
+       return orc_ftrace_find(ip);
+}
+
+#ifdef CONFIG_MODULES
+
+static DEFINE_MUTEX(sort_mutex);
+static int *cur_orc_ip_table = __start_orc_unwind_ip;
+static struct orc_entry *cur_orc_table = __start_orc_unwind;
+
+static void orc_sort_swap(void *_a, void *_b, int size)
+{
+       int delta = _b - _a;
+       int *a = _a, *b = _b, tmp;
+       struct orc_entry *orc_a, *orc_b;
+
+       /* Swap the .orc_unwind_ip entries: */
+       tmp = *a;
+       *a = *b + delta;
+       *b = tmp - delta;
+
+       /* Swap the corresponding .orc_unwind entries: */
+       orc_a = cur_orc_table + (a - cur_orc_ip_table);
+       orc_b = cur_orc_table + (b - cur_orc_ip_table);
+       swap(*orc_a, *orc_b);
+}
+
+static int orc_sort_cmp(const void *_a, const void *_b)
+{
+       const int *a = _a, *b = _b;
+       unsigned long a_val = orc_ip(a);
+       unsigned long b_val = orc_ip(b);
+       struct orc_entry *orc_a;
+
+       if (a_val > b_val)
+               return 1;
+       if (a_val < b_val)
+               return -1;
+
+       /*
+        * The "weak" section terminator entries need to always be first
+        * to ensure the lookup code skips them in favor of real entries.
+        * These terminator entries exist to handle any gaps created by
+        * whitelisted .o files which didn't get objtool generation.
+        */
+       orc_a = cur_orc_table + (a - cur_orc_ip_table);
+
+       return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
+}
+
+void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size,
+                       void *_orc, size_t orc_size)
+{
+       int *orc_ip = _orc_ip;
+       struct orc_entry *orc = _orc;
+       unsigned int num_entries = orc_ip_size / sizeof(int);
+
+       WARN_ON_ONCE(orc_ip_size % sizeof(int) != 0 ||
+                    orc_size % sizeof(*orc) != 0 ||
+                    num_entries != orc_size / sizeof(*orc));
+
+       /*
+        * The 'cur_orc_*' globals allow the orc_sort_swap() callback to
+        * associate an .orc_unwind_ip table entry with its corresponding
+        * .orc_unwind entry so they can both be swapped.
+        */
+       mutex_lock(&sort_mutex);
+       cur_orc_ip_table = orc_ip;
+       cur_orc_table = orc;
+       sort(orc_ip, num_entries, sizeof(int), orc_sort_cmp, orc_sort_swap);
+       mutex_unlock(&sort_mutex);
+
+       mod->arch.orc_unwind_ip = orc_ip;
+       mod->arch.orc_unwind = orc;
+       mod->arch.num_orcs = num_entries;
+}
+#endif
+
+void __init unwind_init(void)
+{
+       int i;
+       size_t orc_size = (void *)__stop_orc_unwind - (void *)__start_orc_unwind;
+       size_t orc_ip_size = (void *)__stop_orc_unwind_ip - (void *)__start_orc_unwind_ip;
+       size_t num_entries = orc_ip_size / sizeof(int);
+       struct orc_entry *orc;
+
+       if (!num_entries || orc_ip_size % sizeof(int) != 0 ||
+           orc_size % sizeof(struct orc_entry) != 0 ||
+           num_entries != orc_size / sizeof(struct orc_entry)) {
+               orc_warn("WARNING: Bad or missing .orc_unwind table.  Disabling unwinder.\n");
+               return;
+       }
+
+       /*
+        * Note, the orc_unwind and orc_unwind_ip tables were already
+        * sorted at build time via the 'sorttable' tool.
+        * It's ready for binary search straight away, no need to sort it.
+        */
+
+       /* Initialize the fast lookup table: */
+       lookup_num_blocks = orc_lookup_end - orc_lookup;
+       for (i = 0; i < lookup_num_blocks-1; i++) {
+               orc = __orc_find(__start_orc_unwind_ip, __start_orc_unwind,
+                                num_entries, LOOKUP_START_IP + (LOOKUP_BLOCK_SIZE * i));
+               if (!orc) {
+                       orc_warn("WARNING: Corrupt .orc_unwind table.  Disabling unwinder.\n");
+                       return;
+               }
+
+               orc_lookup[i] = orc - __start_orc_unwind;
+       }
+
+       /* Initialize the ending block: */
+       orc = __orc_find(__start_orc_unwind_ip, __start_orc_unwind, num_entries, LOOKUP_STOP_IP);
+       if (!orc) {
+               orc_warn("WARNING: Corrupt .orc_unwind table.  Disabling unwinder.\n");
+               return;
+       }
+       orc_lookup[lookup_num_blocks-1] = orc - __start_orc_unwind;
+
+       orc_init = true;
+}
+
+static inline bool on_stack(struct stack_info *info, unsigned long addr, size_t len)
+{
+       unsigned long begin = info->begin;
+       unsigned long end   = info->end;
+
+       return (info->type != STACK_TYPE_UNKNOWN &&
+               addr >= begin && addr < end && addr + len > begin && addr + len <= end);
+}
+
+static bool stack_access_ok(struct unwind_state *state, unsigned long addr, size_t len)
+{
+       struct stack_info *info = &state->stack_info;
+
+       if (on_stack(info, addr, len))
+               return true;
+
+       return !get_stack_info(addr, state->task, info) && on_stack(info, addr, len);
+}
+
+unsigned long unwind_get_return_address(struct unwind_state *state)
+{
+       return __unwind_get_return_address(state);
+}
+EXPORT_SYMBOL_GPL(unwind_get_return_address);
+
+void unwind_start(struct unwind_state *state, struct task_struct *task,
+                   struct pt_regs *regs)
+{
+       __unwind_start(state, task, regs);
+       state->type = UNWINDER_ORC;
+       if (!unwind_done(state) && !__kernel_text_address(state->pc))
+               unwind_next_frame(state);
+}
+EXPORT_SYMBOL_GPL(unwind_start);
+
+static bool is_entry_func(unsigned long addr)
+{
+       extern u32 kernel_entry;
+       extern u32 kernel_entry_end;
+
+       return addr >= (unsigned long)&kernel_entry && addr < (unsigned long)&kernel_entry_end;
+}
+
+static inline unsigned long bt_address(unsigned long ra)
+{
+       extern unsigned long eentry;
+
+       if (__kernel_text_address(ra))
+               return ra;
+
+       if (__module_text_address(ra))
+               return ra;
+
+       if (ra >= eentry && ra < eentry +  EXCCODE_INT_END * VECSIZE) {
+               unsigned long func;
+               unsigned long type = (ra - eentry) / VECSIZE;
+               unsigned long offset = (ra - eentry) % VECSIZE;
+
+               switch (type) {
+               case 0 ... EXCCODE_INT_START - 1:
+                       func = (unsigned long)exception_table[type];
+                       break;
+               case EXCCODE_INT_START ... EXCCODE_INT_END:
+                       func = (unsigned long)handle_vint;
+                       break;
+               default:
+                       func = (unsigned long)handle_reserved;
+                       break;
+               }
+
+               return func + offset;
+       }
+
+       return ra;
+}
+
+bool unwind_next_frame(struct unwind_state *state)
+{
+       unsigned long *p, pc;
+       struct pt_regs *regs;
+       struct orc_entry *orc;
+       struct stack_info *info = &state->stack_info;
+
+       if (unwind_done(state))
+               return false;
+
+       /* Don't let modules unload while we're reading their ORC data. */
+       preempt_disable();
+
+       if (is_entry_func(state->pc))
+               goto end;
+
+       orc = orc_find(state->pc);
+       if (!orc) {
+               /*
+                * As a fallback, try to assume this code uses a frame pointer.
+                * This is useful for generated code, like BPF, which ORC
+                * doesn't know about.  This is just a guess, so the rest of
+                * the unwind is no longer considered reliable.
+                */
+               orc = &orc_fp_entry;
+               state->error = true;
+       } else {
+               if (orc->type == ORC_TYPE_UNDEFINED)
+                       goto err;
+
+               if (orc->type == ORC_TYPE_END_OF_STACK)
+                       goto end;
+       }
+
+       switch (orc->sp_reg) {
+       case ORC_REG_SP:
+               if (info->type == STACK_TYPE_IRQ && state->sp == info->end)
+                       orc->type = ORC_TYPE_REGS;
+               else
+                       state->sp = state->sp + orc->sp_offset;
+               break;
+       case ORC_REG_FP:
+               state->sp = state->fp;
+               break;
+       default:
+               orc_warn("unknown SP base reg %d at %pB\n", orc->sp_reg, (void *)state->pc);
+               goto err;
+       }
+
+       switch (orc->fp_reg) {
+       case ORC_REG_PREV_SP:
+               p = (unsigned long *)(state->sp + orc->fp_offset);
+               if (!stack_access_ok(state, (unsigned long)p, sizeof(unsigned long)))
+                       goto err;
+
+               state->fp = *p;
+               break;
+       case ORC_REG_UNDEFINED:
+               /* Nothing. */
+               break;
+       default:
+               orc_warn("unknown FP base reg %d at %pB\n", orc->fp_reg, (void *)state->pc);
+               goto err;
+       }
+
+       switch (orc->type) {
+       case ORC_TYPE_CALL:
+               if (orc->ra_reg == ORC_REG_PREV_SP) {
+                       p = (unsigned long *)(state->sp + orc->ra_offset);
+                       if (!stack_access_ok(state, (unsigned long)p, sizeof(unsigned long)))
+                               goto err;
+
+                       pc = unwind_graph_addr(state, *p, state->sp);
+                       pc -= LOONGARCH_INSN_SIZE;
+               } else if (orc->ra_reg == ORC_REG_UNDEFINED) {
+                       if (!state->ra || state->ra == state->pc)
+                               goto err;
+
+                       pc = unwind_graph_addr(state, state->ra, state->sp);
+                       pc -=  LOONGARCH_INSN_SIZE;
+                       state->ra = 0;
+               } else {
+                       orc_warn("unknown ra base reg %d at %pB\n", orc->ra_reg, (void *)state->pc);
+                       goto err;
+               }
+               break;
+       case ORC_TYPE_REGS:
+               if (info->type == STACK_TYPE_IRQ && state->sp == info->end)
+                       regs = (struct pt_regs *)info->next_sp;
+               else
+                       regs = (struct pt_regs *)state->sp;
+
+               if (!stack_access_ok(state, (unsigned long)regs, sizeof(*regs)))
+                       goto err;
+
+               if ((info->end == (unsigned long)regs + sizeof(*regs)) &&
+                   !regs->regs[3] && !regs->regs[1])
+                       goto end;
+
+               if (user_mode(regs))
+                       goto end;
+
+               pc = regs->csr_era;
+               if (!__kernel_text_address(pc))
+                       goto err;
+
+               state->sp = regs->regs[3];
+               state->ra = regs->regs[1];
+               state->fp = regs->regs[22];
+               get_stack_info(state->sp, state->task, info);
+
+               break;
+       default:
+               orc_warn("unknown .orc_unwind entry type %d at %pB\n", orc->type, (void *)state->pc);
+               goto err;
+       }
+
+       state->pc = bt_address(pc);
+       if (!state->pc) {
+               pr_err("cannot find unwind pc at %pK\n", (void *)pc);
+               goto err;
+       }
+
+       if (!__kernel_text_address(state->pc))
+               goto err;
+
+       preempt_enable();
+       return true;
+
+err:
+       state->error = true;
+
+end:
+       preempt_enable();
+       state->stack_info.type = STACK_TYPE_UNKNOWN;
+       return false;
+}
+EXPORT_SYMBOL_GPL(unwind_next_frame);
index a5d0cd2035da04c9797bf5cee73a04ecd0b52bda..e8e97dbf9ca40ff243e33f1d2cfa9fdbb59d54b4 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/sizes.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
+#include <asm/orc_lookup.h>
 
 #define PAGE_SIZE _PAGE_SIZE
 #define RO_EXCEPTION_TABLE_ALIGN       4
@@ -122,6 +123,8 @@ SECTIONS
        }
 #endif
 
+       ORC_UNWIND_TABLE
+
        .sdata : {
                *(.sdata)
        }
index 3634431db18a4a4992ea9b7d1ed44545214ff3df..80e988985a6adfa97cce7e92d1ebdef4b0cc1ca4 100644 (file)
@@ -8,7 +8,7 @@
 #include <asm/asmmacro.h>
 #include <asm/loongarch.h>
 #include <asm/regdef.h>
-#include <asm/stackframe.h>
+#include <asm/unwind_hints.h>
 
 #define HGPR_OFFSET(x)         (PT_R0 + 8*x)
 #define GGPR_OFFSET(x)         (KVM_ARCH_GGPR + 8*x)
        .text
        .cfi_sections   .debug_frame
 SYM_CODE_START(kvm_exc_entry)
+       UNWIND_HINT_UNDEFINED
        csrwr   a2,   KVM_TEMP_KS
        csrrd   a2,   KVM_VCPU_KS
        addi.d  a2,   a2, KVM_VCPU_ARCH
@@ -273,3 +274,9 @@ SYM_FUNC_END(kvm_restore_lasx)
        .section ".rodata"
 SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry)
 SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
+
+#ifdef CONFIG_CPU_HAS_LBT
+STACK_FRAME_NON_STANDARD kvm_restore_fpu
+STACK_FRAME_NON_STANDARD kvm_restore_lsx
+STACK_FRAME_NON_STANDARD kvm_restore_lasx
+#endif
index be741544e62bf63f7198d451c72c8f47eb0501d7..7a0db643b2866c604a916ea4f992bba30e97eace 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/asm-extable.h>
 #include <asm/cpu.h>
 #include <asm/regdef.h>
+#include <asm/unwind_hints.h>
 
 SYM_FUNC_START(__clear_user)
        /*
@@ -204,3 +205,5 @@ SYM_FUNC_START(__clear_user_fast)
        _asm_extable 28b, .Lsmall_fixup
        _asm_extable 29b, .Lexit
 SYM_FUNC_END(__clear_user_fast)
+
+STACK_FRAME_NON_STANDARD __clear_user_fast
index feec3d3628032f433dbf65e006b8a07acfbc161c..095ce9181c6c04c512111671f29177ae1f1fd484 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/asm-extable.h>
 #include <asm/cpu.h>
 #include <asm/regdef.h>
+#include <asm/unwind_hints.h>
 
 SYM_FUNC_START(__copy_user)
        /*
@@ -278,3 +279,5 @@ SYM_FUNC_START(__copy_user_fast)
        _asm_extable 58b, .Lexit
        _asm_extable 59b, .Lexit
 SYM_FUNC_END(__copy_user_fast)
+
+STACK_FRAME_NON_STANDARD __copy_user_fast
index fa1148878d2b9d06ccdfcf6f2c14fd302fd14114..9517a2f961af3dd4de5ac916d0bc52c4df2c2a46 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/asmmacro.h>
 #include <asm/cpu.h>
 #include <asm/regdef.h>
+#include <asm/unwind_hints.h>
 
 .section .noinstr.text, "ax"
 
@@ -197,3 +198,5 @@ SYM_FUNC_START(__memcpy_fast)
        jr      ra
 SYM_FUNC_END(__memcpy_fast)
 _ASM_NOKPROBE(__memcpy_fast)
+
+STACK_FRAME_NON_STANDARD __memcpy_small
index 06d3ca54cbfe7d73c6cc7a5cadeca4d558b3e6dc..df38466205531dc20d2aad086e6b9d85a44b1a65 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/asmmacro.h>
 #include <asm/cpu.h>
 #include <asm/regdef.h>
+#include <asm/unwind_hints.h>
 
 .macro fill_to_64 r0
        bstrins.d \r0, \r0, 15, 8
@@ -166,3 +167,5 @@ SYM_FUNC_START(__memset_fast)
        jr      ra
 SYM_FUNC_END(__memset_fast)
 _ASM_NOKPROBE(__memset_fast)
+
+STACK_FRAME_NON_STANDARD __memset_fast
index 0b95d32b30c94704a0108fdffcae68c148403ce7..5ac9beb5f0935e051e285526afe04b850473d703 100644 (file)
@@ -9,8 +9,9 @@
 #include <linux/hugetlb.h>
 #include <linux/export.h>
 
-#include <asm/cpu.h>
 #include <asm/bootinfo.h>
+#include <asm/cpu.h>
+#include <asm/exception.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/tlb.h>
@@ -266,24 +267,20 @@ static void setup_tlb_handler(int cpu)
        setup_ptwalker();
        local_flush_tlb_all();
 
+       if (cpu_has_ptw) {
+               exception_table[EXCCODE_TLBI] = handle_tlb_load_ptw;
+               exception_table[EXCCODE_TLBL] = handle_tlb_load_ptw;
+               exception_table[EXCCODE_TLBS] = handle_tlb_store_ptw;
+               exception_table[EXCCODE_TLBM] = handle_tlb_modify_ptw;
+       }
+
        /* The tlb handlers are generated only once */
        if (cpu == 0) {
                memcpy((void *)tlbrentry, handle_tlb_refill, 0x80);
                local_flush_icache_range(tlbrentry, tlbrentry + 0x80);
-               if (!cpu_has_ptw) {
-                       set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load, VECSIZE);
-                       set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load, VECSIZE);
-                       set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store, VECSIZE);
-                       set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify, VECSIZE);
-               } else {
-                       set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load_ptw, VECSIZE);
-                       set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load_ptw, VECSIZE);
-                       set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store_ptw, VECSIZE);
-                       set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify_ptw, VECSIZE);
-               }
-               set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE);
-               set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE);
-               set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE);
+
+               for (int i = EXCCODE_TLBL; i <= EXCCODE_TLBPE; i++)
+                       set_handler(i * VECSIZE, exception_table[i], VECSIZE);
        } else {
                int vec_sz __maybe_unused;
                void *addr __maybe_unused;
index d5d682f3d29f3a808f37e1d23f2887d0ffece071..a44387b838af61b3598b734dca6c5efc6c749a55 100644 (file)
@@ -18,6 +18,7 @@
 
        .macro tlb_do_page_fault, write
        SYM_CODE_START(tlb_do_page_fault_\write)
+       UNWIND_HINT_UNDEFINED
        SAVE_ALL
        csrrd           a2, LOONGARCH_CSR_BADV
        move            a0, sp
@@ -32,6 +33,7 @@
        tlb_do_page_fault 1
 
 SYM_CODE_START(handle_tlb_protect)
+       UNWIND_HINT_UNDEFINED
        BACKUP_T0T1
        SAVE_ALL
        move            a0, sp
@@ -44,6 +46,7 @@ SYM_CODE_START(handle_tlb_protect)
 SYM_CODE_END(handle_tlb_protect)
 
 SYM_CODE_START(handle_tlb_load)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, EXCEPTION_KS0
        csrwr           t1, EXCEPTION_KS1
        csrwr           ra, EXCEPTION_KS2
@@ -190,6 +193,7 @@ nopage_tlb_load:
 SYM_CODE_END(handle_tlb_load)
 
 SYM_CODE_START(handle_tlb_load_ptw)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, LOONGARCH_CSR_KS0
        csrwr           t1, LOONGARCH_CSR_KS1
        la_abs          t0, tlb_do_page_fault_0
@@ -197,6 +201,7 @@ SYM_CODE_START(handle_tlb_load_ptw)
 SYM_CODE_END(handle_tlb_load_ptw)
 
 SYM_CODE_START(handle_tlb_store)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, EXCEPTION_KS0
        csrwr           t1, EXCEPTION_KS1
        csrwr           ra, EXCEPTION_KS2
@@ -346,6 +351,7 @@ nopage_tlb_store:
 SYM_CODE_END(handle_tlb_store)
 
 SYM_CODE_START(handle_tlb_store_ptw)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, LOONGARCH_CSR_KS0
        csrwr           t1, LOONGARCH_CSR_KS1
        la_abs          t0, tlb_do_page_fault_1
@@ -353,6 +359,7 @@ SYM_CODE_START(handle_tlb_store_ptw)
 SYM_CODE_END(handle_tlb_store_ptw)
 
 SYM_CODE_START(handle_tlb_modify)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, EXCEPTION_KS0
        csrwr           t1, EXCEPTION_KS1
        csrwr           ra, EXCEPTION_KS2
@@ -500,6 +507,7 @@ nopage_tlb_modify:
 SYM_CODE_END(handle_tlb_modify)
 
 SYM_CODE_START(handle_tlb_modify_ptw)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, LOONGARCH_CSR_KS0
        csrwr           t1, LOONGARCH_CSR_KS1
        la_abs          t0, tlb_do_page_fault_1
@@ -507,6 +515,7 @@ SYM_CODE_START(handle_tlb_modify_ptw)
 SYM_CODE_END(handle_tlb_modify_ptw)
 
 SYM_CODE_START(handle_tlb_refill)
+       UNWIND_HINT_UNDEFINED
        csrwr           t0, LOONGARCH_CSR_TLBRSAVE
        csrrd           t0, LOONGARCH_CSR_PGD
        lddir           t0, t0, 3
index f597cd08a96be0a19084884bd175678a6a83d6ab..75c6726382c34f8a0a99a90d51e12276213df407 100644 (file)
@@ -4,6 +4,7 @@
 KASAN_SANITIZE := n
 UBSAN_SANITIZE := n
 KCOV_INSTRUMENT := n
+OBJECT_FILES_NON_STANDARD := y
 
 # Include the generic Makefile to check the built vdso.
 include $(srctree)/lib/vdso/Makefile
index 7791673e547bf7955baf5a2f91f2754852d66810..99718f3dc686717c9e4756e3dce0cdf6793b8144 100644 (file)
@@ -846,6 +846,6 @@ static void amiga_get_hardware_list(struct seq_file *m)
  * The Amiga keyboard driver needs key_maps, but we cannot export it in
  * drivers/char/defkeymap.c, as it is autogenerated
  */
-#ifdef CONFIG_HW_CONSOLE
+#ifdef CONFIG_VT
 EXPORT_SYMBOL_GPL(key_maps);
 #endif
index e4bd6913f50e9ef3d392d789fbbdce06202f0954..1a27398523517a6592654e806f46f4829ac722c2 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/serial_8250.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
@@ -67,9 +68,6 @@ static char *hp300_models[] __initdata = {
 static char hp300_model_name[13] = "HP9000/";
 
 extern void hp300_reset(void);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-extern int hp300_setup_serial_console(void) __init;
-#endif
 
 int __init hp300_parse_bootinfo(const struct bi_record *record)
 {
@@ -263,7 +261,5 @@ void __init config_hp300(void)
        } else {
                panic("Unknown HP9000 Model");
        }
-#ifdef CONFIG_SERIAL_8250_CONSOLE
        hp300_setup_serial_console();
-#endif
 }
index ee29c4c8d7c1c5d3d553fa37388a4510f0fa0b9b..daafeb20f99370310feceaaeb1186e8f9fa8e74c 100644 (file)
@@ -238,9 +238,9 @@ config PARISC_HUGE_KERNEL
        def_bool y if !MODULES || UBSAN || FTRACE || COMPILE_TEST
 
 config MLONGCALLS
-       def_bool y if PARISC_HUGE_KERNEL
        bool "Enable the -mlong-calls compiler option for big kernels" if !PARISC_HUGE_KERNEL
        depends on PA8X00
+       default PARISC_HUGE_KERNEL
        help
          If you configure the kernel to include many drivers built-in instead
          as modules, the kernel executable may become too big, so that the
@@ -255,9 +255,9 @@ config MLONGCALLS
          Enabling this option will probably slow down your kernel.
 
 config 64BIT
-       def_bool y if "$(ARCH)" = "parisc64"
        bool "64-bit kernel" if "$(ARCH)" = "parisc"
        depends on PA8X00
+       default "$(ARCH)" = "parisc64"
        help
          Enable this if you want to support 64bit kernel on PA-RISC platform.
 
index a68b9e637eda04e343a99b5c5bc23ad692d0dba9..1c4be337368604a78d0dd901a68f308493e1a021 100644 (file)
@@ -607,11 +607,6 @@ config PPC64_SUPPORTS_MEMORY_FAILURE
 config ARCH_SUPPORTS_KEXEC
        def_bool PPC_BOOK3S || PPC_E500 || (44x && !SMP)
 
-config ARCH_SELECTS_KEXEC
-       def_bool y
-       depends on KEXEC
-       select CRASH_DUMP
-
 config ARCH_SUPPORTS_KEXEC_FILE
        def_bool PPC64
 
@@ -622,7 +617,6 @@ config ARCH_SELECTS_KEXEC_FILE
        def_bool y
        depends on KEXEC_FILE
        select KEXEC_ELF
-       select CRASH_DUMP
        select HAVE_IMA_KEXEC if IMA
 
 config PPC64_BIG_ENDIAN_ELF_ABI_V2
@@ -694,8 +688,7 @@ config ARCH_SELECTS_CRASH_DUMP
 
 config FA_DUMP
        bool "Firmware-assisted dump"
-       depends on PPC64 && (PPC_RTAS || PPC_POWERNV)
-       select CRASH_DUMP
+       depends on CRASH_DUMP && PPC64 && (PPC_RTAS || PPC_POWERNV)
        help
          A robust mechanism to get reliable kernel crash dump with
          assistance from firmware. This approach does not use kexec,
index df18f8dc464288e1f2f328192f8ada5528c6cf3a..343326c3038027494bb1d33128385fd681e61263 100644 (file)
                        interrupts = <93 2>;
                };
 
-               EHCI0: ehci@30010000000 {
+               EHCI0: usb@30010000000 {
                        compatible = "ibm,476gtr-ehci", "generic-ehci";
                        reg = <0x300 0x10000000 0x0 0x10000>;
                        interrupt-parent = <&MPIC>;
                        interrupt-parent = <&MPIC>;
                };
 
-               OHCI0: ohci@30010010000 {
+               OHCI0: usb@30010010000 {
                        compatible = "ibm,476gtr-ohci", "generic-ohci";
                        reg = <0x300 0x10010000 0x0 0x10000>;
                        interrupt-parent = <&MPIC>;
                        interrupts = <89 1>;
                        };
 
-               OHCI1: ohci@30010020000 {
+               OHCI1: usb@30010020000 {
                        compatible = "ibm,476gtr-ohci", "generic-ohci";
                        reg = <0x300 0x10020000 0x0 0x10000>;
                        interrupt-parent = <&MPIC>;
index e1b43aa121753529a6cb659f77c0a192bab659ea..fdb90e24dc74d4d5d3826a1eee4f410ac9b3835d 100644 (file)
 typedef void (*crash_shutdown_t)(void);
 
 #ifdef CONFIG_KEXEC_CORE
-
-/*
- * This function is responsible for capturing register states if coming
- * via panic or invoking dump using sysrq-trigger.
- */
-static inline void crash_setup_regs(struct pt_regs *newregs,
-                                       struct pt_regs *oldregs)
-{
-       if (oldregs)
-               memcpy(newregs, oldregs, sizeof(*newregs));
-       else
-               ppc_save_regs(newregs);
-}
+struct kimage;
+struct pt_regs;
 
 extern void kexec_smp_wait(void);      /* get and clear naca physid, wait for
                                          master to copy new code to 0 */
-extern int crashing_cpu;
-extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
-extern void crash_ipi_callback(struct pt_regs *);
-extern int crash_wake_offline;
-
-struct kimage;
-struct pt_regs;
 extern void default_machine_kexec(struct kimage *image);
-extern void default_machine_crash_shutdown(struct pt_regs *regs);
-extern int crash_shutdown_register(crash_shutdown_t handler);
-extern int crash_shutdown_unregister(crash_shutdown_t handler);
-
-extern void crash_kexec_prepare(void);
-extern void crash_kexec_secondary(struct pt_regs *regs);
-int __init overlaps_crashkernel(unsigned long start, unsigned long size);
-extern void reserve_crashkernel(void);
 extern void machine_kexec_mask_interrupts(void);
 
-static inline bool kdump_in_progress(void)
-{
-       return crashing_cpu >= 0;
-}
-
 void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_code_buffer,
                         unsigned long start_address) __noreturn;
-
 void kexec_copy_flush(struct kimage *image);
 
-#if defined(CONFIG_CRASH_DUMP)
-bool is_kdump_kernel(void);
-#define is_kdump_kernel                        is_kdump_kernel
-#if defined(CONFIG_PPC_RTAS)
-void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
-#define crash_free_reserved_phys_range crash_free_reserved_phys_range
-#endif /* CONFIG_PPC_RTAS */
-#endif /* CONFIG_CRASH_DUMP */
-
 #ifdef CONFIG_KEXEC_FILE
 extern const struct kexec_file_ops kexec_elf64_ops;
 
@@ -152,15 +111,56 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
 
 #endif /* CONFIG_KEXEC_FILE */
 
-#else /* !CONFIG_KEXEC_CORE */
-static inline void crash_kexec_secondary(struct pt_regs *regs) { }
+#endif /* CONFIG_KEXEC_CORE */
+
+#ifdef CONFIG_CRASH_RESERVE
+int __init overlaps_crashkernel(unsigned long start, unsigned long size);
+extern void reserve_crashkernel(void);
+#else
+static inline void reserve_crashkernel(void) {}
+static inline int overlaps_crashkernel(unsigned long start, unsigned long size) { return 0; }
+#endif
 
-static inline int overlaps_crashkernel(unsigned long start, unsigned long size)
+#if defined(CONFIG_CRASH_DUMP)
+/*
+ * This function is responsible for capturing register states if coming
+ * via panic or invoking dump using sysrq-trigger.
+ */
+static inline void crash_setup_regs(struct pt_regs *newregs,
+                                       struct pt_regs *oldregs)
 {
-       return 0;
+       if (oldregs)
+               memcpy(newregs, oldregs, sizeof(*newregs));
+       else
+               ppc_save_regs(newregs);
+}
+
+extern int crashing_cpu;
+extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+extern void crash_ipi_callback(struct pt_regs *regs);
+extern int crash_wake_offline;
+
+extern int crash_shutdown_register(crash_shutdown_t handler);
+extern int crash_shutdown_unregister(crash_shutdown_t handler);
+extern void default_machine_crash_shutdown(struct pt_regs *regs);
+
+extern void crash_kexec_prepare(void);
+extern void crash_kexec_secondary(struct pt_regs *regs);
+
+static inline bool kdump_in_progress(void)
+{
+       return crashing_cpu >= 0;
 }
 
-static inline void reserve_crashkernel(void) { ; }
+bool is_kdump_kernel(void);
+#define is_kdump_kernel                        is_kdump_kernel
+#if defined(CONFIG_PPC_RTAS)
+void crash_free_reserved_phys_range(unsigned long begin, unsigned long end);
+#define crash_free_reserved_phys_range crash_free_reserved_phys_range
+#endif /* CONFIG_PPC_RTAS */
+
+#else /* !CONFIG_CRASH_DUMP */
+static inline void crash_kexec_secondary(struct pt_regs *regs) { }
 
 static inline int crash_shutdown_register(crash_shutdown_t handler)
 {
@@ -183,7 +183,7 @@ static inline void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
 {
 }
 
-#endif /* CONFIG_KEXEC_CORE */
+#endif /* CONFIG_CRASH_DUMP */
 
 #ifdef CONFIG_PPC_BOOK3S_64
 #include <asm/book3s/64/kexec.h>
index 1dc32a05815612b4fb45f64f163f6eea94438fe5..cd8d8883de90409bb77691302b6d378be8f25c6f 100644 (file)
@@ -475,7 +475,7 @@ static int __init early_init_dt_scan_chosen_ppc(unsigned long node,
                tce_alloc_end = *lprop;
 #endif
 
-#ifdef CONFIG_KEXEC_CORE
+#ifdef CONFIG_CRASH_RESERVE
        lprop = of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL);
        if (lprop)
                crashk_res.start = *lprop;
index 2add292da49432ee8db5ff5bad9b70871d7f4f48..01ed1263e1a9890e66dfa21a1e7e2bacae54768a 100644 (file)
@@ -110,7 +110,7 @@ int ppc_do_canonicalize_irqs;
 EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
 #endif
 
-#ifdef CONFIG_VMCORE_INFO
+#ifdef CONFIG_CRASH_DUMP
 /* This keeps a track of which one is the crashing cpu. */
 int crashing_cpu = -1;
 #endif
index a60e4139214be58384edca3e282f8df936b8c4ea..12e53b3d792379998922d23d8ffe9327bec4d067 100644 (file)
@@ -588,7 +588,7 @@ void smp_send_debugger_break(void)
 }
 #endif
 
-#ifdef CONFIG_KEXEC_CORE
+#ifdef CONFIG_CRASH_DUMP
 void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
 {
        int cpu;
@@ -631,7 +631,7 @@ void crash_smp_send_stop(void)
 
        stopped = true;
 
-#ifdef CONFIG_KEXEC_CORE
+#ifdef CONFIG_CRASH_DUMP
        if (kexec_crash_image) {
                crash_kexec_prepare();
                return;
index 91e96f5168b753ea8e358c8820ccfdc368bb8004..8e469c4da3f882e7352dd7e3216235f145729d94 100644 (file)
@@ -3,12 +3,13 @@
 # Makefile for the linux kernel.
 #
 
-obj-y                          += core.o crash.o core_$(BITS).o
+obj-y                          += core.o core_$(BITS).o
 
 obj-$(CONFIG_PPC32)            += relocate_32.o
 
 obj-$(CONFIG_KEXEC_FILE)       += file_load.o ranges.o file_load_$(BITS).o elf_$(BITS).o
 obj-$(CONFIG_VMCORE_INFO)      += vmcore_info.o
+obj-$(CONFIG_CRASH_DUMP)       += crash.o
 
 # Disable GCOV, KCOV & sanitizers in odd or sensitive code
 GCOV_PROFILE_core_$(BITS).o := n
index 3ff4411ed49671baf2a6834d611d20346622f57b..b8333a49ea5daa5a6e841af145287a7d046c965d 100644 (file)
@@ -44,10 +44,12 @@ void machine_kexec_mask_interrupts(void) {
        }
 }
 
+#ifdef CONFIG_CRASH_DUMP
 void machine_crash_shutdown(struct pt_regs *regs)
 {
        default_machine_crash_shutdown(regs);
 }
+#endif
 
 void machine_kexec_cleanup(struct kimage *image)
 {
@@ -77,6 +79,7 @@ void machine_kexec(struct kimage *image)
        for(;;);
 }
 
+#ifdef CONFIG_CRASH_RESERVE
 void __init reserve_crashkernel(void)
 {
        unsigned long long crash_size, crash_base, total_mem_sz;
@@ -251,3 +254,4 @@ static int __init kexec_setup(void)
        return 0;
 }
 late_initcall(kexec_setup);
+#endif /* CONFIG_CRASH_RESERVE */
index 904016cf89ea46ab4002f6eed57363ec4f833815..6d8951e8e96663d16911140d83d9606deda29efe 100644 (file)
@@ -47,7 +47,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
        if (ret)
                return ERR_PTR(ret);
 
-       if (image->type == KEXEC_TYPE_CRASH) {
+       if (IS_ENABLED(CONFIG_CRASH_DUMP) && image->type == KEXEC_TYPE_CRASH) {
                /* min & max buffer values for kdump case */
                kbuf.buf_min = pbuf.buf_min = crashk_res.start;
                kbuf.buf_max = pbuf.buf_max =
@@ -70,7 +70,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
        kexec_dprintk("Loaded purgatory at 0x%lx\n", pbuf.mem);
 
        /* Load additional segments needed for panic kernel */
-       if (image->type == KEXEC_TYPE_CRASH) {
+       if (IS_ENABLED(CONFIG_CRASH_DUMP) && image->type == KEXEC_TYPE_CRASH) {
                ret = load_crashdump_segments_ppc64(image, &kbuf);
                if (ret) {
                        pr_err("Failed to load kdump kernel segments\n");
index 5b4c5cb233548509f3db2c3953ba7877debde09d..1bc65de6174f3eed7240f5fb715723591a73fdb6 100644 (file)
@@ -96,119 +96,6 @@ out:
        return ret;
 }
 
-/**
- * get_usable_memory_ranges - Get usable memory ranges. This list includes
- *                            regions like crashkernel, opal/rtas & tce-table,
- *                            that kdump kernel could use.
- * @mem_ranges:               Range list to add the memory ranges to.
- *
- * Returns 0 on success, negative errno on error.
- */
-static int get_usable_memory_ranges(struct crash_mem **mem_ranges)
-{
-       int ret;
-
-       /*
-        * Early boot failure observed on guests when low memory (first memory
-        * block?) is not added to usable memory. So, add [0, crashk_res.end]
-        * instead of [crashk_res.start, crashk_res.end] to workaround it.
-        * Also, crashed kernel's memory must be added to reserve map to
-        * avoid kdump kernel from using it.
-        */
-       ret = add_mem_range(mem_ranges, 0, crashk_res.end + 1);
-       if (ret)
-               goto out;
-
-       ret = add_rtas_mem_range(mem_ranges);
-       if (ret)
-               goto out;
-
-       ret = add_opal_mem_range(mem_ranges);
-       if (ret)
-               goto out;
-
-       ret = add_tce_mem_ranges(mem_ranges);
-out:
-       if (ret)
-               pr_err("Failed to setup usable memory ranges\n");
-       return ret;
-}
-
-/**
- * get_crash_memory_ranges - Get crash memory ranges. This list includes
- *                           first/crashing kernel's memory regions that
- *                           would be exported via an elfcore.
- * @mem_ranges:              Range list to add the memory ranges to.
- *
- * Returns 0 on success, negative errno on error.
- */
-static int get_crash_memory_ranges(struct crash_mem **mem_ranges)
-{
-       phys_addr_t base, end;
-       struct crash_mem *tmem;
-       u64 i;
-       int ret;
-
-       for_each_mem_range(i, &base, &end) {
-               u64 size = end - base;
-
-               /* Skip backup memory region, which needs a separate entry */
-               if (base == BACKUP_SRC_START) {
-                       if (size > BACKUP_SRC_SIZE) {
-                               base = BACKUP_SRC_END + 1;
-                               size -= BACKUP_SRC_SIZE;
-                       } else
-                               continue;
-               }
-
-               ret = add_mem_range(mem_ranges, base, size);
-               if (ret)
-                       goto out;
-
-               /* Try merging adjacent ranges before reallocation attempt */
-               if ((*mem_ranges)->nr_ranges == (*mem_ranges)->max_nr_ranges)
-                       sort_memory_ranges(*mem_ranges, true);
-       }
-
-       /* Reallocate memory ranges if there is no space to split ranges */
-       tmem = *mem_ranges;
-       if (tmem && (tmem->nr_ranges == tmem->max_nr_ranges)) {
-               tmem = realloc_mem_ranges(mem_ranges);
-               if (!tmem)
-                       goto out;
-       }
-
-       /* Exclude crashkernel region */
-       ret = crash_exclude_mem_range(tmem, crashk_res.start, crashk_res.end);
-       if (ret)
-               goto out;
-
-       /*
-        * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
-        *        regions are exported to save their context at the time of
-        *        crash, they should actually be backed up just like the
-        *        first 64K bytes of memory.
-        */
-       ret = add_rtas_mem_range(mem_ranges);
-       if (ret)
-               goto out;
-
-       ret = add_opal_mem_range(mem_ranges);
-       if (ret)
-               goto out;
-
-       /* create a separate program header for the backup region */
-       ret = add_mem_range(mem_ranges, BACKUP_SRC_START, BACKUP_SRC_SIZE);
-       if (ret)
-               goto out;
-
-       sort_memory_ranges(*mem_ranges, false);
-out:
-       if (ret)
-               pr_err("Failed to setup crash memory ranges\n");
-       return ret;
-}
-
 /**
  * get_reserved_memory_ranges - Get reserve memory ranges. This list includes
  *                              memory regions that should be added to the
@@ -434,6 +321,120 @@ static int locate_mem_hole_bottom_up_ppc64(struct kexec_buf *kbuf,
        return ret;
 }
 
+#ifdef CONFIG_CRASH_DUMP
+/**
+ * get_usable_memory_ranges - Get usable memory ranges. This list includes
+ *                            regions like crashkernel, opal/rtas & tce-table,
+ *                            that kdump kernel could use.
+ * @mem_ranges:               Range list to add the memory ranges to.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+static int get_usable_memory_ranges(struct crash_mem **mem_ranges)
+{
+       int ret;
+
+       /*
+        * Early boot failure observed on guests when low memory (first memory
+        * block?) is not added to usable memory. So, add [0, crashk_res.end]
+        * instead of [crashk_res.start, crashk_res.end] to workaround it.
+        * Also, crashed kernel's memory must be added to reserve map to
+        * avoid kdump kernel from using it.
+        */
+       ret = add_mem_range(mem_ranges, 0, crashk_res.end + 1);
+       if (ret)
+               goto out;
+
+       ret = add_rtas_mem_range(mem_ranges);
+       if (ret)
+               goto out;
+
+       ret = add_opal_mem_range(mem_ranges);
+       if (ret)
+               goto out;
+
+       ret = add_tce_mem_ranges(mem_ranges);
+out:
+       if (ret)
+               pr_err("Failed to setup usable memory ranges\n");
+       return ret;
+}
+
+/**
+ * get_crash_memory_ranges - Get crash memory ranges. This list includes
+ *                           first/crashing kernel's memory regions that
+ *                           would be exported via an elfcore.
+ * @mem_ranges:              Range list to add the memory ranges to.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+static int get_crash_memory_ranges(struct crash_mem **mem_ranges)
+{
+       phys_addr_t base, end;
+       struct crash_mem *tmem;
+       u64 i;
+       int ret;
+
+       for_each_mem_range(i, &base, &end) {
+               u64 size = end - base;
+
+               /* Skip backup memory region, which needs a separate entry */
+               if (base == BACKUP_SRC_START) {
+                       if (size > BACKUP_SRC_SIZE) {
+                               base = BACKUP_SRC_END + 1;
+                               size -= BACKUP_SRC_SIZE;
+                       } else
+                               continue;
+               }
+
+               ret = add_mem_range(mem_ranges, base, size);
+               if (ret)
+                       goto out;
+
+               /* Try merging adjacent ranges before reallocation attempt */
+               if ((*mem_ranges)->nr_ranges == (*mem_ranges)->max_nr_ranges)
+                       sort_memory_ranges(*mem_ranges, true);
+       }
+
+       /* Reallocate memory ranges if there is no space to split ranges */
+       tmem = *mem_ranges;
+       if (tmem && (tmem->nr_ranges == tmem->max_nr_ranges)) {
+               tmem = realloc_mem_ranges(mem_ranges);
+               if (!tmem)
+                       goto out;
+       }
+
+       /* Exclude crashkernel region */
+       ret = crash_exclude_mem_range(tmem, crashk_res.start, crashk_res.end);
+       if (ret)
+               goto out;
+
+       /*
+        * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
+        *        regions are exported to save their context at the time of
+        *        crash, they should actually be backed up just like the
+        *        first 64K bytes of memory.
+        */
+       ret = add_rtas_mem_range(mem_ranges);
+       if (ret)
+               goto out;
+
+       ret = add_opal_mem_range(mem_ranges);
+       if (ret)
+               goto out;
+
+       /* create a separate program header for the backup region */
+       ret = add_mem_range(mem_ranges, BACKUP_SRC_START, BACKUP_SRC_SIZE);
+       if (ret)
+               goto out;
+
+       sort_memory_ranges(*mem_ranges, false);
+out:
+       if (ret)
+               pr_err("Failed to setup crash memory ranges\n");
+       return ret;
+}
+
 /**
  * check_realloc_usable_mem - Reallocate buffer if it can't accommodate entries
  * @um_info:                  Usable memory buffer and ranges info.
@@ -863,6 +864,7 @@ int load_crashdump_segments_ppc64(struct kimage *image,
 
        return 0;
 }
+#endif
 
 /**
  * setup_purgatory_ppc64 - initialize PPC64 specific purgatory's global
@@ -972,26 +974,14 @@ static unsigned int cpu_node_size(void)
        return size;
 }
 
-/**
- * kexec_extra_fdt_size_ppc64 - Return the estimated additional size needed to
- *                              setup FDT for kexec/kdump kernel.
- * @image:                      kexec image being loaded.
- *
- * Returns the estimated extra size needed for kexec/kdump kernel FDT.
- */
-unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
+static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image)
 {
        unsigned int cpu_nodes, extra_size = 0;
        struct device_node *dn;
        u64 usm_entries;
 
-       // Budget some space for the password blob. There's already extra space
-       // for the key name
-       if (plpks_is_available())
-               extra_size += (unsigned int)plpks_get_passwordlen();
-
-       if (image->type != KEXEC_TYPE_CRASH)
-               return extra_size;
+       if (!IS_ENABLED(CONFIG_CRASH_DUMP) || image->type != KEXEC_TYPE_CRASH)
+               return 0;
 
        /*
         * For kdump kernel, account for linux,usable-memory and
@@ -1019,6 +1009,25 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
        return extra_size;
 }
 
+/**
+ * kexec_extra_fdt_size_ppc64 - Return the estimated additional size needed to
+ *                              setup FDT for kexec/kdump kernel.
+ * @image:                      kexec image being loaded.
+ *
+ * Returns the estimated extra size needed for kexec/kdump kernel FDT.
+ */
+unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
+{
+       unsigned int extra_size = 0;
+
+       // Budget some space for the password blob. There's already extra space
+       // for the key name
+       if (plpks_is_available())
+               extra_size += (unsigned int)plpks_get_passwordlen();
+
+       return extra_size + kdump_extra_fdt_size_ppc64(image);
+}
+
 /**
  * add_node_props - Reads node properties from device node structure and add
  *                  them to fdt.
@@ -1171,6 +1180,7 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
        struct crash_mem *umem = NULL, *rmem = NULL;
        int i, nr_ranges, ret;
 
+#ifdef CONFIG_CRASH_DUMP
        /*
         * Restrict memory usage for kdump kernel by setting up
         * usable memory ranges and memory reserve map.
@@ -1207,6 +1217,7 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
                        goto out;
                }
        }
+#endif
 
        /* Update cpus nodes information to account hotplug CPUs. */
        ret =  update_cpus_node(fdt);
@@ -1278,7 +1289,7 @@ int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf)
        buf_min = kbuf->buf_min;
        buf_max = kbuf->buf_max;
        /* Segments for kdump kernel should be within crashkernel region */
-       if (kbuf->image->type == KEXEC_TYPE_CRASH) {
+       if (IS_ENABLED(CONFIG_CRASH_DUMP) && kbuf->image->type == KEXEC_TYPE_CRASH) {
                buf_min = (buf_min < crashk_res.start ?
                           crashk_res.start : buf_min);
                buf_max = (buf_max > crashk_res.end ?
index 5445587bfe8418a5ea40cbde0c525d3c462eab4a..100f999871bc3be6c56e2ca53ff58f54c2909234 100644 (file)
@@ -193,7 +193,7 @@ static bool is_module_segment(unsigned long addr)
        return true;
 }
 
-void mmu_mark_initmem_nx(void)
+int mmu_mark_initmem_nx(void)
 {
        int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
        int i;
@@ -230,9 +230,10 @@ void mmu_mark_initmem_nx(void)
 
                mtsr(mfsr(i << 28) | 0x10000000, i << 28);
        }
+       return 0;
 }
 
-void mmu_mark_rodata_ro(void)
+int mmu_mark_rodata_ro(void)
 {
        int nb = mmu_has_feature(MMU_FTR_USE_HIGH_BATS) ? 8 : 4;
        int i;
@@ -245,6 +246,8 @@ void mmu_mark_rodata_ro(void)
        }
 
        update_bats();
+
+       return 0;
 }
 
 /*
index 8e84bc214d133c0b29cae908e048747cd5b2993b..6949c2c937e72f0a537ce2a46e78a8fe09c35e55 100644 (file)
@@ -160,11 +160,11 @@ static inline unsigned long p_block_mapped(phys_addr_t pa) { return 0; }
 #endif
 
 #if defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_PPC_8xx) || defined(CONFIG_PPC_E500)
-void mmu_mark_initmem_nx(void);
-void mmu_mark_rodata_ro(void);
+int mmu_mark_initmem_nx(void);
+int mmu_mark_rodata_ro(void);
 #else
-static inline void mmu_mark_initmem_nx(void) { }
-static inline void mmu_mark_rodata_ro(void) { }
+static inline int mmu_mark_initmem_nx(void) { return 0; }
+static inline int mmu_mark_rodata_ro(void) { return 0; }
 #endif
 
 #ifdef CONFIG_PPC_8xx
index 6be6421086ed990b35428742b3c26f03ecde5668..43d4842bb1c7a787d11dfec71d4c3814592ae99d 100644 (file)
@@ -119,23 +119,26 @@ void __init mmu_mapin_immr(void)
                                    PAGE_KERNEL_NCG, MMU_PAGE_512K, true);
 }
 
-static void mmu_mapin_ram_chunk(unsigned long offset, unsigned long top,
-                               pgprot_t prot, bool new)
+static int mmu_mapin_ram_chunk(unsigned long offset, unsigned long top,
+                              pgprot_t prot, bool new)
 {
        unsigned long v = PAGE_OFFSET + offset;
        unsigned long p = offset;
+       int err = 0;
 
        WARN_ON(!IS_ALIGNED(offset, SZ_512K) || !IS_ALIGNED(top, SZ_512K));
 
-       for (; p < ALIGN(p, SZ_8M) && p < top; p += SZ_512K, v += SZ_512K)
-               __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
-       for (; p < ALIGN_DOWN(top, SZ_8M) && p < top; p += SZ_8M, v += SZ_8M)
-               __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_8M, new);
-       for (; p < ALIGN_DOWN(top, SZ_512K) && p < top; p += SZ_512K, v += SZ_512K)
-               __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
+       for (; p < ALIGN(p, SZ_8M) && p < top && !err; p += SZ_512K, v += SZ_512K)
+               err = __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
+       for (; p < ALIGN_DOWN(top, SZ_8M) && p < top && !err; p += SZ_8M, v += SZ_8M)
+               err = __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_8M, new);
+       for (; p < ALIGN_DOWN(top, SZ_512K) && p < top && !err; p += SZ_512K, v += SZ_512K)
+               err = __early_map_kernel_hugepage(v, p, prot, MMU_PAGE_512K, new);
 
        if (!new)
                flush_tlb_kernel_range(PAGE_OFFSET + v, PAGE_OFFSET + top);
+
+       return err;
 }
 
 unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
@@ -166,27 +169,33 @@ unsigned long __init mmu_mapin_ram(unsigned long base, unsigned long top)
        return top;
 }
 
-void mmu_mark_initmem_nx(void)
+int mmu_mark_initmem_nx(void)
 {
        unsigned long etext8 = ALIGN(__pa(_etext), SZ_8M);
        unsigned long sinittext = __pa(_sinittext);
        unsigned long boundary = strict_kernel_rwx_enabled() ? sinittext : etext8;
        unsigned long einittext8 = ALIGN(__pa(_einittext), SZ_8M);
+       int err = 0;
 
        if (!debug_pagealloc_enabled_or_kfence())
-               mmu_mapin_ram_chunk(boundary, einittext8, PAGE_KERNEL, false);
+               err = mmu_mapin_ram_chunk(boundary, einittext8, PAGE_KERNEL, false);
 
        mmu_pin_tlb(block_mapped_ram, false);
+
+       return err;
 }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
-void mmu_mark_rodata_ro(void)
+int mmu_mark_rodata_ro(void)
 {
        unsigned long sinittext = __pa(_sinittext);
+       int err;
 
-       mmu_mapin_ram_chunk(0, sinittext, PAGE_KERNEL_ROX, false);
+       err = mmu_mapin_ram_chunk(0, sinittext, PAGE_KERNEL_ROX, false);
        if (IS_ENABLED(CONFIG_PIN_TLB_DATA))
                mmu_pin_tlb(block_mapped_ram, true);
+
+       return err;
 }
 #endif
 
index 921c3521ec113e1d99f79230b857d18bf8eb0d9a..266fb22131fc1e0e6c60e2eb95dbaa18e6badbcd 100644 (file)
@@ -285,19 +285,23 @@ void __init adjust_total_lowmem(void)
 }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
-void mmu_mark_rodata_ro(void)
+int mmu_mark_rodata_ro(void)
 {
        unsigned long remapped;
 
        remapped = map_mem_in_cams(__max_low_memory, CONFIG_LOWMEM_CAM_NUM, false, false);
 
-       WARN_ON(__max_low_memory != remapped);
+       if (WARN_ON(__max_low_memory != remapped))
+               return -EINVAL;
+
+       return 0;
 }
 #endif
 
-void mmu_mark_initmem_nx(void)
+int mmu_mark_initmem_nx(void)
 {
        /* Everything is done in mmu_mark_rodata_ro() */
+       return 0;
 }
 
 void setup_initial_memory_limit(phys_addr_t first_memblock_base,
index face94977cb2fb406711b03b15486d6b64b90a46..cfd622ebf774b01971e8695ed6e997e794b96ea5 100644 (file)
@@ -130,31 +130,41 @@ void __init mapin_ram(void)
        }
 }
 
-void mark_initmem_nx(void)
+static int __mark_initmem_nx(void)
 {
        unsigned long numpages = PFN_UP((unsigned long)_einittext) -
                                 PFN_DOWN((unsigned long)_sinittext);
+       int err;
 
-       mmu_mark_initmem_nx();
+       err = mmu_mark_initmem_nx();
 
        if (!v_block_mapped((unsigned long)_sinittext)) {
-               set_memory_nx((unsigned long)_sinittext, numpages);
-               set_memory_rw((unsigned long)_sinittext, numpages);
+               err = set_memory_nx((unsigned long)_sinittext, numpages);
+               if (err)
+                       return err;
+               err = set_memory_rw((unsigned long)_sinittext, numpages);
        }
+       return err;
+}
+
+void mark_initmem_nx(void)
+{
+       int err = __mark_initmem_nx();
+
+       if (err)
+               panic("%s() failed, err = %d\n", __func__, err);
 }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
-void mark_rodata_ro(void)
+static int __mark_rodata_ro(void)
 {
        unsigned long numpages;
 
        if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX) && mmu_has_feature(MMU_FTR_HPTE_TABLE))
                pr_warn("This platform has HASH MMU, STRICT_MODULE_RWX won't work\n");
 
-       if (v_block_mapped((unsigned long)_stext + 1)) {
-               mmu_mark_rodata_ro();
-               return;
-       }
+       if (v_block_mapped((unsigned long)_stext + 1))
+               return mmu_mark_rodata_ro();
 
        /*
         * mark text and rodata as read only. __end_rodata is set by
@@ -164,6 +174,14 @@ void mark_rodata_ro(void)
        numpages = PFN_UP((unsigned long)__end_rodata) -
                   PFN_DOWN((unsigned long)_stext);
 
-       set_memory_ro((unsigned long)_stext, numpages);
+       return set_memory_ro((unsigned long)_stext, numpages);
+}
+
+void mark_rodata_ro(void)
+{
+       int err = __mark_rodata_ro();
+
+       if (err)
+               panic("%s() failed, err = %d\n", __func__, err);
 }
 #endif
index 9e1a25398f98cbe383be9fdaaf6f2194f9fab3fc..8f14f0581a21b131411eedcccec5c6775a0353fe 100644 (file)
@@ -434,7 +434,7 @@ void __init pnv_smp_init(void)
        smp_ops = &pnv_smp_ops;
 
 #ifdef CONFIG_HOTPLUG_CPU
-#ifdef CONFIG_KEXEC_CORE
+#ifdef CONFIG_CRASH_DUMP
        crash_wake_offline = 1;
 #endif
 #endif
index d25ad1c19f881d0ed299a191908af885b1baa91b..2c585f7a0b6ef325e0954d88e64a3c2310af3740 100644 (file)
@@ -2,6 +2,7 @@
 
 obj-y += kernel/ mm/ net/
 obj-$(CONFIG_BUILTIN_DTB) += boot/dts/
+obj-$(CONFIG_CRYPTO) += crypto/
 obj-y += errata/
 obj-$(CONFIG_KVM) += kvm/
 
index 92b1dbf55176fa1ec989a6b6567e3418a496ed13..be09c8836d56be91d24a768cbe3a2411423716f6 100644 (file)
@@ -27,14 +27,18 @@ config RISCV
        select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_HAS_KCOV
+       select ARCH_HAS_MEMBARRIER_CALLBACKS
+       select ARCH_HAS_MEMBARRIER_SYNC_CORE
        select ARCH_HAS_MMIOWB
        select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
        select ARCH_HAS_PMEM_API
+       select ARCH_HAS_PREPARE_SYNC_CORE_CMD
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SET_DIRECT_MAP if MMU
        select ARCH_HAS_SET_MEMORY if MMU
        select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
        select ARCH_HAS_STRICT_MODULE_RWX if MMU && !XIP_KERNEL
+       select ARCH_HAS_SYNC_CORE_BEFORE_USERMODE
        select ARCH_HAS_SYSCALL_WRAPPER
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
        select ARCH_HAS_UBSAN
@@ -47,6 +51,9 @@ config RISCV
        select ARCH_SUPPORTS_CFI_CLANG
        select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
        select ARCH_SUPPORTS_HUGETLBFS if MMU
+       # LLD >= 14: https://github.com/llvm/llvm-project/issues/50505
+       select ARCH_SUPPORTS_LTO_CLANG if LLD_VERSION >= 140000
+       select ARCH_SUPPORTS_LTO_CLANG_THIN if LLD_VERSION >= 140000
        select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
        select ARCH_SUPPORTS_PER_VMA_LOCK if MMU
        select ARCH_SUPPORTS_SHADOW_CALL_STACK if HAVE_SHADOW_CALL_STACK
@@ -106,6 +113,7 @@ config RISCV
        select HAVE_ARCH_KGDB_QXFER_PKT
        select HAVE_ARCH_MMAP_RND_BITS if MMU
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
+       select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_THREAD_STRUCT_WHITELIST
        select HAVE_ARCH_TRACEHOOK
@@ -124,6 +132,7 @@ config RISCV
        select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION
        select HAVE_EBPF_JIT if MMU
+       select HAVE_FAST_GUP if MMU
        select HAVE_FUNCTION_ARG_ACCESS_API
        select HAVE_FUNCTION_ERROR_INJECTION
        select HAVE_GCC_PLUGINS
@@ -155,6 +164,7 @@ config RISCV
        select IRQ_FORCED_THREADING
        select KASAN_VMALLOC if KASAN
        select LOCK_MM_AND_FIND_VMA
+       select MMU_GATHER_RCU_TABLE_FREE if SMP && MMU
        select MODULES_USE_ELF_RELA if MODULES
        select MODULE_SECTIONS if MODULES
        select OF
@@ -576,6 +586,13 @@ config TOOLCHAIN_HAS_ZBB
        depends on LLD_VERSION >= 150000 || LD_VERSION >= 23900
        depends on AS_HAS_OPTION_ARCH
 
+# This symbol indicates that the toolchain supports all v1.0 vector crypto
+# extensions, including Zvk*, Zvbb, and Zvbc.  LLVM added all of these at once.
+# binutils added all except Zvkb, then added Zvkb.  So we just check for Zvkb.
+config TOOLCHAIN_HAS_VECTOR_CRYPTO
+       def_bool $(as-instr, .option arch$(comma) +v$(comma) +zvkb)
+       depends on AS_HAS_OPTION_ARCH
+
 config RISCV_ISA_ZBB
        bool "Zbb extension support for bit manipulation instructions"
        depends on TOOLCHAIN_HAS_ZBB
@@ -686,27 +703,61 @@ config THREAD_SIZE_ORDER
          affects irq stack size, which is equal to thread stack size.
 
 config RISCV_MISALIGNED
-       bool "Support misaligned load/store traps for kernel and userspace"
+       bool
        select SYSCTL_ARCH_UNALIGN_ALLOW
-       default y
        help
-         Say Y here if you want the kernel to embed support for misaligned
-         load/store for both kernel and userspace. When disable, misaligned
-         accesses will generate SIGBUS in userspace and panic in kernel.
+         Embed support for emulating misaligned loads and stores.
+
+choice
+       prompt "Unaligned Accesses Support"
+       default RISCV_PROBE_UNALIGNED_ACCESS
+       help
+         This determines the level of support for unaligned accesses. This
+         information is used by the kernel to perform optimizations. It is also
+         exposed to user space via the hwprobe syscall. The hardware will be
+         probed at boot by default.
+
+config RISCV_PROBE_UNALIGNED_ACCESS
+       bool "Probe for hardware unaligned access support"
+       select RISCV_MISALIGNED
+       help
+         During boot, the kernel will run a series of tests to determine the
+         speed of unaligned accesses. This probing will dynamically determine
+         the speed of unaligned accesses on the underlying system. If unaligned
+         memory accesses trap into the kernel as they are not supported by the
+         system, the kernel will emulate the unaligned accesses to preserve the
+         UABI.
+
+config RISCV_EMULATED_UNALIGNED_ACCESS
+       bool "Emulate unaligned access where system support is missing"
+       select RISCV_MISALIGNED
+       help
+         If unaligned memory accesses trap into the kernel as they are not
+         supported by the system, the kernel will emulate the unaligned
+         accesses to preserve the UABI. When the underlying system does support
+         unaligned accesses, the unaligned accesses are assumed to be slow.
+
+config RISCV_SLOW_UNALIGNED_ACCESS
+       bool "Assume the system supports slow unaligned memory accesses"
+       depends on NONPORTABLE
+       help
+         Assume that the system supports slow unaligned memory accesses. The
+         kernel and userspace programs may not be able to run at all on systems
+         that do not support unaligned memory accesses.
 
 config RISCV_EFFICIENT_UNALIGNED_ACCESS
-       bool "Assume the CPU supports fast unaligned memory accesses"
+       bool "Assume the system supports fast unaligned memory accesses"
        depends on NONPORTABLE
        select DCACHE_WORD_ACCESS if MMU
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
        help
-         Say Y here if you want the kernel to assume that the CPU supports
-         efficient unaligned memory accesses.  When enabled, this option
-         improves the performance of the kernel on such CPUs.  However, the
-         kernel will run much more slowly, or will not be able to run at all,
-         on CPUs that do not support efficient unaligned memory accesses.
+         Assume that the system supports fast unaligned memory accesses. When
+         enabled, this option improves the performance of the kernel on such
+         systems. However, the kernel and userspace programs will run much more
+         slowly, or will not be able to run at all, on systems that do not
+         support efficient unaligned memory accesses.
 
-         If unsure what to do here, say N.
+endchoice
 
 endmenu # "Platform type"
 
@@ -1011,11 +1062,8 @@ menu "Power management options"
 
 source "kernel/power/Kconfig"
 
-# Hibernation is only possible on systems where the SBI implementation has
-# marked its reserved memory as not accessible from, or does not run
-# from the same memory as, Linux
 config ARCH_HIBERNATION_POSSIBLE
-       def_bool NONPORTABLE
+       def_bool y
 
 config ARCH_HIBERNATION_HEADER
        def_bool HIBERNATION
index 0b7d109258e7d850846bb3c5f084a0482f07d02b..252d63942f34ebe08a3087d12bee3a1c4833f15a 100644 (file)
@@ -50,6 +50,11 @@ ifndef CONFIG_AS_IS_LLVM
        KBUILD_CFLAGS += -Wa,-mno-relax
        KBUILD_AFLAGS += -Wa,-mno-relax
 endif
+# LLVM has an issue with target-features and LTO: https://github.com/llvm/llvm-project/issues/59350
+# Ensure it is aware of linker relaxation with LTO, otherwise relocations may
+# be incorrect: https://github.com/llvm/llvm-project/issues/65090
+else ifeq ($(CONFIG_LTO_CLANG),y)
+       KBUILD_LDFLAGS += -mllvm -mattr=+c -mllvm -mattr=+relax
 endif
 
 ifeq ($(CONFIG_SHADOW_CALL_STACK),y)
index 59fd2d4ea523b8a6f6a4c63ed098d8bb3032c00c..9883ca3554c50a5258aac50ef10a4c98311956ac 100644 (file)
                };
 
                pdma: dma-controller@3000000 {
-                       compatible = "sifive,fu540-c000-pdma", "sifive,pdma0";
+                       compatible = "microchip,mpfs-pdma", "sifive,pdma0";
                        reg = <0x0 0x3000000 0x0 0x8000>;
                        interrupt-parent = <&plic>;
                        interrupts = <5 6>, <7 8>, <9 10>, <11 12>;
                can0: can@2010c000 {
                        compatible = "microchip,mpfs-can";
                        reg = <0x0 0x2010c000 0x0 0x1000>;
-                       clocks = <&clkcfg CLK_CAN0>;
+                       clocks = <&clkcfg CLK_CAN0>, <&clkcfg CLK_MSSPLL3>;
                        interrupt-parent = <&plic>;
                        interrupts = <56>;
                        status = "disabled";
                can1: can@2010d000 {
                        compatible = "microchip,mpfs-can";
                        reg = <0x0 0x2010d000 0x0 0x1000>;
-                       clocks = <&clkcfg CLK_CAN1>;
+                       clocks = <&clkcfg CLK_CAN1>, <&clkcfg CLK_MSSPLL3>;
                        interrupt-parent = <&plic>;
                        interrupts = <57>;
                        status = "disabled";
index 09ef10b39f46cfd5313910a540908f14428177c1..f35324b9173cde4985e0eba9dc807c4bcfc7f534 100644 (file)
@@ -27,7 +27,7 @@
                        riscv,isa-base = "rv64i";
                        riscv,isa-extensions = "i", "m", "a", "f", "d", "c",
                                               "zicntr", "zicsr", "zifencei",
-                                              "zihpm";
+                                              "zihpm", "xandespmu";
                        mmu-type = "riscv,sv39";
                        i-cache-size = <0x8000>;
                        i-cache-line-size = <0x40>;
@@ -39,7 +39,7 @@
 
                        cpu0_intc: interrupt-controller {
                                #interrupt-cells = <1>;
-                               compatible = "riscv,cpu-intc";
+                               compatible = "andestech,cpu-intc", "riscv,cpu-intc";
                                interrupt-controller;
                        };
                };
index 7cda3a89020a49f70a83dcac02d633e786dc0f7d..168f5d9895a9ddc24d864ebf2e2b6a648dc554c8 100644 (file)
        model = "BeagleV Starlight Beta";
        compatible = "beagle,beaglev-starlight-jh7100-r0", "starfive,jh7100";
 };
+
+&gmac {
+       phy-handle = <&phy>;
+};
+
+&mdio {
+       phy: ethernet-phy@7 {
+               reg = <7>;
+               reset-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
+       };
+};
index 42fb61c36068cd7e42dada8025b3d15b9ca2b0fc..ae1a6aeb0aeaa1182ece8005f4ed9686adec6398 100644 (file)
        };
 };
 
+&gmac {
+       pinctrl-names = "default";
+       pinctrl-0 = <&gmac_pins>;
+       phy-mode = "rgmii-id";
+       status = "okay";
+
+       mdio: mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "snps,dwmac-mdio";
+       };
+};
+
 &gpio {
+       gmac_pins: gmac-0 {
+               gtxclk-pins {
+                       pins = <PAD_FUNC_SHARE(115)>;
+                       bias-pull-up;
+                       drive-strength = <35>;
+                       input-enable;
+                       input-schmitt-enable;
+                       slew-rate = <0>;
+               };
+               miitxclk-pins {
+                       pins = <PAD_FUNC_SHARE(116)>;
+                       bias-pull-up;
+                       drive-strength = <14>;
+                       input-enable;
+                       input-schmitt-disable;
+                       slew-rate = <0>;
+               };
+               tx-pins {
+                       pins = <PAD_FUNC_SHARE(117)>,
+                              <PAD_FUNC_SHARE(119)>,
+                              <PAD_FUNC_SHARE(120)>,
+                              <PAD_FUNC_SHARE(121)>,
+                              <PAD_FUNC_SHARE(122)>,
+                              <PAD_FUNC_SHARE(123)>,
+                              <PAD_FUNC_SHARE(124)>,
+                              <PAD_FUNC_SHARE(125)>,
+                              <PAD_FUNC_SHARE(126)>;
+                       bias-pull-up;
+                       drive-strength = <35>;
+                       input-disable;
+                       input-schmitt-disable;
+                       slew-rate = <0>;
+               };
+               rxclk-pins {
+                       pins = <PAD_FUNC_SHARE(127)>;
+                       bias-pull-up;
+                       drive-strength = <14>;
+                       input-enable;
+                       input-schmitt-disable;
+                       slew-rate = <6>;
+               };
+               rxer-pins {
+                       pins = <PAD_FUNC_SHARE(129)>;
+                       bias-pull-up;
+                       drive-strength = <14>;
+                       input-enable;
+                       input-schmitt-disable;
+                       slew-rate = <0>;
+               };
+               rx-pins {
+                       pins = <PAD_FUNC_SHARE(128)>,
+                              <PAD_FUNC_SHARE(130)>,
+                              <PAD_FUNC_SHARE(131)>,
+                              <PAD_FUNC_SHARE(132)>,
+                              <PAD_FUNC_SHARE(133)>,
+                              <PAD_FUNC_SHARE(134)>,
+                              <PAD_FUNC_SHARE(135)>,
+                              <PAD_FUNC_SHARE(136)>,
+                              <PAD_FUNC_SHARE(137)>,
+                              <PAD_FUNC_SHARE(138)>,
+                              <PAD_FUNC_SHARE(139)>,
+                              <PAD_FUNC_SHARE(140)>,
+                              <PAD_FUNC_SHARE(141)>;
+                       bias-pull-up;
+                       drive-strength = <14>;
+                       input-enable;
+                       input-schmitt-enable;
+                       slew-rate = <0>;
+               };
+       };
+
        i2c0_pins: i2c0-0 {
                i2c-pins {
                        pinmux = <GPIOMUX(62, GPO_LOW,
                };
        };
 
+       pwm_pins: pwm-0 {
+               pwm-pins {
+                       pinmux = <GPIOMUX(7,
+                                 GPO_PWM_PAD_OUT_BIT0,
+                                 GPO_PWM_PAD_OE_N_BIT0,
+                                 GPI_NONE)>,
+                                <GPIOMUX(5,
+                                 GPO_PWM_PAD_OUT_BIT1,
+                                 GPO_PWM_PAD_OE_N_BIT1,
+                                 GPI_NONE)>;
+                       bias-disable;
+                       drive-strength = <35>;
+                       input-disable;
+                       input-schmitt-disable;
+                       slew-rate = <0>;
+               };
+       };
+
        sdio0_pins: sdio0-0 {
                clk-pins {
                        pinmux = <GPIOMUX(54, GPO_SDIO0_PAD_CCLK_OUT,
        clock-frequency = <27000000>;
 };
 
+&pwm {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pwm_pins>;
+       status = "okay";
+};
+
 &sdio0 {
        broken-cd;
        bus-width = <4>;
index e82af72f1aaf17c6f70d275229310eb40e46630d..692c696e1ab472106f669582bf65ce54986a0772 100644 (file)
@@ -6,7 +6,6 @@
 
 /dts-v1/;
 #include "jh7100-common.dtsi"
-#include <dt-bindings/gpio/gpio.h>
 
 / {
        model = "StarFive VisionFive V1";
                priority = <224>;
        };
 };
+
+&gmac {
+       phy-handle = <&phy>;
+};
+
+/*
+ * The board uses a Motorcomm YT8521 PHY supporting RGMII-ID, but requires
+ * manual adjustment of the RX internal delay to work properly.  The default
+ * RX delay provided by the driver (1.95ns) is too high, but applying a 50%
+ * reduction seems to mitigate the issue.
+ *
+ * It is worth noting the adjustment is not necessary on BeagleV Starlight SBC,
+ * which uses a Microchip PHY.  Hence, most likely the Motorcomm PHY is the one
+ * responsible for the misbehaviour, not the GMAC.
+ */
+&mdio {
+       phy: ethernet-phy@0 {
+               reg = <0>;
+               rx-internal-delay-ps = <900>;
+       };
+};
index 5d499d8aa8044672664af972d788819a56ca3f55..9a2e9583af88d78d085584ab61a8ce211aa055c0 100644 (file)
                        status = "disabled";
                };
 
+               gmac: ethernet@10020000 {
+                       compatible = "starfive,jh7100-dwmac", "snps,dwmac";
+                       reg = <0x0 0x10020000 0x0 0x10000>;
+                       clocks = <&clkgen JH7100_CLK_GMAC_ROOT_DIV>,
+                                <&clkgen JH7100_CLK_GMAC_AHB>,
+                                <&clkgen JH7100_CLK_GMAC_PTP_REF>,
+                                <&clkgen JH7100_CLK_GMAC_TX_INV>,
+                                <&clkgen JH7100_CLK_GMAC_GTX>;
+                       clock-names = "stmmaceth", "pclk", "ptp_ref", "tx", "gtx";
+                       resets = <&rstgen JH7100_RSTN_GMAC_AHB>;
+                       reset-names = "ahb";
+                       interrupts = <6>, <7>;
+                       interrupt-names = "macirq", "eth_wake_irq";
+                       max-frame-size = <9000>;
+                       snps,multicast-filter-bins = <32>;
+                       snps,perfect-filter-entries = <128>;
+                       starfive,syscon = <&sysmain 0x70 0>;
+                       rx-fifo-depth = <32768>;
+                       tx-fifo-depth = <16384>;
+                       snps,axi-config = <&stmmac_axi_setup>;
+                       snps,fixed-burst;
+                       snps,force_thresh_dma_mode;
+                       status = "disabled";
+
+                       stmmac_axi_setup: stmmac-axi-config {
+                               snps,wr_osr_lmt = <16>;
+                               snps,rd_osr_lmt = <16>;
+                               snps,blen = <256 128 64 32 0 0 0>;
+                       };
+               };
+
                clkgen: clock-controller@11800000 {
                        compatible = "starfive,jh7100-clkgen";
                        reg = <0x0 0x11800000 0x0 0x10000>;
                        #reset-cells = <1>;
                };
 
+               sysmain: syscon@11850000 {
+                       compatible = "starfive,jh7100-sysmain", "syscon";
+                       reg = <0x0 0x11850000 0x0 0x10000>;
+               };
+
                i2c0: i2c@118b0000 {
                        compatible = "snps,designware-i2c";
                        reg = <0x0 0x118b0000 0x0 0x10000>;
                                 <&rstgen JH7100_RSTN_WDT>;
                };
 
+               pwm: pwm@12490000 {
+                       compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+                       reg = <0x0 0x12490000 0x0 0x10000>;
+                       clocks = <&clkgen JH7100_CLK_PWM_APB>;
+                       resets = <&rstgen JH7100_RSTN_PWM_APB>;
+                       #pwm-cells = <3>;
+                       status = "disabled";
+               };
+
                sfctemp: temperature-sensor@124a0000 {
                        compatible = "starfive,jh7100-temp";
                        reg = <0x0 0x124a0000 0x0 0x10000>;
index b89e9791efa72a2a0bf1393d8c97d5043a9a024f..45b58b6f3df88e81aea2bc4f5eca344d03362bac 100644 (file)
        clock-frequency = <49152000>;
 };
 
+&camss {
+       assigned-clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>,
+                         <&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>;
+       assigned-clock-rates = <49500000>, <198000000>;
+       status = "okay";
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       camss_from_csi2rx: endpoint {
+                               remote-endpoint = <&csi2rx_to_camss>;
+                       };
+               };
+       };
+};
+
+&csi2rx {
+       assigned-clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>;
+       assigned-clock-rates = <297000000>;
+       status = "okay";
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       /* remote MIPI sensor endpoint */
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       csi2rx_to_camss: endpoint {
+                               remote-endpoint = <&camss_from_csi2rx>;
+                       };
+               };
+       };
+};
+
 &gmac0 {
        phy-handle = <&phy0>;
        phy-mode = "rgmii-id";
        };
 };
 
+&pwm {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pwm_pins>;
+       status = "okay";
+};
+
 &spi0 {
        pinctrl-names = "default";
        pinctrl-0 = <&spi0_pins>;
                };
        };
 
+       pwm_pins: pwm-0 {
+               pwm-pins {
+                       pinmux = <GPIOMUX(46, GPOUT_SYS_PWM_CHANNEL0,
+                                             GPOEN_SYS_PWM0_CHANNEL0,
+                                             GPI_NONE)>,
+                                <GPIOMUX(59, GPOUT_SYS_PWM_CHANNEL1,
+                                             GPOEN_SYS_PWM0_CHANNEL1,
+                                             GPI_NONE)>;
+                       bias-disable;
+                       drive-strength = <12>;
+                       input-disable;
+                       input-schmitt-disable;
+                       slew-rate = <0>;
+               };
+       };
+
        spi0_pins: spi0-0 {
                mosi-pins {
                        pinmux = <GPIOMUX(52, GPOUT_SYS_SPI0_TXD,
index 74ed3b9264d8f15ee10400b4bf5fcf855b7cecd0..4a5708f7fcf7292f63fe975f3fd26cd7becc90d2 100644 (file)
                        status = "disabled";
                };
 
+               pwm: pwm@120d0000 {
+                       compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+                       reg = <0x0 0x120d0000 0x0 0x10000>;
+                       clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+                       resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+                       #pwm-cells = <3>;
+                       status = "disabled";
+               };
+
                sfctemp: temperature-sensor@120e0000 {
                        compatible = "starfive,jh7110-temp";
                        reg = <0x0 0x120e0000 0x0 0x10000>;
                        #power-domain-cells = <1>;
                };
 
+               csi2rx: csi@19800000 {
+                       compatible = "starfive,jh7110-csi2rx", "cdns,csi2rx";
+                       reg = <0x0 0x19800000 0x0 0x10000>;
+                       clocks = <&ispcrg JH7110_ISPCLK_VIN_SYS>,
+                                <&ispcrg JH7110_ISPCLK_VIN_APB>,
+                                <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF0>,
+                                <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF1>,
+                                <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF2>,
+                                <&ispcrg JH7110_ISPCLK_VIN_PIXEL_IF3>;
+                       clock-names = "sys_clk", "p_clk",
+                                     "pixel_if0_clk", "pixel_if1_clk",
+                                     "pixel_if2_clk", "pixel_if3_clk";
+                       resets = <&ispcrg JH7110_ISPRST_VIN_SYS>,
+                                <&ispcrg JH7110_ISPRST_VIN_APB>,
+                                <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF0>,
+                                <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF1>,
+                                <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF2>,
+                                <&ispcrg JH7110_ISPRST_VIN_PIXEL_IF3>;
+                       reset-names = "sys", "reg_bank",
+                                     "pixel_if0", "pixel_if1",
+                                     "pixel_if2", "pixel_if3";
+                       phys = <&csi_phy>;
+                       phy-names = "dphy";
+                       status = "disabled";
+               };
+
                ispcrg: clock-controller@19810000 {
                        compatible = "starfive,jh7110-ispcrg";
                        reg = <0x0 0x19810000 0x0 0x10000>;
                        power-domains = <&pwrc JH7110_PD_ISP>;
                };
 
+               csi_phy: phy@19820000 {
+                       compatible = "starfive,jh7110-dphy-rx";
+                       reg = <0x0 0x19820000 0x0 0x10000>;
+                       clocks = <&ispcrg JH7110_ISPCLK_M31DPHY_CFG_IN>,
+                                <&ispcrg JH7110_ISPCLK_M31DPHY_REF_IN>,
+                                <&ispcrg JH7110_ISPCLK_M31DPHY_TX_ESC_LAN0>;
+                       clock-names = "cfg", "ref", "tx";
+                       resets = <&ispcrg JH7110_ISPRST_M31DPHY_HW>,
+                                <&ispcrg JH7110_ISPRST_M31DPHY_B09_AON>;
+                       power-domains = <&aon_syscon JH7110_AON_PD_DPHY_RX>;
+                       #phy-cells = <0>;
+               };
+
+               camss: isp@19840000 {
+                       compatible = "starfive,jh7110-camss";
+                       reg = <0x0 0x19840000 0x0 0x10000>,
+                             <0x0 0x19870000 0x0 0x30000>;
+                       reg-names = "syscon", "isp";
+                       clocks = <&ispcrg JH7110_ISPCLK_DOM4_APB_FUNC>,
+                                <&ispcrg JH7110_ISPCLK_ISPV2_TOP_WRAPPER_C>,
+                                <&ispcrg JH7110_ISPCLK_DVP_INV>,
+                                <&ispcrg JH7110_ISPCLK_VIN_P_AXI_WR>,
+                                <&ispcrg JH7110_ISPCLK_MIPI_RX0_PXL>,
+                                <&syscrg JH7110_SYSCLK_ISP_TOP_CORE>,
+                                <&syscrg JH7110_SYSCLK_ISP_TOP_AXI>;
+                       clock-names = "apb_func", "wrapper_clk_c", "dvp_inv",
+                                     "axiwr", "mipi_rx0_pxl", "ispcore_2x",
+                                     "isp_axi";
+                       resets = <&ispcrg JH7110_ISPRST_ISPV2_TOP_WRAPPER_P>,
+                                <&ispcrg JH7110_ISPRST_ISPV2_TOP_WRAPPER_C>,
+                                <&ispcrg JH7110_ISPRST_VIN_P_AXI_RD>,
+                                <&ispcrg JH7110_ISPRST_VIN_P_AXI_WR>,
+                                <&syscrg JH7110_SYSRST_ISP_TOP>,
+                                <&syscrg JH7110_SYSRST_ISP_TOP_AXI>;
+                       reset-names = "wrapper_p", "wrapper_c", "axird",
+                                     "axiwr", "isp_top_n", "isp_top_axi";
+                       power-domains = <&pwrc JH7110_PD_ISP>;
+                       interrupts = <92>, <87>, <90>, <88>;
+                       status = "disabled";
+               };
+
                voutcrg: clock-controller@295c0000 {
                        compatible = "starfive,jh7110-voutcrg";
                        reg = <0x0 0x295c0000 0x0 0x10000>;
index eaf34e871e308f0db7a0a578b34940d8d551b163..fc0ec2ee13bc22c842e7ce4025e92e05599b5e1c 100644 (file)
@@ -44,6 +44,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
 CONFIG_CPUFREQ_DT=y
+CONFIG_ACPI_CPPC_CPUFREQ=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM=m
 CONFIG_ACPI=y
@@ -215,6 +216,7 @@ CONFIG_MMC=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_CADENCE=y
+CONFIG_MMC_SDHCI_OF_DWCMSHC=y
 CONFIG_MMC_SPI=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_STARFIVE=y
@@ -224,6 +226,7 @@ CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_SUN6I=y
 CONFIG_DMADEVICES=y
 CONFIG_DMA_SUN6I=m
+CONFIG_DW_AXI_DMAC=y
 CONFIG_RZ_DMAC=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
diff --git a/arch/riscv/crypto/Kconfig b/arch/riscv/crypto/Kconfig
new file mode 100644 (file)
index 0000000..ad58dad
--- /dev/null
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: GPL-2.0
+
+menu "Accelerated Cryptographic Algorithms for CPU (riscv)"
+
+config CRYPTO_AES_RISCV64
+       tristate "Ciphers: AES, modes: ECB, CBC, CTS, CTR, XTS"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_ALGAPI
+       select CRYPTO_LIB_AES
+       select CRYPTO_SKCIPHER
+       help
+         Block cipher: AES cipher algorithms
+         Length-preserving ciphers: AES with ECB, CBC, CTS, CTR, XTS
+
+         Architecture: riscv64 using:
+         - Zvkned vector crypto extension
+         - Zvbb vector extension (XTS)
+         - Zvkb vector crypto extension (CTR)
+         - Zvkg vector crypto extension (XTS)
+
+config CRYPTO_CHACHA_RISCV64
+       tristate "Ciphers: ChaCha"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_CHACHA_GENERIC
+       help
+         Length-preserving ciphers: ChaCha20 stream cipher algorithm
+
+         Architecture: riscv64 using:
+         - Zvkb vector crypto extension
+
+config CRYPTO_GHASH_RISCV64
+       tristate "Hash functions: GHASH"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_GCM
+       help
+         GCM GHASH function (NIST SP 800-38D)
+
+         Architecture: riscv64 using:
+         - Zvkg vector crypto extension
+
+config CRYPTO_SHA256_RISCV64
+       tristate "Hash functions: SHA-224 and SHA-256"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_SHA256
+       help
+         SHA-224 and SHA-256 secure hash algorithm (FIPS 180)
+
+         Architecture: riscv64 using:
+         - Zvknha or Zvknhb vector crypto extensions
+         - Zvkb vector crypto extension
+
+config CRYPTO_SHA512_RISCV64
+       tristate "Hash functions: SHA-384 and SHA-512"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_SHA512
+       help
+         SHA-384 and SHA-512 secure hash algorithm (FIPS 180)
+
+         Architecture: riscv64 using:
+         - Zvknhb vector crypto extension
+         - Zvkb vector crypto extension
+
+config CRYPTO_SM3_RISCV64
+       tristate "Hash functions: SM3 (ShangMi 3)"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_HASH
+       select CRYPTO_SM3
+       help
+         SM3 (ShangMi 3) secure hash function (OSCCA GM/T 0004-2012)
+
+         Architecture: riscv64 using:
+         - Zvksh vector crypto extension
+         - Zvkb vector crypto extension
+
+config CRYPTO_SM4_RISCV64
+       tristate "Ciphers: SM4 (ShangMi 4)"
+       depends on 64BIT && RISCV_ISA_V && TOOLCHAIN_HAS_VECTOR_CRYPTO
+       select CRYPTO_ALGAPI
+       select CRYPTO_SM4
+       help
+         SM4 block cipher algorithm (OSCCA GB/T 32907-2016,
+         ISO/IEC 18033-3:2010/Amd 1:2021)
+
+         SM4 (GBT.32907-2016) is a cryptographic standard issued by the
+         Organization of State Commercial Administration of China (OSCCA)
+         as an authorized cryptographic algorithm for use within China.
+
+         Architecture: riscv64 using:
+         - Zvksed vector crypto extension
+         - Zvkb vector crypto extension
+
+endmenu
diff --git a/arch/riscv/crypto/Makefile b/arch/riscv/crypto/Makefile
new file mode 100644 (file)
index 0000000..247c7bc
--- /dev/null
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_CRYPTO_AES_RISCV64) += aes-riscv64.o
+aes-riscv64-y := aes-riscv64-glue.o aes-riscv64-zvkned.o \
+                aes-riscv64-zvkned-zvbb-zvkg.o aes-riscv64-zvkned-zvkb.o
+
+obj-$(CONFIG_CRYPTO_CHACHA_RISCV64) += chacha-riscv64.o
+chacha-riscv64-y := chacha-riscv64-glue.o chacha-riscv64-zvkb.o
+
+obj-$(CONFIG_CRYPTO_GHASH_RISCV64) += ghash-riscv64.o
+ghash-riscv64-y := ghash-riscv64-glue.o ghash-riscv64-zvkg.o
+
+obj-$(CONFIG_CRYPTO_SHA256_RISCV64) += sha256-riscv64.o
+sha256-riscv64-y := sha256-riscv64-glue.o sha256-riscv64-zvknha_or_zvknhb-zvkb.o
+
+obj-$(CONFIG_CRYPTO_SHA512_RISCV64) += sha512-riscv64.o
+sha512-riscv64-y := sha512-riscv64-glue.o sha512-riscv64-zvknhb-zvkb.o
+
+obj-$(CONFIG_CRYPTO_SM3_RISCV64) += sm3-riscv64.o
+sm3-riscv64-y := sm3-riscv64-glue.o sm3-riscv64-zvksh-zvkb.o
+
+obj-$(CONFIG_CRYPTO_SM4_RISCV64) += sm4-riscv64.o
+sm4-riscv64-y := sm4-riscv64-glue.o sm4-riscv64-zvksed-zvkb.o
diff --git a/arch/riscv/crypto/aes-macros.S b/arch/riscv/crypto/aes-macros.S
new file mode 100644 (file)
index 0000000..d1a258d
--- /dev/null
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com>
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file contains macros that are shared by the other aes-*.S files.  The
+// generated code of these macros depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector AES block cipher extension ('Zvkned')
+
+// Loads the AES round keys from \keyp into vector registers and jumps to code
+// specific to the length of the key.  Specifically:
+//   - If AES-128, loads round keys into v1-v11 and jumps to \label128.
+//   - If AES-192, loads round keys into v1-v13 and jumps to \label192.
+//   - If AES-256, loads round keys into v1-v15 and continues onwards.
+//
+// Also sets vl=4 and vtype=e32,m1,ta,ma.  Clobbers t0 and t1.
+.macro aes_begin       keyp, label128, label192
+       lwu             t0, 480(\keyp)  // t0 = key length in bytes
+       li              t1, 24          // t1 = key length for AES-192
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vle32.v         v1, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v2, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v3, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v4, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v5, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v6, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v7, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v8, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v9, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v10, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v11, (\keyp)
+       blt             t0, t1, \label128       // If AES-128, goto label128.
+       addi            \keyp, \keyp, 16
+       vle32.v         v12, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v13, (\keyp)
+       beq             t0, t1, \label192       // If AES-192, goto label192.
+       // Else, it's AES-256.
+       addi            \keyp, \keyp, 16
+       vle32.v         v14, (\keyp)
+       addi            \keyp, \keyp, 16
+       vle32.v         v15, (\keyp)
+.endm
+
+// Encrypts \data using zvkned instructions, using the round keys loaded into
+// v1-v11 (for AES-128), v1-v13 (for AES-192), or v1-v15 (for AES-256).  \keylen
+// is the AES key length in bits.  vl and vtype must already be set
+// appropriately.  Note that if vl > 4, multiple blocks are encrypted.
+.macro aes_encrypt     data, keylen
+       vaesz.vs        \data, v1
+       vaesem.vs       \data, v2
+       vaesem.vs       \data, v3
+       vaesem.vs       \data, v4
+       vaesem.vs       \data, v5
+       vaesem.vs       \data, v6
+       vaesem.vs       \data, v7
+       vaesem.vs       \data, v8
+       vaesem.vs       \data, v9
+       vaesem.vs       \data, v10
+.if \keylen == 128
+       vaesef.vs       \data, v11
+.elseif \keylen == 192
+       vaesem.vs       \data, v11
+       vaesem.vs       \data, v12
+       vaesef.vs       \data, v13
+.else
+       vaesem.vs       \data, v11
+       vaesem.vs       \data, v12
+       vaesem.vs       \data, v13
+       vaesem.vs       \data, v14
+       vaesef.vs       \data, v15
+.endif
+.endm
+
+// Same as aes_encrypt, but decrypts instead of encrypts.
+.macro aes_decrypt     data, keylen
+.if \keylen == 128
+       vaesz.vs        \data, v11
+.elseif \keylen == 192
+       vaesz.vs        \data, v13
+       vaesdm.vs       \data, v12
+       vaesdm.vs       \data, v11
+.else
+       vaesz.vs        \data, v15
+       vaesdm.vs       \data, v14
+       vaesdm.vs       \data, v13
+       vaesdm.vs       \data, v12
+       vaesdm.vs       \data, v11
+.endif
+       vaesdm.vs       \data, v10
+       vaesdm.vs       \data, v9
+       vaesdm.vs       \data, v8
+       vaesdm.vs       \data, v7
+       vaesdm.vs       \data, v6
+       vaesdm.vs       \data, v5
+       vaesdm.vs       \data, v4
+       vaesdm.vs       \data, v3
+       vaesdm.vs       \data, v2
+       vaesdf.vs       \data, v1
+.endm
+
+// Expands to aes_encrypt or aes_decrypt according to \enc, which is 1 or 0.
+.macro aes_crypt       data, enc, keylen
+.if \enc
+       aes_encrypt     \data, \keylen
+.else
+       aes_decrypt     \data, \keylen
+.endif
+.endm
diff --git a/arch/riscv/crypto/aes-riscv64-glue.c b/arch/riscv/crypto/aes-riscv64-glue.c
new file mode 100644 (file)
index 0000000..f814ee0
--- /dev/null
@@ -0,0 +1,637 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AES using the RISC-V vector crypto extensions.  Includes the bare block
+ * cipher and the ECB, CBC, CBC-CTS, CTR, and XTS modes.
+ *
+ * Copyright (C) 2023 VRULL GmbH
+ * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ *
+ * Copyright 2024 Google LLC
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/aes.h>
+#include <crypto/internal/cipher.h>
+#include <crypto/internal/simd.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/xts.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+asmlinkage void aes_encrypt_zvkned(const struct crypto_aes_ctx *key,
+                                  const u8 in[AES_BLOCK_SIZE],
+                                  u8 out[AES_BLOCK_SIZE]);
+asmlinkage void aes_decrypt_zvkned(const struct crypto_aes_ctx *key,
+                                  const u8 in[AES_BLOCK_SIZE],
+                                  u8 out[AES_BLOCK_SIZE]);
+
+asmlinkage void aes_ecb_encrypt_zvkned(const struct crypto_aes_ctx *key,
+                                      const u8 *in, u8 *out, size_t len);
+asmlinkage void aes_ecb_decrypt_zvkned(const struct crypto_aes_ctx *key,
+                                      const u8 *in, u8 *out, size_t len);
+
+asmlinkage void aes_cbc_encrypt_zvkned(const struct crypto_aes_ctx *key,
+                                      const u8 *in, u8 *out, size_t len,
+                                      u8 iv[AES_BLOCK_SIZE]);
+asmlinkage void aes_cbc_decrypt_zvkned(const struct crypto_aes_ctx *key,
+                                      const u8 *in, u8 *out, size_t len,
+                                      u8 iv[AES_BLOCK_SIZE]);
+
+asmlinkage void aes_cbc_cts_crypt_zvkned(const struct crypto_aes_ctx *key,
+                                        const u8 *in, u8 *out, size_t len,
+                                        const u8 iv[AES_BLOCK_SIZE], bool enc);
+
+asmlinkage void aes_ctr32_crypt_zvkned_zvkb(const struct crypto_aes_ctx *key,
+                                           const u8 *in, u8 *out, size_t len,
+                                           u8 iv[AES_BLOCK_SIZE]);
+
+asmlinkage void aes_xts_encrypt_zvkned_zvbb_zvkg(
+                       const struct crypto_aes_ctx *key,
+                       const u8 *in, u8 *out, size_t len,
+                       u8 tweak[AES_BLOCK_SIZE]);
+
+asmlinkage void aes_xts_decrypt_zvkned_zvbb_zvkg(
+                       const struct crypto_aes_ctx *key,
+                       const u8 *in, u8 *out, size_t len,
+                       u8 tweak[AES_BLOCK_SIZE]);
+
+static int riscv64_aes_setkey(struct crypto_aes_ctx *ctx,
+                             const u8 *key, unsigned int keylen)
+{
+       /*
+        * For now we just use the generic key expansion, for these reasons:
+        *
+        * - zvkned's key expansion instructions don't support AES-192.
+        *   So, non-zvkned fallback code would be needed anyway.
+        *
+        * - Users of AES in Linux usually don't change keys frequently.
+        *   So, key expansion isn't performance-critical.
+        *
+        * - For single-block AES exposed as a "cipher" algorithm, it's
+        *   necessary to use struct crypto_aes_ctx and initialize its 'key_dec'
+        *   field with the round keys for the Equivalent Inverse Cipher.  This
+        *   is because with "cipher", decryption can be requested from a
+        *   context where the vector unit isn't usable, necessitating a
+        *   fallback to aes_decrypt().  But, zvkned can only generate and use
+        *   the normal round keys.  Of course, it's preferable to not have
+        *   special code just for "cipher", as e.g. XTS also uses a
+        *   single-block AES encryption.  It's simplest to just use
+        *   struct crypto_aes_ctx and aes_expandkey() everywhere.
+        */
+       return aes_expandkey(ctx, key, keylen);
+}
+
+static int riscv64_aes_setkey_cipher(struct crypto_tfm *tfm,
+                                    const u8 *key, unsigned int keylen)
+{
+       struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       return riscv64_aes_setkey(ctx, key, keylen);
+}
+
+static int riscv64_aes_setkey_skcipher(struct crypto_skcipher *tfm,
+                                      const u8 *key, unsigned int keylen)
+{
+       struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+       return riscv64_aes_setkey(ctx, key, keylen);
+}
+
+/* Bare AES, without a mode of operation */
+
+static void riscv64_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               aes_encrypt_zvkned(ctx, src, dst);
+               kernel_vector_end();
+       } else {
+               aes_encrypt(ctx, dst, src);
+       }
+}
+
+static void riscv64_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               aes_decrypt_zvkned(ctx, src, dst);
+               kernel_vector_end();
+       } else {
+               aes_decrypt(ctx, dst, src);
+       }
+}
+
+/* AES-ECB */
+
+static inline int riscv64_aes_ecb_crypt(struct skcipher_request *req, bool enc)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
+       struct skcipher_walk walk;
+       unsigned int nbytes;
+       int err;
+
+       err = skcipher_walk_virt(&walk, req, false);
+       while ((nbytes = walk.nbytes) != 0) {
+               kernel_vector_begin();
+               if (enc)
+                       aes_ecb_encrypt_zvkned(ctx, walk.src.virt.addr,
+                                              walk.dst.virt.addr,
+                                              nbytes & ~(AES_BLOCK_SIZE - 1));
+               else
+                       aes_ecb_decrypt_zvkned(ctx, walk.src.virt.addr,
+                                              walk.dst.virt.addr,
+                                              nbytes & ~(AES_BLOCK_SIZE - 1));
+               kernel_vector_end();
+               err = skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1));
+       }
+
+       return err;
+}
+
+static int riscv64_aes_ecb_encrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_ecb_crypt(req, true);
+}
+
+static int riscv64_aes_ecb_decrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_ecb_crypt(req, false);
+}
+
+/* AES-CBC */
+
+static int riscv64_aes_cbc_crypt(struct skcipher_request *req, bool enc)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
+       struct skcipher_walk walk;
+       unsigned int nbytes;
+       int err;
+
+       err = skcipher_walk_virt(&walk, req, false);
+       while ((nbytes = walk.nbytes) != 0) {
+               kernel_vector_begin();
+               if (enc)
+                       aes_cbc_encrypt_zvkned(ctx, walk.src.virt.addr,
+                                              walk.dst.virt.addr,
+                                              nbytes & ~(AES_BLOCK_SIZE - 1),
+                                              walk.iv);
+               else
+                       aes_cbc_decrypt_zvkned(ctx, walk.src.virt.addr,
+                                              walk.dst.virt.addr,
+                                              nbytes & ~(AES_BLOCK_SIZE - 1),
+                                              walk.iv);
+               kernel_vector_end();
+               err = skcipher_walk_done(&walk, nbytes & (AES_BLOCK_SIZE - 1));
+       }
+
+       return err;
+}
+
+static int riscv64_aes_cbc_encrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_cbc_crypt(req, true);
+}
+
+static int riscv64_aes_cbc_decrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_cbc_crypt(req, false);
+}
+
+/* AES-CBC-CTS */
+
+static int riscv64_aes_cbc_cts_crypt(struct skcipher_request *req, bool enc)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
+       struct scatterlist sg_src[2], sg_dst[2];
+       struct skcipher_request subreq;
+       struct scatterlist *src, *dst;
+       struct skcipher_walk walk;
+       unsigned int cbc_len;
+       int err;
+
+       if (req->cryptlen < AES_BLOCK_SIZE)
+               return -EINVAL;
+
+       err = skcipher_walk_virt(&walk, req, false);
+       if (err)
+               return err;
+       /*
+        * If the full message is available in one step, decrypt it in one call
+        * to the CBC-CTS assembly function.  This reduces overhead, especially
+        * on short messages.  Otherwise, fall back to doing CBC up to the last
+        * two blocks, then invoke CTS just for the ciphertext stealing.
+        */
+       if (unlikely(walk.nbytes != req->cryptlen)) {
+               cbc_len = round_down(req->cryptlen - AES_BLOCK_SIZE - 1,
+                                    AES_BLOCK_SIZE);
+               skcipher_walk_abort(&walk);
+               skcipher_request_set_tfm(&subreq, tfm);
+               skcipher_request_set_callback(&subreq,
+                                             skcipher_request_flags(req),
+                                             NULL, NULL);
+               skcipher_request_set_crypt(&subreq, req->src, req->dst,
+                                          cbc_len, req->iv);
+               err = riscv64_aes_cbc_crypt(&subreq, enc);
+               if (err)
+                       return err;
+               dst = src = scatterwalk_ffwd(sg_src, req->src, cbc_len);
+               if (req->dst != req->src)
+                       dst = scatterwalk_ffwd(sg_dst, req->dst, cbc_len);
+               skcipher_request_set_crypt(&subreq, src, dst,
+                                          req->cryptlen - cbc_len, req->iv);
+               err = skcipher_walk_virt(&walk, &subreq, false);
+               if (err)
+                       return err;
+       }
+       kernel_vector_begin();
+       aes_cbc_cts_crypt_zvkned(ctx, walk.src.virt.addr, walk.dst.virt.addr,
+                                walk.nbytes, req->iv, enc);
+       kernel_vector_end();
+       return skcipher_walk_done(&walk, 0);
+}
+
+static int riscv64_aes_cbc_cts_encrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_cbc_cts_crypt(req, true);
+}
+
+static int riscv64_aes_cbc_cts_decrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_cbc_cts_crypt(req, false);
+}
+
+/* AES-CTR */
+
+static int riscv64_aes_ctr_crypt(struct skcipher_request *req)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
+       unsigned int nbytes, p1_nbytes;
+       struct skcipher_walk walk;
+       u32 ctr32, nblocks;
+       int err;
+
+       /* Get the low 32-bit word of the 128-bit big endian counter. */
+       ctr32 = get_unaligned_be32(req->iv + 12);
+
+       err = skcipher_walk_virt(&walk, req, false);
+       while ((nbytes = walk.nbytes) != 0) {
+               if (nbytes < walk.total) {
+                       /* Not the end yet, so keep the length block-aligned. */
+                       nbytes = round_down(nbytes, AES_BLOCK_SIZE);
+                       nblocks = nbytes / AES_BLOCK_SIZE;
+               } else {
+                       /* It's the end, so include any final partial block. */
+                       nblocks = DIV_ROUND_UP(nbytes, AES_BLOCK_SIZE);
+               }
+               ctr32 += nblocks;
+
+               kernel_vector_begin();
+               if (ctr32 >= nblocks) {
+                       /* The low 32-bit word of the counter won't overflow. */
+                       aes_ctr32_crypt_zvkned_zvkb(ctx, walk.src.virt.addr,
+                                                   walk.dst.virt.addr, nbytes,
+                                                   req->iv);
+               } else {
+                       /*
+                        * The low 32-bit word of the counter will overflow.
+                        * The assembly doesn't handle this case, so split the
+                        * operation into two at the point where the overflow
+                        * will occur.  After the first part, add the carry bit.
+                        */
+                       p1_nbytes = min_t(unsigned int, nbytes,
+                                         (nblocks - ctr32) * AES_BLOCK_SIZE);
+                       aes_ctr32_crypt_zvkned_zvkb(ctx, walk.src.virt.addr,
+                                                   walk.dst.virt.addr,
+                                                   p1_nbytes, req->iv);
+                       crypto_inc(req->iv, 12);
+
+                       if (ctr32) {
+                               aes_ctr32_crypt_zvkned_zvkb(
+                                       ctx,
+                                       walk.src.virt.addr + p1_nbytes,
+                                       walk.dst.virt.addr + p1_nbytes,
+                                       nbytes - p1_nbytes, req->iv);
+                       }
+               }
+               kernel_vector_end();
+
+               err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+       }
+
+       return err;
+}
+
+/* AES-XTS */
+
+struct riscv64_aes_xts_ctx {
+       struct crypto_aes_ctx ctx1;
+       struct crypto_aes_ctx ctx2;
+};
+
+static int riscv64_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
+                                 unsigned int keylen)
+{
+       struct riscv64_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+       return xts_verify_key(tfm, key, keylen) ?:
+              riscv64_aes_setkey(&ctx->ctx1, key, keylen / 2) ?:
+              riscv64_aes_setkey(&ctx->ctx2, key + keylen / 2, keylen / 2);
+}
+
+static int riscv64_aes_xts_crypt(struct skcipher_request *req, bool enc)
+{
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct riscv64_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
+       int tail = req->cryptlen % AES_BLOCK_SIZE;
+       struct scatterlist sg_src[2], sg_dst[2];
+       struct skcipher_request subreq;
+       struct scatterlist *src, *dst;
+       struct skcipher_walk walk;
+       int err;
+
+       if (req->cryptlen < AES_BLOCK_SIZE)
+               return -EINVAL;
+
+       /* Encrypt the IV with the tweak key to get the first tweak. */
+       kernel_vector_begin();
+       aes_encrypt_zvkned(&ctx->ctx2, req->iv, req->iv);
+       kernel_vector_end();
+
+       err = skcipher_walk_virt(&walk, req, false);
+
+       /*
+        * If the message length isn't divisible by the AES block size and the
+        * full message isn't available in one step of the scatterlist walk,
+        * then separate off the last full block and the partial block.  This
+        * ensures that they are processed in the same call to the assembly
+        * function, which is required for ciphertext stealing.
+        */
+       if (unlikely(tail > 0 && walk.nbytes < walk.total)) {
+               skcipher_walk_abort(&walk);
+
+               skcipher_request_set_tfm(&subreq, tfm);
+               skcipher_request_set_callback(&subreq,
+                                             skcipher_request_flags(req),
+                                             NULL, NULL);
+               skcipher_request_set_crypt(&subreq, req->src, req->dst,
+                                          req->cryptlen - tail - AES_BLOCK_SIZE,
+                                          req->iv);
+               req = &subreq;
+               err = skcipher_walk_virt(&walk, req, false);
+       } else {
+               tail = 0;
+       }
+
+       while (walk.nbytes) {
+               unsigned int nbytes = walk.nbytes;
+
+               if (nbytes < walk.total)
+                       nbytes = round_down(nbytes, AES_BLOCK_SIZE);
+
+               kernel_vector_begin();
+               if (enc)
+                       aes_xts_encrypt_zvkned_zvbb_zvkg(
+                               &ctx->ctx1, walk.src.virt.addr,
+                               walk.dst.virt.addr, nbytes, req->iv);
+               else
+                       aes_xts_decrypt_zvkned_zvbb_zvkg(
+                               &ctx->ctx1, walk.src.virt.addr,
+                               walk.dst.virt.addr, nbytes, req->iv);
+               kernel_vector_end();
+               err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
+       }
+
+       if (err || likely(!tail))
+               return err;
+
+       /* Do ciphertext stealing with the last full block and partial block. */
+
+       dst = src = scatterwalk_ffwd(sg_src, req->src, req->cryptlen);
+       if (req->dst != req->src)
+               dst = scatterwalk_ffwd(sg_dst, req->dst, req->cryptlen);
+
+       skcipher_request_set_crypt(req, src, dst, AES_BLOCK_SIZE + tail,
+                                  req->iv);
+
+       err = skcipher_walk_virt(&walk, req, false);
+       if (err)
+               return err;
+
+       kernel_vector_begin();
+       if (enc)
+               aes_xts_encrypt_zvkned_zvbb_zvkg(
+                       &ctx->ctx1, walk.src.virt.addr,
+                       walk.dst.virt.addr, walk.nbytes, req->iv);
+       else
+               aes_xts_decrypt_zvkned_zvbb_zvkg(
+                       &ctx->ctx1, walk.src.virt.addr,
+                       walk.dst.virt.addr, walk.nbytes, req->iv);
+       kernel_vector_end();
+
+       return skcipher_walk_done(&walk, 0);
+}
+
+static int riscv64_aes_xts_encrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_xts_crypt(req, true);
+}
+
+static int riscv64_aes_xts_decrypt(struct skcipher_request *req)
+{
+       return riscv64_aes_xts_crypt(req, false);
+}
+
+/* Algorithm definitions */
+
+static struct crypto_alg riscv64_zvkned_aes_cipher_alg = {
+       .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize = AES_BLOCK_SIZE,
+       .cra_ctxsize = sizeof(struct crypto_aes_ctx),
+       .cra_priority = 300,
+       .cra_name = "aes",
+       .cra_driver_name = "aes-riscv64-zvkned",
+       .cra_cipher = {
+               .cia_min_keysize = AES_MIN_KEY_SIZE,
+               .cia_max_keysize = AES_MAX_KEY_SIZE,
+               .cia_setkey = riscv64_aes_setkey_cipher,
+               .cia_encrypt = riscv64_aes_encrypt,
+               .cia_decrypt = riscv64_aes_decrypt,
+       },
+       .cra_module = THIS_MODULE,
+};
+
+static struct skcipher_alg riscv64_zvkned_aes_skcipher_algs[] = {
+       {
+               .setkey = riscv64_aes_setkey_skcipher,
+               .encrypt = riscv64_aes_ecb_encrypt,
+               .decrypt = riscv64_aes_ecb_decrypt,
+               .min_keysize = AES_MIN_KEY_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE,
+               .walksize = 8 * AES_BLOCK_SIZE, /* matches LMUL=8 */
+               .base = {
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_ctxsize = sizeof(struct crypto_aes_ctx),
+                       .cra_priority = 300,
+                       .cra_name = "ecb(aes)",
+                       .cra_driver_name = "ecb-aes-riscv64-zvkned",
+                       .cra_module = THIS_MODULE,
+               },
+       }, {
+               .setkey = riscv64_aes_setkey_skcipher,
+               .encrypt = riscv64_aes_cbc_encrypt,
+               .decrypt = riscv64_aes_cbc_decrypt,
+               .min_keysize = AES_MIN_KEY_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE,
+               .ivsize = AES_BLOCK_SIZE,
+               .base = {
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_ctxsize = sizeof(struct crypto_aes_ctx),
+                       .cra_priority = 300,
+                       .cra_name = "cbc(aes)",
+                       .cra_driver_name = "cbc-aes-riscv64-zvkned",
+                       .cra_module = THIS_MODULE,
+               },
+       }, {
+               .setkey = riscv64_aes_setkey_skcipher,
+               .encrypt = riscv64_aes_cbc_cts_encrypt,
+               .decrypt = riscv64_aes_cbc_cts_decrypt,
+               .min_keysize = AES_MIN_KEY_SIZE,
+               .max_keysize = AES_MAX_KEY_SIZE,
+               .ivsize = AES_BLOCK_SIZE,
+               .walksize = 4 * AES_BLOCK_SIZE, /* matches LMUL=4 */
+               .base = {
+                       .cra_blocksize = AES_BLOCK_SIZE,
+                       .cra_ctxsize = sizeof(struct crypto_aes_ctx),
+                       .cra_priority = 300,
+                       .cra_name = "cts(cbc(aes))",
+                       .cra_driver_name = "cts-cbc-aes-riscv64-zvkned",
+                       .cra_module = THIS_MODULE,
+               },
+       }
+};
+
+static struct skcipher_alg riscv64_zvkned_zvkb_aes_skcipher_alg = {
+       .setkey = riscv64_aes_setkey_skcipher,
+       .encrypt = riscv64_aes_ctr_crypt,
+       .decrypt = riscv64_aes_ctr_crypt,
+       .min_keysize = AES_MIN_KEY_SIZE,
+       .max_keysize = AES_MAX_KEY_SIZE,
+       .ivsize = AES_BLOCK_SIZE,
+       .chunksize = AES_BLOCK_SIZE,
+       .walksize = 4 * AES_BLOCK_SIZE, /* matches LMUL=4 */
+       .base = {
+               .cra_blocksize = 1,
+               .cra_ctxsize = sizeof(struct crypto_aes_ctx),
+               .cra_priority = 300,
+               .cra_name = "ctr(aes)",
+               .cra_driver_name = "ctr-aes-riscv64-zvkned-zvkb",
+               .cra_module = THIS_MODULE,
+       },
+};
+
+static struct skcipher_alg riscv64_zvkned_zvbb_zvkg_aes_skcipher_alg = {
+       .setkey = riscv64_aes_xts_setkey,
+       .encrypt = riscv64_aes_xts_encrypt,
+       .decrypt = riscv64_aes_xts_decrypt,
+       .min_keysize = 2 * AES_MIN_KEY_SIZE,
+       .max_keysize = 2 * AES_MAX_KEY_SIZE,
+       .ivsize = AES_BLOCK_SIZE,
+       .chunksize = AES_BLOCK_SIZE,
+       .walksize = 4 * AES_BLOCK_SIZE, /* matches LMUL=4 */
+       .base = {
+               .cra_blocksize = AES_BLOCK_SIZE,
+               .cra_ctxsize = sizeof(struct riscv64_aes_xts_ctx),
+               .cra_priority = 300,
+               .cra_name = "xts(aes)",
+               .cra_driver_name = "xts-aes-riscv64-zvkned-zvbb-zvkg",
+               .cra_module = THIS_MODULE,
+       },
+};
+
+static inline bool riscv64_aes_xts_supported(void)
+{
+       return riscv_isa_extension_available(NULL, ZVBB) &&
+              riscv_isa_extension_available(NULL, ZVKG) &&
+              riscv_vector_vlen() < 2048 /* Implementation limitation */;
+}
+
+static int __init riscv64_aes_mod_init(void)
+{
+       int err = -ENODEV;
+
+       if (riscv_isa_extension_available(NULL, ZVKNED) &&
+           riscv_vector_vlen() >= 128) {
+               err = crypto_register_alg(&riscv64_zvkned_aes_cipher_alg);
+               if (err)
+                       return err;
+
+               err = crypto_register_skciphers(
+                       riscv64_zvkned_aes_skcipher_algs,
+                       ARRAY_SIZE(riscv64_zvkned_aes_skcipher_algs));
+               if (err)
+                       goto unregister_zvkned_cipher_alg;
+
+               if (riscv_isa_extension_available(NULL, ZVKB)) {
+                       err = crypto_register_skcipher(
+                               &riscv64_zvkned_zvkb_aes_skcipher_alg);
+                       if (err)
+                               goto unregister_zvkned_skcipher_algs;
+               }
+
+               if (riscv64_aes_xts_supported()) {
+                       err = crypto_register_skcipher(
+                               &riscv64_zvkned_zvbb_zvkg_aes_skcipher_alg);
+                       if (err)
+                               goto unregister_zvkned_zvkb_skcipher_alg;
+               }
+       }
+
+       return err;
+
+unregister_zvkned_zvkb_skcipher_alg:
+       if (riscv_isa_extension_available(NULL, ZVKB))
+               crypto_unregister_skcipher(&riscv64_zvkned_zvkb_aes_skcipher_alg);
+unregister_zvkned_skcipher_algs:
+       crypto_unregister_skciphers(riscv64_zvkned_aes_skcipher_algs,
+                                   ARRAY_SIZE(riscv64_zvkned_aes_skcipher_algs));
+unregister_zvkned_cipher_alg:
+       crypto_unregister_alg(&riscv64_zvkned_aes_cipher_alg);
+       return err;
+}
+
+static void __exit riscv64_aes_mod_exit(void)
+{
+       if (riscv64_aes_xts_supported())
+               crypto_unregister_skcipher(&riscv64_zvkned_zvbb_zvkg_aes_skcipher_alg);
+       if (riscv_isa_extension_available(NULL, ZVKB))
+               crypto_unregister_skcipher(&riscv64_zvkned_zvkb_aes_skcipher_alg);
+       crypto_unregister_skciphers(riscv64_zvkned_aes_skcipher_algs,
+                                   ARRAY_SIZE(riscv64_zvkned_aes_skcipher_algs));
+       crypto_unregister_alg(&riscv64_zvkned_aes_cipher_alg);
+}
+
+module_init(riscv64_aes_mod_init);
+module_exit(riscv64_aes_mod_exit);
+
+MODULE_DESCRIPTION("AES-ECB/CBC/CTS/CTR/XTS (RISC-V accelerated)");
+MODULE_AUTHOR("Jerry Shih <jerry.shih@sifive.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("aes");
+MODULE_ALIAS_CRYPTO("ecb(aes)");
+MODULE_ALIAS_CRYPTO("cbc(aes)");
+MODULE_ALIAS_CRYPTO("cts(cbc(aes))");
+MODULE_ALIAS_CRYPTO("ctr(aes)");
+MODULE_ALIAS_CRYPTO("xts(aes)");
diff --git a/arch/riscv/crypto/aes-riscv64-zvkned-zvbb-zvkg.S b/arch/riscv/crypto/aes-riscv64-zvkned-zvbb-zvkg.S
new file mode 100644 (file)
index 0000000..146fc9c
--- /dev/null
@@ -0,0 +1,312 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128 && VLEN < 2048
+// - RISC-V Vector AES block cipher extension ('Zvkned')
+// - RISC-V Vector Bit-manipulation extension ('Zvbb')
+// - RISC-V Vector GCM/GMAC extension ('Zvkg')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvkned, +zvbb, +zvkg
+
+#include "aes-macros.S"
+
+#define KEYP           a0
+#define INP            a1
+#define OUTP           a2
+#define LEN            a3
+#define TWEAKP         a4
+
+#define LEN32          a5
+#define TAIL_LEN       a6
+#define VL             a7
+#define VLMAX          t4
+
+// v1-v15 contain the AES round keys, but they are used for temporaries before
+// the AES round keys have been loaded.
+#define TWEAKS         v16     // LMUL=4 (most of the time)
+#define TWEAKS_BREV    v20     // LMUL=4 (most of the time)
+#define MULTS_BREV     v24     // LMUL=4 (most of the time)
+#define TMP0           v28
+#define TMP1           v29
+#define TMP2           v30
+#define TMP3           v31
+
+// xts_init initializes the following values:
+//
+//     TWEAKS: N 128-bit tweaks T*(x^i) for i in 0..(N - 1)
+//     TWEAKS_BREV: same as TWEAKS, but bit-reversed
+//     MULTS_BREV: N 128-bit values x^N, bit-reversed.  Only if N > 1.
+//
+// N is the maximum number of blocks that will be processed per loop iteration,
+// computed using vsetvli.
+//
+// The field convention used by XTS is the same as that of GHASH, but with the
+// bits reversed within each byte.  The zvkg extension provides the vgmul
+// instruction which does multiplication in this field.  Therefore, for tweak
+// computation we use vgmul to do multiplications in parallel, instead of
+// serially multiplying by x using shifting+xoring.  Note that for this to work,
+// the inputs and outputs to vgmul must be bit-reversed (we do it with vbrev8).
+.macro xts_init
+
+       // Load the first tweak T.
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vle32.v         TWEAKS, (TWEAKP)
+
+       // If there's only one block (or no blocks at all), then skip the tweak
+       // sequence computation because (at most) T itself is needed.
+       li              t0, 16
+       ble             LEN, t0, .Linit_single_block\@
+
+       // Save a copy of T bit-reversed in v12.
+       vbrev8.v        v12, TWEAKS
+
+       //
+       // Generate x^i for i in 0..(N - 1), i.e. 128-bit values 1 << i assuming
+       // that N <= 128.  Though, this code actually requires N < 64 (or
+       // equivalently VLEN < 2048) due to the use of 64-bit intermediate
+       // values here and in the x^N computation later.
+       //
+       vsetvli         VL, LEN32, e32, m4, ta, ma
+       srli            t0, VL, 2       // t0 = N (num blocks)
+       // Generate two sequences, each with N 32-bit values:
+       // v0=[1, 1, 1, ...] and v1=[0, 1, 2, ...].
+       vsetvli         zero, t0, e32, m1, ta, ma
+       vmv.v.i         v0, 1
+       vid.v           v1
+       // Use vzext to zero-extend the sequences to 64 bits.  Reinterpret them
+       // as two sequences, each with 2*N 32-bit values:
+       // v2=[1, 0, 1, 0, 1, 0, ...] and v4=[0, 0, 1, 0, 2, 0, ...].
+       vsetvli         zero, t0, e64, m2, ta, ma
+       vzext.vf2       v2, v0
+       vzext.vf2       v4, v1
+       slli            t1, t0, 1       // t1 = 2*N
+       vsetvli         zero, t1, e32, m2, ta, ma
+       // Use vwsll to compute [1<<0, 0<<0, 1<<1, 0<<0, 1<<2, 0<<0, ...],
+       // widening to 64 bits per element.  When reinterpreted as N 128-bit
+       // values, this is the needed sequence of 128-bit values 1 << i (x^i).
+       vwsll.vv        v8, v2, v4
+
+       // Copy the bit-reversed T to all N elements of TWEAKS_BREV, then
+       // multiply by x^i.  This gives the sequence T*(x^i), bit-reversed.
+       vsetvli         zero, LEN32, e32, m4, ta, ma
+       vmv.v.i         TWEAKS_BREV, 0
+       vaesz.vs        TWEAKS_BREV, v12
+       vbrev8.v        v8, v8
+       vgmul.vv        TWEAKS_BREV, v8
+
+       // Save a copy of the sequence T*(x^i) with the bit reversal undone.
+       vbrev8.v        TWEAKS, TWEAKS_BREV
+
+       // Generate N copies of x^N, i.e. 128-bit values 1 << N, bit-reversed.
+       li              t1, 1
+       sll             t1, t1, t0      // t1 = 1 << N
+       vsetivli        zero, 2, e64, m1, ta, ma
+       vmv.v.i         v0, 0
+       vsetivli        zero, 1, e64, m1, tu, ma
+       vmv.v.x         v0, t1
+       vbrev8.v        v0, v0
+       vsetvli         zero, LEN32, e32, m4, ta, ma
+       vmv.v.i         MULTS_BREV, 0
+       vaesz.vs        MULTS_BREV, v0
+
+       j               .Linit_done\@
+
+.Linit_single_block\@:
+       vbrev8.v        TWEAKS_BREV, TWEAKS
+.Linit_done\@:
+.endm
+
+// Set the first 128 bits of MULTS_BREV to 0x40, i.e. 'x' bit-reversed.  This is
+// the multiplier required to advance the tweak by one.
+.macro load_x
+       li              t0, 0x40
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vmv.v.i         MULTS_BREV, 0
+       vsetivli        zero, 1, e8, m1, tu, ma
+       vmv.v.x         MULTS_BREV, t0
+.endm
+
+.macro __aes_xts_crypt enc, keylen
+       // With 16 < len <= 31, there's no main loop, just ciphertext stealing.
+       beqz            LEN32, .Lcts_without_main_loop\@
+
+       vsetvli         VLMAX, zero, e32, m4, ta, ma
+1:
+       vsetvli         VL, LEN32, e32, m4, ta, ma
+2:
+       // Encrypt or decrypt VL/4 blocks.
+       vle32.v         TMP0, (INP)
+       vxor.vv         TMP0, TMP0, TWEAKS
+       aes_crypt       TMP0, \enc, \keylen
+       vxor.vv         TMP0, TMP0, TWEAKS
+       vse32.v         TMP0, (OUTP)
+
+       // Update the pointers and the remaining length.
+       slli            t0, VL, 2
+       add             INP, INP, t0
+       add             OUTP, OUTP, t0
+       sub             LEN32, LEN32, VL
+
+       // Check whether more blocks remain.
+       beqz            LEN32, .Lmain_loop_done\@
+
+       // Compute the next sequence of tweaks by multiplying the previous
+       // sequence by x^N.  Store the result in both bit-reversed order and
+       // regular order (i.e. with the bit reversal undone).
+       vgmul.vv        TWEAKS_BREV, MULTS_BREV
+       vbrev8.v        TWEAKS, TWEAKS_BREV
+
+       // Since we compute the tweak multipliers x^N in advance, we require
+       // that each iteration process the same length except possibly the last.
+       // This conflicts slightly with the behavior allowed by RISC-V Vector
+       // Extension, where CPUs can select a lower length for both of the last
+       // two iterations.  E.g., vl might take the sequence of values
+       // [16, 16, 16, 12, 12], whereas we need [16, 16, 16, 16, 8] so that we
+       // can use x^4 again instead of computing x^3.  Therefore, we explicitly
+       // keep the vl at VLMAX if there is at least VLMAX remaining.
+       bge             LEN32, VLMAX, 2b
+       j               1b
+
+.Lmain_loop_done\@:
+       load_x
+
+       // Compute the next tweak.
+       addi            t0, VL, -4
+       vsetivli        zero, 4, e32, m4, ta, ma
+       vslidedown.vx   TWEAKS_BREV, TWEAKS_BREV, t0    // Extract last tweak
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vgmul.vv        TWEAKS_BREV, MULTS_BREV         // Advance to next tweak
+
+       bnez            TAIL_LEN, .Lcts\@
+
+       // Update *TWEAKP to contain the next tweak.
+       vbrev8.v        TWEAKS, TWEAKS_BREV
+       vse32.v         TWEAKS, (TWEAKP)
+       ret
+
+.Lcts_without_main_loop\@:
+       load_x
+.Lcts\@:
+       // TWEAKS_BREV now contains the next tweak.  Compute the one after that.
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vmv.v.v         TMP0, TWEAKS_BREV
+       vgmul.vv        TMP0, MULTS_BREV
+       // Undo the bit reversal of the next two tweaks and store them in TMP1
+       // and TMP2, such that TMP1 is the first needed and TMP2 the second.
+.if \enc
+       vbrev8.v        TMP1, TWEAKS_BREV
+       vbrev8.v        TMP2, TMP0
+.else
+       vbrev8.v        TMP1, TMP0
+       vbrev8.v        TMP2, TWEAKS_BREV
+.endif
+
+       // Encrypt/decrypt the last full block.
+       vle32.v         TMP0, (INP)
+       vxor.vv         TMP0, TMP0, TMP1
+       aes_crypt       TMP0, \enc, \keylen
+       vxor.vv         TMP0, TMP0, TMP1
+
+       // Swap the first TAIL_LEN bytes of the above result with the tail.
+       // Note that to support in-place encryption/decryption, the load from
+       // the input tail must happen before the store to the output tail.
+       addi            t0, INP, 16
+       addi            t1, OUTP, 16
+       vmv.v.v         TMP3, TMP0
+       vsetvli         zero, TAIL_LEN, e8, m1, tu, ma
+       vle8.v          TMP0, (t0)
+       vse8.v          TMP3, (t1)
+
+       // Encrypt/decrypt again and store the last full block.
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vxor.vv         TMP0, TMP0, TMP2
+       aes_crypt       TMP0, \enc, \keylen
+       vxor.vv         TMP0, TMP0, TMP2
+       vse32.v         TMP0, (OUTP)
+
+       ret
+.endm
+
+.macro aes_xts_crypt   enc
+
+       // Check whether the length is a multiple of the AES block size.
+       andi            TAIL_LEN, LEN, 15
+       beqz            TAIL_LEN, 1f
+
+       // The length isn't a multiple of the AES block size, so ciphertext
+       // stealing will be required.  Ciphertext stealing involves special
+       // handling of the partial block and the last full block, so subtract
+       // the length of both from the length to be processed in the main loop.
+       sub             LEN, LEN, TAIL_LEN
+       addi            LEN, LEN, -16
+1:
+       srli            LEN32, LEN, 2
+       // LEN and LEN32 now contain the total length of the blocks that will be
+       // processed in the main loop, in bytes and 32-bit words respectively.
+
+       xts_init
+       aes_begin       KEYP, 128f, 192f
+       __aes_xts_crypt \enc, 256
+128:
+       __aes_xts_crypt \enc, 128
+192:
+       __aes_xts_crypt \enc, 192
+.endm
+
+// void aes_xts_encrypt_zvkned_zvbb_zvkg(const struct crypto_aes_ctx *key,
+//                                      const u8 *in, u8 *out, size_t len,
+//                                      u8 tweak[16]);
+//
+// |key| is the data key.  |tweak| contains the next tweak; the encryption of
+// the original IV with the tweak key was already done.  This function supports
+// incremental computation, but |len| must always be >= 16 (AES_BLOCK_SIZE), and
+// |len| must be a multiple of 16 except on the last call.  If |len| is a
+// multiple of 16, then this function updates |tweak| to contain the next tweak.
+SYM_FUNC_START(aes_xts_encrypt_zvkned_zvbb_zvkg)
+       aes_xts_crypt   1
+SYM_FUNC_END(aes_xts_encrypt_zvkned_zvbb_zvkg)
+
+// Same prototype and calling convention as the encryption function
+SYM_FUNC_START(aes_xts_decrypt_zvkned_zvbb_zvkg)
+       aes_xts_crypt   0
+SYM_FUNC_END(aes_xts_decrypt_zvkned_zvbb_zvkg)
diff --git a/arch/riscv/crypto/aes-riscv64-zvkned-zvkb.S b/arch/riscv/crypto/aes-riscv64-zvkned-zvkb.S
new file mode 100644 (file)
index 0000000..9962d45
--- /dev/null
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector AES block cipher extension ('Zvkned')
+// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvkned, +zvkb
+
+#include "aes-macros.S"
+
+#define KEYP           a0
+#define INP            a1
+#define OUTP           a2
+#define LEN            a3
+#define IVP            a4
+
+#define LEN32          a5
+#define VL_E32         a6
+#define VL_BLOCKS      a7
+
+.macro aes_ctr32_crypt keylen
+       // LEN32 = number of blocks, rounded up, in 32-bit words.
+       addi            t0, LEN, 15
+       srli            t0, t0, 4
+       slli            LEN32, t0, 2
+
+       // Create a mask that selects the last 32-bit word of each 128-bit
+       // block.  This is the word that contains the (big-endian) counter.
+       li              t0, 0x88
+       vsetvli         t1, zero, e8, m1, ta, ma
+       vmv.v.x         v0, t0
+
+       // Load the IV into v31.  The last 32-bit word contains the counter.
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vle32.v         v31, (IVP)
+
+       // Convert the big-endian counter into little-endian.
+       vsetivli        zero, 4, e32, m1, ta, mu
+       vrev8.v         v31, v31, v0.t
+
+       // Splat the IV to v16 (with LMUL=4).  The number of copies is the
+       // maximum number of blocks that will be processed per iteration.
+       vsetvli         zero, LEN32, e32, m4, ta, ma
+       vmv.v.i         v16, 0
+       vaesz.vs        v16, v31
+
+       // v20 = [x, x, x, 0, x, x, x, 1, ...]
+       viota.m         v20, v0, v0.t
+       // v16 = [IV0, IV1, IV2, counter+0, IV0, IV1, IV2, counter+1, ...]
+       vsetvli         VL_E32, LEN32, e32, m4, ta, mu
+       vadd.vv         v16, v16, v20, v0.t
+
+       j 2f
+1:
+       // Set the number of blocks to process in this iteration.  vl=VL_E32 is
+       // the length in 32-bit words, i.e. 4 times the number of blocks.
+       vsetvli         VL_E32, LEN32, e32, m4, ta, mu
+
+       // Increment the counters by the number of blocks processed in the
+       // previous iteration.
+       vadd.vx         v16, v16, VL_BLOCKS, v0.t
+2:
+       // Prepare the AES inputs into v24.
+       vmv.v.v         v24, v16
+       vrev8.v         v24, v24, v0.t  // Convert counters back to big-endian.
+
+       // Encrypt the AES inputs to create the next portion of the keystream.
+       aes_encrypt     v24, \keylen
+
+       // XOR the data with the keystream.
+       vsetvli         t0, LEN, e8, m4, ta, ma
+       vle8.v          v20, (INP)
+       vxor.vv         v20, v20, v24
+       vse8.v          v20, (OUTP)
+
+       // Advance the pointers and update the remaining length.
+       add             INP, INP, t0
+       add             OUTP, OUTP, t0
+       sub             LEN, LEN, t0
+       sub             LEN32, LEN32, VL_E32
+       srli            VL_BLOCKS, VL_E32, 2
+
+       // Repeat if more data remains.
+       bnez            LEN, 1b
+
+       // Update *IVP to contain the next counter.
+       vsetivli        zero, 4, e32, m1, ta, mu
+       vadd.vx         v16, v16, VL_BLOCKS, v0.t
+       vrev8.v         v16, v16, v0.t  // Convert counters back to big-endian.
+       vse32.v         v16, (IVP)
+
+       ret
+.endm
+
+// void aes_ctr32_crypt_zvkned_zvkb(const struct crypto_aes_ctx *key,
+//                                 const u8 *in, u8 *out, size_t len,
+//                                 u8 iv[16]);
+SYM_FUNC_START(aes_ctr32_crypt_zvkned_zvkb)
+       aes_begin       KEYP, 128f, 192f
+       aes_ctr32_crypt 256
+128:
+       aes_ctr32_crypt 128
+192:
+       aes_ctr32_crypt 192
+SYM_FUNC_END(aes_ctr32_crypt_zvkned_zvkb)
diff --git a/arch/riscv/crypto/aes-riscv64-zvkned.S b/arch/riscv/crypto/aes-riscv64-zvkned.S
new file mode 100644 (file)
index 0000000..23d063f
--- /dev/null
@@ -0,0 +1,339 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com>
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector AES block cipher extension ('Zvkned')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvkned
+
+#include "aes-macros.S"
+
+#define KEYP           a0
+#define INP            a1
+#define OUTP           a2
+#define LEN            a3
+#define IVP            a4
+
+.macro __aes_crypt_zvkned      enc, keylen
+       vle32.v         v16, (INP)
+       aes_crypt       v16, \enc, \keylen
+       vse32.v         v16, (OUTP)
+       ret
+.endm
+
+.macro aes_crypt_zvkned        enc
+       aes_begin       KEYP, 128f, 192f
+       __aes_crypt_zvkned      \enc, 256
+128:
+       __aes_crypt_zvkned      \enc, 128
+192:
+       __aes_crypt_zvkned      \enc, 192
+.endm
+
+// void aes_encrypt_zvkned(const struct crypto_aes_ctx *key,
+//                        const u8 in[16], u8 out[16]);
+SYM_FUNC_START(aes_encrypt_zvkned)
+       aes_crypt_zvkned        1
+SYM_FUNC_END(aes_encrypt_zvkned)
+
+// Same prototype and calling convention as the encryption function
+SYM_FUNC_START(aes_decrypt_zvkned)
+       aes_crypt_zvkned        0
+SYM_FUNC_END(aes_decrypt_zvkned)
+
+.macro __aes_ecb_crypt enc, keylen
+       srli            t0, LEN, 2
+       // t0 is the remaining length in 32-bit words.  It's a multiple of 4.
+1:
+       vsetvli         t1, t0, e32, m8, ta, ma
+       sub             t0, t0, t1      // Subtract number of words processed
+       slli            t1, t1, 2       // Words to bytes
+       vle32.v         v16, (INP)
+       aes_crypt       v16, \enc, \keylen
+       vse32.v         v16, (OUTP)
+       add             INP, INP, t1
+       add             OUTP, OUTP, t1
+       bnez            t0, 1b
+
+       ret
+.endm
+
+.macro aes_ecb_crypt   enc
+       aes_begin       KEYP, 128f, 192f
+       __aes_ecb_crypt \enc, 256
+128:
+       __aes_ecb_crypt \enc, 128
+192:
+       __aes_ecb_crypt \enc, 192
+.endm
+
+// void aes_ecb_encrypt_zvkned(const struct crypto_aes_ctx *key,
+//                            const u8 *in, u8 *out, size_t len);
+//
+// |len| must be nonzero and a multiple of 16 (AES_BLOCK_SIZE).
+SYM_FUNC_START(aes_ecb_encrypt_zvkned)
+       aes_ecb_crypt   1
+SYM_FUNC_END(aes_ecb_encrypt_zvkned)
+
+// Same prototype and calling convention as the encryption function
+SYM_FUNC_START(aes_ecb_decrypt_zvkned)
+       aes_ecb_crypt   0
+SYM_FUNC_END(aes_ecb_decrypt_zvkned)
+
+.macro aes_cbc_encrypt keylen
+       vle32.v         v16, (IVP)      // Load IV
+1:
+       vle32.v         v17, (INP)      // Load plaintext block
+       vxor.vv         v16, v16, v17   // XOR with IV or prev ciphertext block
+       aes_encrypt     v16, \keylen    // Encrypt
+       vse32.v         v16, (OUTP)     // Store ciphertext block
+       addi            INP, INP, 16
+       addi            OUTP, OUTP, 16
+       addi            LEN, LEN, -16
+       bnez            LEN, 1b
+
+       vse32.v         v16, (IVP)      // Store next IV
+       ret
+.endm
+
+.macro aes_cbc_decrypt keylen
+       srli            LEN, LEN, 2     // Convert LEN from bytes to words
+       vle32.v         v16, (IVP)      // Load IV
+1:
+       vsetvli         t0, LEN, e32, m4, ta, ma
+       vle32.v         v20, (INP)      // Load ciphertext blocks
+       vslideup.vi     v16, v20, 4     // Setup prev ciphertext blocks
+       addi            t1, t0, -4
+       vslidedown.vx   v24, v20, t1    // Save last ciphertext block
+       aes_decrypt     v20, \keylen    // Decrypt the blocks
+       vxor.vv         v20, v20, v16   // XOR with prev ciphertext blocks
+       vse32.v         v20, (OUTP)     // Store plaintext blocks
+       vmv.v.v         v16, v24        // Next "IV" is last ciphertext block
+       slli            t1, t0, 2       // Words to bytes
+       add             INP, INP, t1
+       add             OUTP, OUTP, t1
+       sub             LEN, LEN, t0
+       bnez            LEN, 1b
+
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vse32.v         v16, (IVP)      // Store next IV
+       ret
+.endm
+
+// void aes_cbc_encrypt_zvkned(const struct crypto_aes_ctx *key,
+//                            const u8 *in, u8 *out, size_t len, u8 iv[16]);
+//
+// |len| must be nonzero and a multiple of 16 (AES_BLOCK_SIZE).
+SYM_FUNC_START(aes_cbc_encrypt_zvkned)
+       aes_begin       KEYP, 128f, 192f
+       aes_cbc_encrypt 256
+128:
+       aes_cbc_encrypt 128
+192:
+       aes_cbc_encrypt 192
+SYM_FUNC_END(aes_cbc_encrypt_zvkned)
+
+// Same prototype and calling convention as the encryption function
+SYM_FUNC_START(aes_cbc_decrypt_zvkned)
+       aes_begin       KEYP, 128f, 192f
+       aes_cbc_decrypt 256
+128:
+       aes_cbc_decrypt 128
+192:
+       aes_cbc_decrypt 192
+SYM_FUNC_END(aes_cbc_decrypt_zvkned)
+
+.macro aes_cbc_cts_encrypt     keylen
+
+       // CBC-encrypt all blocks except the last.  But don't store the
+       // second-to-last block to the output buffer yet, since it will be
+       // handled specially in the ciphertext stealing step.  Exception: if the
+       // message is single-block, still encrypt the last (and only) block.
+       li              t0, 16
+       j               2f
+1:
+       vse32.v         v16, (OUTP)     // Store ciphertext block
+       addi            OUTP, OUTP, 16
+2:
+       vle32.v         v17, (INP)      // Load plaintext block
+       vxor.vv         v16, v16, v17   // XOR with IV or prev ciphertext block
+       aes_encrypt     v16, \keylen    // Encrypt
+       addi            INP, INP, 16
+       addi            LEN, LEN, -16
+       bgt             LEN, t0, 1b     // Repeat if more than one block remains
+
+       // Special case: if the message is a single block, just do CBC.
+       beqz            LEN, .Lcts_encrypt_done\@
+
+       // Encrypt the last two blocks using ciphertext stealing as follows:
+       //      C[n-1] = Encrypt(Encrypt(P[n-1] ^ C[n-2]) ^ P[n])
+       //      C[n] = Encrypt(P[n-1] ^ C[n-2])[0..LEN]
+       //
+       // C[i] denotes the i'th ciphertext block, and likewise P[i] the i'th
+       // plaintext block.  Block n, the last block, may be partial; its length
+       // is 1 <= LEN <= 16.  If there are only 2 blocks, C[n-2] means the IV.
+       //
+       // v16 already contains Encrypt(P[n-1] ^ C[n-2]).
+       // INP points to P[n].  OUTP points to where C[n-1] should go.
+       // To support in-place encryption, load P[n] before storing C[n].
+       addi            t0, OUTP, 16    // Get pointer to where C[n] should go
+       vsetvli         zero, LEN, e8, m1, tu, ma
+       vle8.v          v17, (INP)      // Load P[n]
+       vse8.v          v16, (t0)       // Store C[n]
+       vxor.vv         v16, v16, v17   // v16 = Encrypt(P[n-1] ^ C[n-2]) ^ P[n]
+       vsetivli        zero, 4, e32, m1, ta, ma
+       aes_encrypt     v16, \keylen
+.Lcts_encrypt_done\@:
+       vse32.v         v16, (OUTP)     // Store C[n-1] (or C[n] in single-block case)
+       ret
+.endm
+
+#define LEN32          t4 // Length of remaining full blocks in 32-bit words
+#define LEN_MOD16      t5 // Length of message in bytes mod 16
+
+.macro aes_cbc_cts_decrypt     keylen
+       andi            LEN32, LEN, ~15
+       srli            LEN32, LEN32, 2
+       andi            LEN_MOD16, LEN, 15
+
+       // Save C[n-2] in v28 so that it's available later during the ciphertext
+       // stealing step.  If there are fewer than three blocks, C[n-2] means
+       // the IV, otherwise it means the third-to-last ciphertext block.
+       vmv.v.v         v28, v16        // IV
+       add             t0, LEN, -33
+       bltz            t0, .Lcts_decrypt_loop\@
+       andi            t0, t0, ~15
+       add             t0, t0, INP
+       vle32.v         v28, (t0)
+
+       // CBC-decrypt all full blocks.  For the last full block, or the last 2
+       // full blocks if the message is block-aligned, this doesn't write the
+       // correct output blocks (unless the message is only a single block),
+       // because it XORs the wrong values with the raw AES plaintexts.  But we
+       // fix this after this loop without redoing the AES decryptions.  This
+       // approach allows more of the AES decryptions to be parallelized.
+.Lcts_decrypt_loop\@:
+       vsetvli         t0, LEN32, e32, m4, ta, ma
+       addi            t1, t0, -4
+       vle32.v         v20, (INP)      // Load next set of ciphertext blocks
+       vmv.v.v         v24, v16        // Get IV or last ciphertext block of prev set
+       vslideup.vi     v24, v20, 4     // Setup prev ciphertext blocks
+       vslidedown.vx   v16, v20, t1    // Save last ciphertext block of this set
+       aes_decrypt     v20, \keylen    // Decrypt this set of blocks
+       vxor.vv         v24, v24, v20   // XOR prev ciphertext blocks with decrypted blocks
+       vse32.v         v24, (OUTP)     // Store this set of plaintext blocks
+       sub             LEN32, LEN32, t0
+       slli            t0, t0, 2       // Words to bytes
+       add             INP, INP, t0
+       add             OUTP, OUTP, t0
+       bnez            LEN32, .Lcts_decrypt_loop\@
+
+       vsetivli        zero, 4, e32, m4, ta, ma
+       vslidedown.vx   v20, v20, t1    // Extract raw plaintext of last full block
+       addi            t0, OUTP, -16   // Get pointer to last full plaintext block
+       bnez            LEN_MOD16, .Lcts_decrypt_non_block_aligned\@
+
+       // Special case: if the message is a single block, just do CBC.
+       li              t1, 16
+       beq             LEN, t1, .Lcts_decrypt_done\@
+
+       // Block-aligned message.  Just fix up the last 2 blocks.  We need:
+       //
+       //      P[n-1] = Decrypt(C[n]) ^ C[n-2]
+       //      P[n] = Decrypt(C[n-1]) ^ C[n]
+       //
+       // We have C[n] in v16, Decrypt(C[n]) in v20, and C[n-2] in v28.
+       // Together with Decrypt(C[n-1]) ^ C[n-2] from the output buffer, this
+       // is everything needed to fix the output without re-decrypting blocks.
+       addi            t1, OUTP, -32   // Get pointer to where P[n-1] should go
+       vxor.vv         v20, v20, v28   // Decrypt(C[n]) ^ C[n-2] == P[n-1]
+       vle32.v         v24, (t1)       // Decrypt(C[n-1]) ^ C[n-2]
+       vse32.v         v20, (t1)       // Store P[n-1]
+       vxor.vv         v20, v24, v16   // Decrypt(C[n-1]) ^ C[n-2] ^ C[n] == P[n] ^ C[n-2]
+       j               .Lcts_decrypt_finish\@
+
+.Lcts_decrypt_non_block_aligned\@:
+       // Decrypt the last two blocks using ciphertext stealing as follows:
+       //
+       //      P[n-1] = Decrypt(C[n] || Decrypt(C[n-1])[LEN_MOD16..16]) ^ C[n-2]
+       //      P[n] = (Decrypt(C[n-1]) ^ C[n])[0..LEN_MOD16]
+       //
+       // We already have Decrypt(C[n-1]) in v20 and C[n-2] in v28.
+       vmv.v.v         v16, v20        // v16 = Decrypt(C[n-1])
+       vsetvli         zero, LEN_MOD16, e8, m1, tu, ma
+       vle8.v          v20, (INP)      // v20 = C[n] || Decrypt(C[n-1])[LEN_MOD16..16]
+       vxor.vv         v16, v16, v20   // v16 = Decrypt(C[n-1]) ^ C[n]
+       vse8.v          v16, (OUTP)     // Store P[n]
+       vsetivli        zero, 4, e32, m1, ta, ma
+       aes_decrypt     v20, \keylen    // v20 = Decrypt(C[n] || Decrypt(C[n-1])[LEN_MOD16..16])
+.Lcts_decrypt_finish\@:
+       vxor.vv         v20, v20, v28   // XOR with C[n-2]
+       vse32.v         v20, (t0)       // Store last full plaintext block
+.Lcts_decrypt_done\@:
+       ret
+.endm
+
+.macro aes_cbc_cts_crypt       keylen
+       vle32.v         v16, (IVP)      // Load IV
+       beqz            a5, .Lcts_decrypt\@
+       aes_cbc_cts_encrypt \keylen
+.Lcts_decrypt\@:
+       aes_cbc_cts_decrypt \keylen
+.endm
+
+// void aes_cbc_cts_crypt_zvkned(const struct crypto_aes_ctx *key,
+//                              const u8 *in, u8 *out, size_t len,
+//                              const u8 iv[16], bool enc);
+//
+// Encrypts or decrypts a message with the CS3 variant of AES-CBC-CTS.
+// This is the variant that unconditionally swaps the last two blocks.
+SYM_FUNC_START(aes_cbc_cts_crypt_zvkned)
+       aes_begin       KEYP, 128f, 192f
+       aes_cbc_cts_crypt 256
+128:
+       aes_cbc_cts_crypt 128
+192:
+       aes_cbc_cts_crypt 192
+SYM_FUNC_END(aes_cbc_cts_crypt_zvkned)
diff --git a/arch/riscv/crypto/chacha-riscv64-glue.c b/arch/riscv/crypto/chacha-riscv64-glue.c
new file mode 100644 (file)
index 0000000..10b46f3
--- /dev/null
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ChaCha20 using the RISC-V vector crypto extensions
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/internal/chacha.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+asmlinkage void chacha20_zvkb(const u32 key[8], const u8 *in, u8 *out,
+                             size_t len, const u32 iv[4]);
+
+static int riscv64_chacha20_crypt(struct skcipher_request *req)
+{
+       u32 iv[CHACHA_IV_SIZE / sizeof(u32)];
+       u8 block_buffer[CHACHA_BLOCK_SIZE];
+       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+       const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
+       struct skcipher_walk walk;
+       unsigned int nbytes;
+       unsigned int tail_bytes;
+       int err;
+
+       iv[0] = get_unaligned_le32(req->iv);
+       iv[1] = get_unaligned_le32(req->iv + 4);
+       iv[2] = get_unaligned_le32(req->iv + 8);
+       iv[3] = get_unaligned_le32(req->iv + 12);
+
+       err = skcipher_walk_virt(&walk, req, false);
+       while (walk.nbytes) {
+               nbytes = walk.nbytes & ~(CHACHA_BLOCK_SIZE - 1);
+               tail_bytes = walk.nbytes & (CHACHA_BLOCK_SIZE - 1);
+               kernel_vector_begin();
+               if (nbytes) {
+                       chacha20_zvkb(ctx->key, walk.src.virt.addr,
+                                     walk.dst.virt.addr, nbytes, iv);
+                       iv[0] += nbytes / CHACHA_BLOCK_SIZE;
+               }
+               if (walk.nbytes == walk.total && tail_bytes > 0) {
+                       memcpy(block_buffer, walk.src.virt.addr + nbytes,
+                              tail_bytes);
+                       chacha20_zvkb(ctx->key, block_buffer, block_buffer,
+                                     CHACHA_BLOCK_SIZE, iv);
+                       memcpy(walk.dst.virt.addr + nbytes, block_buffer,
+                              tail_bytes);
+                       tail_bytes = 0;
+               }
+               kernel_vector_end();
+
+               err = skcipher_walk_done(&walk, tail_bytes);
+       }
+
+       return err;
+}
+
+static struct skcipher_alg riscv64_chacha_alg = {
+       .setkey = chacha20_setkey,
+       .encrypt = riscv64_chacha20_crypt,
+       .decrypt = riscv64_chacha20_crypt,
+       .min_keysize = CHACHA_KEY_SIZE,
+       .max_keysize = CHACHA_KEY_SIZE,
+       .ivsize = CHACHA_IV_SIZE,
+       .chunksize = CHACHA_BLOCK_SIZE,
+       .walksize = 4 * CHACHA_BLOCK_SIZE,
+       .base = {
+               .cra_blocksize = 1,
+               .cra_ctxsize = sizeof(struct chacha_ctx),
+               .cra_priority = 300,
+               .cra_name = "chacha20",
+               .cra_driver_name = "chacha20-riscv64-zvkb",
+               .cra_module = THIS_MODULE,
+       },
+};
+
+static int __init riscv64_chacha_mod_init(void)
+{
+       if (riscv_isa_extension_available(NULL, ZVKB) &&
+           riscv_vector_vlen() >= 128)
+               return crypto_register_skcipher(&riscv64_chacha_alg);
+
+       return -ENODEV;
+}
+
+static void __exit riscv64_chacha_mod_exit(void)
+{
+       crypto_unregister_skcipher(&riscv64_chacha_alg);
+}
+
+module_init(riscv64_chacha_mod_init);
+module_exit(riscv64_chacha_mod_exit);
+
+MODULE_DESCRIPTION("ChaCha20 (RISC-V accelerated)");
+MODULE_AUTHOR("Jerry Shih <jerry.shih@sifive.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("chacha20");
diff --git a/arch/riscv/crypto/chacha-riscv64-zvkb.S b/arch/riscv/crypto/chacha-riscv64-zvkb.S
new file mode 100644 (file)
index 0000000..bf05773
--- /dev/null
@@ -0,0 +1,294 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvkb
+
+#define KEYP           a0
+#define INP            a1
+#define OUTP           a2
+#define LEN            a3
+#define IVP            a4
+
+#define CONSTS0                a5
+#define CONSTS1                a6
+#define CONSTS2                a7
+#define CONSTS3                t0
+#define TMP            t1
+#define VL             t2
+#define STRIDE         t3
+#define NROUNDS                t4
+#define KEY0           s0
+#define KEY1           s1
+#define KEY2           s2
+#define KEY3           s3
+#define KEY4           s4
+#define KEY5           s5
+#define KEY6           s6
+#define KEY7           s7
+#define COUNTER                s8
+#define NONCE0         s9
+#define NONCE1         s10
+#define NONCE2         s11
+
+.macro chacha_round    a0, b0, c0, d0,  a1, b1, c1, d1, \
+                       a2, b2, c2, d2,  a3, b3, c3, d3
+       // a += b; d ^= a; d = rol(d, 16);
+       vadd.vv         \a0, \a0, \b0
+       vadd.vv         \a1, \a1, \b1
+       vadd.vv         \a2, \a2, \b2
+       vadd.vv         \a3, \a3, \b3
+       vxor.vv         \d0, \d0, \a0
+       vxor.vv         \d1, \d1, \a1
+       vxor.vv         \d2, \d2, \a2
+       vxor.vv         \d3, \d3, \a3
+       vror.vi         \d0, \d0, 32 - 16
+       vror.vi         \d1, \d1, 32 - 16
+       vror.vi         \d2, \d2, 32 - 16
+       vror.vi         \d3, \d3, 32 - 16
+
+       // c += d; b ^= c; b = rol(b, 12);
+       vadd.vv         \c0, \c0, \d0
+       vadd.vv         \c1, \c1, \d1
+       vadd.vv         \c2, \c2, \d2
+       vadd.vv         \c3, \c3, \d3
+       vxor.vv         \b0, \b0, \c0
+       vxor.vv         \b1, \b1, \c1
+       vxor.vv         \b2, \b2, \c2
+       vxor.vv         \b3, \b3, \c3
+       vror.vi         \b0, \b0, 32 - 12
+       vror.vi         \b1, \b1, 32 - 12
+       vror.vi         \b2, \b2, 32 - 12
+       vror.vi         \b3, \b3, 32 - 12
+
+       // a += b; d ^= a; d = rol(d, 8);
+       vadd.vv         \a0, \a0, \b0
+       vadd.vv         \a1, \a1, \b1
+       vadd.vv         \a2, \a2, \b2
+       vadd.vv         \a3, \a3, \b3
+       vxor.vv         \d0, \d0, \a0
+       vxor.vv         \d1, \d1, \a1
+       vxor.vv         \d2, \d2, \a2
+       vxor.vv         \d3, \d3, \a3
+       vror.vi         \d0, \d0, 32 - 8
+       vror.vi         \d1, \d1, 32 - 8
+       vror.vi         \d2, \d2, 32 - 8
+       vror.vi         \d3, \d3, 32 - 8
+
+       // c += d; b ^= c; b = rol(b, 7);
+       vadd.vv         \c0, \c0, \d0
+       vadd.vv         \c1, \c1, \d1
+       vadd.vv         \c2, \c2, \d2
+       vadd.vv         \c3, \c3, \d3
+       vxor.vv         \b0, \b0, \c0
+       vxor.vv         \b1, \b1, \c1
+       vxor.vv         \b2, \b2, \c2
+       vxor.vv         \b3, \b3, \c3
+       vror.vi         \b0, \b0, 32 - 7
+       vror.vi         \b1, \b1, 32 - 7
+       vror.vi         \b2, \b2, 32 - 7
+       vror.vi         \b3, \b3, 32 - 7
+.endm
+
+// void chacha20_zvkb(const u32 key[8], const u8 *in, u8 *out, size_t len,
+//                   const u32 iv[4]);
+//
+// |len| must be nonzero and a multiple of 64 (CHACHA_BLOCK_SIZE).
+// The counter is treated as 32-bit, following the RFC7539 convention.
+SYM_FUNC_START(chacha20_zvkb)
+       srli            LEN, LEN, 6     // Bytes to blocks
+
+       addi            sp, sp, -96
+       sd              s0, 0(sp)
+       sd              s1, 8(sp)
+       sd              s2, 16(sp)
+       sd              s3, 24(sp)
+       sd              s4, 32(sp)
+       sd              s5, 40(sp)
+       sd              s6, 48(sp)
+       sd              s7, 56(sp)
+       sd              s8, 64(sp)
+       sd              s9, 72(sp)
+       sd              s10, 80(sp)
+       sd              s11, 88(sp)
+
+       li              STRIDE, 64
+
+       // Set up the initial state matrix in scalar registers.
+       li              CONSTS0, 0x61707865     // "expa" little endian
+       li              CONSTS1, 0x3320646e     // "nd 3" little endian
+       li              CONSTS2, 0x79622d32     // "2-by" little endian
+       li              CONSTS3, 0x6b206574     // "te k" little endian
+       lw              KEY0, 0(KEYP)
+       lw              KEY1, 4(KEYP)
+       lw              KEY2, 8(KEYP)
+       lw              KEY3, 12(KEYP)
+       lw              KEY4, 16(KEYP)
+       lw              KEY5, 20(KEYP)
+       lw              KEY6, 24(KEYP)
+       lw              KEY7, 28(KEYP)
+       lw              COUNTER, 0(IVP)
+       lw              NONCE0, 4(IVP)
+       lw              NONCE1, 8(IVP)
+       lw              NONCE2, 12(IVP)
+
+.Lblock_loop:
+       // Set vl to the number of blocks to process in this iteration.
+       vsetvli         VL, LEN, e32, m1, ta, ma
+
+       // Set up the initial state matrix for the next VL blocks in v0-v15.
+       // v{i} holds the i'th 32-bit word of the state matrix for all blocks.
+       // Note that only the counter word, at index 12, differs across blocks.
+       vmv.v.x         v0, CONSTS0
+       vmv.v.x         v1, CONSTS1
+       vmv.v.x         v2, CONSTS2
+       vmv.v.x         v3, CONSTS3
+       vmv.v.x         v4, KEY0
+       vmv.v.x         v5, KEY1
+       vmv.v.x         v6, KEY2
+       vmv.v.x         v7, KEY3
+       vmv.v.x         v8, KEY4
+       vmv.v.x         v9, KEY5
+       vmv.v.x         v10, KEY6
+       vmv.v.x         v11, KEY7
+       vid.v           v12
+       vadd.vx         v12, v12, COUNTER
+       vmv.v.x         v13, NONCE0
+       vmv.v.x         v14, NONCE1
+       vmv.v.x         v15, NONCE2
+
+       // Load the first half of the input data for each block into v16-v23.
+       // v{16+i} holds the i'th 32-bit word for all blocks.
+       vlsseg8e32.v    v16, (INP), STRIDE
+
+       li              NROUNDS, 20
+.Lnext_doubleround:
+       addi            NROUNDS, NROUNDS, -2
+       // column round
+       chacha_round    v0, v4, v8, v12, v1, v5, v9, v13, \
+                       v2, v6, v10, v14, v3, v7, v11, v15
+       // diagonal round
+       chacha_round    v0, v5, v10, v15, v1, v6, v11, v12, \
+                       v2, v7, v8, v13, v3, v4, v9, v14
+       bnez            NROUNDS, .Lnext_doubleround
+
+       // Load the second half of the input data for each block into v24-v31.
+       // v{24+i} holds the {8+i}'th 32-bit word for all blocks.
+       addi            TMP, INP, 32
+       vlsseg8e32.v    v24, (TMP), STRIDE
+
+       // Finalize the first half of the keystream for each block.
+       vadd.vx         v0, v0, CONSTS0
+       vadd.vx         v1, v1, CONSTS1
+       vadd.vx         v2, v2, CONSTS2
+       vadd.vx         v3, v3, CONSTS3
+       vadd.vx         v4, v4, KEY0
+       vadd.vx         v5, v5, KEY1
+       vadd.vx         v6, v6, KEY2
+       vadd.vx         v7, v7, KEY3
+
+       // Encrypt/decrypt the first half of the data for each block.
+       vxor.vv         v16, v16, v0
+       vxor.vv         v17, v17, v1
+       vxor.vv         v18, v18, v2
+       vxor.vv         v19, v19, v3
+       vxor.vv         v20, v20, v4
+       vxor.vv         v21, v21, v5
+       vxor.vv         v22, v22, v6
+       vxor.vv         v23, v23, v7
+
+       // Store the first half of the output data for each block.
+       vssseg8e32.v    v16, (OUTP), STRIDE
+
+       // Finalize the second half of the keystream for each block.
+       vadd.vx         v8, v8, KEY4
+       vadd.vx         v9, v9, KEY5
+       vadd.vx         v10, v10, KEY6
+       vadd.vx         v11, v11, KEY7
+       vid.v           v0
+       vadd.vx         v12, v12, COUNTER
+       vadd.vx         v13, v13, NONCE0
+       vadd.vx         v14, v14, NONCE1
+       vadd.vx         v15, v15, NONCE2
+       vadd.vv         v12, v12, v0
+
+       // Encrypt/decrypt the second half of the data for each block.
+       vxor.vv         v24, v24, v8
+       vxor.vv         v25, v25, v9
+       vxor.vv         v26, v26, v10
+       vxor.vv         v27, v27, v11
+       vxor.vv         v29, v29, v13
+       vxor.vv         v28, v28, v12
+       vxor.vv         v30, v30, v14
+       vxor.vv         v31, v31, v15
+
+       // Store the second half of the output data for each block.
+       addi            TMP, OUTP, 32
+       vssseg8e32.v    v24, (TMP), STRIDE
+
+       // Update the counter, the remaining number of blocks, and the input and
+       // output pointers according to the number of blocks processed (VL).
+       add             COUNTER, COUNTER, VL
+       sub             LEN, LEN, VL
+       slli            TMP, VL, 6
+       add             OUTP, OUTP, TMP
+       add             INP, INP, TMP
+       bnez            LEN, .Lblock_loop
+
+       ld              s0, 0(sp)
+       ld              s1, 8(sp)
+       ld              s2, 16(sp)
+       ld              s3, 24(sp)
+       ld              s4, 32(sp)
+       ld              s5, 40(sp)
+       ld              s6, 48(sp)
+       ld              s7, 56(sp)
+       ld              s8, 64(sp)
+       ld              s9, 72(sp)
+       ld              s10, 80(sp)
+       ld              s11, 88(sp)
+       addi            sp, sp, 96
+       ret
+SYM_FUNC_END(chacha20_zvkb)
diff --git a/arch/riscv/crypto/ghash-riscv64-glue.c b/arch/riscv/crypto/ghash-riscv64-glue.c
new file mode 100644 (file)
index 0000000..312e789
--- /dev/null
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * GHASH using the RISC-V vector crypto extensions
+ *
+ * Copyright (C) 2023 VRULL GmbH
+ * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/ghash.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/simd.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+asmlinkage void ghash_zvkg(be128 *accumulator, const be128 *key, const u8 *data,
+                          size_t len);
+
+struct riscv64_ghash_tfm_ctx {
+       be128 key;
+};
+
+struct riscv64_ghash_desc_ctx {
+       be128 accumulator;
+       u8 buffer[GHASH_BLOCK_SIZE];
+       u32 bytes;
+};
+
+static int riscv64_ghash_setkey(struct crypto_shash *tfm, const u8 *key,
+                               unsigned int keylen)
+{
+       struct riscv64_ghash_tfm_ctx *tctx = crypto_shash_ctx(tfm);
+
+       if (keylen != GHASH_BLOCK_SIZE)
+               return -EINVAL;
+
+       memcpy(&tctx->key, key, GHASH_BLOCK_SIZE);
+
+       return 0;
+}
+
+static int riscv64_ghash_init(struct shash_desc *desc)
+{
+       struct riscv64_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+       *dctx = (struct riscv64_ghash_desc_ctx){};
+
+       return 0;
+}
+
+static inline void
+riscv64_ghash_blocks(const struct riscv64_ghash_tfm_ctx *tctx,
+                    struct riscv64_ghash_desc_ctx *dctx,
+                    const u8 *src, size_t srclen)
+{
+       /* The srclen is nonzero and a multiple of 16. */
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               ghash_zvkg(&dctx->accumulator, &tctx->key, src, srclen);
+               kernel_vector_end();
+       } else {
+               do {
+                       crypto_xor((u8 *)&dctx->accumulator, src,
+                                  GHASH_BLOCK_SIZE);
+                       gf128mul_lle(&dctx->accumulator, &tctx->key);
+                       src += GHASH_BLOCK_SIZE;
+                       srclen -= GHASH_BLOCK_SIZE;
+               } while (srclen);
+       }
+}
+
+static int riscv64_ghash_update(struct shash_desc *desc, const u8 *src,
+                               unsigned int srclen)
+{
+       const struct riscv64_ghash_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+       struct riscv64_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+       unsigned int len;
+
+       if (dctx->bytes) {
+               if (dctx->bytes + srclen < GHASH_BLOCK_SIZE) {
+                       memcpy(dctx->buffer + dctx->bytes, src, srclen);
+                       dctx->bytes += srclen;
+                       return 0;
+               }
+               memcpy(dctx->buffer + dctx->bytes, src,
+                      GHASH_BLOCK_SIZE - dctx->bytes);
+               riscv64_ghash_blocks(tctx, dctx, dctx->buffer,
+                                    GHASH_BLOCK_SIZE);
+               src += GHASH_BLOCK_SIZE - dctx->bytes;
+               srclen -= GHASH_BLOCK_SIZE - dctx->bytes;
+               dctx->bytes = 0;
+       }
+
+       len = round_down(srclen, GHASH_BLOCK_SIZE);
+       if (len) {
+               riscv64_ghash_blocks(tctx, dctx, src, len);
+               src += len;
+               srclen -= len;
+       }
+
+       if (srclen) {
+               memcpy(dctx->buffer, src, srclen);
+               dctx->bytes = srclen;
+       }
+
+       return 0;
+}
+
+static int riscv64_ghash_final(struct shash_desc *desc, u8 *out)
+{
+       const struct riscv64_ghash_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
+       struct riscv64_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+       int i;
+
+       if (dctx->bytes) {
+               for (i = dctx->bytes; i < GHASH_BLOCK_SIZE; i++)
+                       dctx->buffer[i] = 0;
+
+               riscv64_ghash_blocks(tctx, dctx, dctx->buffer,
+                                    GHASH_BLOCK_SIZE);
+       }
+
+       memcpy(out, &dctx->accumulator, GHASH_DIGEST_SIZE);
+       return 0;
+}
+
+static struct shash_alg riscv64_ghash_alg = {
+       .init = riscv64_ghash_init,
+       .update = riscv64_ghash_update,
+       .final = riscv64_ghash_final,
+       .setkey = riscv64_ghash_setkey,
+       .descsize = sizeof(struct riscv64_ghash_desc_ctx),
+       .digestsize = GHASH_DIGEST_SIZE,
+       .base = {
+               .cra_blocksize = GHASH_BLOCK_SIZE,
+               .cra_ctxsize = sizeof(struct riscv64_ghash_tfm_ctx),
+               .cra_priority = 300,
+               .cra_name = "ghash",
+               .cra_driver_name = "ghash-riscv64-zvkg",
+               .cra_module = THIS_MODULE,
+       },
+};
+
+static int __init riscv64_ghash_mod_init(void)
+{
+       if (riscv_isa_extension_available(NULL, ZVKG) &&
+           riscv_vector_vlen() >= 128)
+               return crypto_register_shash(&riscv64_ghash_alg);
+
+       return -ENODEV;
+}
+
+static void __exit riscv64_ghash_mod_exit(void)
+{
+       crypto_unregister_shash(&riscv64_ghash_alg);
+}
+
+module_init(riscv64_ghash_mod_init);
+module_exit(riscv64_ghash_mod_exit);
+
+MODULE_DESCRIPTION("GHASH (RISC-V accelerated)");
+MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@vrull.eu>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("ghash");
diff --git a/arch/riscv/crypto/ghash-riscv64-zvkg.S b/arch/riscv/crypto/ghash-riscv64-zvkg.S
new file mode 100644 (file)
index 0000000..f2b43fb
--- /dev/null
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector GCM/GMAC extension ('Zvkg')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvkg
+
+#define ACCUMULATOR    a0
+#define KEY            a1
+#define DATA           a2
+#define LEN            a3
+
+// void ghash_zvkg(be128 *accumulator, const be128 *key, const u8 *data,
+//                size_t len);
+//
+// |len| must be nonzero and a multiple of 16 (GHASH_BLOCK_SIZE).
+SYM_FUNC_START(ghash_zvkg)
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vle32.v         v1, (ACCUMULATOR)
+       vle32.v         v2, (KEY)
+.Lnext_block:
+       vle32.v         v3, (DATA)
+       vghsh.vv        v1, v2, v3
+       addi            DATA, DATA, 16
+       addi            LEN, LEN, -16
+       bnez            LEN, .Lnext_block
+
+       vse32.v         v1, (ACCUMULATOR)
+       ret
+SYM_FUNC_END(ghash_zvkg)
diff --git a/arch/riscv/crypto/sha256-riscv64-glue.c b/arch/riscv/crypto/sha256-riscv64-glue.c
new file mode 100644 (file)
index 0000000..71e051e
--- /dev/null
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SHA-256 and SHA-224 using the RISC-V vector crypto extensions
+ *
+ * Copyright (C) 2022 VRULL GmbH
+ * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/simd.h>
+#include <crypto/sha256_base.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+/*
+ * Note: the asm function only uses the 'state' field of struct sha256_state.
+ * It is assumed to be the first field.
+ */
+asmlinkage void sha256_transform_zvknha_or_zvknhb_zvkb(
+       struct sha256_state *state, const u8 *data, int num_blocks);
+
+static int riscv64_sha256_update(struct shash_desc *desc, const u8 *data,
+                                unsigned int len)
+{
+       /*
+        * Ensure struct sha256_state begins directly with the SHA-256
+        * 256-bit internal state, as this is what the asm function expects.
+        */
+       BUILD_BUG_ON(offsetof(struct sha256_state, state) != 0);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               sha256_base_do_update(desc, data, len,
+                                     sha256_transform_zvknha_or_zvknhb_zvkb);
+               kernel_vector_end();
+       } else {
+               crypto_sha256_update(desc, data, len);
+       }
+       return 0;
+}
+
+static int riscv64_sha256_finup(struct shash_desc *desc, const u8 *data,
+                               unsigned int len, u8 *out)
+{
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               if (len)
+                       sha256_base_do_update(
+                               desc, data, len,
+                               sha256_transform_zvknha_or_zvknhb_zvkb);
+               sha256_base_do_finalize(
+                       desc, sha256_transform_zvknha_or_zvknhb_zvkb);
+               kernel_vector_end();
+
+               return sha256_base_finish(desc, out);
+       }
+
+       return crypto_sha256_finup(desc, data, len, out);
+}
+
+static int riscv64_sha256_final(struct shash_desc *desc, u8 *out)
+{
+       return riscv64_sha256_finup(desc, NULL, 0, out);
+}
+
+static int riscv64_sha256_digest(struct shash_desc *desc, const u8 *data,
+                                unsigned int len, u8 *out)
+{
+       return sha256_base_init(desc) ?:
+              riscv64_sha256_finup(desc, data, len, out);
+}
+
+static struct shash_alg riscv64_sha256_algs[] = {
+       {
+               .init = sha256_base_init,
+               .update = riscv64_sha256_update,
+               .final = riscv64_sha256_final,
+               .finup = riscv64_sha256_finup,
+               .digest = riscv64_sha256_digest,
+               .descsize = sizeof(struct sha256_state),
+               .digestsize = SHA256_DIGEST_SIZE,
+               .base = {
+                       .cra_blocksize = SHA256_BLOCK_SIZE,
+                       .cra_priority = 300,
+                       .cra_name = "sha256",
+                       .cra_driver_name = "sha256-riscv64-zvknha_or_zvknhb-zvkb",
+                       .cra_module = THIS_MODULE,
+               },
+       }, {
+               .init = sha224_base_init,
+               .update = riscv64_sha256_update,
+               .final = riscv64_sha256_final,
+               .finup = riscv64_sha256_finup,
+               .descsize = sizeof(struct sha256_state),
+               .digestsize = SHA224_DIGEST_SIZE,
+               .base = {
+                       .cra_blocksize = SHA224_BLOCK_SIZE,
+                       .cra_priority = 300,
+                       .cra_name = "sha224",
+                       .cra_driver_name = "sha224-riscv64-zvknha_or_zvknhb-zvkb",
+                       .cra_module = THIS_MODULE,
+               },
+       },
+};
+
+static int __init riscv64_sha256_mod_init(void)
+{
+       /* Both zvknha and zvknhb provide the SHA-256 instructions. */
+       if ((riscv_isa_extension_available(NULL, ZVKNHA) ||
+            riscv_isa_extension_available(NULL, ZVKNHB)) &&
+           riscv_isa_extension_available(NULL, ZVKB) &&
+           riscv_vector_vlen() >= 128)
+               return crypto_register_shashes(riscv64_sha256_algs,
+                                              ARRAY_SIZE(riscv64_sha256_algs));
+
+       return -ENODEV;
+}
+
+static void __exit riscv64_sha256_mod_exit(void)
+{
+       crypto_unregister_shashes(riscv64_sha256_algs,
+                                 ARRAY_SIZE(riscv64_sha256_algs));
+}
+
+module_init(riscv64_sha256_mod_init);
+module_exit(riscv64_sha256_mod_exit);
+
+MODULE_DESCRIPTION("SHA-256 (RISC-V accelerated)");
+MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@vrull.eu>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("sha256");
+MODULE_ALIAS_CRYPTO("sha224");
diff --git a/arch/riscv/crypto/sha256-riscv64-zvknha_or_zvknhb-zvkb.S b/arch/riscv/crypto/sha256-riscv64-zvknha_or_zvknhb-zvkb.S
new file mode 100644 (file)
index 0000000..8ebcc17
--- /dev/null
@@ -0,0 +1,225 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector SHA-2 Secure Hash extension ('Zvknha' or 'Zvknhb')
+// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
+
+#include <linux/cfi_types.h>
+
+.text
+.option arch, +zvknha, +zvkb
+
+#define STATEP         a0
+#define DATA           a1
+#define NUM_BLOCKS     a2
+
+#define STATEP_C       a3
+
+#define MASK           v0
+#define INDICES                v1
+#define W0             v2
+#define W1             v3
+#define W2             v4
+#define W3             v5
+#define VTMP           v6
+#define FEBA           v7
+#define HGDC           v8
+#define K0             v10
+#define K1             v11
+#define K2             v12
+#define K3             v13
+#define K4             v14
+#define K5             v15
+#define K6             v16
+#define K7             v17
+#define K8             v18
+#define K9             v19
+#define K10            v20
+#define K11            v21
+#define K12            v22
+#define K13            v23
+#define K14            v24
+#define K15            v25
+#define PREV_FEBA      v26
+#define PREV_HGDC      v27
+
+// Do 4 rounds of SHA-256.  w0 contains the current 4 message schedule words.
+//
+// If not all the message schedule words have been computed yet, then this also
+// computes 4 more message schedule words.  w1-w3 contain the next 3 groups of 4
+// message schedule words; this macro computes the group after w3 and writes it
+// to w0.  This means that the next (w0, w1, w2, w3) is the current (w1, w2, w3,
+// w0), so the caller must cycle through the registers accordingly.
+.macro sha256_4rounds  last, k, w0, w1, w2, w3
+       vadd.vv         VTMP, \k, \w0
+       vsha2cl.vv      HGDC, FEBA, VTMP
+       vsha2ch.vv      FEBA, HGDC, VTMP
+.if !\last
+       vmerge.vvm      VTMP, \w2, \w1, MASK
+       vsha2ms.vv      \w0, VTMP, \w3
+.endif
+.endm
+
+.macro sha256_16rounds last, k0, k1, k2, k3
+       sha256_4rounds  \last, \k0, W0, W1, W2, W3
+       sha256_4rounds  \last, \k1, W1, W2, W3, W0
+       sha256_4rounds  \last, \k2, W2, W3, W0, W1
+       sha256_4rounds  \last, \k3, W3, W0, W1, W2
+.endm
+
+// void sha256_transform_zvknha_or_zvknhb_zvkb(u32 state[8], const u8 *data,
+//                                            int num_blocks);
+SYM_TYPED_FUNC_START(sha256_transform_zvknha_or_zvknhb_zvkb)
+
+       // Load the round constants into K0-K15.
+       vsetivli        zero, 4, e32, m1, ta, ma
+       la              t0, K256
+       vle32.v         K0, (t0)
+       addi            t0, t0, 16
+       vle32.v         K1, (t0)
+       addi            t0, t0, 16
+       vle32.v         K2, (t0)
+       addi            t0, t0, 16
+       vle32.v         K3, (t0)
+       addi            t0, t0, 16
+       vle32.v         K4, (t0)
+       addi            t0, t0, 16
+       vle32.v         K5, (t0)
+       addi            t0, t0, 16
+       vle32.v         K6, (t0)
+       addi            t0, t0, 16
+       vle32.v         K7, (t0)
+       addi            t0, t0, 16
+       vle32.v         K8, (t0)
+       addi            t0, t0, 16
+       vle32.v         K9, (t0)
+       addi            t0, t0, 16
+       vle32.v         K10, (t0)
+       addi            t0, t0, 16
+       vle32.v         K11, (t0)
+       addi            t0, t0, 16
+       vle32.v         K12, (t0)
+       addi            t0, t0, 16
+       vle32.v         K13, (t0)
+       addi            t0, t0, 16
+       vle32.v         K14, (t0)
+       addi            t0, t0, 16
+       vle32.v         K15, (t0)
+
+       // Setup mask for the vmerge to replace the first word (idx==0) in
+       // message scheduling.  There are 4 words, so an 8-bit mask suffices.
+       vsetivli        zero, 1, e8, m1, ta, ma
+       vmv.v.i         MASK, 0x01
+
+       // Load the state.  The state is stored as {a,b,c,d,e,f,g,h}, but we
+       // need {f,e,b,a},{h,g,d,c}.  The dst vtype is e32m1 and the index vtype
+       // is e8mf4.  We use index-load with the i8 indices {20, 16, 4, 0},
+       // loaded using the 32-bit little endian value 0x00041014.
+       li              t0, 0x00041014
+       vsetivli        zero, 1, e32, m1, ta, ma
+       vmv.v.x         INDICES, t0
+       addi            STATEP_C, STATEP, 8
+       vsetivli        zero, 4, e32, m1, ta, ma
+       vluxei8.v       FEBA, (STATEP), INDICES
+       vluxei8.v       HGDC, (STATEP_C), INDICES
+
+.Lnext_block:
+       addi            NUM_BLOCKS, NUM_BLOCKS, -1
+
+       // Save the previous state, as it's needed later.
+       vmv.v.v         PREV_FEBA, FEBA
+       vmv.v.v         PREV_HGDC, HGDC
+
+       // Load the next 512-bit message block and endian-swap each 32-bit word.
+       vle32.v         W0, (DATA)
+       vrev8.v         W0, W0
+       addi            DATA, DATA, 16
+       vle32.v         W1, (DATA)
+       vrev8.v         W1, W1
+       addi            DATA, DATA, 16
+       vle32.v         W2, (DATA)
+       vrev8.v         W2, W2
+       addi            DATA, DATA, 16
+       vle32.v         W3, (DATA)
+       vrev8.v         W3, W3
+       addi            DATA, DATA, 16
+
+       // Do the 64 rounds of SHA-256.
+       sha256_16rounds 0, K0, K1, K2, K3
+       sha256_16rounds 0, K4, K5, K6, K7
+       sha256_16rounds 0, K8, K9, K10, K11
+       sha256_16rounds 1, K12, K13, K14, K15
+
+       // Add the previous state.
+       vadd.vv         FEBA, FEBA, PREV_FEBA
+       vadd.vv         HGDC, HGDC, PREV_HGDC
+
+       // Repeat if more blocks remain.
+       bnez            NUM_BLOCKS, .Lnext_block
+
+       // Store the new state and return.
+       vsuxei8.v       FEBA, (STATEP), INDICES
+       vsuxei8.v       HGDC, (STATEP_C), INDICES
+       ret
+SYM_FUNC_END(sha256_transform_zvknha_or_zvknhb_zvkb)
+
+.section ".rodata"
+.p2align 2
+.type K256, @object
+K256:
+       .word           0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5
+       .word           0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5
+       .word           0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3
+       .word           0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174
+       .word           0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc
+       .word           0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da
+       .word           0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7
+       .word           0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967
+       .word           0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13
+       .word           0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85
+       .word           0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3
+       .word           0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070
+       .word           0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5
+       .word           0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3
+       .word           0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208
+       .word           0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+.size K256, . - K256
diff --git a/arch/riscv/crypto/sha512-riscv64-glue.c b/arch/riscv/crypto/sha512-riscv64-glue.c
new file mode 100644 (file)
index 0000000..43b56a0
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SHA-512 and SHA-384 using the RISC-V vector crypto extensions
+ *
+ * Copyright (C) 2023 VRULL GmbH
+ * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/simd.h>
+#include <crypto/sha512_base.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+/*
+ * Note: the asm function only uses the 'state' field of struct sha512_state.
+ * It is assumed to be the first field.
+ */
+asmlinkage void sha512_transform_zvknhb_zvkb(
+       struct sha512_state *state, const u8 *data, int num_blocks);
+
+static int riscv64_sha512_update(struct shash_desc *desc, const u8 *data,
+                                unsigned int len)
+{
+       /*
+        * Ensure struct sha512_state begins directly with the SHA-512
+        * 512-bit internal state, as this is what the asm function expects.
+        */
+       BUILD_BUG_ON(offsetof(struct sha512_state, state) != 0);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               sha512_base_do_update(desc, data, len,
+                                     sha512_transform_zvknhb_zvkb);
+               kernel_vector_end();
+       } else {
+               crypto_sha512_update(desc, data, len);
+       }
+       return 0;
+}
+
+static int riscv64_sha512_finup(struct shash_desc *desc, const u8 *data,
+                               unsigned int len, u8 *out)
+{
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               if (len)
+                       sha512_base_do_update(desc, data, len,
+                                             sha512_transform_zvknhb_zvkb);
+               sha512_base_do_finalize(desc, sha512_transform_zvknhb_zvkb);
+               kernel_vector_end();
+
+               return sha512_base_finish(desc, out);
+       }
+
+       return crypto_sha512_finup(desc, data, len, out);
+}
+
+static int riscv64_sha512_final(struct shash_desc *desc, u8 *out)
+{
+       return riscv64_sha512_finup(desc, NULL, 0, out);
+}
+
+static int riscv64_sha512_digest(struct shash_desc *desc, const u8 *data,
+                                unsigned int len, u8 *out)
+{
+       return sha512_base_init(desc) ?:
+              riscv64_sha512_finup(desc, data, len, out);
+}
+
+static struct shash_alg riscv64_sha512_algs[] = {
+       {
+               .init = sha512_base_init,
+               .update = riscv64_sha512_update,
+               .final = riscv64_sha512_final,
+               .finup = riscv64_sha512_finup,
+               .digest = riscv64_sha512_digest,
+               .descsize = sizeof(struct sha512_state),
+               .digestsize = SHA512_DIGEST_SIZE,
+               .base = {
+                       .cra_blocksize = SHA512_BLOCK_SIZE,
+                       .cra_priority = 300,
+                       .cra_name = "sha512",
+                       .cra_driver_name = "sha512-riscv64-zvknhb-zvkb",
+                       .cra_module = THIS_MODULE,
+               },
+       }, {
+               .init = sha384_base_init,
+               .update = riscv64_sha512_update,
+               .final = riscv64_sha512_final,
+               .finup = riscv64_sha512_finup,
+               .descsize = sizeof(struct sha512_state),
+               .digestsize = SHA384_DIGEST_SIZE,
+               .base = {
+                       .cra_blocksize = SHA384_BLOCK_SIZE,
+                       .cra_priority = 300,
+                       .cra_name = "sha384",
+                       .cra_driver_name = "sha384-riscv64-zvknhb-zvkb",
+                       .cra_module = THIS_MODULE,
+               },
+       },
+};
+
+static int __init riscv64_sha512_mod_init(void)
+{
+       if (riscv_isa_extension_available(NULL, ZVKNHB) &&
+           riscv_isa_extension_available(NULL, ZVKB) &&
+           riscv_vector_vlen() >= 128)
+               return crypto_register_shashes(riscv64_sha512_algs,
+                                              ARRAY_SIZE(riscv64_sha512_algs));
+
+       return -ENODEV;
+}
+
+static void __exit riscv64_sha512_mod_exit(void)
+{
+       crypto_unregister_shashes(riscv64_sha512_algs,
+                                 ARRAY_SIZE(riscv64_sha512_algs));
+}
+
+module_init(riscv64_sha512_mod_init);
+module_exit(riscv64_sha512_mod_exit);
+
+MODULE_DESCRIPTION("SHA-512 (RISC-V accelerated)");
+MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@vrull.eu>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("sha512");
+MODULE_ALIAS_CRYPTO("sha384");
diff --git a/arch/riscv/crypto/sha512-riscv64-zvknhb-zvkb.S b/arch/riscv/crypto/sha512-riscv64-zvknhb-zvkb.S
new file mode 100644 (file)
index 0000000..3a9ae21
--- /dev/null
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Phoebe Chen <phoebe.chen@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector SHA-2 Secure Hash extension ('Zvknhb')
+// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
+
+#include <linux/cfi_types.h>
+
+.text
+.option arch, +zvknhb, +zvkb
+
+#define STATEP         a0
+#define DATA           a1
+#define NUM_BLOCKS     a2
+
+#define STATEP_C       a3
+#define K              a4
+
+#define MASK           v0
+#define INDICES                v1
+#define W0             v10     // LMUL=2
+#define W1             v12     // LMUL=2
+#define W2             v14     // LMUL=2
+#define W3             v16     // LMUL=2
+#define VTMP           v20     // LMUL=2
+#define FEBA           v22     // LMUL=2
+#define HGDC           v24     // LMUL=2
+#define PREV_FEBA      v26     // LMUL=2
+#define PREV_HGDC      v28     // LMUL=2
+
+// Do 4 rounds of SHA-512.  w0 contains the current 4 message schedule words.
+//
+// If not all the message schedule words have been computed yet, then this also
+// computes 4 more message schedule words.  w1-w3 contain the next 3 groups of 4
+// message schedule words; this macro computes the group after w3 and writes it
+// to w0.  This means that the next (w0, w1, w2, w3) is the current (w1, w2, w3,
+// w0), so the caller must cycle through the registers accordingly.
+.macro sha512_4rounds  last, w0, w1, w2, w3
+       vle64.v         VTMP, (K)
+       addi            K, K, 32
+       vadd.vv         VTMP, VTMP, \w0
+       vsha2cl.vv      HGDC, FEBA, VTMP
+       vsha2ch.vv      FEBA, HGDC, VTMP
+.if !\last
+       vmerge.vvm      VTMP, \w2, \w1, MASK
+       vsha2ms.vv      \w0, VTMP, \w3
+.endif
+.endm
+
+.macro sha512_16rounds last
+       sha512_4rounds  \last, W0, W1, W2, W3
+       sha512_4rounds  \last, W1, W2, W3, W0
+       sha512_4rounds  \last, W2, W3, W0, W1
+       sha512_4rounds  \last, W3, W0, W1, W2
+.endm
+
+// void sha512_transform_zvknhb_zvkb(u64 state[8], const u8 *data,
+//                                  int num_blocks);
+SYM_TYPED_FUNC_START(sha512_transform_zvknhb_zvkb)
+
+       // Setup mask for the vmerge to replace the first word (idx==0) in
+       // message scheduling.  There are 4 words, so an 8-bit mask suffices.
+       vsetivli        zero, 1, e8, m1, ta, ma
+       vmv.v.i         MASK, 0x01
+
+       // Load the state.  The state is stored as {a,b,c,d,e,f,g,h}, but we
+       // need {f,e,b,a},{h,g,d,c}.  The dst vtype is e64m2 and the index vtype
+       // is e8mf4.  We use index-load with the i8 indices {40, 32, 8, 0},
+       // loaded using the 32-bit little endian value 0x00082028.
+       li              t0, 0x00082028
+       vsetivli        zero, 1, e32, m1, ta, ma
+       vmv.v.x         INDICES, t0
+       addi            STATEP_C, STATEP, 16
+       vsetivli        zero, 4, e64, m2, ta, ma
+       vluxei8.v       FEBA, (STATEP), INDICES
+       vluxei8.v       HGDC, (STATEP_C), INDICES
+
+.Lnext_block:
+       la              K, K512
+       addi            NUM_BLOCKS, NUM_BLOCKS, -1
+
+       // Save the previous state, as it's needed later.
+       vmv.v.v         PREV_FEBA, FEBA
+       vmv.v.v         PREV_HGDC, HGDC
+
+       // Load the next 1024-bit message block and endian-swap each 64-bit word
+       vle64.v         W0, (DATA)
+       vrev8.v         W0, W0
+       addi            DATA, DATA, 32
+       vle64.v         W1, (DATA)
+       vrev8.v         W1, W1
+       addi            DATA, DATA, 32
+       vle64.v         W2, (DATA)
+       vrev8.v         W2, W2
+       addi            DATA, DATA, 32
+       vle64.v         W3, (DATA)
+       vrev8.v         W3, W3
+       addi            DATA, DATA, 32
+
+       // Do the 80 rounds of SHA-512.
+       sha512_16rounds 0
+       sha512_16rounds 0
+       sha512_16rounds 0
+       sha512_16rounds 0
+       sha512_16rounds 1
+
+       // Add the previous state.
+       vadd.vv         FEBA, FEBA, PREV_FEBA
+       vadd.vv         HGDC, HGDC, PREV_HGDC
+
+       // Repeat if more blocks remain.
+       bnez            NUM_BLOCKS, .Lnext_block
+
+       // Store the new state and return.
+       vsuxei8.v       FEBA, (STATEP), INDICES
+       vsuxei8.v       HGDC, (STATEP_C), INDICES
+       ret
+SYM_FUNC_END(sha512_transform_zvknhb_zvkb)
+
+.section ".rodata"
+.p2align 3
+.type K512, @object
+K512:
+       .dword          0x428a2f98d728ae22, 0x7137449123ef65cd
+       .dword          0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc
+       .dword          0x3956c25bf348b538, 0x59f111f1b605d019
+       .dword          0x923f82a4af194f9b, 0xab1c5ed5da6d8118
+       .dword          0xd807aa98a3030242, 0x12835b0145706fbe
+       .dword          0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2
+       .dword          0x72be5d74f27b896f, 0x80deb1fe3b1696b1
+       .dword          0x9bdc06a725c71235, 0xc19bf174cf692694
+       .dword          0xe49b69c19ef14ad2, 0xefbe4786384f25e3
+       .dword          0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65
+       .dword          0x2de92c6f592b0275, 0x4a7484aa6ea6e483
+       .dword          0x5cb0a9dcbd41fbd4, 0x76f988da831153b5
+       .dword          0x983e5152ee66dfab, 0xa831c66d2db43210
+       .dword          0xb00327c898fb213f, 0xbf597fc7beef0ee4
+       .dword          0xc6e00bf33da88fc2, 0xd5a79147930aa725
+       .dword          0x06ca6351e003826f, 0x142929670a0e6e70
+       .dword          0x27b70a8546d22ffc, 0x2e1b21385c26c926
+       .dword          0x4d2c6dfc5ac42aed, 0x53380d139d95b3df
+       .dword          0x650a73548baf63de, 0x766a0abb3c77b2a8
+       .dword          0x81c2c92e47edaee6, 0x92722c851482353b
+       .dword          0xa2bfe8a14cf10364, 0xa81a664bbc423001
+       .dword          0xc24b8b70d0f89791, 0xc76c51a30654be30
+       .dword          0xd192e819d6ef5218, 0xd69906245565a910
+       .dword          0xf40e35855771202a, 0x106aa07032bbd1b8
+       .dword          0x19a4c116b8d2d0c8, 0x1e376c085141ab53
+       .dword          0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8
+       .dword          0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb
+       .dword          0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3
+       .dword          0x748f82ee5defb2fc, 0x78a5636f43172f60
+       .dword          0x84c87814a1f0ab72, 0x8cc702081a6439ec
+       .dword          0x90befffa23631e28, 0xa4506cebde82bde9
+       .dword          0xbef9a3f7b2c67915, 0xc67178f2e372532b
+       .dword          0xca273eceea26619c, 0xd186b8c721c0c207
+       .dword          0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178
+       .dword          0x06f067aa72176fba, 0x0a637dc5a2c898a6
+       .dword          0x113f9804bef90dae, 0x1b710b35131c471b
+       .dword          0x28db77f523047d84, 0x32caab7b40c72493
+       .dword          0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c
+       .dword          0x4cc5d4becb3e42b6, 0x597f299cfc657e2a
+       .dword          0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+.size K512, . - K512
diff --git a/arch/riscv/crypto/sm3-riscv64-glue.c b/arch/riscv/crypto/sm3-riscv64-glue.c
new file mode 100644 (file)
index 0000000..e1737a9
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SM3 using the RISC-V vector crypto extensions
+ *
+ * Copyright (C) 2023 VRULL GmbH
+ * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/simd.h>
+#include <crypto/sm3_base.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+/*
+ * Note: the asm function only uses the 'state' field of struct sm3_state.
+ * It is assumed to be the first field.
+ */
+asmlinkage void sm3_transform_zvksh_zvkb(
+       struct sm3_state *state, const u8 *data, int num_blocks);
+
+static int riscv64_sm3_update(struct shash_desc *desc, const u8 *data,
+                             unsigned int len)
+{
+       /*
+        * Ensure struct sm3_state begins directly with the SM3
+        * 256-bit internal state, as this is what the asm function expects.
+        */
+       BUILD_BUG_ON(offsetof(struct sm3_state, state) != 0);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               sm3_base_do_update(desc, data, len, sm3_transform_zvksh_zvkb);
+               kernel_vector_end();
+       } else {
+               sm3_update(shash_desc_ctx(desc), data, len);
+       }
+       return 0;
+}
+
+static int riscv64_sm3_finup(struct shash_desc *desc, const u8 *data,
+                            unsigned int len, u8 *out)
+{
+       struct sm3_state *ctx;
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               if (len)
+                       sm3_base_do_update(desc, data, len,
+                                          sm3_transform_zvksh_zvkb);
+               sm3_base_do_finalize(desc, sm3_transform_zvksh_zvkb);
+               kernel_vector_end();
+
+               return sm3_base_finish(desc, out);
+       }
+
+       ctx = shash_desc_ctx(desc);
+       if (len)
+               sm3_update(ctx, data, len);
+       sm3_final(ctx, out);
+
+       return 0;
+}
+
+static int riscv64_sm3_final(struct shash_desc *desc, u8 *out)
+{
+       return riscv64_sm3_finup(desc, NULL, 0, out);
+}
+
+static struct shash_alg riscv64_sm3_alg = {
+       .init = sm3_base_init,
+       .update = riscv64_sm3_update,
+       .final = riscv64_sm3_final,
+       .finup = riscv64_sm3_finup,
+       .descsize = sizeof(struct sm3_state),
+       .digestsize = SM3_DIGEST_SIZE,
+       .base = {
+               .cra_blocksize = SM3_BLOCK_SIZE,
+               .cra_priority = 300,
+               .cra_name = "sm3",
+               .cra_driver_name = "sm3-riscv64-zvksh-zvkb",
+               .cra_module = THIS_MODULE,
+       },
+};
+
+static int __init riscv64_sm3_mod_init(void)
+{
+       if (riscv_isa_extension_available(NULL, ZVKSH) &&
+           riscv_isa_extension_available(NULL, ZVKB) &&
+           riscv_vector_vlen() >= 128)
+               return crypto_register_shash(&riscv64_sm3_alg);
+
+       return -ENODEV;
+}
+
+static void __exit riscv64_sm3_mod_exit(void)
+{
+       crypto_unregister_shash(&riscv64_sm3_alg);
+}
+
+module_init(riscv64_sm3_mod_init);
+module_exit(riscv64_sm3_mod_exit);
+
+MODULE_DESCRIPTION("SM3 (RISC-V accelerated)");
+MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@vrull.eu>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("sm3");
diff --git a/arch/riscv/crypto/sm3-riscv64-zvksh-zvkb.S b/arch/riscv/crypto/sm3-riscv64-zvksh-zvkb.S
new file mode 100644 (file)
index 0000000..a2b65d9
--- /dev/null
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector SM3 Secure Hash extension ('Zvksh')
+// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
+
+#include <linux/cfi_types.h>
+
+.text
+.option arch, +zvksh, +zvkb
+
+#define STATEP         a0
+#define DATA           a1
+#define NUM_BLOCKS     a2
+
+#define STATE          v0      // LMUL=2
+#define PREV_STATE     v2      // LMUL=2
+#define W0             v4      // LMUL=2
+#define W1             v6      // LMUL=2
+#define VTMP           v8      // LMUL=2
+
+.macro sm3_8rounds     i, w0, w1
+       // Do 4 rounds using W_{0+i}..W_{7+i}.
+       vsm3c.vi        STATE, \w0, \i + 0
+       vslidedown.vi   VTMP, \w0, 2
+       vsm3c.vi        STATE, VTMP, \i + 1
+
+       // Compute W_{4+i}..W_{11+i}.
+       vslidedown.vi   VTMP, \w0, 4
+       vslideup.vi     VTMP, \w1, 4
+
+       // Do 4 rounds using W_{4+i}..W_{11+i}.
+       vsm3c.vi        STATE, VTMP, \i + 2
+       vslidedown.vi   VTMP, VTMP, 2
+       vsm3c.vi        STATE, VTMP, \i + 3
+
+.if \i < 28
+       // Compute W_{16+i}..W_{23+i}.
+       vsm3me.vv       \w0, \w1, \w0
+.endif
+       // For the next 8 rounds, w0 and w1 are swapped.
+.endm
+
+// void sm3_transform_zvksh_zvkb(u32 state[8], const u8 *data, int num_blocks);
+SYM_TYPED_FUNC_START(sm3_transform_zvksh_zvkb)
+
+       // Load the state and endian-swap each 32-bit word.
+       vsetivli        zero, 8, e32, m2, ta, ma
+       vle32.v         STATE, (STATEP)
+       vrev8.v         STATE, STATE
+
+.Lnext_block:
+       addi            NUM_BLOCKS, NUM_BLOCKS, -1
+
+       // Save the previous state, as it's needed later.
+       vmv.v.v         PREV_STATE, STATE
+
+       // Load the next 512-bit message block into W0-W1.
+       vle32.v         W0, (DATA)
+       addi            DATA, DATA, 32
+       vle32.v         W1, (DATA)
+       addi            DATA, DATA, 32
+
+       // Do the 64 rounds of SM3.
+       sm3_8rounds     0, W0, W1
+       sm3_8rounds     4, W1, W0
+       sm3_8rounds     8, W0, W1
+       sm3_8rounds     12, W1, W0
+       sm3_8rounds     16, W0, W1
+       sm3_8rounds     20, W1, W0
+       sm3_8rounds     24, W0, W1
+       sm3_8rounds     28, W1, W0
+
+       // XOR in the previous state.
+       vxor.vv         STATE, STATE, PREV_STATE
+
+       // Repeat if more blocks remain.
+       bnez            NUM_BLOCKS, .Lnext_block
+
+       // Store the new state and return.
+       vrev8.v         STATE, STATE
+       vse32.v         STATE, (STATEP)
+       ret
+SYM_FUNC_END(sm3_transform_zvksh_zvkb)
diff --git a/arch/riscv/crypto/sm4-riscv64-glue.c b/arch/riscv/crypto/sm4-riscv64-glue.c
new file mode 100644 (file)
index 0000000..47fb84e
--- /dev/null
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SM4 using the RISC-V vector crypto extensions
+ *
+ * Copyright (C) 2023 VRULL GmbH
+ * Author: Heiko Stuebner <heiko.stuebner@vrull.eu>
+ *
+ * Copyright (C) 2023 SiFive, Inc.
+ * Author: Jerry Shih <jerry.shih@sifive.com>
+ */
+
+#include <asm/simd.h>
+#include <asm/vector.h>
+#include <crypto/internal/cipher.h>
+#include <crypto/internal/simd.h>
+#include <crypto/sm4.h>
+#include <linux/linkage.h>
+#include <linux/module.h>
+
+asmlinkage void sm4_expandkey_zvksed_zvkb(const u8 user_key[SM4_KEY_SIZE],
+                                         u32 rkey_enc[SM4_RKEY_WORDS],
+                                         u32 rkey_dec[SM4_RKEY_WORDS]);
+asmlinkage void sm4_crypt_zvksed_zvkb(const u32 rkey[SM4_RKEY_WORDS],
+                                     const u8 in[SM4_BLOCK_SIZE],
+                                     u8 out[SM4_BLOCK_SIZE]);
+
+static int riscv64_sm4_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct sm4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (crypto_simd_usable()) {
+               if (keylen != SM4_KEY_SIZE)
+                       return -EINVAL;
+               kernel_vector_begin();
+               sm4_expandkey_zvksed_zvkb(key, ctx->rkey_enc, ctx->rkey_dec);
+               kernel_vector_end();
+               return 0;
+       }
+       return sm4_expandkey(ctx, key, keylen);
+}
+
+static void riscv64_sm4_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       const struct sm4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               sm4_crypt_zvksed_zvkb(ctx->rkey_enc, src, dst);
+               kernel_vector_end();
+       } else {
+               sm4_crypt_block(ctx->rkey_enc, dst, src);
+       }
+}
+
+static void riscv64_sm4_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       const struct sm4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (crypto_simd_usable()) {
+               kernel_vector_begin();
+               sm4_crypt_zvksed_zvkb(ctx->rkey_dec, src, dst);
+               kernel_vector_end();
+       } else {
+               sm4_crypt_block(ctx->rkey_dec, dst, src);
+       }
+}
+
+static struct crypto_alg riscv64_sm4_alg = {
+       .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize = SM4_BLOCK_SIZE,
+       .cra_ctxsize = sizeof(struct sm4_ctx),
+       .cra_priority = 300,
+       .cra_name = "sm4",
+       .cra_driver_name = "sm4-riscv64-zvksed-zvkb",
+       .cra_cipher = {
+               .cia_min_keysize = SM4_KEY_SIZE,
+               .cia_max_keysize = SM4_KEY_SIZE,
+               .cia_setkey = riscv64_sm4_setkey,
+               .cia_encrypt = riscv64_sm4_encrypt,
+               .cia_decrypt = riscv64_sm4_decrypt,
+       },
+       .cra_module = THIS_MODULE,
+};
+
+static int __init riscv64_sm4_mod_init(void)
+{
+       if (riscv_isa_extension_available(NULL, ZVKSED) &&
+           riscv_isa_extension_available(NULL, ZVKB) &&
+           riscv_vector_vlen() >= 128)
+               return crypto_register_alg(&riscv64_sm4_alg);
+
+       return -ENODEV;
+}
+
+static void __exit riscv64_sm4_mod_exit(void)
+{
+       crypto_unregister_alg(&riscv64_sm4_alg);
+}
+
+module_init(riscv64_sm4_mod_init);
+module_exit(riscv64_sm4_mod_exit);
+
+MODULE_DESCRIPTION("SM4 (RISC-V accelerated)");
+MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@vrull.eu>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("sm4");
diff --git a/arch/riscv/crypto/sm4-riscv64-zvksed-zvkb.S b/arch/riscv/crypto/sm4-riscv64-zvksed-zvkb.S
new file mode 100644 (file)
index 0000000..fae6217
--- /dev/null
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause */
+//
+// This file is dual-licensed, meaning that you can use it under your
+// choice of either of the following two licenses:
+//
+// Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the Apache License 2.0 (the "License"). You can obtain
+// a copy in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+//
+// or
+//
+// Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
+// Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
+// Copyright 2024 Google LLC
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The generated code of this file depends on the following RISC-V extensions:
+// - RV64I
+// - RISC-V Vector ('V') with VLEN >= 128
+// - RISC-V Vector SM4 Block Cipher extension ('Zvksed')
+// - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
+
+#include <linux/linkage.h>
+
+.text
+.option arch, +zvksed, +zvkb
+
+// void sm4_expandkey_zksed_zvkb(const u8 user_key[16], u32 rkey_enc[32],
+//                              u32 rkey_dec[32]);
+SYM_FUNC_START(sm4_expandkey_zvksed_zvkb)
+       vsetivli        zero, 4, e32, m1, ta, ma
+
+       // Load the user key.
+       vle32.v         v1, (a0)
+       vrev8.v         v1, v1
+
+       // XOR the user key with the family key.
+       la              t0, FAMILY_KEY
+       vle32.v         v2, (t0)
+       vxor.vv         v1, v1, v2
+
+       // Compute the round keys.  Store them in forwards order in rkey_enc
+       // and in reverse order in rkey_dec.
+       addi            a2, a2, 31*4
+       li              t0, -4
+       .set            i, 0
+.rept 8
+       vsm4k.vi        v1, v1, i
+       vse32.v         v1, (a1)        // Store to rkey_enc.
+       vsse32.v        v1, (a2), t0    // Store to rkey_dec.
+.if i < 7
+       addi            a1, a1, 16
+       addi            a2, a2, -16
+.endif
+       .set            i, i + 1
+.endr
+
+       ret
+SYM_FUNC_END(sm4_expandkey_zvksed_zvkb)
+
+// void sm4_crypt_zvksed_zvkb(const u32 rkey[32], const u8 in[16], u8 out[16]);
+SYM_FUNC_START(sm4_crypt_zvksed_zvkb)
+       vsetivli        zero, 4, e32, m1, ta, ma
+
+       // Load the input data.
+       vle32.v         v1, (a1)
+       vrev8.v         v1, v1
+
+       // Do the 32 rounds of SM4, 4 at a time.
+       .set            i, 0
+.rept 8
+       vle32.v         v2, (a0)
+       vsm4r.vs        v1, v2
+.if i < 7
+       addi            a0, a0, 16
+.endif
+       .set            i, i + 1
+.endr
+
+       // Store the output data (in reverse element order).
+       vrev8.v         v1, v1
+       li              t0, -4
+       addi            a2, a2, 12
+       vsse32.v        v1, (a2), t0
+
+       ret
+SYM_FUNC_END(sm4_crypt_zvksed_zvkb)
+
+.section ".rodata"
+.p2align 2
+.type FAMILY_KEY, @object
+FAMILY_KEY:
+       .word 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC
+.size FAMILY_KEY, . - FAMILY_KEY
index 17a90486972468fce5e85c9287f091da14a77e66..f2708a9494a10f0012ef7ac6068a8615b3efbced 100644 (file)
@@ -18,9 +18,9 @@
 #include <asm/sbi.h>
 #include <asm/vendorid_list.h>
 
-#define ANDESTECH_AX45MP_MARCHID       0x8000000000008a45UL
-#define ANDESTECH_AX45MP_MIMPID                0x500UL
-#define ANDESTECH_SBI_EXT_ANDES                0x0900031E
+#define ANDES_AX45MP_MARCHID           0x8000000000008a45UL
+#define ANDES_AX45MP_MIMPID            0x500UL
+#define ANDES_SBI_EXT_ANDES            0x0900031E
 
 #define ANDES_SBI_EXT_IOCP_SW_WORKAROUND       1
 
@@ -32,7 +32,7 @@ static long ax45mp_iocp_sw_workaround(void)
         * ANDES_SBI_EXT_IOCP_SW_WORKAROUND SBI EXT checks if the IOCP is missing and
         * cache is controllable only then CMO will be applied to the platform.
         */
-       ret = sbi_ecall(ANDESTECH_SBI_EXT_ANDES, ANDES_SBI_EXT_IOCP_SW_WORKAROUND,
+       ret = sbi_ecall(ANDES_SBI_EXT_ANDES, ANDES_SBI_EXT_IOCP_SW_WORKAROUND,
                        0, 0, 0, 0, 0, 0);
 
        return ret.error ? 0 : ret.value;
@@ -50,7 +50,7 @@ static void errata_probe_iocp(unsigned int stage, unsigned long arch_id, unsigne
 
        done = true;
 
-       if (arch_id != ANDESTECH_AX45MP_MARCHID || impid != ANDESTECH_AX45MP_MIMPID)
+       if (arch_id != ANDES_AX45MP_MARCHID || impid != ANDES_AX45MP_MIMPID)
                return;
 
        if (!ax45mp_iocp_sw_workaround())
index b0487b39e6747ae384fb51f310bf784759825240..776354895b81e7dc332e58265548aaf7365a6037 100644 (file)
        REG_L x31, PT_T6(sp)
        .endm
 
+/* Annotate a function as being unsuitable for kprobes. */
+#ifdef CONFIG_KPROBES
+#define ASM_NOKPROBE(name)                             \
+       .pushsection "_kprobe_blacklist", "aw";         \
+       RISCV_PTR name;                                 \
+       .popsection
+#else
+#define ASM_NOKPROBE(name)
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_RISCV_ASM_H */
index f5dfef6c2153f189288d3a4f3fa7a1d5d1b5021b..0e0522e588ca6e5378589e5c443c37e97cc5fa53 100644 (file)
@@ -17,7 +17,6 @@
 #endif
 
 #include <asm/cmpxchg.h>
-#include <asm/barrier.h>
 
 #define __atomic_acquire_fence()                                       \
        __asm__ __volatile__(RISCV_ACQUIRE_BARRIER "" ::: "memory")
@@ -207,7 +206,7 @@ static __always_inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int
                "       add      %[rc], %[p], %[a]\n"
                "       sc.w.rl  %[rc], %[rc], %[c]\n"
                "       bnez     %[rc], 0b\n"
-               "       fence    rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                : [a]"r" (a), [u]"r" (u)
@@ -228,7 +227,7 @@ static __always_inline s64 arch_atomic64_fetch_add_unless(atomic64_t *v, s64 a,
                "       add      %[rc], %[p], %[a]\n"
                "       sc.d.rl  %[rc], %[rc], %[c]\n"
                "       bnez     %[rc], 0b\n"
-               "       fence    rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                : [a]"r" (a), [u]"r" (u)
@@ -248,7 +247,7 @@ static __always_inline bool arch_atomic_inc_unless_negative(atomic_t *v)
                "       addi      %[rc], %[p], 1\n"
                "       sc.w.rl   %[rc], %[rc], %[c]\n"
                "       bnez      %[rc], 0b\n"
-               "       fence     rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                :
@@ -268,7 +267,7 @@ static __always_inline bool arch_atomic_dec_unless_positive(atomic_t *v)
                "       addi      %[rc], %[p], -1\n"
                "       sc.w.rl   %[rc], %[rc], %[c]\n"
                "       bnez      %[rc], 0b\n"
-               "       fence     rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                :
@@ -288,7 +287,7 @@ static __always_inline int arch_atomic_dec_if_positive(atomic_t *v)
                "       bltz     %[rc], 1f\n"
                "       sc.w.rl  %[rc], %[rc], %[c]\n"
                "       bnez     %[rc], 0b\n"
-               "       fence    rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                :
@@ -310,7 +309,7 @@ static __always_inline bool arch_atomic64_inc_unless_negative(atomic64_t *v)
                "       addi      %[rc], %[p], 1\n"
                "       sc.d.rl   %[rc], %[rc], %[c]\n"
                "       bnez      %[rc], 0b\n"
-               "       fence     rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                :
@@ -331,7 +330,7 @@ static __always_inline bool arch_atomic64_dec_unless_positive(atomic64_t *v)
                "       addi      %[rc], %[p], -1\n"
                "       sc.d.rl   %[rc], %[rc], %[c]\n"
                "       bnez      %[rc], 0b\n"
-               "       fence     rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                :
@@ -352,7 +351,7 @@ static __always_inline s64 arch_atomic64_dec_if_positive(atomic64_t *v)
                "       bltz     %[rc], 1f\n"
                "       sc.d.rl  %[rc], %[rc], %[c]\n"
                "       bnez     %[rc], 0b\n"
-               "       fence    rw, rw\n"
+               RISCV_FULL_BARRIER
                "1:\n"
                : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter)
                :
index 110752594228e23125bd7a16b4c0469cbfcda4f5..880b56d8480d19cb8038c366988a7369eeeaff4a 100644 (file)
 #define _ASM_RISCV_BARRIER_H
 
 #ifndef __ASSEMBLY__
+#include <asm/fence.h>
 
 #define nop()          __asm__ __volatile__ ("nop")
 #define __nops(n)      ".rept  " #n "\nnop\n.endr\n"
 #define nops(n)                __asm__ __volatile__ (__nops(n))
 
-#define RISCV_FENCE(p, s) \
-       __asm__ __volatile__ ("fence " #p "," #s : : : "memory")
 
 /* These barriers need to enforce ordering on both devices or memory. */
-#define mb()           RISCV_FENCE(iorw,iorw)
-#define rmb()          RISCV_FENCE(ir,ir)
-#define wmb()          RISCV_FENCE(ow,ow)
+#define __mb()         RISCV_FENCE(iorw, iorw)
+#define __rmb()                RISCV_FENCE(ir, ir)
+#define __wmb()                RISCV_FENCE(ow, ow)
 
 /* These barriers do not need to enforce ordering on devices, just memory. */
-#define __smp_mb()     RISCV_FENCE(rw,rw)
-#define __smp_rmb()    RISCV_FENCE(r,r)
-#define __smp_wmb()    RISCV_FENCE(w,w)
+#define __smp_mb()     RISCV_FENCE(rw, rw)
+#define __smp_rmb()    RISCV_FENCE(r, r)
+#define __smp_wmb()    RISCV_FENCE(w, w)
 
 #define __smp_store_release(p, v)                                      \
 do {                                                                   \
        compiletime_assert_atomic_type(*p);                             \
-       RISCV_FENCE(rw,w);                                              \
+       RISCV_FENCE(rw, w);                                             \
        WRITE_ONCE(*p, v);                                              \
 } while (0)
 
@@ -40,7 +39,7 @@ do {                                                                  \
 ({                                                                     \
        typeof(*p) ___p1 = READ_ONCE(*p);                               \
        compiletime_assert_atomic_type(*p);                             \
-       RISCV_FENCE(r,rw);                                              \
+       RISCV_FENCE(r, rw);                                             \
        ___p1;                                                          \
 })
 
@@ -69,7 +68,7 @@ do {                                                                  \
  * instances the scheduler pairs this with an mb(), so nothing is necessary on
  * the new hart.
  */
-#define smp_mb__after_spinlock()       RISCV_FENCE(iorw,iorw)
+#define smp_mb__after_spinlock()       RISCV_FENCE(iorw, iorw)
 
 #include <asm-generic/barrier.h>
 
index 329d8244a9b3fd516104808db5a959acfb469b22..880606b0469a83bc97d864da9235ce29b5807970 100644 (file)
 #include <asm-generic/bitops/fls.h>
 
 #else
+#define __HAVE_ARCH___FFS
+#define __HAVE_ARCH___FLS
+#define __HAVE_ARCH_FFS
+#define __HAVE_ARCH_FLS
+
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/fls.h>
+
 #include <asm/alternative-macros.h>
 #include <asm/hwcap.h>
 
@@ -37,8 +47,6 @@
 
 static __always_inline unsigned long variable__ffs(unsigned long word)
 {
-       int num;
-
        asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
                                      RISCV_ISA_EXT_ZBB, 1)
                          : : : : legacy);
@@ -52,32 +60,7 @@ static __always_inline unsigned long variable__ffs(unsigned long word)
        return word;
 
 legacy:
-       num = 0;
-#if BITS_PER_LONG == 64
-       if ((word & 0xffffffff) == 0) {
-               num += 32;
-               word >>= 32;
-       }
-#endif
-       if ((word & 0xffff) == 0) {
-               num += 16;
-               word >>= 16;
-       }
-       if ((word & 0xff) == 0) {
-               num += 8;
-               word >>= 8;
-       }
-       if ((word & 0xf) == 0) {
-               num += 4;
-               word >>= 4;
-       }
-       if ((word & 0x3) == 0) {
-               num += 2;
-               word >>= 2;
-       }
-       if ((word & 0x1) == 0)
-               num += 1;
-       return num;
+       return generic___ffs(word);
 }
 
 /**
@@ -93,8 +76,6 @@ legacy:
 
 static __always_inline unsigned long variable__fls(unsigned long word)
 {
-       int num;
-
        asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
                                      RISCV_ISA_EXT_ZBB, 1)
                          : : : : legacy);
@@ -108,32 +89,7 @@ static __always_inline unsigned long variable__fls(unsigned long word)
        return BITS_PER_LONG - 1 - word;
 
 legacy:
-       num = BITS_PER_LONG - 1;
-#if BITS_PER_LONG == 64
-       if (!(word & (~0ul << 32))) {
-               num -= 32;
-               word <<= 32;
-       }
-#endif
-       if (!(word & (~0ul << (BITS_PER_LONG - 16)))) {
-               num -= 16;
-               word <<= 16;
-       }
-       if (!(word & (~0ul << (BITS_PER_LONG - 8)))) {
-               num -= 8;
-               word <<= 8;
-       }
-       if (!(word & (~0ul << (BITS_PER_LONG - 4)))) {
-               num -= 4;
-               word <<= 4;
-       }
-       if (!(word & (~0ul << (BITS_PER_LONG - 2)))) {
-               num -= 2;
-               word <<= 2;
-       }
-       if (!(word & (~0ul << (BITS_PER_LONG - 1))))
-               num -= 1;
-       return num;
+       return generic___fls(word);
 }
 
 /**
@@ -149,46 +105,23 @@ legacy:
 
 static __always_inline int variable_ffs(int x)
 {
-       int r;
-
-       if (!x)
-               return 0;
-
        asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
                                      RISCV_ISA_EXT_ZBB, 1)
                          : : : : legacy);
 
+       if (!x)
+               return 0;
+
        asm volatile (".option push\n"
                      ".option arch,+zbb\n"
                      CTZW "%0, %1\n"
                      ".option pop\n"
-                     : "=r" (r) : "r" (x) :);
+                     : "=r" (x) : "r" (x) :);
 
-       return r + 1;
+       return x + 1;
 
 legacy:
-       r = 1;
-       if (!(x & 0xffff)) {
-               x >>= 16;
-               r += 16;
-       }
-       if (!(x & 0xff)) {
-               x >>= 8;
-               r += 8;
-       }
-       if (!(x & 0xf)) {
-               x >>= 4;
-               r += 4;
-       }
-       if (!(x & 3)) {
-               x >>= 2;
-               r += 2;
-       }
-       if (!(x & 1)) {
-               x >>= 1;
-               r += 1;
-       }
-       return r;
+       return generic_ffs(x);
 }
 
 /**
@@ -204,46 +137,23 @@ legacy:
 
 static __always_inline int variable_fls(unsigned int x)
 {
-       int r;
-
-       if (!x)
-               return 0;
-
        asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0,
                                      RISCV_ISA_EXT_ZBB, 1)
                          : : : : legacy);
 
+       if (!x)
+               return 0;
+
        asm volatile (".option push\n"
                      ".option arch,+zbb\n"
                      CLZW "%0, %1\n"
                      ".option pop\n"
-                     : "=r" (r) : "r" (x) :);
+                     : "=r" (x) : "r" (x) :);
 
-       return 32 - r;
+       return 32 - x;
 
 legacy:
-       r = 32;
-       if (!(x & 0xffff0000u)) {
-               x <<= 16;
-               r -= 16;
-       }
-       if (!(x & 0xff000000u)) {
-               x <<= 8;
-               r -= 8;
-       }
-       if (!(x & 0xf0000000u)) {
-               x <<= 4;
-               r -= 4;
-       }
-       if (!(x & 0xc0000000u)) {
-               x <<= 2;
-               r -= 2;
-       }
-       if (!(x & 0x80000000u)) {
-               x <<= 1;
-               r -= 1;
-       }
-       return r;
+       return generic_fls(x);
 }
 
 /**
index 2f4726d3cfcc25a805adacc0b0e85c4ff8bcc220..2fee65cc8443246c07ca1f2c53e896cad426ae77 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/bug.h>
 
-#include <asm/barrier.h>
 #include <asm/fence.h>
 
 #define __xchg_relaxed(ptr, new, size)                                 \
                        "       bne  %0, %z3, 1f\n"                     \
                        "       sc.w.rl %1, %z4, %2\n"                  \
                        "       bnez %1, 0b\n"                          \
-                       "       fence rw, rw\n"                         \
+                       RISCV_FULL_BARRIER                              \
                        "1:\n"                                          \
                        : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)    \
                        : "rJ" ((long)__old), "rJ" (__new)              \
                        "       bne %0, %z3, 1f\n"                      \
                        "       sc.d.rl %1, %z4, %2\n"                  \
                        "       bnez %1, 0b\n"                          \
-                       "       fence rw, rw\n"                         \
+                       RISCV_FULL_BARRIER                              \
                        "1:\n"                                          \
                        : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr)    \
                        : "rJ" (__old), "rJ" (__new)                    \
index 2ac955b51148f4f12d23c03b42aae76d79b79bed..aa103530a5c83a501ac00c0e00c5e15f8e6a59a9 100644 (file)
 
 static inline int is_compat_task(void)
 {
+       if (!IS_ENABLED(CONFIG_COMPAT))
+               return 0;
+
        return test_thread_flag(TIF_32BIT);
 }
 
+static inline int is_compat_thread(struct thread_info *thread)
+{
+       if (!IS_ENABLED(CONFIG_COMPAT))
+               return 0;
+
+       return test_ti_thread_flag(thread, TIF_32BIT);
+}
+
+static inline void set_compat_task(bool is_compat)
+{
+       if (is_compat)
+               set_thread_flag(TIF_32BIT);
+       else
+               clear_thread_flag(TIF_32BIT);
+}
+
 struct compat_user_regs_struct {
        compat_ulong_t pc;
        compat_ulong_t ra;
index 0bd11862b7607b9ffebf8460ea6cc00cc1e4ff62..3478054461510ea79abd70aa81c8d817b64ad32c 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright 2022-2023 Rivos, Inc
+ * Copyright 2022-2024 Rivos, Inc
  */
 
 #ifndef _ASM_CPUFEATURE_H
@@ -28,29 +28,38 @@ struct riscv_isainfo {
 
 DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
 
-DECLARE_PER_CPU(long, misaligned_access_speed);
-
 /* Per-cpu ISA extensions. */
 extern struct riscv_isainfo hart_isa[NR_CPUS];
 
 void riscv_user_isa_enable(void);
 
-#ifdef CONFIG_RISCV_MISALIGNED
-bool unaligned_ctl_available(void);
-bool check_unaligned_access_emulated(int cpu);
+#if defined(CONFIG_RISCV_MISALIGNED)
+bool check_unaligned_access_emulated_all_cpus(void);
 void unaligned_emulation_finish(void);
+bool unaligned_ctl_available(void);
+DECLARE_PER_CPU(long, misaligned_access_speed);
 #else
 static inline bool unaligned_ctl_available(void)
 {
        return false;
 }
+#endif
+
+#if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
+DECLARE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key);
 
-static inline bool check_unaligned_access_emulated(int cpu)
+static __always_inline bool has_fast_unaligned_accesses(void)
 {
-       return false;
+       return static_branch_likely(&fast_unaligned_access_speed_key);
+}
+#else
+static __always_inline bool has_fast_unaligned_accesses(void)
+{
+       if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
+               return true;
+       else
+               return false;
 }
-
-static inline void unaligned_emulation_finish(void) {}
 #endif
 
 unsigned long riscv_get_elf_hwcap(void);
@@ -135,6 +144,4 @@ static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsi
        return __riscv_isa_extension_available(hart_isa[cpu].isa, ext);
 }
 
-DECLARE_STATIC_KEY_FALSE(fast_misaligned_access_speed_key);
-
 #endif
index 06c236bfab53b323491ce6ae3bbdbbbcd6206318..c7aea7886d22aaede04dba348c38779f139c31ee 100644 (file)
@@ -53,13 +53,9 @@ extern bool compat_elf_check_arch(Elf32_Ehdr *hdr);
 #define ELF_ET_DYN_BASE                ((DEFAULT_MAP_WINDOW / 3) * 2)
 
 #ifdef CONFIG_64BIT
-#ifdef CONFIG_COMPAT
-#define STACK_RND_MASK         (test_thread_flag(TIF_32BIT) ? \
+#define STACK_RND_MASK         (is_compat_task() ? \
                                 0x7ff >> (PAGE_SHIFT - 12) : \
                                 0x3ffff >> (PAGE_SHIFT - 12))
-#else
-#define STACK_RND_MASK         (0x3ffff >> (PAGE_SHIFT - 12))
-#endif
 #endif
 
 /*
@@ -139,10 +135,7 @@ do {                                                       \
 #ifdef CONFIG_COMPAT
 
 #define SET_PERSONALITY(ex)                                    \
-do {    if ((ex).e_ident[EI_CLASS] == ELFCLASS32)              \
-               set_thread_flag(TIF_32BIT);                     \
-       else                                                    \
-               clear_thread_flag(TIF_32BIT);                   \
+do {   set_compat_task((ex).e_ident[EI_CLASS] == ELFCLASS32);  \
        if (personality(current->personality) != PER_LINUX32)   \
                set_personality(PER_LINUX |                     \
                        (current->personality & (~PER_MASK)));  \
index ea33288f8a25b4f76e59bd65e8f869ee842c6e14..1f2dbfb8a8bfc8c9f5d46b9129c26756941c4918 100644 (file)
@@ -12,8 +12,8 @@
 #include <asm/vendorid_list.h>
 
 #ifdef CONFIG_ERRATA_ANDES
-#define ERRATA_ANDESTECH_NO_IOCP       0
-#define ERRATA_ANDESTECH_NUMBER                1
+#define ERRATA_ANDES_NO_IOCP 0
+#define ERRATA_ANDES_NUMBER 1
 #endif
 
 #ifdef CONFIG_ERRATA_SIFIVE
@@ -112,15 +112,6 @@ asm volatile(ALTERNATIVE(                                          \
 #define THEAD_C9XX_RV_IRQ_PMU                  17
 #define THEAD_C9XX_CSR_SCOUNTEROF              0x5c5
 
-#define ALT_SBI_PMU_OVERFLOW(__ovl)                                    \
-asm volatile(ALTERNATIVE(                                              \
-       "csrr %0, " __stringify(CSR_SSCOUNTOVF),                        \
-       "csrr %0, " __stringify(THEAD_C9XX_CSR_SCOUNTEROF),             \
-               THEAD_VENDOR_ID, ERRATA_THEAD_PMU,                      \
-               CONFIG_ERRATA_THEAD_PMU)                                \
-       : "=r" (__ovl) :                                                \
-       : "memory")
-
 #endif /* __ASSEMBLY__ */
 
 #endif
index 2b443a3a487f3cdc509b5f80c7c343065ae85ef7..6bcd80325dfc1724aee2e5863ba39881ebea120b 100644 (file)
@@ -1,12 +1,18 @@
 #ifndef _ASM_RISCV_FENCE_H
 #define _ASM_RISCV_FENCE_H
 
+#define RISCV_FENCE_ASM(p, s)          "\tfence " #p "," #s "\n"
+#define RISCV_FENCE(p, s) \
+       ({ __asm__ __volatile__ (RISCV_FENCE_ASM(p, s) : : : "memory"); })
+
 #ifdef CONFIG_SMP
-#define RISCV_ACQUIRE_BARRIER          "\tfence r , rw\n"
-#define RISCV_RELEASE_BARRIER          "\tfence rw,  w\n"
+#define RISCV_ACQUIRE_BARRIER          RISCV_FENCE_ASM(r, rw)
+#define RISCV_RELEASE_BARRIER          RISCV_FENCE_ASM(rw, w)
+#define RISCV_FULL_BARRIER             RISCV_FENCE_ASM(rw, rw)
 #else
 #define RISCV_ACQUIRE_BARRIER
 #define RISCV_RELEASE_BARRIER
+#define RISCV_FULL_BARRIER
 #endif
 
 #endif /* _ASM_RISCV_FENCE_H */
index 1f2d2599c655d20be6df7516382e20a7e3956301..e17d0078a65116810cda686225c78e0ff420a603 100644 (file)
@@ -80,6 +80,7 @@
 #define RISCV_ISA_EXT_ZFA              71
 #define RISCV_ISA_EXT_ZTSO             72
 #define RISCV_ISA_EXT_ZACAS            73
+#define RISCV_ISA_EXT_XANDESPMU                74
 
 #define RISCV_ISA_EXT_XLINUXENVCFG     127
 
index 42497d487a174642bee085b3a950ee6211396fd3..1c5c641075d2fd48d2f20fa8993875261ada4eb4 100644 (file)
  * sufficient to ensure this works sanely on controllers that support I/O
  * writes.
  */
-#define __io_pbr()     __asm__ __volatile__ ("fence io,i"  : : : "memory");
-#define __io_par(v)    __asm__ __volatile__ ("fence i,ior" : : : "memory");
-#define __io_pbw()     __asm__ __volatile__ ("fence iow,o" : : : "memory");
-#define __io_paw()     __asm__ __volatile__ ("fence o,io"  : : : "memory");
+#define __io_pbr()     RISCV_FENCE(io, i)
+#define __io_par(v)    RISCV_FENCE(i, ior)
+#define __io_pbw()     RISCV_FENCE(iow, o)
+#define __io_paw()     RISCV_FENCE(o, io)
 
 /*
  * Accesses from a single hart to a single I/O address must be ordered.  This
diff --git a/arch/riscv/include/asm/membarrier.h b/arch/riscv/include/asm/membarrier.h
new file mode 100644 (file)
index 0000000..47b240d
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_RISCV_MEMBARRIER_H
+#define _ASM_RISCV_MEMBARRIER_H
+
+static inline void membarrier_arch_switch_mm(struct mm_struct *prev,
+                                            struct mm_struct *next,
+                                            struct task_struct *tsk)
+{
+       /*
+        * Only need the full barrier when switching between processes.
+        * Barrier when switching from kernel to userspace is not
+        * required here, given that it is implied by mmdrop(). Barrier
+        * when switching from userspace to kernel is not needed after
+        * store to rq->curr.
+        */
+       if (IS_ENABLED(CONFIG_SMP) &&
+           likely(!(atomic_read(&next->membarrier_state) &
+                    (MEMBARRIER_STATE_PRIVATE_EXPEDITED |
+                     MEMBARRIER_STATE_GLOBAL_EXPEDITED)) || !prev))
+               return;
+
+       /*
+        * The membarrier system call requires a full memory barrier
+        * after storing to rq->curr, before going back to user-space.
+        *
+        * This barrier is also needed for the SYNC_CORE command when
+        * switching between processes; in particular, on a transition
+        * from a thread belonging to another mm to a thread belonging
+        * to the mm for which a membarrier SYNC_CORE is done on CPU0:
+        *
+        *   - [CPU0] sets all bits in the mm icache_stale_mask (in
+        *     prepare_sync_core_cmd());
+        *
+        *   - [CPU1] stores to rq->curr (by the scheduler);
+        *
+        *   - [CPU0] loads rq->curr within membarrier and observes
+        *     cpu_rq(1)->curr->mm != mm, so the IPI is skipped on
+        *     CPU1; this means membarrier relies on switch_mm() to
+        *     issue the sync-core;
+        *
+        *   - [CPU1] switch_mm() loads icache_stale_mask; if the bit
+        *     is zero, switch_mm() may incorrectly skip the sync-core.
+        *
+        * Matches a full barrier in the proximity of the membarrier
+        * system call entry.
+        */
+       smp_mb();
+}
+
+#endif /* _ASM_RISCV_MEMBARRIER_H */
index 4c58ee7f95ecfa65ae11de96eda76347e747fe56..06cadfd7a237aceec28e4a3db693b1ae57db8e8e 100644 (file)
@@ -12,6 +12,7 @@
 #define _ASM_RISCV_MMIO_H
 
 #include <linux/types.h>
+#include <asm/fence.h>
 #include <asm/mmiowb.h>
 
 /* Generic IO read/write.  These perform native-endian accesses. */
@@ -131,8 +132,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
  * doesn't define any ordering between the memory space and the I/O space.
  */
 #define __io_br()      do {} while (0)
-#define __io_ar(v)     ({ __asm__ __volatile__ ("fence i,ir" : : : "memory"); })
-#define __io_bw()      ({ __asm__ __volatile__ ("fence w,o" : : : "memory"); })
+#define __io_ar(v)     RISCV_FENCE(i, ir)
+#define __io_bw()      RISCV_FENCE(w, o)
 #define __io_aw()      mmiowb_set_pending()
 
 #define readb(c)       ({ u8  __v; __io_br(); __v = readb_cpu(c); __io_ar(__v); __v; })
index 0b2333e71fdc5d52b06f2b96d88ab7f39ff37d70..52ce4a399d9b2b1ecab80ba7b7525c2e148cee35 100644 (file)
@@ -7,7 +7,7 @@
  * "o,w" is sufficient to ensure that all writes to the device have completed
  * before the write to the spinlock is allowed to commit.
  */
-#define mmiowb()       __asm__ __volatile__ ("fence o,w" : : : "memory");
+#define mmiowb()       RISCV_FENCE(o, w)
 
 #include <linux/smp.h>
 #include <asm-generic/mmiowb.h>
index c80bb9990d32ef706452d7d4fcc1c049cd7436d9..deaf971253a20102685aff042b10f8edbf7e614f 100644 (file)
@@ -95,13 +95,19 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud)
                __pud_free(mm, pud);
 }
 
-#define __pud_free_tlb(tlb, pud, addr)                                 \
-do {                                                                   \
-       if (pgtable_l4_enabled) {                                       \
-               pagetable_pud_dtor(virt_to_ptdesc(pud));                \
-               tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pud));     \
-       }                                                               \
-} while (0)
+static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
+                                 unsigned long addr)
+{
+       if (pgtable_l4_enabled) {
+               struct ptdesc *ptdesc = virt_to_ptdesc(pud);
+
+               pagetable_pud_dtor(ptdesc);
+               if (riscv_use_ipi_for_rfence())
+                       tlb_remove_page_ptdesc(tlb, ptdesc);
+               else
+                       tlb_remove_ptdesc(tlb, ptdesc);
+       }
+}
 
 #define p4d_alloc_one p4d_alloc_one
 static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr)
@@ -130,11 +136,16 @@ static inline void p4d_free(struct mm_struct *mm, p4d_t *p4d)
                __p4d_free(mm, p4d);
 }
 
-#define __p4d_free_tlb(tlb, p4d, addr)                                 \
-do {                                                                   \
-       if (pgtable_l5_enabled)                                         \
-               tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(p4d));     \
-} while (0)
+static inline void __p4d_free_tlb(struct mmu_gather *tlb, p4d_t *p4d,
+                                 unsigned long addr)
+{
+       if (pgtable_l5_enabled) {
+               if (riscv_use_ipi_for_rfence())
+                       tlb_remove_page_ptdesc(tlb, virt_to_ptdesc(p4d));
+               else
+                       tlb_remove_ptdesc(tlb, virt_to_ptdesc(p4d));
+       }
+}
 #endif /* __PAGETABLE_PMD_FOLDED */
 
 static inline void sync_kernel_mappings(pgd_t *pgd)
@@ -159,19 +170,31 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 #ifndef __PAGETABLE_PMD_FOLDED
 
-#define __pmd_free_tlb(tlb, pmd, addr)                         \
-do {                                                           \
-       pagetable_pmd_dtor(virt_to_ptdesc(pmd));                \
-       tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pmd));     \
-} while (0)
+static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
+                                 unsigned long addr)
+{
+       struct ptdesc *ptdesc = virt_to_ptdesc(pmd);
+
+       pagetable_pmd_dtor(ptdesc);
+       if (riscv_use_ipi_for_rfence())
+               tlb_remove_page_ptdesc(tlb, ptdesc);
+       else
+               tlb_remove_ptdesc(tlb, ptdesc);
+}
 
 #endif /* __PAGETABLE_PMD_FOLDED */
 
-#define __pte_free_tlb(tlb, pte, buf)                  \
-do {                                                   \
-       pagetable_pte_dtor(page_ptdesc(pte));           \
-       tlb_remove_page_ptdesc((tlb), page_ptdesc(pte));\
-} while (0)
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+                                 unsigned long addr)
+{
+       struct ptdesc *ptdesc = page_ptdesc(pte);
+
+       pagetable_pte_dtor(ptdesc);
+       if (riscv_use_ipi_for_rfence())
+               tlb_remove_page_ptdesc(tlb, ptdesc);
+       else
+               tlb_remove_ptdesc(tlb, ptdesc);
+}
 #endif /* CONFIG_MMU */
 
 #endif /* _ASM_RISCV_PGALLOC_H */
index 20242402fc11baa76b435be4f3872487f17d961d..97fcde30e2477d55f8046d844191a1e4b0ba5e1a 100644 (file)
 #define VA_USER_SV48 (UL(1) << (VA_BITS_SV48 - 1))
 #define VA_USER_SV57 (UL(1) << (VA_BITS_SV57 - 1))
 
-#ifdef CONFIG_COMPAT
 #define MMAP_VA_BITS_64 ((VA_BITS >= VA_BITS_SV48) ? VA_BITS_SV48 : VA_BITS)
 #define MMAP_MIN_VA_BITS_64 (VA_BITS_SV39)
 #define MMAP_VA_BITS (is_compat_task() ? VA_BITS_SV32 : MMAP_VA_BITS_64)
 #define MMAP_MIN_VA_BITS (is_compat_task() ? VA_BITS_SV32 : MMAP_MIN_VA_BITS_64)
-#else
-#define MMAP_VA_BITS ((VA_BITS >= VA_BITS_SV48) ? VA_BITS_SV48 : VA_BITS)
-#define MMAP_MIN_VA_BITS (VA_BITS_SV39)
-#endif /* CONFIG_COMPAT */
-
 #else
 #include <asm/pgtable-32.h>
 #endif /* CONFIG_64BIT */
@@ -439,9 +433,11 @@ static inline pte_t pte_mkhuge(pte_t pte)
        return pte;
 }
 
+#ifdef CONFIG_RISCV_ISA_SVNAPOT
 #define pte_leaf_size(pte)     (pte_napot(pte) ?                               \
                                        napot_cont_size(napot_cont_order(pte)) :\
                                        PAGE_SIZE)
+#endif
 
 #ifdef CONFIG_NUMA_BALANCING
 /*
@@ -517,12 +513,12 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
        WRITE_ONCE(*ptep, pteval);
 }
 
-void flush_icache_pte(pte_t pte);
+void flush_icache_pte(struct mm_struct *mm, pte_t pte);
 
-static inline void __set_pte_at(pte_t *ptep, pte_t pteval)
+static inline void __set_pte_at(struct mm_struct *mm, pte_t *ptep, pte_t pteval)
 {
        if (pte_present(pteval) && pte_exec(pteval))
-               flush_icache_pte(pteval);
+               flush_icache_pte(mm, pteval);
 
        set_pte(ptep, pteval);
 }
@@ -535,7 +531,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
        page_table_check_ptes_set(mm, ptep, pteval, nr);
 
        for (;;) {
-               __set_pte_at(ptep, pteval);
+               __set_pte_at(mm, ptep, pteval);
                if (--nr == 0)
                        break;
                ptep++;
@@ -547,7 +543,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
 static inline void pte_clear(struct mm_struct *mm,
        unsigned long addr, pte_t *ptep)
 {
-       __set_pte_at(ptep, __pte(0));
+       __set_pte_at(mm, ptep, __pte(0));
 }
 
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS      /* defined in mm/pgtable.c */
@@ -662,6 +658,12 @@ static inline int pmd_write(pmd_t pmd)
        return pte_write(pmd_pte(pmd));
 }
 
+#define pud_write pud_write
+static inline int pud_write(pud_t pud)
+{
+       return pte_write(pud_pte(pud));
+}
+
 #define pmd_dirty pmd_dirty
 static inline int pmd_dirty(pmd_t pmd)
 {
@@ -713,14 +715,14 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                                pmd_t *pmdp, pmd_t pmd)
 {
        page_table_check_pmd_set(mm, pmdp, pmd);
-       return __set_pte_at((pte_t *)pmdp, pmd_pte(pmd));
+       return __set_pte_at(mm, (pte_t *)pmdp, pmd_pte(pmd));
 }
 
 static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
                                pud_t *pudp, pud_t pud)
 {
        page_table_check_pud_set(mm, pudp, pud);
-       return __set_pte_at((pte_t *)pudp, pud_pte(pud));
+       return __set_pte_at(mm, (pte_t *)pudp, pud_pte(pud));
 }
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
@@ -871,8 +873,8 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
 #define TASK_SIZE_MIN  (PGDIR_SIZE_L3 * PTRS_PER_PGD / 2)
 
 #ifdef CONFIG_COMPAT
-#define TASK_SIZE_32   (_AC(0x80000000, UL))
-#define TASK_SIZE      (test_thread_flag(TIF_32BIT) ? \
+#define TASK_SIZE_32   (_AC(0x80000000, UL) - PAGE_SIZE)
+#define TASK_SIZE      (is_compat_task() ? \
                         TASK_SIZE_32 : TASK_SIZE_64)
 #else
 #define TASK_SIZE      TASK_SIZE_64
index a8509cc31ab25a5dcc75765bdb99e43e87dded3b..0faf5f161f1e4957b4cbeac63cf4d69c4dbd55e6 100644 (file)
 
 #include <asm/ptrace.h>
 
-#ifdef CONFIG_64BIT
-#define DEFAULT_MAP_WINDOW     (UL(1) << (MMAP_VA_BITS - 1))
-#define STACK_TOP_MAX          TASK_SIZE
-
+/*
+ * addr is a hint to the maximum userspace address that mmap should provide, so
+ * this macro needs to return the largest address space available so that
+ * mmap_end < addr, being mmap_end the top of that address space.
+ * See Documentation/arch/riscv/vm-layout.rst for more details.
+ */
 #define arch_get_mmap_end(addr, len, flags)                    \
 ({                                                             \
        unsigned long mmap_end;                                 \
        typeof(addr) _addr = (addr);                            \
-       if ((_addr) == 0 || (IS_ENABLED(CONFIG_COMPAT) && is_compat_task())) \
-               mmap_end = STACK_TOP_MAX;                       \
-       else if ((_addr) >= VA_USER_SV57)                       \
+       if ((_addr) == 0 || is_compat_task() ||                 \
+           ((_addr + len) > BIT(VA_BITS - 1)))                 \
                mmap_end = STACK_TOP_MAX;                       \
-       else if ((((_addr) >= VA_USER_SV48)) && (VA_BITS >= VA_BITS_SV48)) \
-               mmap_end = VA_USER_SV48;                        \
        else                                                    \
-               mmap_end = VA_USER_SV39;                        \
+               mmap_end = (_addr + len);                       \
        mmap_end;                                               \
 })
 
        typeof(addr) _addr = (addr);                            \
        typeof(base) _base = (base);                            \
        unsigned long rnd_gap = DEFAULT_MAP_WINDOW - (_base);   \
-       if ((_addr) == 0 || (IS_ENABLED(CONFIG_COMPAT) && is_compat_task())) \
+       if ((_addr) == 0 || is_compat_task() ||                 \
+           ((_addr + len) > BIT(VA_BITS - 1)))                 \
                mmap_base = (_base);                            \
-       else if (((_addr) >= VA_USER_SV57) && (VA_BITS >= VA_BITS_SV57)) \
-               mmap_base = VA_USER_SV57 - rnd_gap;             \
-       else if ((((_addr) >= VA_USER_SV48)) && (VA_BITS >= VA_BITS_SV48)) \
-               mmap_base = VA_USER_SV48 - rnd_gap;             \
        else                                                    \
-               mmap_base = VA_USER_SV39 - rnd_gap;             \
+               mmap_base = (_addr + len) - rnd_gap;            \
        mmap_base;                                              \
 })
 
+#ifdef CONFIG_64BIT
+#define DEFAULT_MAP_WINDOW     (UL(1) << (MMAP_VA_BITS - 1))
+#define STACK_TOP_MAX          TASK_SIZE_64
 #else
 #define DEFAULT_MAP_WINDOW     TASK_SIZE
 #define STACK_TOP_MAX          TASK_SIZE
index 54efbf523d49c67d75921c7f8454efc87ad0f257..adb50f3ec2057ba02252a5d016c00a3b102059a1 100644 (file)
@@ -34,9 +34,9 @@ static __must_check inline bool may_use_simd(void)
                return false;
 
        /*
-        * Nesting is acheived in preempt_v by spreading the control for
+        * Nesting is achieved in preempt_v by spreading the control for
         * preemptible and non-preemptible kernel-mode Vector into two fields.
-        * Always try to match with prempt_v if kernel V-context exists. Then,
+        * Always try to match with preempt_v if kernel V-context exists. Then,
         * fallback to check non preempt_v if nesting happens, or if the config
         * is not set.
         */
index 491296a335d0ce6cd9c8f242646c3c60c762bc87..4718096fa5e3fc19306239de2ecfa353fc755991 100644 (file)
@@ -56,4 +56,7 @@ int hibernate_resume_nonboot_cpu_disable(void);
 asmlinkage void hibernate_restore_image(unsigned long resume_satp, unsigned long satp_temp,
                                        unsigned long cpu_resume);
 asmlinkage int hibernate_core_restore_code(void);
+bool riscv_sbi_hsm_is_supported(void);
+bool riscv_sbi_suspend_state_is_valid(u32 state);
+int riscv_sbi_hart_suspend(u32 state);
 #endif
diff --git a/arch/riscv/include/asm/sync_core.h b/arch/riscv/include/asm/sync_core.h
new file mode 100644 (file)
index 0000000..9153016
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_SYNC_CORE_H
+#define _ASM_RISCV_SYNC_CORE_H
+
+/*
+ * RISC-V implements return to user-space through an xRET instruction,
+ * which is not core serializing.
+ */
+static inline void sync_core_before_usermode(void)
+{
+       asm volatile ("fence.i" ::: "memory");
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Ensure the next switch_mm() on every CPU issues a core serializing
+ * instruction for the given @mm.
+ */
+static inline void prepare_sync_core_cmd(struct mm_struct *mm)
+{
+       cpumask_setall(&mm->context.icache_stale_mask);
+}
+#else
+static inline void prepare_sync_core_cmd(struct mm_struct *mm)
+{
+}
+#endif /* CONFIG_SMP */
+
+#endif /* _ASM_RISCV_SYNC_CORE_H */
index eeec04b7dae67b905e97e84f5ab238e6f0eb0ce6..980094c2e9761d19b562d4dd8f9f707fd13480ae 100644 (file)
 
 asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *);
 
-#define SC_RISCV_REGS_TO_ARGS(x, ...)                          \
-       __MAP(x,__SC_ARGS                                       \
-             ,,regs->orig_a0,,regs->a1,,regs->a2               \
+#ifdef CONFIG_64BIT
+
+#define __SYSCALL_SE_DEFINEx(x, prefix, name, ...)                                     \
+       static long __se_##prefix##name(__MAP(x,__SC_LONG,__VA_ARGS__));                \
+       static long __se_##prefix##name(__MAP(x,__SC_LONG,__VA_ARGS__))
+
+#define SC_RISCV_REGS_TO_ARGS(x, ...)                                                  \
+       __MAP(x,__SC_ARGS                                                               \
+             ,,regs->orig_a0,,regs->a1,,regs->a2                                       \
              ,,regs->a3,,regs->a4,,regs->a5,,regs->a6)
 
+#else
+/*
+ * Use type aliasing to ensure registers a0-a6 are correctly passed to the syscall
+ * implementation when >word-size arguments are used.
+ */
+#define __SYSCALL_SE_DEFINEx(x, prefix, name, ...)                                     \
+       __diag_push();                                                                  \
+       __diag_ignore(GCC, 8, "-Wattribute-alias",                                      \
+                       "Type aliasing is used to sanitize syscall arguments");         \
+       static long __se_##prefix##name(ulong, ulong, ulong, ulong, ulong, ulong,       \
+                                       ulong)                                          \
+                       __attribute__((alias(__stringify(___se_##prefix##name))));      \
+       __diag_pop();                                                                   \
+       static long noinline ___se_##prefix##name(__MAP(x,__SC_LONG,__VA_ARGS__));      \
+       static long ___se_##prefix##name(__MAP(x,__SC_LONG,__VA_ARGS__))
+
+#define SC_RISCV_REGS_TO_ARGS(x, ...) \
+       regs->orig_a0,regs->a1,regs->a2,regs->a3,regs->a4,regs->a5,regs->a6
+
+#endif /* CONFIG_64BIT */
+
 #ifdef CONFIG_COMPAT
 
 #define COMPAT_SYSCALL_DEFINEx(x, name, ...)                                           \
        asmlinkage long __riscv_compat_sys##name(const struct pt_regs *regs);           \
        ALLOW_ERROR_INJECTION(__riscv_compat_sys##name, ERRNO);                         \
-       static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));              \
        static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));       \
-       asmlinkage long __riscv_compat_sys##name(const struct pt_regs *regs)            \
+       __SYSCALL_SE_DEFINEx(x, compat_sys, name, __VA_ARGS__)                          \
        {                                                                               \
-               return __se_compat_sys##name(SC_RISCV_REGS_TO_ARGS(x,__VA_ARGS__));     \
+               return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));        \
        }                                                                               \
-       static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))               \
+       asmlinkage long __riscv_compat_sys##name(const struct pt_regs *regs)            \
        {                                                                               \
-               return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));        \
+               return __se_compat_sys##name(SC_RISCV_REGS_TO_ARGS(x,__VA_ARGS__));     \
        }                                                                               \
        static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
 
@@ -51,19 +77,18 @@ asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *);
 #define __SYSCALL_DEFINEx(x, name, ...)                                                \
        asmlinkage long __riscv_sys##name(const struct pt_regs *regs);          \
        ALLOW_ERROR_INJECTION(__riscv_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 __riscv_sys##name(const struct pt_regs *regs)           \
-       {                                                                       \
-               return __se_sys##name(SC_RISCV_REGS_TO_ARGS(x,__VA_ARGS__));    \
-       }                                                                       \
-       static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))              \
+       __SYSCALL_SE_DEFINEx(x, sys, name, __VA_ARGS__)                         \
        {                                                                       \
                long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));      \
                __MAP(x,__SC_TEST,__VA_ARGS__);                                 \
                __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));               \
                return ret;                                                     \
        }                                                                       \
+       asmlinkage long __riscv_sys##name(const struct pt_regs *regs)           \
+       {                                                                       \
+               return __se_sys##name(SC_RISCV_REGS_TO_ARGS(x,__VA_ARGS__));    \
+       }                                                                       \
        static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
 
 #define SYSCALL_DEFINE0(sname)                                                 \
index 50b63b5c15bd8b19dac37176ef98c3489c837e05..1f6c38420d8e0764d74a27e870f74d055a67f08e 100644 (file)
@@ -10,6 +10,24 @@ struct mmu_gather;
 
 static void tlb_flush(struct mmu_gather *tlb);
 
+#ifdef CONFIG_MMU
+#include <linux/swap.h>
+
+/*
+ * While riscv platforms with riscv_ipi_for_rfence as true require an IPI to
+ * perform TLB shootdown, some platforms with riscv_ipi_for_rfence as false use
+ * SBI to perform TLB shootdown. To keep software pagetable walkers safe in this
+ * case we switch to RCU based table free (MMU_GATHER_RCU_TABLE_FREE). See the
+ * comment below 'ifdef CONFIG_MMU_GATHER_RCU_TABLE_FREE' in include/asm-generic/tlb.h
+ * for more details.
+ */
+static inline void __tlb_remove_table(void *table)
+{
+       free_page_and_swap_cache(table);
+}
+
+#endif /* CONFIG_MMU */
+
 #define tlb_flush tlb_flush
 #include <asm-generic/tlb.h>
 
index 0cd6f0a027d1f7ae7bb95b509bad3400c9fa71a5..731dcd0ed4de92ac7a00b1e1c534b2c33d905d2d 100644 (file)
@@ -284,4 +284,15 @@ static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }
 
 #endif /* CONFIG_RISCV_ISA_V */
 
+/*
+ * Return the implementation's vlen value.
+ *
+ * riscv_v_vsize contains the value of "32 vector registers with vlenb length"
+ * so rebuild the vlen value in bits from it.
+ */
+static inline int riscv_vector_vlen(void)
+{
+       return riscv_v_vsize / 32 * 8;
+}
+
 #endif /* ! __ASM_RISCV_VECTOR_H */
index e55407ace0c3617631df5c887338bf7e43727e7f..2f2bb0c84f9a71f4350e6794c913c9b9bee442e4 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef ASM_VENDOR_LIST_H
 #define ASM_VENDOR_LIST_H
 
-#define ANDESTECH_VENDOR_ID    0x31e
+#define ANDES_VENDOR_ID                0x31e
 #define SIFIVE_VENDOR_ID       0x489
 #define THEAD_VENDOR_ID                0x5b7
 
index 5e591f831638f2a18aa3008edb400c6f2f0c71ca..81d94a8ee10f29d3104a4f82c58eba92d124c329 100644 (file)
@@ -39,7 +39,6 @@ extra-y += vmlinux.lds
 obj-y  += head.o
 obj-y  += soc.o
 obj-$(CONFIG_RISCV_ALTERNATIVE) += alternative.o
-obj-y  += copy-unaligned.o
 obj-y  += cpu.o
 obj-y  += cpufeature.o
 obj-y  += entry.o
@@ -64,6 +63,9 @@ obj-y += tests/
 obj-$(CONFIG_MMU) += vdso.o vdso/
 
 obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o
+obj-$(CONFIG_RISCV_MISALIGNED) += unaligned_access_speed.o
+obj-$(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)     += copy-unaligned.o
+
 obj-$(CONFIG_FPU)              += fpu.o
 obj-$(CONFIG_RISCV_ISA_V)      += vector.o
 obj-$(CONFIG_RISCV_ISA_V)      += kernel_mode_vector.o
index 319a1da0358b4924b706d1eaff6dc89343d6e54d..0128b161bfdab2d88377b99386490e8a4f3571d8 100644 (file)
@@ -43,7 +43,7 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info
 
        switch (cpu_mfr_info->vendor_id) {
 #ifdef CONFIG_ERRATA_ANDES
-       case ANDESTECH_VENDOR_ID:
+       case ANDES_VENDOR_ID:
                cpu_mfr_info->patch_func = andes_errata_patch_func;
                break;
 #endif
index 79a5a35fab964d3b54db97b5504f45f68dface11..3ed2359eae353f863561c02983e4e5e5bf27603d 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/cpu.h>
 #include <linux/cpuhotplug.h>
 #include <linux/ctype.h>
-#include <linux/jump_label.h>
 #include <linux/log2.h>
 #include <linux/memory.h>
 #include <linux/module.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
 #include <asm/hwcap.h>
-#include <asm/hwprobe.h>
 #include <asm/patch.h>
 #include <asm/processor.h>
 #include <asm/sbi.h>
 #include <asm/vector.h>
 
-#include "copy-unaligned.h"
-
 #define NUM_ALPHA_EXTS ('z' - 'a' + 1)
 
-#define MISALIGNED_ACCESS_JIFFIES_LG2 1
-#define MISALIGNED_BUFFER_SIZE 0x4000
-#define MISALIGNED_BUFFER_ORDER get_order(MISALIGNED_BUFFER_SIZE)
-#define MISALIGNED_COPY_SIZE ((MISALIGNED_BUFFER_SIZE / 2) - 0x80)
-
 unsigned long elf_hwcap __read_mostly;
 
 /* Host ISA bitmap */
@@ -44,11 +35,6 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 /* Per-cpu ISA extensions. */
 struct riscv_isainfo hart_isa[NR_CPUS];
 
-/* Performance information */
-DEFINE_PER_CPU(long, misaligned_access_speed);
-
-static cpumask_t fast_misaligned_access;
-
 /**
  * riscv_isa_extension_base() - Get base extension word
  *
@@ -318,6 +304,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
        __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
        __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
        __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
+       __RISCV_ISA_EXT_DATA(xandespmu, RISCV_ISA_EXT_XANDESPMU),
 };
 
 const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext);
@@ -731,247 +718,6 @@ unsigned long riscv_get_elf_hwcap(void)
        return hwcap;
 }
 
-static int check_unaligned_access(void *param)
-{
-       int cpu = smp_processor_id();
-       u64 start_cycles, end_cycles;
-       u64 word_cycles;
-       u64 byte_cycles;
-       int ratio;
-       unsigned long start_jiffies, now;
-       struct page *page = param;
-       void *dst;
-       void *src;
-       long speed = RISCV_HWPROBE_MISALIGNED_SLOW;
-
-       if (check_unaligned_access_emulated(cpu))
-               return 0;
-
-       /* Make an unaligned destination buffer. */
-       dst = (void *)((unsigned long)page_address(page) | 0x1);
-       /* Unalign src as well, but differently (off by 1 + 2 = 3). */
-       src = dst + (MISALIGNED_BUFFER_SIZE / 2);
-       src += 2;
-       word_cycles = -1ULL;
-       /* Do a warmup. */
-       __riscv_copy_words_unaligned(dst, src, MISALIGNED_COPY_SIZE);
-       preempt_disable();
-       start_jiffies = jiffies;
-       while ((now = jiffies) == start_jiffies)
-               cpu_relax();
-
-       /*
-        * For a fixed amount of time, repeatedly try the function, and take
-        * the best time in cycles as the measurement.
-        */
-       while (time_before(jiffies, now + (1 << MISALIGNED_ACCESS_JIFFIES_LG2))) {
-               start_cycles = get_cycles64();
-               /* Ensure the CSR read can't reorder WRT to the copy. */
-               mb();
-               __riscv_copy_words_unaligned(dst, src, MISALIGNED_COPY_SIZE);
-               /* Ensure the copy ends before the end time is snapped. */
-               mb();
-               end_cycles = get_cycles64();
-               if ((end_cycles - start_cycles) < word_cycles)
-                       word_cycles = end_cycles - start_cycles;
-       }
-
-       byte_cycles = -1ULL;
-       __riscv_copy_bytes_unaligned(dst, src, MISALIGNED_COPY_SIZE);
-       start_jiffies = jiffies;
-       while ((now = jiffies) == start_jiffies)
-               cpu_relax();
-
-       while (time_before(jiffies, now + (1 << MISALIGNED_ACCESS_JIFFIES_LG2))) {
-               start_cycles = get_cycles64();
-               mb();
-               __riscv_copy_bytes_unaligned(dst, src, MISALIGNED_COPY_SIZE);
-               mb();
-               end_cycles = get_cycles64();
-               if ((end_cycles - start_cycles) < byte_cycles)
-                       byte_cycles = end_cycles - start_cycles;
-       }
-
-       preempt_enable();
-
-       /* Don't divide by zero. */
-       if (!word_cycles || !byte_cycles) {
-               pr_warn("cpu%d: rdtime lacks granularity needed to measure unaligned access speed\n",
-                       cpu);
-
-               return 0;
-       }
-
-       if (word_cycles < byte_cycles)
-               speed = RISCV_HWPROBE_MISALIGNED_FAST;
-
-       ratio = div_u64((byte_cycles * 100), word_cycles);
-       pr_info("cpu%d: Ratio of byte access time to unaligned word access is %d.%02d, unaligned accesses are %s\n",
-               cpu,
-               ratio / 100,
-               ratio % 100,
-               (speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow");
-
-       per_cpu(misaligned_access_speed, cpu) = speed;
-
-       /*
-        * Set the value of fast_misaligned_access of a CPU. These operations
-        * are atomic to avoid race conditions.
-        */
-       if (speed == RISCV_HWPROBE_MISALIGNED_FAST)
-               cpumask_set_cpu(cpu, &fast_misaligned_access);
-       else
-               cpumask_clear_cpu(cpu, &fast_misaligned_access);
-
-       return 0;
-}
-
-static void check_unaligned_access_nonboot_cpu(void *param)
-{
-       unsigned int cpu = smp_processor_id();
-       struct page **pages = param;
-
-       if (smp_processor_id() != 0)
-               check_unaligned_access(pages[cpu]);
-}
-
-DEFINE_STATIC_KEY_FALSE(fast_misaligned_access_speed_key);
-
-static void modify_unaligned_access_branches(cpumask_t *mask, int weight)
-{
-       if (cpumask_weight(mask) == weight)
-               static_branch_enable_cpuslocked(&fast_misaligned_access_speed_key);
-       else
-               static_branch_disable_cpuslocked(&fast_misaligned_access_speed_key);
-}
-
-static void set_unaligned_access_static_branches_except_cpu(int cpu)
-{
-       /*
-        * Same as set_unaligned_access_static_branches, except excludes the
-        * given CPU from the result. When a CPU is hotplugged into an offline
-        * state, this function is called before the CPU is set to offline in
-        * the cpumask, and thus the CPU needs to be explicitly excluded.
-        */
-
-       cpumask_t fast_except_me;
-
-       cpumask_and(&fast_except_me, &fast_misaligned_access, cpu_online_mask);
-       cpumask_clear_cpu(cpu, &fast_except_me);
-
-       modify_unaligned_access_branches(&fast_except_me, num_online_cpus() - 1);
-}
-
-static void set_unaligned_access_static_branches(void)
-{
-       /*
-        * This will be called after check_unaligned_access_all_cpus so the
-        * result of unaligned access speed for all CPUs will be available.
-        *
-        * To avoid the number of online cpus changing between reading
-        * cpu_online_mask and calling num_online_cpus, cpus_read_lock must be
-        * held before calling this function.
-        */
-
-       cpumask_t fast_and_online;
-
-       cpumask_and(&fast_and_online, &fast_misaligned_access, cpu_online_mask);
-
-       modify_unaligned_access_branches(&fast_and_online, num_online_cpus());
-}
-
-static int lock_and_set_unaligned_access_static_branch(void)
-{
-       cpus_read_lock();
-       set_unaligned_access_static_branches();
-       cpus_read_unlock();
-
-       return 0;
-}
-
-arch_initcall_sync(lock_and_set_unaligned_access_static_branch);
-
-static int riscv_online_cpu(unsigned int cpu)
-{
-       static struct page *buf;
-
-       /* We are already set since the last check */
-       if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
-               goto exit;
-
-       buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
-       if (!buf) {
-               pr_warn("Allocation failure, not measuring misaligned performance\n");
-               return -ENOMEM;
-       }
-
-       check_unaligned_access(buf);
-       __free_pages(buf, MISALIGNED_BUFFER_ORDER);
-
-exit:
-       set_unaligned_access_static_branches();
-
-       return 0;
-}
-
-static int riscv_offline_cpu(unsigned int cpu)
-{
-       set_unaligned_access_static_branches_except_cpu(cpu);
-
-       return 0;
-}
-
-/* Measure unaligned access on all CPUs present at boot in parallel. */
-static int check_unaligned_access_all_cpus(void)
-{
-       unsigned int cpu;
-       unsigned int cpu_count = num_possible_cpus();
-       struct page **bufs = kzalloc(cpu_count * sizeof(struct page *),
-                                    GFP_KERNEL);
-
-       if (!bufs) {
-               pr_warn("Allocation failure, not measuring misaligned performance\n");
-               return 0;
-       }
-
-       /*
-        * Allocate separate buffers for each CPU so there's no fighting over
-        * cache lines.
-        */
-       for_each_cpu(cpu, cpu_online_mask) {
-               bufs[cpu] = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
-               if (!bufs[cpu]) {
-                       pr_warn("Allocation failure, not measuring misaligned performance\n");
-                       goto out;
-               }
-       }
-
-       /* Check everybody except 0, who stays behind to tend jiffies. */
-       on_each_cpu(check_unaligned_access_nonboot_cpu, bufs, 1);
-
-       /* Check core 0. */
-       smp_call_on_cpu(0, check_unaligned_access, bufs[0], true);
-
-       /*
-        * Setup hotplug callbacks for any new CPUs that come online or go
-        * offline.
-        */
-       cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online",
-                                 riscv_online_cpu, riscv_offline_cpu);
-
-out:
-       unaligned_emulation_finish();
-       for_each_cpu(cpu, cpu_online_mask) {
-               if (bufs[cpu])
-                       __free_pages(bufs[cpu], MISALIGNED_BUFFER_ORDER);
-       }
-
-       kfree(bufs);
-       return 0;
-}
-
-arch_initcall(check_unaligned_access_all_cpus);
-
 void riscv_user_isa_enable(void)
 {
        if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_ZICBOZ))
index 9d1a305d55087bb3a6bdc73f8ed8ebe3206775b1..68a24cf9481afe0649e671bd764fa688307c23bf 100644 (file)
@@ -111,6 +111,7 @@ SYM_CODE_START(handle_exception)
 1:
        tail do_trap_unknown
 SYM_CODE_END(handle_exception)
+ASM_NOKPROBE(handle_exception)
 
 /*
  * The ret_from_exception must be called with interrupt disabled. Here is the
@@ -184,6 +185,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception)
        sret
 #endif
 SYM_CODE_END(ret_from_exception)
+ASM_NOKPROBE(ret_from_exception)
 
 #ifdef CONFIG_VMAP_STACK
 SYM_CODE_START_LOCAL(handle_kernel_stack_overflow)
@@ -219,6 +221,7 @@ SYM_CODE_START_LOCAL(handle_kernel_stack_overflow)
        move a0, sp
        tail handle_bad_stack
 SYM_CODE_END(handle_kernel_stack_overflow)
+ASM_NOKPROBE(handle_kernel_stack_overflow)
 #endif
 
 SYM_CODE_START(ret_from_fork)
index 07915dc9279e9219fc2c7abc54ba749d4a48597e..b75f150b923d68c189e5017a9ddf0f171d099687 100644 (file)
@@ -9,6 +9,9 @@ KBUILD_CFLAGS   := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
                   -fno-asynchronous-unwind-tables -fno-unwind-tables \
                   $(call cc-option,-fno-addrsig)
 
+# Disable LTO
+KBUILD_CFLAGS  := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS))
+
 KBUILD_CFLAGS  += -mcmodel=medany
 
 CFLAGS_cmdline_early.o += -D__NO_FORTIFY
index e8515aa9d80bf82fd6ff2598664b9fe18a6b1de3..92731ff8c79ad02b6f3db9375b84635d3ea13f41 100644 (file)
@@ -377,14 +377,14 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
        return ret;
 }
+#else
+static const struct user_regset_view compat_riscv_user_native_view = {};
 #endif /* CONFIG_COMPAT */
 
 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 {
-#ifdef CONFIG_COMPAT
-       if (test_tsk_thread_flag(task, TIF_32BIT))
+       if (is_compat_thread(&task->thread_info))
                return &compat_riscv_user_native_view;
        else
-#endif
                return &riscv_user_native_view;
 }
index c4ed7d977f57b2c305e5ecbf2b767fd9b0c175df..d41090fc3203533cc7e40973e3a6cae14da91c47 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
-#include <asm/cpufeature.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
 #include <asm/numa.h>
index 299795341e8a2207dc922373511e31118bbd0f8b..8a327b485b90e7c690d33c92b144b114b998a3a8 100644 (file)
@@ -132,4 +132,53 @@ static int __init sbi_system_suspend_init(void)
 }
 
 arch_initcall(sbi_system_suspend_init);
+
+static int sbi_suspend_finisher(unsigned long suspend_type,
+                               unsigned long resume_addr,
+                               unsigned long opaque)
+{
+       struct sbiret ret;
+
+       ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_SUSPEND,
+                       suspend_type, resume_addr, opaque, 0, 0, 0);
+
+       return (ret.error) ? sbi_err_map_linux_errno(ret.error) : 0;
+}
+
+int riscv_sbi_hart_suspend(u32 state)
+{
+       if (state & SBI_HSM_SUSP_NON_RET_BIT)
+               return cpu_suspend(state, sbi_suspend_finisher);
+       else
+               return sbi_suspend_finisher(state, 0, 0);
+}
+
+bool riscv_sbi_suspend_state_is_valid(u32 state)
+{
+       if (state > SBI_HSM_SUSPEND_RET_DEFAULT &&
+           state < SBI_HSM_SUSPEND_RET_PLATFORM)
+               return false;
+
+       if (state > SBI_HSM_SUSPEND_NON_RET_DEFAULT &&
+           state < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
+               return false;
+
+       return true;
+}
+
+bool riscv_sbi_hsm_is_supported(void)
+{
+       /*
+        * The SBI HSM suspend function is only available when:
+        * 1) SBI version is 0.3 or higher
+        * 2) SBI HSM extension is available
+        */
+       if (sbi_spec_version < sbi_mk_version(0, 3) ||
+           !sbi_probe_extension(SBI_EXT_HSM)) {
+               pr_info("HSM suspend not available\n");
+               return false;
+       }
+
+       return true;
+}
 #endif /* CONFIG_RISCV_SBI */
index a7c56b41efd24d826a9baaed7575c3508e49a9de..8cae41a502dd4a9e9c3a23c3a63d998c3e9de2d3 100644 (file)
@@ -147,6 +147,7 @@ static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext)
        return (pair.value & ext);
 }
 
+#if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
 static u64 hwprobe_misaligned(const struct cpumask *cpus)
 {
        int cpu;
@@ -169,6 +170,18 @@ static u64 hwprobe_misaligned(const struct cpumask *cpus)
 
        return perf;
 }
+#else
+static u64 hwprobe_misaligned(const struct cpumask *cpus)
+{
+       if (IS_ENABLED(CONFIG_RISCV_EFFICIENT_UNALIGNED_ACCESS))
+               return RISCV_HWPROBE_MISALIGNED_FAST;
+
+       if (IS_ENABLED(CONFIG_RISCV_EMULATED_UNALIGNED_ACCESS) && unaligned_ctl_available())
+               return RISCV_HWPROBE_MISALIGNED_EMULATED;
+
+       return RISCV_HWPROBE_MISALIGNED_SLOW;
+}
+#endif
 
 static void hwprobe_one_pair(struct riscv_hwprobe *pair,
                             const struct cpumask *cpus)
index 5dba64e8e977cdeab7340f023ffa2656b24636e0..78cea5d2c27022fc74ea5e9f9c1b5956f64314af 100644 (file)
@@ -6,7 +6,7 @@ config AS_HAS_ULEB128
 
 menuconfig RUNTIME_KERNEL_TESTING_MENU
        bool "arch/riscv/kernel runtime Testing"
-       def_bool y
+       default y
        help
          Enable riscv kernel runtime testing.
 
index a1b9be3c4332d97f08b50beebfcadba5adaa02be..868d6280cf667e655de2d5003c2fd57d129b3127 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/randomize_kstack.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/signal.h>
@@ -310,7 +311,8 @@ asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
        }
 }
 
-asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs)
+asmlinkage __visible __trap_section  __no_stack_protector
+void do_trap_ecall_u(struct pt_regs *regs)
 {
        if (user_mode(regs)) {
                long syscall = regs->a7;
@@ -322,10 +324,23 @@ asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs)
 
                syscall = syscall_enter_from_user_mode(regs, syscall);
 
+               add_random_kstack_offset();
+
                if (syscall >= 0 && syscall < NR_syscalls)
                        syscall_handler(regs, syscall);
                else if (syscall != -1)
                        regs->a0 = -ENOSYS;
+               /*
+                * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
+                * so the maximum stack offset is 1k bytes (10 bits).
+                *
+                * The actual entropy will be further reduced by the compiler when
+                * applying stack alignment constraints: 16-byte (i.e. 4-bit) aligned
+                * for RV32I or RV64I.
+                *
+                * The resulting 6 bits of entropy is seen in SP[9:4].
+                */
+               choose_random_kstack_offset(get_random_u16());
 
                syscall_exit_to_user_mode(regs);
        } else {
index 8ded225e8c5b1313d800c8f87878212c48c9b250..2adb7c3e4dd5bfc3fceb34a2e71bd915e5658674 100644 (file)
@@ -413,7 +413,9 @@ int handle_misaligned_load(struct pt_regs *regs)
 
        perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
 
+#ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS
        *this_cpu_ptr(&misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_EMULATED;
+#endif
 
        if (!unaligned_enabled)
                return -1;
@@ -596,7 +598,7 @@ int handle_misaligned_store(struct pt_regs *regs)
        return 0;
 }
 
-bool check_unaligned_access_emulated(int cpu)
+static bool check_unaligned_access_emulated(int cpu)
 {
        long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu);
        unsigned long tmp_var, tmp_val;
@@ -623,7 +625,7 @@ bool check_unaligned_access_emulated(int cpu)
        return misaligned_emu_detected;
 }
 
-void unaligned_emulation_finish(void)
+bool check_unaligned_access_emulated_all_cpus(void)
 {
        int cpu;
 
@@ -632,13 +634,12 @@ void unaligned_emulation_finish(void)
         * accesses emulated since tasks requesting such control can run on any
         * CPU.
         */
-       for_each_present_cpu(cpu) {
-               if (per_cpu(misaligned_access_speed, cpu) !=
-                                       RISCV_HWPROBE_MISALIGNED_EMULATED) {
-                       return;
-               }
-       }
+       for_each_online_cpu(cpu)
+               if (!check_unaligned_access_emulated(cpu))
+                       return false;
+
        unaligned_ctl = true;
+       return true;
 }
 
 bool unaligned_ctl_available(void)
diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c
new file mode 100644 (file)
index 0000000..a9a6bcb
--- /dev/null
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2024 Rivos Inc.
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/jump_label.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <asm/cpufeature.h>
+#include <asm/hwprobe.h>
+
+#include "copy-unaligned.h"
+
+#define MISALIGNED_ACCESS_JIFFIES_LG2 1
+#define MISALIGNED_BUFFER_SIZE 0x4000
+#define MISALIGNED_BUFFER_ORDER get_order(MISALIGNED_BUFFER_SIZE)
+#define MISALIGNED_COPY_SIZE ((MISALIGNED_BUFFER_SIZE / 2) - 0x80)
+
+DEFINE_PER_CPU(long, misaligned_access_speed);
+
+#ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS
+static cpumask_t fast_misaligned_access;
+static int check_unaligned_access(void *param)
+{
+       int cpu = smp_processor_id();
+       u64 start_cycles, end_cycles;
+       u64 word_cycles;
+       u64 byte_cycles;
+       int ratio;
+       unsigned long start_jiffies, now;
+       struct page *page = param;
+       void *dst;
+       void *src;
+       long speed = RISCV_HWPROBE_MISALIGNED_SLOW;
+
+       if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
+               return 0;
+
+       /* Make an unaligned destination buffer. */
+       dst = (void *)((unsigned long)page_address(page) | 0x1);
+       /* Unalign src as well, but differently (off by 1 + 2 = 3). */
+       src = dst + (MISALIGNED_BUFFER_SIZE / 2);
+       src += 2;
+       word_cycles = -1ULL;
+       /* Do a warmup. */
+       __riscv_copy_words_unaligned(dst, src, MISALIGNED_COPY_SIZE);
+       preempt_disable();
+       start_jiffies = jiffies;
+       while ((now = jiffies) == start_jiffies)
+               cpu_relax();
+
+       /*
+        * For a fixed amount of time, repeatedly try the function, and take
+        * the best time in cycles as the measurement.
+        */
+       while (time_before(jiffies, now + (1 << MISALIGNED_ACCESS_JIFFIES_LG2))) {
+               start_cycles = get_cycles64();
+               /* Ensure the CSR read can't reorder WRT to the copy. */
+               mb();
+               __riscv_copy_words_unaligned(dst, src, MISALIGNED_COPY_SIZE);
+               /* Ensure the copy ends before the end time is snapped. */
+               mb();
+               end_cycles = get_cycles64();
+               if ((end_cycles - start_cycles) < word_cycles)
+                       word_cycles = end_cycles - start_cycles;
+       }
+
+       byte_cycles = -1ULL;
+       __riscv_copy_bytes_unaligned(dst, src, MISALIGNED_COPY_SIZE);
+       start_jiffies = jiffies;
+       while ((now = jiffies) == start_jiffies)
+               cpu_relax();
+
+       while (time_before(jiffies, now + (1 << MISALIGNED_ACCESS_JIFFIES_LG2))) {
+               start_cycles = get_cycles64();
+               mb();
+               __riscv_copy_bytes_unaligned(dst, src, MISALIGNED_COPY_SIZE);
+               mb();
+               end_cycles = get_cycles64();
+               if ((end_cycles - start_cycles) < byte_cycles)
+                       byte_cycles = end_cycles - start_cycles;
+       }
+
+       preempt_enable();
+
+       /* Don't divide by zero. */
+       if (!word_cycles || !byte_cycles) {
+               pr_warn("cpu%d: rdtime lacks granularity needed to measure unaligned access speed\n",
+                       cpu);
+
+               return 0;
+       }
+
+       if (word_cycles < byte_cycles)
+               speed = RISCV_HWPROBE_MISALIGNED_FAST;
+
+       ratio = div_u64((byte_cycles * 100), word_cycles);
+       pr_info("cpu%d: Ratio of byte access time to unaligned word access is %d.%02d, unaligned accesses are %s\n",
+               cpu,
+               ratio / 100,
+               ratio % 100,
+               (speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow");
+
+       per_cpu(misaligned_access_speed, cpu) = speed;
+
+       /*
+        * Set the value of fast_misaligned_access of a CPU. These operations
+        * are atomic to avoid race conditions.
+        */
+       if (speed == RISCV_HWPROBE_MISALIGNED_FAST)
+               cpumask_set_cpu(cpu, &fast_misaligned_access);
+       else
+               cpumask_clear_cpu(cpu, &fast_misaligned_access);
+
+       return 0;
+}
+
+static void check_unaligned_access_nonboot_cpu(void *param)
+{
+       unsigned int cpu = smp_processor_id();
+       struct page **pages = param;
+
+       if (smp_processor_id() != 0)
+               check_unaligned_access(pages[cpu]);
+}
+
+DEFINE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key);
+
+static void modify_unaligned_access_branches(cpumask_t *mask, int weight)
+{
+       if (cpumask_weight(mask) == weight)
+               static_branch_enable_cpuslocked(&fast_unaligned_access_speed_key);
+       else
+               static_branch_disable_cpuslocked(&fast_unaligned_access_speed_key);
+}
+
+static void set_unaligned_access_static_branches_except_cpu(int cpu)
+{
+       /*
+        * Same as set_unaligned_access_static_branches, except excludes the
+        * given CPU from the result. When a CPU is hotplugged into an offline
+        * state, this function is called before the CPU is set to offline in
+        * the cpumask, and thus the CPU needs to be explicitly excluded.
+        */
+
+       cpumask_t fast_except_me;
+
+       cpumask_and(&fast_except_me, &fast_misaligned_access, cpu_online_mask);
+       cpumask_clear_cpu(cpu, &fast_except_me);
+
+       modify_unaligned_access_branches(&fast_except_me, num_online_cpus() - 1);
+}
+
+static void set_unaligned_access_static_branches(void)
+{
+       /*
+        * This will be called after check_unaligned_access_all_cpus so the
+        * result of unaligned access speed for all CPUs will be available.
+        *
+        * To avoid the number of online cpus changing between reading
+        * cpu_online_mask and calling num_online_cpus, cpus_read_lock must be
+        * held before calling this function.
+        */
+
+       cpumask_t fast_and_online;
+
+       cpumask_and(&fast_and_online, &fast_misaligned_access, cpu_online_mask);
+
+       modify_unaligned_access_branches(&fast_and_online, num_online_cpus());
+}
+
+static int lock_and_set_unaligned_access_static_branch(void)
+{
+       cpus_read_lock();
+       set_unaligned_access_static_branches();
+       cpus_read_unlock();
+
+       return 0;
+}
+
+arch_initcall_sync(lock_and_set_unaligned_access_static_branch);
+
+static int riscv_online_cpu(unsigned int cpu)
+{
+       static struct page *buf;
+
+       /* We are already set since the last check */
+       if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
+               goto exit;
+
+       buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
+       if (!buf) {
+               pr_warn("Allocation failure, not measuring misaligned performance\n");
+               return -ENOMEM;
+       }
+
+       check_unaligned_access(buf);
+       __free_pages(buf, MISALIGNED_BUFFER_ORDER);
+
+exit:
+       set_unaligned_access_static_branches();
+
+       return 0;
+}
+
+static int riscv_offline_cpu(unsigned int cpu)
+{
+       set_unaligned_access_static_branches_except_cpu(cpu);
+
+       return 0;
+}
+
+/* Measure unaligned access speed on all CPUs present at boot in parallel. */
+static int check_unaligned_access_speed_all_cpus(void)
+{
+       unsigned int cpu;
+       unsigned int cpu_count = num_possible_cpus();
+       struct page **bufs = kcalloc(cpu_count, sizeof(*bufs), GFP_KERNEL);
+
+       if (!bufs) {
+               pr_warn("Allocation failure, not measuring misaligned performance\n");
+               return 0;
+       }
+
+       /*
+        * Allocate separate buffers for each CPU so there's no fighting over
+        * cache lines.
+        */
+       for_each_cpu(cpu, cpu_online_mask) {
+               bufs[cpu] = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
+               if (!bufs[cpu]) {
+                       pr_warn("Allocation failure, not measuring misaligned performance\n");
+                       goto out;
+               }
+       }
+
+       /* Check everybody except 0, who stays behind to tend jiffies. */
+       on_each_cpu(check_unaligned_access_nonboot_cpu, bufs, 1);
+
+       /* Check core 0. */
+       smp_call_on_cpu(0, check_unaligned_access, bufs[0], true);
+
+       /*
+        * Setup hotplug callbacks for any new CPUs that come online or go
+        * offline.
+        */
+       cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online",
+                                 riscv_online_cpu, riscv_offline_cpu);
+
+out:
+       for_each_cpu(cpu, cpu_online_mask) {
+               if (bufs[cpu])
+                       __free_pages(bufs[cpu], MISALIGNED_BUFFER_ORDER);
+       }
+
+       kfree(bufs);
+       return 0;
+}
+
+static int check_unaligned_access_all_cpus(void)
+{
+       bool all_cpus_emulated = check_unaligned_access_emulated_all_cpus();
+
+       if (!all_cpus_emulated)
+               return check_unaligned_access_speed_all_cpus();
+
+       return 0;
+}
+#else /* CONFIG_RISCV_PROBE_UNALIGNED_ACCESS */
+static int check_unaligned_access_all_cpus(void)
+{
+       check_unaligned_access_emulated_all_cpus();
+
+       return 0;
+}
+#endif
+
+arch_initcall(check_unaligned_access_all_cpus);
index 74af3ab520b6d433836930937dd90ffa2e672339..7fb12c59e571911e2756ce1c747fd6d4ac30fbd1 100644 (file)
@@ -3,7 +3,7 @@
  * Checksum library
  *
  * Influenced by arch/arm64/lib/csum.c
- * Copyright (C) 2023 Rivos Inc.
+ * Copyright (C) 2023-2024 Rivos Inc.
  */
 #include <linux/bitops.h>
 #include <linux/compiler.h>
@@ -318,10 +318,7 @@ unsigned int do_csum(const unsigned char *buff, int len)
         * branches. The largest chunk of overlap was delegated into the
         * do_csum_common function.
         */
-       if (static_branch_likely(&fast_misaligned_access_speed_key))
-               return do_csum_no_alignment(buff, len);
-
-       if (((unsigned long)buff & OFFSET_MASK) == 0)
+       if (has_fast_unaligned_accesses() || (((unsigned long)buff & OFFSET_MASK) == 0))
                return do_csum_no_alignment(buff, len);
 
        return do_csum_with_alignment(buff, len);
index 51ab5588e9ff36b8b7dc80096be587d09da2881f..7c45f26de4f79b75f5235e3bdb64658aa6bafbce 100644 (file)
@@ -1,7 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
 #include <linux/linkage.h>
-#include <asm-generic/export.h>
 #include <asm/asm.h>
 #include <asm/asm-extable.h>
 #include <asm/csr.h>
index 55a34f2020a85a895932c92d94a7577bf410f8dc..bc61ee5975e4124ffc91ca52fd7a852ee9412597 100644 (file)
@@ -82,12 +82,12 @@ void flush_icache_mm(struct mm_struct *mm, bool local)
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_MMU
-void flush_icache_pte(pte_t pte)
+void flush_icache_pte(struct mm_struct *mm, pte_t pte)
 {
        struct folio *folio = page_folio(pte_page(pte));
 
        if (!test_bit(PG_dcache_clean, &folio->flags)) {
-               flush_icache_all();
+               flush_icache_mm(mm, false);
                set_bit(PG_dcache_clean, &folio->flags);
        }
 }
index 217fd4de6134224655db81759f0b35c73948e46d..ba8eb3944687cfd445770c357b32cb4fa0e37564 100644 (file)
@@ -323,6 +323,8 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        if (unlikely(prev == next))
                return;
 
+       membarrier_arch_switch_mm(prev, next, task);
+
        /*
         * Mark the current MM context as inactive, and the next as
         * active.  This is at least used by the icache flushing
index b5ffb2ef54ad2244ae59598782c3ad3307b5ffe5..fe8e159394d8eeeeab34f83ae97ffadbec979b77 100644 (file)
@@ -764,6 +764,11 @@ static int __init print_no5lvl(char *p)
 }
 early_param("no5lvl", print_no5lvl);
 
+static void __init set_mmap_rnd_bits_max(void)
+{
+       mmap_rnd_bits_max = MMAP_VA_BITS - PAGE_SHIFT - 3;
+}
+
 /*
  * There is a simple way to determine if 4-level is supported by the
  * underlying hardware: establish 1:1 mapping in 4-level page table mode
@@ -1078,6 +1083,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 
 #if defined(CONFIG_64BIT) && !defined(CONFIG_XIP_KERNEL)
        set_satp_mode(dtb_pa);
+       set_mmap_rnd_bits_max();
 #endif
 
        /*
index ef887efcb67900d94b97e603225f3c4d088fea9b..533ec9055fa0da75597bce9619d24f18c58577ac 100644 (file)
@@ -10,7 +10,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
                          pte_t entry, int dirty)
 {
        if (!pte_same(ptep_get(ptep), entry))
-               __set_pte_at(ptep, entry);
+               __set_pte_at(vma->vm_mm, ptep, entry);
        /*
         * update_mmu_cache will unconditionally execute, handling both
         * the case that the PTE changed and the spurious fault case.
index 367bf5bc4a5bc5353fe2c7060de487a870258d53..8f01ada6845e36086d85c32a076c8057208e498c 100644 (file)
@@ -63,6 +63,7 @@ config S390
        select ARCH_ENABLE_MEMORY_HOTREMOVE
        select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
        select ARCH_HAS_CURRENT_STACK_POINTER
+       select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEBUG_VM_PGTABLE
        select ARCH_HAS_DEBUG_WX
        select ARCH_HAS_DEVMEM_IS_ALLOWED
index 2a58e1864931913dbbcc78cf76545775fa000630..2dbb2d2f22f99c265ba416176f49e3b9c12f5cf5 100644 (file)
@@ -29,6 +29,7 @@ KBUILD_AFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO),$(aflags_dwarf))
 endif
 KBUILD_CFLAGS_DECOMPRESSOR := $(CLANG_FLAGS) -m64 -O2 -mpacked-stack
 KBUILD_CFLAGS_DECOMPRESSOR += -DDISABLE_BRANCH_PROFILING -D__NO_FORTIFY
+KBUILD_CFLAGS_DECOMPRESSOR += -D__DECOMPRESSOR
 KBUILD_CFLAGS_DECOMPRESSOR += -fno-delete-null-pointer-checks -msoft-float -mbackchain
 KBUILD_CFLAGS_DECOMPRESSOR += -fno-asynchronous-unwind-tables
 KBUILD_CFLAGS_DECOMPRESSOR += -ffreestanding
index 4032e6e136ac1dfb23e207aa6d21e3d62e9c42af..f1fb01cd5a259fff6af5077170770a944d0d4e68 100644 (file)
@@ -810,6 +810,7 @@ CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_PGFLAGS=y
+CONFIG_DEBUG_VIRTUAL=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
 CONFIG_DEBUG_PER_CPU_MAPS=y
index 91d261751d25baefdaa9f9ad7725e0b4bb9750f6..436365ff6c19b6ebad01d0de70b846a720e9aa74 100644 (file)
@@ -217,7 +217,8 @@ extern void ccw_device_destroy_console(struct ccw_device *);
 extern int ccw_device_enable_console(struct ccw_device *);
 extern void ccw_device_wait_idle(struct ccw_device *);
 
-extern void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size);
+extern void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size,
+                                  dma32_t *dma_handle);
 extern void ccw_device_dma_free(struct ccw_device *cdev,
                                void *cpu_addr, size_t size);
 
index 1c4f585dd39b6c96a02ba1c73c17dadc1fdc7c0b..b6b619f340a5eb0eadd0f593e4bee291ec1828e6 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/bitops.h>
 #include <linux/genalloc.h>
+#include <asm/dma-types.h>
 #include <asm/types.h>
 #include <asm/tpi.h>
 
@@ -32,7 +33,7 @@ struct ccw1 {
        __u8  cmd_code;
        __u8  flags;
        __u16 count;
-       __u32 cda;
+       dma32_t cda;
 } __attribute__ ((packed,aligned(8)));
 
 /**
@@ -152,8 +153,8 @@ struct sublog {
 struct esw0 {
        struct sublog sublog;
        struct erw erw;
-       __u32  faddr[2];
-       __u32  saddr;
+       dma32_t faddr[2];
+       dma32_t saddr;
 } __attribute__ ((packed));
 
 /**
@@ -364,6 +365,8 @@ extern struct device *cio_get_dma_css_dev(void);
 
 void *cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
                        size_t size);
+void *__cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
+                         size_t size, dma32_t *dma_handle);
 void cio_gp_dma_free(struct gen_pool *gp_dma, void *cpu_addr, size_t size);
 void cio_gp_dma_destroy(struct gen_pool *gp_dma, struct device *dma_dev);
 struct gen_pool *cio_gp_dma_create(struct device *dma_dev, int nr_pages);
diff --git a/arch/s390/include/asm/dma-types.h b/arch/s390/include/asm/dma-types.h
new file mode 100644 (file)
index 0000000..5c5734e
--- /dev/null
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_S390_DMA_TYPES_H_
+#define _ASM_S390_DMA_TYPES_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * typedef dma32_t
+ * Contains a 31 bit absolute address to a DMA capable piece of storage.
+ *
+ * For CIO, DMA addresses are always absolute addresses. These addresses tend
+ * to be used in architectured memory blocks (like ORB, IDAW, MIDAW). Under
+ * certain circumstances 31 bit wide addresses must be used because the
+ * address must fit in 31 bits.
+ *
+ * This type is to be used when such fields can be modelled as 32 bit wide.
+ */
+typedef u32 __bitwise dma32_t;
+
+/*
+ * typedef dma64_t
+ * Contains a 64 bit absolute address to a DMA capable piece of storage.
+ *
+ * For CIO, DMA addresses are always absolute addresses. These addresses tend
+ * to be used in architectured memory blocks (like ORB, IDAW, MIDAW).
+ *
+ * This type is to be used to model such 64 bit wide fields.
+ */
+typedef u64 __bitwise dma64_t;
+
+/*
+ * Although DMA addresses should be obtained using the DMA API, in cases when
+ * it is known that the first argument holds a virtual address that points to
+ * DMA-able 31 bit addressable storage, then this function can be safely used.
+ */
+static inline dma32_t virt_to_dma32(void *ptr)
+{
+       return (__force dma32_t)__pa32(ptr);
+}
+
+static inline void *dma32_to_virt(dma32_t addr)
+{
+       return __va((__force unsigned long)addr);
+}
+
+static inline dma32_t u32_to_dma32(u32 addr)
+{
+       return (__force dma32_t)addr;
+}
+
+static inline u32 dma32_to_u32(dma32_t addr)
+{
+       return (__force u32)addr;
+}
+
+static inline dma32_t dma32_add(dma32_t a, u32 b)
+{
+       return (__force dma32_t)((__force u32)a + b);
+}
+
+static inline dma32_t dma32_and(dma32_t a, u32 b)
+{
+       return (__force dma32_t)((__force u32)a & b);
+}
+
+/*
+ * Although DMA addresses should be obtained using the DMA API, in cases when
+ * it is known that the first argument holds a virtual address that points to
+ * DMA-able storage, then this function can be safely used.
+ */
+static inline dma64_t virt_to_dma64(void *ptr)
+{
+       return (__force dma64_t)__pa(ptr);
+}
+
+static inline void *dma64_to_virt(dma64_t addr)
+{
+       return __va((__force unsigned long)addr);
+}
+
+static inline dma64_t u64_to_dma64(u64 addr)
+{
+       return (__force dma64_t)addr;
+}
+
+static inline u64 dma64_to_u64(dma64_t addr)
+{
+       return (__force u64)addr;
+}
+
+static inline dma64_t dma64_add(dma64_t a, u64 b)
+{
+       return (__force dma64_t)((__force u64)a + b);
+}
+
+static inline dma64_t dma64_and(dma64_t a, u64 b)
+{
+       return (__force dma64_t)((__force u64)a & b);
+}
+
+#endif /* _ASM_S390_DMA_TYPES_H_ */
index 06f795855af787884d885d97525cae6eaea1a30d..c4589ec4505ed03aefd889d59cfb3f854f1b5d43 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 #include <linux/device.h>
 #include <linux/blk_types.h>
+#include <asm/dma-types.h>
 
 struct arqb {
        u64 data;
@@ -45,7 +46,7 @@ struct msb {
        u16:12;
        u16 bs:4;
        u32 blk_count;
-       u64 data_addr;
+       dma64_t data_addr;
        u64 scm_addr;
        u64:64;
 } __packed;
@@ -54,7 +55,7 @@ struct aidaw {
        u8 flags;
        u32 :24;
        u32 :32;
-       u64 data_addr;
+       dma64_t data_addr;
 } __packed;
 
 #define MSB_OC_CLEAR   0
index 29784b4b44f6d88f00b7b558639d505beb04389d..80f82a739b4530c916d8663e00c337f64a4552d1 100644 (file)
@@ -10,6 +10,7 @@
 #define _ASM_S390_FCX_H
 
 #include <linux/types.h>
+#include <asm/dma-types.h>
 
 #define TCW_FORMAT_DEFAULT             0
 #define TCW_TIDAW_FORMAT_DEFAULT       0
@@ -43,16 +44,16 @@ struct tcw {
        u32 r:1;
        u32 w:1;
        u32 :16;
-       u64 output;
-       u64 input;
-       u64 tsb;
-       u64 tccb;
+       dma64_t output;
+       dma64_t input;
+       dma64_t tsb;
+       dma64_t tccb;
        u32 output_count;
        u32 input_count;
        u32 :32;
        u32 :32;
        u32 :32;
-       u32 intrg;
+       dma32_t intrg;
 } __attribute__ ((packed, aligned(64)));
 
 #define TIDAW_FLAGS_LAST               (1 << (7 - 0))
@@ -73,7 +74,7 @@ struct tidaw {
        u32 flags:8;
        u32 :24;
        u32 count;
-       u64 addr;
+       dma64_t addr;
 } __attribute__ ((packed, aligned(16)));
 
 /**
index 59fcc3c72edfc6080e73ba04b1c4fba3e74a788c..ac68c657b28c8910bf8dda9cca009380eceb517a 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* 
+/*
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
 #include <linux/err.h>
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <asm/cio.h>
 #include <linux/uaccess.h>
+#include <asm/dma-types.h>
+#include <asm/cio.h>
 
-#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
-#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
+#define IDA_SIZE_SHIFT         12
+#define IDA_BLOCK_SIZE         (1UL << IDA_SIZE_SHIFT)
 
-#define IDA_2K_SIZE_LOG 11
-#define IDA_2K_BLOCK_SIZE (1L << IDA_2K_SIZE_LOG)
+#define IDA_2K_SIZE_SHIFT      11
+#define IDA_2K_BLOCK_SIZE      (1UL << IDA_2K_SIZE_SHIFT)
 
 /*
  * Test if an address/length pair needs an idal list.
  */
-static inline int
-idal_is_needed(void *vaddr, unsigned int length)
+static inline bool idal_is_needed(void *vaddr, unsigned int length)
 {
-       return ((__pa(vaddr) + length - 1) >> 31) != 0;
-}
+       dma64_t paddr = virt_to_dma64(vaddr);
 
+       return (((__force unsigned long)(paddr) + length - 1) >> 31) != 0;
+}
 
 /*
  * Return the number of idal words needed for an address/length pair.
  */
 static inline unsigned int idal_nr_words(void *vaddr, unsigned int length)
 {
-       return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length +
-               (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+       unsigned int cidaw;
+
+       cidaw = (unsigned long)vaddr & (IDA_BLOCK_SIZE - 1);
+       cidaw += length + IDA_BLOCK_SIZE - 1;
+       cidaw >>= IDA_SIZE_SHIFT;
+       return cidaw;
 }
 
 /*
@@ -50,26 +55,27 @@ static inline unsigned int idal_nr_words(void *vaddr, unsigned int length)
  */
 static inline unsigned int idal_2k_nr_words(void *vaddr, unsigned int length)
 {
-       return ((__pa(vaddr) & (IDA_2K_BLOCK_SIZE - 1)) + length +
-               (IDA_2K_BLOCK_SIZE - 1)) >> IDA_2K_SIZE_LOG;
+       unsigned int cidaw;
+
+       cidaw = (unsigned long)vaddr & (IDA_2K_BLOCK_SIZE - 1);
+       cidaw += length + IDA_2K_BLOCK_SIZE - 1;
+       cidaw >>= IDA_2K_SIZE_SHIFT;
+       return cidaw;
 }
 
 /*
  * Create the list of idal words for an address/length pair.
  */
-static inline unsigned long *idal_create_words(unsigned long *idaws,
-                                              void *vaddr, unsigned int length)
+static inline dma64_t *idal_create_words(dma64_t *idaws, void *vaddr, unsigned int length)
 {
-       unsigned long paddr;
+       dma64_t paddr = virt_to_dma64(vaddr);
        unsigned int cidaw;
 
-       paddr = __pa(vaddr);
-       cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length + 
-                (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
        *idaws++ = paddr;
-       paddr &= -IDA_BLOCK_SIZE;
+       cidaw = idal_nr_words(vaddr, length);
+       paddr = dma64_and(paddr, -IDA_BLOCK_SIZE);
        while (--cidaw > 0) {
-               paddr += IDA_BLOCK_SIZE;
+               paddr = dma64_add(paddr, IDA_BLOCK_SIZE);
                *idaws++ = paddr;
        }
        return idaws;
@@ -79,36 +85,33 @@ static inline unsigned long *idal_create_words(unsigned long *idaws,
  * Sets the address of the data in CCW.
  * If necessary it allocates an IDAL and sets the appropriate flags.
  */
-static inline int
-set_normalized_cda(struct ccw1 * ccw, void *vaddr)
+static inline int set_normalized_cda(struct ccw1 *ccw, void *vaddr)
 {
        unsigned int nridaws;
-       unsigned long *idal;
+       dma64_t *idal;
 
        if (ccw->flags & CCW_FLAG_IDA)
                return -EINVAL;
        nridaws = idal_nr_words(vaddr, ccw->count);
        if (nridaws > 0) {
-               idal = kmalloc(nridaws * sizeof(unsigned long),
-                              GFP_ATOMIC | GFP_DMA );
-               if (idal == NULL)
+               idal = kcalloc(nridaws, sizeof(*idal), GFP_ATOMIC | GFP_DMA);
+               if (!idal)
                        return -ENOMEM;
                idal_create_words(idal, vaddr, ccw->count);
                ccw->flags |= CCW_FLAG_IDA;
                vaddr = idal;
        }
-       ccw->cda = (__u32)(unsigned long) vaddr;
+       ccw->cda = virt_to_dma32(vaddr);
        return 0;
 }
 
 /*
  * Releases any allocated IDAL related to the CCW.
  */
-static inline void
-clear_normalized_cda(struct ccw1 * ccw)
+static inline void clear_normalized_cda(struct ccw1 *ccw)
 {
        if (ccw->flags & CCW_FLAG_IDA) {
-               kfree((void *)(unsigned long) ccw->cda);
+               kfree(dma32_to_virt(ccw->cda));
                ccw->flags &= ~CCW_FLAG_IDA;
        }
        ccw->cda = 0;
@@ -120,125 +123,138 @@ clear_normalized_cda(struct ccw1 * ccw)
 struct idal_buffer {
        size_t size;
        size_t page_order;
-       void *data[];
+       dma64_t data[];
 };
 
 /*
  * Allocate an idal buffer
  */
-static inline struct idal_buffer *
-idal_buffer_alloc(size_t size, int page_order)
+static inline struct idal_buffer *idal_buffer_alloc(size_t size, int page_order)
 {
-       struct idal_buffer *ib;
        int nr_chunks, nr_ptrs, i;
+       struct idal_buffer *ib;
+       void *vaddr;
 
-       nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
-       nr_chunks = (4096 << page_order) >> IDA_SIZE_LOG;
+       nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_SHIFT;
+       nr_chunks = (PAGE_SIZE << page_order) >> IDA_SIZE_SHIFT;
        ib = kmalloc(struct_size(ib, data, nr_ptrs), GFP_DMA | GFP_KERNEL);
-       if (ib == NULL)
+       if (!ib)
                return ERR_PTR(-ENOMEM);
        ib->size = size;
        ib->page_order = page_order;
        for (i = 0; i < nr_ptrs; i++) {
-               if ((i & (nr_chunks - 1)) != 0) {
-                       ib->data[i] = ib->data[i-1] + IDA_BLOCK_SIZE;
-                       continue;
-               }
-               ib->data[i] = (void *)
-                       __get_free_pages(GFP_KERNEL, page_order);
-               if (ib->data[i] != NULL)
+               if (i & (nr_chunks - 1)) {
+                       ib->data[i] = dma64_add(ib->data[i - 1], IDA_BLOCK_SIZE);
                        continue;
-               // Not enough memory
-               while (i >= nr_chunks) {
-                       i -= nr_chunks;
-                       free_pages((unsigned long) ib->data[i],
-                                  ib->page_order);
                }
-               kfree(ib);
-               return ERR_PTR(-ENOMEM);
+               vaddr = (void *)__get_free_pages(GFP_KERNEL, page_order);
+               if (!vaddr)
+                       goto error;
+               ib->data[i] = virt_to_dma64(vaddr);
        }
        return ib;
+error:
+       while (i >= nr_chunks) {
+               i -= nr_chunks;
+               vaddr = dma64_to_virt(ib->data[i]);
+               free_pages((unsigned long)vaddr, ib->page_order);
+       }
+       kfree(ib);
+       return ERR_PTR(-ENOMEM);
 }
 
 /*
  * Free an idal buffer.
  */
-static inline void
-idal_buffer_free(struct idal_buffer *ib)
+static inline void idal_buffer_free(struct idal_buffer *ib)
 {
        int nr_chunks, nr_ptrs, i;
+       void *vaddr;
 
-       nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
-       nr_chunks = (4096 << ib->page_order) >> IDA_SIZE_LOG;
-       for (i = 0; i < nr_ptrs; i += nr_chunks)
-               free_pages((unsigned long) ib->data[i], ib->page_order);
+       nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_SHIFT;
+       nr_chunks = (PAGE_SIZE << ib->page_order) >> IDA_SIZE_SHIFT;
+       for (i = 0; i < nr_ptrs; i += nr_chunks) {
+               vaddr = dma64_to_virt(ib->data[i]);
+               free_pages((unsigned long)vaddr, ib->page_order);
+       }
        kfree(ib);
 }
 
 /*
  * Test if a idal list is really needed.
  */
-static inline int
-__idal_buffer_is_needed(struct idal_buffer *ib)
+static inline bool __idal_buffer_is_needed(struct idal_buffer *ib)
 {
-       return ib->size > (4096ul << ib->page_order) ||
-               idal_is_needed(ib->data[0], ib->size);
+       if (ib->size > (PAGE_SIZE << ib->page_order))
+               return true;
+       return idal_is_needed(dma64_to_virt(ib->data[0]), ib->size);
 }
 
 /*
  * Set channel data address to idal buffer.
  */
-static inline void
-idal_buffer_set_cda(struct idal_buffer *ib, struct ccw1 *ccw)
+static inline void idal_buffer_set_cda(struct idal_buffer *ib, struct ccw1 *ccw)
 {
+       void *vaddr;
+
        if (__idal_buffer_is_needed(ib)) {
-               // setup idals;
-               ccw->cda = (u32)(addr_t) ib->data;
+               /* Setup idals */
+               ccw->cda = virt_to_dma32(ib->data);
                ccw->flags |= CCW_FLAG_IDA;
-       } else
-               // we do not need idals - use direct addressing
-               ccw->cda = (u32)(addr_t) ib->data[0];
+       } else {
+               /*
+                * No idals needed - use direct addressing. Convert from
+                * dma64_t to virt and then to dma32_t only because of type
+                * checking. The physical address is known to be below 2GB.
+                */
+               vaddr = dma64_to_virt(ib->data[0]);
+               ccw->cda = virt_to_dma32(vaddr);
+       }
        ccw->count = ib->size;
 }
 
 /*
  * Copy count bytes from an idal buffer to user memory
  */
-static inline size_t
-idal_buffer_to_user(struct idal_buffer *ib, void __user *to, size_t count)
+static inline size_t idal_buffer_to_user(struct idal_buffer *ib, void __user *to, size_t count)
 {
        size_t left;
+       void *vaddr;
        int i;
 
        BUG_ON(count > ib->size);
        for (i = 0; count > IDA_BLOCK_SIZE; i++) {
-               left = copy_to_user(to, ib->data[i], IDA_BLOCK_SIZE);
+               vaddr = dma64_to_virt(ib->data[i]);
+               left = copy_to_user(to, vaddr, IDA_BLOCK_SIZE);
                if (left)
                        return left + count - IDA_BLOCK_SIZE;
-               to = (void __user *) to + IDA_BLOCK_SIZE;
+               to = (void __user *)to + IDA_BLOCK_SIZE;
                count -= IDA_BLOCK_SIZE;
        }
-       return copy_to_user(to, ib->data[i], count);
+       vaddr = dma64_to_virt(ib->data[i]);
+       return copy_to_user(to, vaddr, count);
 }
 
 /*
  * Copy count bytes from user memory to an idal buffer
  */
-static inline size_t
-idal_buffer_from_user(struct idal_buffer *ib, const void __user *from, size_t count)
+static inline size_t idal_buffer_from_user(struct idal_buffer *ib, const void __user *from, size_t count)
 {
        size_t left;
+       void *vaddr;
        int i;
 
        BUG_ON(count > ib->size);
        for (i = 0; count > IDA_BLOCK_SIZE; i++) {
-               left = copy_from_user(ib->data[i], from, IDA_BLOCK_SIZE);
+               vaddr = dma64_to_virt(ib->data[i]);
+               left = copy_from_user(vaddr, from, IDA_BLOCK_SIZE);
                if (left)
                        return left + count - IDA_BLOCK_SIZE;
-               from = (void __user *) from + IDA_BLOCK_SIZE;
+               from = (void __user *)from + IDA_BLOCK_SIZE;
                count -= IDA_BLOCK_SIZE;
        }
-       return copy_from_user(ib->data[i], from, count);
+       vaddr = dma64_to_virt(ib->data[i]);
+       return copy_from_user(vaddr, from, count);
 }
 
 #endif
index ded9548d11d92535c4a27cf8d72d11bd680cdd68..9381879f7ecf6c4c59097884b9135cb1b9a84559 100644 (file)
@@ -181,9 +181,35 @@ int arch_make_page_accessible(struct page *page);
 #define __PAGE_OFFSET          0x0UL
 #define PAGE_OFFSET            0x0UL
 
-#define __pa(x)                        ((unsigned long)(x))
+#define __pa_nodebug(x)                ((unsigned long)(x))
+
+#ifdef __DECOMPRESSOR
+
+#define __pa(x)                        __pa_nodebug(x)
+#define __pa32(x)              __pa(x)
 #define __va(x)                        ((void *)(unsigned long)(x))
 
+#else /* __DECOMPRESSOR */
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+
+unsigned long __phys_addr(unsigned long x, bool is_31bit);
+
+#else /* CONFIG_DEBUG_VIRTUAL */
+
+static inline unsigned long __phys_addr(unsigned long x, bool is_31bit)
+{
+       return __pa_nodebug(x);
+}
+
+#endif /* CONFIG_DEBUG_VIRTUAL */
+
+#define __pa(x)                        __phys_addr((unsigned long)(x), false)
+#define __pa32(x)              __phys_addr((unsigned long)(x), true)
+#define __va(x)                        ((void *)(unsigned long)(x))
+
+#endif /* __DECOMPRESSOR */
+
 #define phys_to_pfn(phys)      ((phys) >> PAGE_SHIFT)
 #define pfn_to_phys(pfn)       ((pfn) << PAGE_SHIFT)
 
@@ -205,7 +231,7 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
 #define virt_to_page(kaddr)    pfn_to_page(virt_to_pfn(kaddr))
 #define page_to_virt(page)     pfn_to_virt(page_to_pfn(page))
 
-#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
+#define virt_addr_valid(kaddr) pfn_valid(phys_to_pfn(__pa_nodebug(kaddr)))
 
 #define VM_DATA_DEFAULT_FLAGS  VM_DATA_FLAGS_NON_EXEC
 
index 7cf00cf8fb0bc6197721987037c5f53ded7870bf..db9982f0e8cd02fe36bee8a45690aaa9e10d3b7b 100644 (file)
 
 #include <linux/bits.h>
 
+#define CIF_SIE                        0       /* CPU needs SIE exit cleanup */
 #define CIF_NOHZ_DELAY         2       /* delay HZ disable for a tick */
 #define CIF_ENABLED_WAIT       5       /* in enabled wait state */
 #define CIF_MCCK_GUEST         6       /* machine check happening in guest */
 #define CIF_DEDICATED_CPU      7       /* this CPU is dedicated */
 
+#define _CIF_SIE               BIT(CIF_SIE)
 #define _CIF_NOHZ_DELAY                BIT(CIF_NOHZ_DELAY)
 #define _CIF_ENABLED_WAIT      BIT(CIF_ENABLED_WAIT)
 #define _CIF_MCCK_GUEST                BIT(CIF_MCCK_GUEST)
index 788bc4467445c9da9471cf5037bcf2887f1303e8..2ad9324f633876d84d22025419256aa0ba251dc5 100644 (file)
 #define PIF_SYSCALL                    0       /* inside a system call */
 #define PIF_EXECVE_PGSTE_RESTART       1       /* restart execve for PGSTE binaries */
 #define PIF_SYSCALL_RET_SET            2       /* return value was set via ptrace */
-#define PIF_GUEST_FAULT                        3       /* indicates program check in sie64a */
 #define PIF_FTRACE_FULL_REGS           4       /* all register contents valid (ftrace) */
 
 #define _PIF_SYSCALL                   BIT(PIF_SYSCALL)
 #define _PIF_EXECVE_PGSTE_RESTART      BIT(PIF_EXECVE_PGSTE_RESTART)
 #define _PIF_SYSCALL_RET_SET           BIT(PIF_SYSCALL_RET_SET)
-#define _PIF_GUEST_FAULT               BIT(PIF_GUEST_FAULT)
 #define _PIF_FTRACE_FULL_REGS          BIT(PIF_FTRACE_FULL_REGS)
 
 #define PSW32_MASK_PER         _AC(0x40000000, UL)
index 2f983e0b95e09d98be327b75dd79e435fab8fff8..69c4ead0c33263cb77e01df2dc5ba5d0b88ff3c4 100644 (file)
@@ -9,8 +9,9 @@
 #define __QDIO_H__
 
 #include <linux/interrupt.h>
-#include <asm/cio.h>
+#include <asm/dma-types.h>
 #include <asm/ccwdev.h>
+#include <asm/cio.h>
 
 /* only use 4 queues to save some cachelines */
 #define QDIO_MAX_QUEUES_PER_IRQ                4
@@ -34,9 +35,9 @@
  * @dkey: access key for SLSB
  */
 struct qdesfmt0 {
-       u64 sliba;
-       u64 sla;
-       u64 slsba;
+       dma64_t sliba;
+       dma64_t sla;
+       dma64_t slsba;
        u32      : 32;
        u32 akey : 4;
        u32 bkey : 4;
@@ -74,7 +75,7 @@ struct qdr {
        /* private: */
        u32 res[9];
        /* public: */
-       u64 qiba;
+       dma64_t qiba;
        u32        : 32;
        u32 qkey   : 4;
        u32        : 28;
@@ -146,7 +147,7 @@ struct qaob {
        u8 flags;
        u16 cbtbs;
        u8 sb_count;
-       u64 sba[QDIO_MAX_ELEMENTS_PER_BUFFER];
+       dma64_t sba[QDIO_MAX_ELEMENTS_PER_BUFFER];
        u16 dcount[QDIO_MAX_ELEMENTS_PER_BUFFER];
        u64 user0;
        u64 res4[2];
@@ -208,7 +209,7 @@ struct qdio_buffer_element {
        u8 scount;
        u8 sflags;
        u32 length;
-       u64 addr;
+       dma64_t addr;
 } __attribute__ ((packed, aligned(16)));
 
 /**
@@ -224,7 +225,7 @@ struct qdio_buffer {
  * @sbal: absolute SBAL address
  */
 struct sl_element {
-       u64 sbal;
+       dma64_t sbal;
 } __attribute__ ((packed));
 
 /**
index 322bdcd4b616ada7601cc550f883ad4b71b119a0..56003e26cdbf3cbe5d482882a11f8b2f5ae90f4c 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/types.h>
 #include <asm/css_chars.h>
+#include <asm/dma-types.h>
 #include <asm/cio.h>
 
 /**
@@ -53,7 +54,7 @@ struct cmd_scsw {
        __u32 fctl : 3;
        __u32 actl : 7;
        __u32 stctl : 5;
-       __u32 cpa;
+       dma32_t cpa;
        __u32 dstat : 8;
        __u32 cstat : 8;
        __u32 count : 16;
@@ -93,7 +94,7 @@ struct tm_scsw {
        u32 fctl:3;
        u32 actl:7;
        u32 stctl:5;
-       u32 tcw;
+       dma32_t tcw;
        u32 dstat:8;
        u32 cstat:8;
        u32 fcxs:8;
@@ -125,7 +126,7 @@ struct eadm_scsw {
        u32 fctl:3;
        u32 actl:7;
        u32 stctl:5;
-       u32 aob;
+       dma32_t aob;
        u32 dstat:8;
        u32 cstat:8;
        u32:16;
index fc5277eab554bb4f315bacc87017f8ae95558f81..787394978bc0f86400ce30214c2e1b8eb3e82675 100644 (file)
@@ -119,33 +119,11 @@ _LPP_OFFSET       = __LC_LPP
        .endm
 
 #if IS_ENABLED(CONFIG_KVM)
-       /*
-        * The OUTSIDE macro jumps to the provided label in case the value
-        * in the provided register is outside of the provided range. The
-        * macro is useful for checking whether a PSW stored in a register
-        * pair points inside or outside of a block of instructions.
-        * @reg: register to check
-        * @start: start of the range
-        * @end: end of the range
-        * @outside_label: jump here if @reg is outside of [@start..@end)
-        */
-       .macro OUTSIDE reg,start,end,outside_label
-       lgr     %r14,\reg
-       larl    %r13,\start
-       slgr    %r14,%r13
-       clgfrl  %r14,.Lrange_size\@
-       jhe     \outside_label
-       .section .rodata, "a"
-       .balign 4
-.Lrange_size\@:
-       .long   \end - \start
-       .previous
-       .endm
-
-       .macro SIEEXIT
-       lg      %r9,__SF_SIE_CONTROL(%r15)      # get control block pointer
+       .macro SIEEXIT sie_control
+       lg      %r9,\sie_control                # get control block pointer
        ni      __SIE_PROG0C+3(%r9),0xfe        # no longer in SIE
        lctlg   %c1,%c1,__LC_KERNEL_ASCE        # load primary asce
+       ni      __LC_CPU_FLAGS+7,255-_CIF_SIE
        larl    %r9,sie_exit                    # skip forward to sie_exit
        .endm
 #endif
@@ -214,6 +192,7 @@ SYM_FUNC_START(__sie64a)
        lg      %r14,__LC_GMAP                  # get gmap pointer
        ltgr    %r14,%r14
        jz      .Lsie_gmap
+       oi      __LC_CPU_FLAGS+7,_CIF_SIE
        lctlg   %c1,%c1,__GMAP_ASCE(%r14)       # load primary asce
 .Lsie_gmap:
        lg      %r14,__SF_SIE_CONTROL(%r15)     # get control block pointer
@@ -234,7 +213,7 @@ SYM_FUNC_START(__sie64a)
        lg      %r14,__SF_SIE_CONTROL(%r15)     # get control block pointer
        ni      __SIE_PROG0C+3(%r14),0xfe       # no longer in SIE
        lctlg   %c1,%c1,__LC_KERNEL_ASCE        # load primary asce
-.Lsie_done:
+       ni      __LC_CPU_FLAGS+7,255-_CIF_SIE
 # some program checks are suppressing. C code (e.g. do_protection_exception)
 # will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
 # are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable.
@@ -337,20 +316,13 @@ SYM_CODE_START(pgm_check_handler)
        stpt    __LC_SYS_ENTER_TIMER
        BPOFF
        stmg    %r8,%r15,__LC_SAVE_AREA_SYNC
-       lghi    %r10,0
+       lgr     %r10,%r15
        lmg     %r8,%r9,__LC_PGM_OLD_PSW
        tmhh    %r8,0x0001              # coming from user space?
        jno     .Lpgm_skip_asce
        lctlg   %c1,%c1,__LC_KERNEL_ASCE
        j       3f                      # -> fault in user space
 .Lpgm_skip_asce:
-#if IS_ENABLED(CONFIG_KVM)
-       # cleanup critical section for program checks in __sie64a
-       OUTSIDE %r9,.Lsie_gmap,.Lsie_done,1f
-       BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
-       SIEEXIT
-       lghi    %r10,_PIF_GUEST_FAULT
-#endif
 1:     tmhh    %r8,0x4000              # PER bit set in old PSW ?
        jnz     2f                      # -> enabled, can't be a double fault
        tm      __LC_PGM_ILC+3,0x80     # check for per exception
@@ -361,13 +333,20 @@ SYM_CODE_START(pgm_check_handler)
        CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f
 3:     lg      %r15,__LC_KERNEL_STACK
 4:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
-       stg     %r10,__PT_FLAGS(%r11)
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
-       stmg    %r8,%r9,__PT_PSW(%r11)
-
+       stctg   %c1,%c1,__PT_CR1(%r11)
+#if IS_ENABLED(CONFIG_KVM)
+       lg      %r12,__LC_GMAP
+       clc     __GMAP_ASCE(8,%r12), __PT_CR1(%r11)
+       jne     5f
+       BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST
+       SIEEXIT __SF_SIE_CONTROL(%r10)
+#endif
+5:     stmg    %r8,%r9,__PT_PSW(%r11)
        # clear user controlled registers to prevent speculative use
        xgr     %r0,%r0
        xgr     %r1,%r1
@@ -416,9 +395,10 @@ SYM_CODE_START(\name)
        tmhh    %r8,0x0001                      # interrupting from user ?
        jnz     1f
 #if IS_ENABLED(CONFIG_KVM)
-       OUTSIDE %r9,.Lsie_gmap,.Lsie_done,0f
+       TSTMSK  __LC_CPU_FLAGS,_CIF_SIE
+       jz      0f
        BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
-       SIEEXIT
+       SIEEXIT __SF_SIE_CONTROL(%r15)
 #endif
 0:     CHECK_STACK __LC_SAVE_AREA_ASYNC
        aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
@@ -513,11 +493,20 @@ SYM_CODE_START(mcck_int_handler)
        TSTMSK  __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID
        jno     .Lmcck_panic
 #if IS_ENABLED(CONFIG_KVM)
-       OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_user
-       OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f
+       TSTMSK  __LC_CPU_FLAGS,_CIF_SIE
+       jz      .Lmcck_user
+       # Need to compare the address instead of a CIF_SIE* flag.
+       # Otherwise there would be a race between setting the flag
+       # and entering SIE (or leaving and clearing the flag). This
+       # would cause machine checks targeted at the guest to be
+       # handled by the host.
+       larl    %r14,.Lsie_entry
+       clgrjl  %r9,%r14, 4f
+       larl    %r14,.Lsie_leave
+       clgrjhe %r9,%r14, 4f
        oi      __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
 4:     BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
-       SIEEXIT
+       SIEEXIT __SF_SIE_CONTROL(%r15)
 #endif
 .Lmcck_user:
        lg      %r15,__LC_MCCK_STACK
index 1b1be3110cfc111e71ecf06d2c513700a63b59aa..2be30a96696a382a3e47275977ce42de2b8065c5 100644 (file)
@@ -397,7 +397,7 @@ static void service_level_vm_print(struct seq_file *m,
 {
        char *query_buffer, *str;
 
-       query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA);
+       query_buffer = kmalloc(1024, GFP_KERNEL);
        if (!query_buffer)
                return;
        cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL);
index e0a88dcaf5cb7a16577ec7646d2ec69f76a9386c..24a18e5ef6e8e3ff8fa7754e0e20de0899534511 100644 (file)
@@ -210,13 +210,13 @@ void vtime_flush(struct task_struct *tsk)
                virt_timer_expire();
 
        steal = S390_lowcore.steal_timer;
-       avg_steal = S390_lowcore.avg_steal_timer / 2;
+       avg_steal = S390_lowcore.avg_steal_timer;
        if ((s64) steal > 0) {
                S390_lowcore.steal_timer = 0;
                account_steal_time(cputime_to_nsecs(steal));
                avg_steal += steal;
        }
-       S390_lowcore.avg_steal_timer = avg_steal;
+       S390_lowcore.avg_steal_timer = avg_steal / 2;
 }
 
 static u64 vtime_delta(void)
index 352ff520fd9430a1acffe262c2d7046ba7083890..f6c2db7a86690814e2e26bd5a0a4d0477d1b3648 100644 (file)
@@ -7,6 +7,7 @@ obj-y           := init.o fault.o extmem.o mmap.o vmem.o maccess.o
 obj-y          += page-states.o pageattr.o pgtable.o pgalloc.o extable.o
 
 obj-$(CONFIG_CMM)              += cmm.o
+obj-$(CONFIG_DEBUG_VIRTUAL)    += physaddr.o
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
 obj-$(CONFIG_PTDUMP_CORE)      += dump_pagetables.o
 obj-$(CONFIG_PGSTE)            += gmap.o
index ac4c78546d973713859079520552148ae7b2c0b7..c421dd44ffbe0346ab31028d433e5b3b7a2df626 100644 (file)
@@ -67,13 +67,15 @@ early_initcall(fault_init);
 static enum fault_type get_fault_type(struct pt_regs *regs)
 {
        union teid teid = { .val = regs->int_parm_long };
+       struct gmap *gmap;
 
        if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
                if (user_mode(regs))
                        return USER_FAULT;
                if (!IS_ENABLED(CONFIG_PGSTE))
                        return KERNEL_FAULT;
-               if (test_pt_regs_flag(regs, PIF_GUEST_FAULT))
+               gmap = (struct gmap *)S390_lowcore.gmap;
+               if (regs->cr1 == gmap->asce)
                        return GMAP_FAULT;
                return KERNEL_FAULT;
        }
diff --git a/arch/s390/mm/physaddr.c b/arch/s390/mm/physaddr.c
new file mode 100644 (file)
index 0000000..59de866
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/mmdebug.h>
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+
+unsigned long __phys_addr(unsigned long x, bool is_31bit)
+{
+       VIRTUAL_BUG_ON(is_vmalloc_or_module_addr((void *)(x)));
+       x = __pa_nodebug(x);
+       if (is_31bit)
+               VIRTUAL_BUG_ON(x >> 31);
+       return x;
+}
+EXPORT_SYMBOL(__phys_addr);
index f3fba967445acab88047b5db80ebb5d4bc4a25cd..81764882d87d370e766076a5da652e37e0d7da81 100644 (file)
@@ -72,7 +72,7 @@ static void hd64461_irq_demux(struct irq_desc *desc)
        }
 }
 
-int __init setup_hd64461(void)
+static int __init setup_hd64461(void)
 {
        int irq_base, i;
 
index 431bc18f0a4119bdd11c2fd3c6c3e83a517bc6c1..9f666280d80cc19169cf6331a95d0be8d33cc514 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/string.h>
 #include <asm/dma.h>
 
-static struct bus_type dma_subsys = {
+static const struct bus_type dma_subsys = {
        .name = "dma",
        .dev_name = "dma",
 };
index 7aed87cbf386257237ca55d98ff61eb22b0b7ba2..39886bab943a88b3a8262a733a7e2e82269934f8 100644 (file)
@@ -472,10 +472,6 @@ config X86_MPPARSE
          For old smp systems that do not have proper acpi support. Newer systems
          (esp with 64bit cpus) with acpi support, MADT and DSDT will override it
 
-config GOLDFISH
-       def_bool y
-       depends on X86_GOLDFISH
-
 config X86_CPU_RESCTRL
        bool "x86 CPU resource control support"
        depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD)
index 620f6257bbe9358ce918bbf35aff659b683a2149..fd63051bbbbb8255b8c0d24f89e90d074a51e6f2 100644 (file)
@@ -9,7 +9,9 @@ include $(srctree)/lib/vdso/Makefile
 # Sanitizer runtimes are unavailable and cannot be linked here.
 KASAN_SANITIZE                 := n
 KMSAN_SANITIZE_vclock_gettime.o := n
+KMSAN_SANITIZE_vdso32/vclock_gettime.o := n
 KMSAN_SANITIZE_vgetcpu.o       := n
+KMSAN_SANITIZE_vdso32/vgetcpu.o        := n
 
 UBSAN_SANITIZE                 := n
 KCSAN_SANITIZE                 := n
index 8f3a4d16bb791f37ac924858668d37eb49446f91..17a71e92a343e128dc457e0db61f7185a59c3868 100644 (file)
@@ -667,14 +667,14 @@ void hyperv_cleanup(void)
        hv_hypercall_pg = NULL;
 
        /* Reset the hypercall page */
-       hypercall_msr.as_uint64 = hv_get_register(HV_X64_MSR_HYPERCALL);
+       hypercall_msr.as_uint64 = hv_get_msr(HV_X64_MSR_HYPERCALL);
        hypercall_msr.enable = 0;
-       hv_set_register(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+       hv_set_msr(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 
        /* Reset the TSC page */
-       tsc_msr.as_uint64 = hv_get_register(HV_X64_MSR_REFERENCE_TSC);
+       tsc_msr.as_uint64 = hv_get_msr(HV_X64_MSR_REFERENCE_TSC);
        tsc_msr.enable = 0;
-       hv_set_register(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
+       hv_set_msr(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 }
 
 void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
index 737d6f7a615535374b6f725ca61d1c8d64c1b1dc..151e851bef09dab2790d440da064046b10df2c14 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/paravirt.h>
 #include <asm/apic.h>
 
-static bool __initdata hv_pvspin = true;
+static bool hv_pvspin __initdata = true;
 
 static void hv_qlock_kick(int cpu)
 {
@@ -64,6 +64,7 @@ __visible bool hv_vcpu_is_preempted(int vcpu)
 {
        return false;
 }
+
 PV_CALLEE_SAVE_REGS_THUNK(hv_vcpu_is_preempted);
 
 void __init hv_init_spinlocks(void)
index edd2f35b2a5e100ce9662ceead612bc04c213f29..5c7de79423b8a5e13feea450abea601cae9720d0 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/i8259.h>
 #include <asm/mshyperv.h>
 #include <asm/realmode.h>
+#include <../kernel/smpboot.h>
 
 extern struct boot_params boot_params;
 static struct real_mode_header hv_vtl_real_mode_header;
@@ -65,7 +66,7 @@ static void hv_vtl_ap_entry(void)
        ((secondary_startup_64_fn)secondary_startup_64)(&boot_params, &boot_params);
 }
 
-static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored)
+static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
 {
        u64 status;
        int ret = 0;
@@ -79,7 +80,9 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, u64 eip_ignored)
        struct ldttss_desc *ldt;
        struct desc_struct *gdt;
 
-       u64 rsp = current->thread.sp;
+       struct task_struct *idle = idle_thread_get(cpu);
+       u64 rsp = (unsigned long)idle->thread.sp;
+
        u64 rip = (u64)&hv_vtl_ap_entry;
 
        native_store_gdt(&gdt_ptr);
@@ -206,7 +209,15 @@ static int hv_vtl_apicid_to_vp_id(u32 apic_id)
 
 static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip)
 {
-       int vp_id;
+       int vp_id, cpu;
+
+       /* Find the logical CPU for the APIC ID */
+       for_each_present_cpu(cpu) {
+               if (arch_match_cpu_phys_id(cpu, apicid))
+                       break;
+       }
+       if (cpu >= nr_cpu_ids)
+               return -EINVAL;
 
        pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid);
        vp_id = hv_vtl_apicid_to_vp_id(apicid);
@@ -220,7 +231,7 @@ static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip)
                return -EINVAL;
        }
 
-       return hv_vtl_bringup_vcpu(vp_id, start_eip);
+       return hv_vtl_bringup_vcpu(vp_id, cpu, start_eip);
 }
 
 int __init hv_vtl_early_init(void)
index 2ff26f53cd62446e6260025b7a7094fee1d5b765..3787d26810c1c42902a354c1d0b5a8a6541f9000 100644 (file)
@@ -182,7 +182,7 @@ enum hv_isolation_type {
 #define HV_X64_MSR_HYPERCALL                   0x40000001
 
 /* MSR used to provide vcpu index */
-#define HV_REGISTER_VP_INDEX                   0x40000002
+#define HV_X64_MSR_VP_INDEX                    0x40000002
 
 /* MSR used to reset the guest OS. */
 #define HV_X64_MSR_RESET                       0x40000003
@@ -191,10 +191,10 @@ enum hv_isolation_type {
 #define HV_X64_MSR_VP_RUNTIME                  0x40000010
 
 /* MSR used to read the per-partition time reference counter */
-#define HV_REGISTER_TIME_REF_COUNT             0x40000020
+#define HV_X64_MSR_TIME_REF_COUNT              0x40000020
 
 /* A partition's reference time stamp counter (TSC) page */
-#define HV_REGISTER_REFERENCE_TSC              0x40000021
+#define HV_X64_MSR_REFERENCE_TSC               0x40000021
 
 /* MSR used to retrieve the TSC frequency */
 #define HV_X64_MSR_TSC_FREQUENCY               0x40000022
@@ -209,61 +209,61 @@ enum hv_isolation_type {
 #define HV_X64_MSR_VP_ASSIST_PAGE              0x40000073
 
 /* Define synthetic interrupt controller model specific registers. */
-#define HV_REGISTER_SCONTROL                   0x40000080
-#define HV_REGISTER_SVERSION                   0x40000081
-#define HV_REGISTER_SIEFP                      0x40000082
-#define HV_REGISTER_SIMP                       0x40000083
-#define HV_REGISTER_EOM                                0x40000084
-#define HV_REGISTER_SINT0                      0x40000090
-#define HV_REGISTER_SINT1                      0x40000091
-#define HV_REGISTER_SINT2                      0x40000092
-#define HV_REGISTER_SINT3                      0x40000093
-#define HV_REGISTER_SINT4                      0x40000094
-#define HV_REGISTER_SINT5                      0x40000095
-#define HV_REGISTER_SINT6                      0x40000096
-#define HV_REGISTER_SINT7                      0x40000097
-#define HV_REGISTER_SINT8                      0x40000098
-#define HV_REGISTER_SINT9                      0x40000099
-#define HV_REGISTER_SINT10                     0x4000009A
-#define HV_REGISTER_SINT11                     0x4000009B
-#define HV_REGISTER_SINT12                     0x4000009C
-#define HV_REGISTER_SINT13                     0x4000009D
-#define HV_REGISTER_SINT14                     0x4000009E
-#define HV_REGISTER_SINT15                     0x4000009F
+#define HV_X64_MSR_SCONTROL                    0x40000080
+#define HV_X64_MSR_SVERSION                    0x40000081
+#define HV_X64_MSR_SIEFP                       0x40000082
+#define HV_X64_MSR_SIMP                                0x40000083
+#define HV_X64_MSR_EOM                         0x40000084
+#define HV_X64_MSR_SINT0                       0x40000090
+#define HV_X64_MSR_SINT1                       0x40000091
+#define HV_X64_MSR_SINT2                       0x40000092
+#define HV_X64_MSR_SINT3                       0x40000093
+#define HV_X64_MSR_SINT4                       0x40000094
+#define HV_X64_MSR_SINT5                       0x40000095
+#define HV_X64_MSR_SINT6                       0x40000096
+#define HV_X64_MSR_SINT7                       0x40000097
+#define HV_X64_MSR_SINT8                       0x40000098
+#define HV_X64_MSR_SINT9                       0x40000099
+#define HV_X64_MSR_SINT10                      0x4000009A
+#define HV_X64_MSR_SINT11                      0x4000009B
+#define HV_X64_MSR_SINT12                      0x4000009C
+#define HV_X64_MSR_SINT13                      0x4000009D
+#define HV_X64_MSR_SINT14                      0x4000009E
+#define HV_X64_MSR_SINT15                      0x4000009F
 
 /*
  * Define synthetic interrupt controller model specific registers for
  * nested hypervisor.
  */
-#define HV_REGISTER_NESTED_SCONTROL            0x40001080
-#define HV_REGISTER_NESTED_SVERSION            0x40001081
-#define HV_REGISTER_NESTED_SIEFP               0x40001082
-#define HV_REGISTER_NESTED_SIMP                0x40001083
-#define HV_REGISTER_NESTED_EOM                 0x40001084
-#define HV_REGISTER_NESTED_SINT0               0x40001090
+#define HV_X64_MSR_NESTED_SCONTROL             0x40001080
+#define HV_X64_MSR_NESTED_SVERSION             0x40001081
+#define HV_X64_MSR_NESTED_SIEFP                        0x40001082
+#define HV_X64_MSR_NESTED_SIMP                 0x40001083
+#define HV_X64_MSR_NESTED_EOM                  0x40001084
+#define HV_X64_MSR_NESTED_SINT0                        0x40001090
 
 /*
  * Synthetic Timer MSRs. Four timers per vcpu.
  */
-#define HV_REGISTER_STIMER0_CONFIG             0x400000B0
-#define HV_REGISTER_STIMER0_COUNT              0x400000B1
-#define HV_REGISTER_STIMER1_CONFIG             0x400000B2
-#define HV_REGISTER_STIMER1_COUNT              0x400000B3
-#define HV_REGISTER_STIMER2_CONFIG             0x400000B4
-#define HV_REGISTER_STIMER2_COUNT              0x400000B5
-#define HV_REGISTER_STIMER3_CONFIG             0x400000B6
-#define HV_REGISTER_STIMER3_COUNT              0x400000B7
+#define HV_X64_MSR_STIMER0_CONFIG              0x400000B0
+#define HV_X64_MSR_STIMER0_COUNT               0x400000B1
+#define HV_X64_MSR_STIMER1_CONFIG              0x400000B2
+#define HV_X64_MSR_STIMER1_COUNT               0x400000B3
+#define HV_X64_MSR_STIMER2_CONFIG              0x400000B4
+#define HV_X64_MSR_STIMER2_COUNT               0x400000B5
+#define HV_X64_MSR_STIMER3_CONFIG              0x400000B6
+#define HV_X64_MSR_STIMER3_COUNT               0x400000B7
 
 /* Hyper-V guest idle MSR */
 #define HV_X64_MSR_GUEST_IDLE                  0x400000F0
 
 /* Hyper-V guest crash notification MSR's */
-#define HV_REGISTER_CRASH_P0                   0x40000100
-#define HV_REGISTER_CRASH_P1                   0x40000101
-#define HV_REGISTER_CRASH_P2                   0x40000102
-#define HV_REGISTER_CRASH_P3                   0x40000103
-#define HV_REGISTER_CRASH_P4                   0x40000104
-#define HV_REGISTER_CRASH_CTL                  0x40000105
+#define HV_X64_MSR_CRASH_P0                    0x40000100
+#define HV_X64_MSR_CRASH_P1                    0x40000101
+#define HV_X64_MSR_CRASH_P2                    0x40000102
+#define HV_X64_MSR_CRASH_P3                    0x40000103
+#define HV_X64_MSR_CRASH_P4                    0x40000104
+#define HV_X64_MSR_CRASH_CTL                   0x40000105
 
 /* TSC emulation after migration */
 #define HV_X64_MSR_REENLIGHTENMENT_CONTROL     0x40000106
@@ -276,31 +276,38 @@ enum hv_isolation_type {
 /* HV_X64_MSR_TSC_INVARIANT_CONTROL bits */
 #define HV_EXPOSE_INVARIANT_TSC                BIT_ULL(0)
 
-/* Register name aliases for temporary compatibility */
-#define HV_X64_MSR_STIMER0_COUNT       HV_REGISTER_STIMER0_COUNT
-#define HV_X64_MSR_STIMER0_CONFIG      HV_REGISTER_STIMER0_CONFIG
-#define HV_X64_MSR_STIMER1_COUNT       HV_REGISTER_STIMER1_COUNT
-#define HV_X64_MSR_STIMER1_CONFIG      HV_REGISTER_STIMER1_CONFIG
-#define HV_X64_MSR_STIMER2_COUNT       HV_REGISTER_STIMER2_COUNT
-#define HV_X64_MSR_STIMER2_CONFIG      HV_REGISTER_STIMER2_CONFIG
-#define HV_X64_MSR_STIMER3_COUNT       HV_REGISTER_STIMER3_COUNT
-#define HV_X64_MSR_STIMER3_CONFIG      HV_REGISTER_STIMER3_CONFIG
-#define HV_X64_MSR_SCONTROL            HV_REGISTER_SCONTROL
-#define HV_X64_MSR_SVERSION            HV_REGISTER_SVERSION
-#define HV_X64_MSR_SIMP                        HV_REGISTER_SIMP
-#define HV_X64_MSR_SIEFP               HV_REGISTER_SIEFP
-#define HV_X64_MSR_VP_INDEX            HV_REGISTER_VP_INDEX
-#define HV_X64_MSR_EOM                 HV_REGISTER_EOM
-#define HV_X64_MSR_SINT0               HV_REGISTER_SINT0
-#define HV_X64_MSR_SINT15              HV_REGISTER_SINT15
-#define HV_X64_MSR_CRASH_P0            HV_REGISTER_CRASH_P0
-#define HV_X64_MSR_CRASH_P1            HV_REGISTER_CRASH_P1
-#define HV_X64_MSR_CRASH_P2            HV_REGISTER_CRASH_P2
-#define HV_X64_MSR_CRASH_P3            HV_REGISTER_CRASH_P3
-#define HV_X64_MSR_CRASH_P4            HV_REGISTER_CRASH_P4
-#define HV_X64_MSR_CRASH_CTL           HV_REGISTER_CRASH_CTL
-#define HV_X64_MSR_TIME_REF_COUNT      HV_REGISTER_TIME_REF_COUNT
-#define HV_X64_MSR_REFERENCE_TSC       HV_REGISTER_REFERENCE_TSC
+/*
+ * To support arch-generic code calling hv_set/get_register:
+ * - On x86, HV_MSR_ indicates an MSR accessed via rdmsrl/wrmsrl
+ * - On ARM, HV_MSR_ indicates a VP register accessed via hypercall
+ */
+#define HV_MSR_CRASH_P0                (HV_X64_MSR_CRASH_P0)
+#define HV_MSR_CRASH_P1                (HV_X64_MSR_CRASH_P1)
+#define HV_MSR_CRASH_P2                (HV_X64_MSR_CRASH_P2)
+#define HV_MSR_CRASH_P3                (HV_X64_MSR_CRASH_P3)
+#define HV_MSR_CRASH_P4                (HV_X64_MSR_CRASH_P4)
+#define HV_MSR_CRASH_CTL       (HV_X64_MSR_CRASH_CTL)
+
+#define HV_MSR_VP_INDEX                (HV_X64_MSR_VP_INDEX)
+#define HV_MSR_TIME_REF_COUNT  (HV_X64_MSR_TIME_REF_COUNT)
+#define HV_MSR_REFERENCE_TSC   (HV_X64_MSR_REFERENCE_TSC)
+
+#define HV_MSR_SINT0           (HV_X64_MSR_SINT0)
+#define HV_MSR_SVERSION                (HV_X64_MSR_SVERSION)
+#define HV_MSR_SCONTROL                (HV_X64_MSR_SCONTROL)
+#define HV_MSR_SIEFP           (HV_X64_MSR_SIEFP)
+#define HV_MSR_SIMP            (HV_X64_MSR_SIMP)
+#define HV_MSR_EOM             (HV_X64_MSR_EOM)
+
+#define HV_MSR_NESTED_SCONTROL (HV_X64_MSR_NESTED_SCONTROL)
+#define HV_MSR_NESTED_SVERSION (HV_X64_MSR_NESTED_SVERSION)
+#define HV_MSR_NESTED_SIEFP    (HV_X64_MSR_NESTED_SIEFP)
+#define HV_MSR_NESTED_SIMP     (HV_X64_MSR_NESTED_SIMP)
+#define HV_MSR_NESTED_EOM      (HV_X64_MSR_NESTED_EOM)
+#define HV_MSR_NESTED_SINT0    (HV_X64_MSR_NESTED_SINT0)
+
+#define HV_MSR_STIMER0_CONFIG  (HV_X64_MSR_STIMER0_CONFIG)
+#define HV_MSR_STIMER0_COUNT   (HV_X64_MSR_STIMER0_COUNT)
 
 /*
  * Registers are only accessible via HVCALL_GET_VP_REGISTERS hvcall and
index ce4ce8720d55c90ee12070068452b694adb4d800..390c4d13956d0c051494b3898ab13080a74e7494 100644 (file)
@@ -293,24 +293,24 @@ static inline void hv_ivm_msr_write(u64 msr, u64 value) {}
 static inline void hv_ivm_msr_read(u64 msr, u64 *value) {}
 #endif
 
-static inline bool hv_is_synic_reg(unsigned int reg)
+static inline bool hv_is_synic_msr(unsigned int reg)
 {
-       return (reg >= HV_REGISTER_SCONTROL) &&
-              (reg <= HV_REGISTER_SINT15);
+       return (reg >= HV_X64_MSR_SCONTROL) &&
+              (reg <= HV_X64_MSR_SINT15);
 }
 
-static inline bool hv_is_sint_reg(unsigned int reg)
+static inline bool hv_is_sint_msr(unsigned int reg)
 {
-       return (reg >= HV_REGISTER_SINT0) &&
-              (reg <= HV_REGISTER_SINT15);
+       return (reg >= HV_X64_MSR_SINT0) &&
+              (reg <= HV_X64_MSR_SINT15);
 }
 
-u64 hv_get_register(unsigned int reg);
-void hv_set_register(unsigned int reg, u64 value);
-u64 hv_get_non_nested_register(unsigned int reg);
-void hv_set_non_nested_register(unsigned int reg, u64 value);
+u64 hv_get_msr(unsigned int reg);
+void hv_set_msr(unsigned int reg, u64 value);
+u64 hv_get_non_nested_msr(unsigned int reg);
+void hv_set_non_nested_msr(unsigned int reg, u64 value);
 
-static __always_inline u64 hv_raw_get_register(unsigned int reg)
+static __always_inline u64 hv_raw_get_msr(unsigned int reg)
 {
        return __rdmsr(reg);
 }
@@ -331,10 +331,10 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,
 {
        return -1;
 }
-static inline void hv_set_register(unsigned int reg, u64 value) { }
-static inline u64 hv_get_register(unsigned int reg) { return 0; }
-static inline void hv_set_non_nested_register(unsigned int reg, u64 value) { }
-static inline u64 hv_get_non_nested_register(unsigned int reg) { return 0; }
+static inline void hv_set_msr(unsigned int reg, u64 value) { }
+static inline u64 hv_get_msr(unsigned int reg) { return 0; }
+static inline void hv_set_non_nested_msr(unsigned int reg, u64 value) { }
+static inline u64 hv_get_non_nested_msr(unsigned int reg) { return 0; }
 #endif /* CONFIG_HYPERV */
 
 
index a9088250770f2a3d6320040f815f1b9e6cba653b..64fbd2dbc5b7615bf35ff8dfe9cacec7df1ca485 100644 (file)
@@ -62,6 +62,11 @@ void xen_arch_unregister_cpu(int num);
 #ifdef CONFIG_PVH
 void __init xen_pvh_init(struct boot_params *boot_params);
 void __init mem_map_via_hcall(struct boot_params *boot_params_p);
+#ifdef CONFIG_XEN_PVH
+void __init xen_reserve_extra_memory(struct boot_params *bootp);
+#else
+static inline void xen_reserve_extra_memory(struct boot_params *bootp) { }
+#endif
 #endif
 
 /* Lazy mode for batching updates / context switch */
index 303fef824167d9c57e8b6068eecd62f31f071638..e0fd57a8ba840431e1f48dd61c1bc0ffc9fc0d82 100644 (file)
@@ -45,70 +45,70 @@ bool hyperv_paravisor_present __ro_after_init;
 EXPORT_SYMBOL_GPL(hyperv_paravisor_present);
 
 #if IS_ENABLED(CONFIG_HYPERV)
-static inline unsigned int hv_get_nested_reg(unsigned int reg)
+static inline unsigned int hv_get_nested_msr(unsigned int reg)
 {
-       if (hv_is_sint_reg(reg))
-               return reg - HV_REGISTER_SINT0 + HV_REGISTER_NESTED_SINT0;
+       if (hv_is_sint_msr(reg))
+               return reg - HV_X64_MSR_SINT0 + HV_X64_MSR_NESTED_SINT0;
 
        switch (reg) {
-       case HV_REGISTER_SIMP:
-               return HV_REGISTER_NESTED_SIMP;
-       case HV_REGISTER_SIEFP:
-               return HV_REGISTER_NESTED_SIEFP;
-       case HV_REGISTER_SVERSION:
-               return HV_REGISTER_NESTED_SVERSION;
-       case HV_REGISTER_SCONTROL:
-               return HV_REGISTER_NESTED_SCONTROL;
-       case HV_REGISTER_EOM:
-               return HV_REGISTER_NESTED_EOM;
+       case HV_X64_MSR_SIMP:
+               return HV_X64_MSR_NESTED_SIMP;
+       case HV_X64_MSR_SIEFP:
+               return HV_X64_MSR_NESTED_SIEFP;
+       case HV_X64_MSR_SVERSION:
+               return HV_X64_MSR_NESTED_SVERSION;
+       case HV_X64_MSR_SCONTROL:
+               return HV_X64_MSR_NESTED_SCONTROL;
+       case HV_X64_MSR_EOM:
+               return HV_X64_MSR_NESTED_EOM;
        default:
                return reg;
        }
 }
 
-u64 hv_get_non_nested_register(unsigned int reg)
+u64 hv_get_non_nested_msr(unsigned int reg)
 {
        u64 value;
 
-       if (hv_is_synic_reg(reg) && ms_hyperv.paravisor_present)
+       if (hv_is_synic_msr(reg) && ms_hyperv.paravisor_present)
                hv_ivm_msr_read(reg, &value);
        else
                rdmsrl(reg, value);
        return value;
 }
-EXPORT_SYMBOL_GPL(hv_get_non_nested_register);
+EXPORT_SYMBOL_GPL(hv_get_non_nested_msr);
 
-void hv_set_non_nested_register(unsigned int reg, u64 value)
+void hv_set_non_nested_msr(unsigned int reg, u64 value)
 {
-       if (hv_is_synic_reg(reg) && ms_hyperv.paravisor_present) {
+       if (hv_is_synic_msr(reg) && ms_hyperv.paravisor_present) {
                hv_ivm_msr_write(reg, value);
 
                /* Write proxy bit via wrmsl instruction */
-               if (hv_is_sint_reg(reg))
+               if (hv_is_sint_msr(reg))
                        wrmsrl(reg, value | 1 << 20);
        } else {
                wrmsrl(reg, value);
        }
 }
-EXPORT_SYMBOL_GPL(hv_set_non_nested_register);
+EXPORT_SYMBOL_GPL(hv_set_non_nested_msr);
 
-u64 hv_get_register(unsigned int reg)
+u64 hv_get_msr(unsigned int reg)
 {
        if (hv_nested)
-               reg = hv_get_nested_reg(reg);
+               reg = hv_get_nested_msr(reg);
 
-       return hv_get_non_nested_register(reg);
+       return hv_get_non_nested_msr(reg);
 }
-EXPORT_SYMBOL_GPL(hv_get_register);
+EXPORT_SYMBOL_GPL(hv_get_msr);
 
-void hv_set_register(unsigned int reg, u64 value)
+void hv_set_msr(unsigned int reg, u64 value)
 {
        if (hv_nested)
-               reg = hv_get_nested_reg(reg);
+               reg = hv_get_nested_msr(reg);
 
-       hv_set_non_nested_register(reg, value);
+       hv_set_non_nested_msr(reg, value);
 }
-EXPORT_SYMBOL_GPL(hv_set_register);
+EXPORT_SYMBOL_GPL(hv_set_msr);
 
 static void (*vmbus_handler)(void);
 static void (*hv_stimer0_handler)(void);
@@ -352,13 +352,24 @@ static void __init reduced_hw_init(void)
        x86_init.irqs.pre_vector_init   = x86_init_noop;
 }
 
+int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
+{
+       unsigned int hv_max_functions;
+
+       hv_max_functions = cpuid_eax(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS);
+       if (hv_max_functions < HYPERV_CPUID_VERSION) {
+               pr_err("%s: Could not detect Hyper-V version\n", __func__);
+               return -ENODEV;
+       }
+
+       cpuid(HYPERV_CPUID_VERSION, &info->eax, &info->ebx, &info->ecx, &info->edx);
+
+       return 0;
+}
+
 static void __init ms_hyperv_init_platform(void)
 {
        int hv_max_functions_eax;
-       int hv_host_info_eax;
-       int hv_host_info_ebx;
-       int hv_host_info_ecx;
-       int hv_host_info_edx;
 
 #ifdef CONFIG_PARAVIRT
        pv_info.name = "Hyper-V";
@@ -409,21 +420,6 @@ static void __init ms_hyperv_init_platform(void)
                pr_info("Hyper-V: running on a nested hypervisor\n");
        }
 
-       /*
-        * Extract host information.
-        */
-       if (hv_max_functions_eax >= HYPERV_CPUID_VERSION) {
-               hv_host_info_eax = cpuid_eax(HYPERV_CPUID_VERSION);
-               hv_host_info_ebx = cpuid_ebx(HYPERV_CPUID_VERSION);
-               hv_host_info_ecx = cpuid_ecx(HYPERV_CPUID_VERSION);
-               hv_host_info_edx = cpuid_edx(HYPERV_CPUID_VERSION);
-
-               pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
-                       hv_host_info_ebx >> 16, hv_host_info_ebx & 0xFFFF,
-                       hv_host_info_eax, hv_host_info_edx & 0xFFFFFF,
-                       hv_host_info_ecx, hv_host_info_edx >> 24);
-       }
-
        if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
            ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
                x86_platform.calibrate_tsc = hv_get_tsc_khz;
@@ -456,7 +452,7 @@ static void __init ms_hyperv_init_platform(void)
                                /* To be supported: more work is required.  */
                                ms_hyperv.features &= ~HV_MSR_REFERENCE_TSC_AVAILABLE;
 
-                               /* HV_REGISTER_CRASH_CTL is unsupported. */
+                               /* HV_MSR_CRASH_CTL is unsupported. */
                                ms_hyperv.misc_features &= ~HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
 
                                /* Don't trust Hyper-V's TLB-flushing hypercalls. */
@@ -648,6 +644,7 @@ const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
        .init.x2apic_available  = ms_hyperv_x2apic_available,
        .init.msi_ext_dest_id   = ms_hyperv_msi_ext_dest_id,
        .init.init_platform     = ms_hyperv_init_platform,
+       .init.guest_late_init   = ms_hyperv_late_init,
 #ifdef CONFIG_AMD_MEM_ENCRYPT
        .runtime.sev_es_hcall_prepare = hv_sev_es_hcall_prepare,
        .runtime.sev_es_hcall_finish = hv_sev_es_hcall_finish,
index 8c3032a96caf167b30c1fc76b91039c809bc44e4..3aaf7e86a859a2f680625b4d13b1c27d43fa5629 100644 (file)
@@ -118,8 +118,8 @@ config KVM_AMD
          will be called kvm-amd.
 
 config KVM_AMD_SEV
-       def_bool y
        bool "AMD Secure Encrypted Virtualization (SEV) support"
+       default y
        depends on KVM_AMD && X86_64
        depends on CRYPTO_DEV_SP_PSP && !(KVM_AMD=y && CRYPTO_DEV_CCP_DD=m)
        help
index 475b5fa917a62d03d1a255234833140473b9c737..a88bb14266b69fe9805cb864cbe4c02e928e460b 100644 (file)
@@ -4,7 +4,8 @@ ccflags-y += -I $(srctree)/arch/x86/kvm
 ccflags-$(CONFIG_KVM_WERROR) += -Werror
 
 ifeq ($(CONFIG_FRAME_POINTER),y)
-OBJECT_FILES_NON_STANDARD_vmenter.o := y
+OBJECT_FILES_NON_STANDARD_vmx/vmenter.o := y
+OBJECT_FILES_NON_STANDARD_svm/vmenter.o := y
 endif
 
 include $(srctree)/virt/kvm/Makefile.kvm
index 944e0290f2c001810a16a2eee3c2e87a31ba48e0..8c2d4b8de25d482694101264674f5886758b00ed 100644 (file)
@@ -75,6 +75,9 @@ static void __init init_pvh_bootparams(bool xen_guest)
        } else
                xen_raw_printk("Warning: Can fit ISA range into e820\n");
 
+       if (xen_guest)
+               xen_reserve_extra_memory(&pvh_bootparams);
+
        pvh_bootparams.hdr.cmd_line_ptr =
                pvh_start_info.cmdline_paddr;
 
index a65fc2ae15b4965b12862c3becf25e65e1b0fad7..77e788e928cd4e8d07ca867bd9e2337ea57c90df 100644 (file)
@@ -81,7 +81,6 @@ config XEN_PVH
        bool "Xen PVH guest support"
        depends on XEN && XEN_PVHVM && ACPI
        select PVH
-       def_bool n
        help
          Support for running as a Xen PVH guest.
 
index 3c61bb98c10e283ddccbcc33ce6fd7d860a95280..a01ca255b0c6498704cf640a4462903a971431b4 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/kexec.h>
+#include <linux/memblock.h>
 #include <linux/slab.h>
 #include <linux/panic_notifier.h>
 
@@ -350,3 +351,34 @@ void xen_arch_unregister_cpu(int num)
 }
 EXPORT_SYMBOL(xen_arch_unregister_cpu);
 #endif
+
+/* Amount of extra memory space we add to the e820 ranges */
+struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
+
+void __init xen_add_extra_mem(unsigned long start_pfn, unsigned long n_pfns)
+{
+       unsigned int i;
+
+       /*
+        * No need to check for zero size, should happen rarely and will only
+        * write a new entry regarded to be unused due to zero size.
+        */
+       for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+               /* Add new region. */
+               if (xen_extra_mem[i].n_pfns == 0) {
+                       xen_extra_mem[i].start_pfn = start_pfn;
+                       xen_extra_mem[i].n_pfns = n_pfns;
+                       break;
+               }
+               /* Append to existing region. */
+               if (xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns ==
+                   start_pfn) {
+                       xen_extra_mem[i].n_pfns += n_pfns;
+                       break;
+               }
+       }
+       if (i == XEN_EXTRA_MEM_MAX_REGIONS)
+               printk(KERN_WARNING "Warning: not enough extra memory regions\n");
+
+       memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns));
+}
index 9e9db601bd52a9bf48a2e5ec4c936c0b7db93b39..27a2a02ef8fb1402657754ad5f1ae8c91c6a9d0e 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/acpi.h>
 #include <linux/export.h>
+#include <linux/mm.h>
 
 #include <xen/hvc-console.h>
 
@@ -73,3 +74,70 @@ void __init mem_map_via_hcall(struct boot_params *boot_params_p)
        }
        boot_params_p->e820_entries = memmap.nr_entries;
 }
+
+/*
+ * Reserve e820 UNUSABLE regions to inflate the memory balloon.
+ *
+ * On PVH dom0 the host memory map is used, RAM regions available to dom0 are
+ * located as the same place as in the native memory map, but since dom0 gets
+ * less memory than the total amount of host RAM the ranges that can't be
+ * populated are converted from RAM -> UNUSABLE.  Use such regions (up to the
+ * ratio signaled in EXTRA_MEM_RATIO) in order to inflate the balloon driver at
+ * boot.  Doing so prevents the guest (even if just temporary) from using holes
+ * in the memory map in order to map grants or foreign addresses, and
+ * hopefully limits the risk of a clash with a device MMIO region.  Ideally the
+ * hypervisor should notify us which memory ranges are suitable for creating
+ * foreign mappings, but that's not yet implemented.
+ */
+void __init xen_reserve_extra_memory(struct boot_params *bootp)
+{
+       unsigned int i, ram_pages = 0, extra_pages;
+
+       for (i = 0; i < bootp->e820_entries; i++) {
+               struct boot_e820_entry *e = &bootp->e820_table[i];
+
+               if (e->type != E820_TYPE_RAM)
+                       continue;
+               ram_pages += PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr);
+       }
+
+       /* Max amount of extra memory. */
+       extra_pages = EXTRA_MEM_RATIO * ram_pages;
+
+       /*
+        * Convert UNUSABLE ranges to RAM and reserve them for foreign mapping
+        * purposes.
+        */
+       for (i = 0; i < bootp->e820_entries && extra_pages; i++) {
+               struct boot_e820_entry *e = &bootp->e820_table[i];
+               unsigned long pages;
+
+               if (e->type != E820_TYPE_UNUSABLE)
+                       continue;
+
+               pages = min(extra_pages,
+                       PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr));
+
+               if (pages != (PFN_DOWN(e->addr + e->size) - PFN_UP(e->addr))) {
+                       struct boot_e820_entry *next;
+
+                       if (bootp->e820_entries ==
+                           ARRAY_SIZE(bootp->e820_table))
+                               /* No space left to split - skip region. */
+                               continue;
+
+                       /* Split entry. */
+                       next = e + 1;
+                       memmove(next, e,
+                               (bootp->e820_entries - i) * sizeof(*e));
+                       bootp->e820_entries++;
+                       next->addr = PAGE_ALIGN(e->addr) + PFN_PHYS(pages);
+                       e->size = next->addr - e->addr;
+                       next->size -= e->size;
+               }
+               e->type = E820_TYPE_RAM;
+               extra_pages -= pages;
+
+               xen_add_extra_mem(PFN_UP(e->addr), pages);
+       }
+}
index b3e37961065a2c411a06dde8d06d01ce40479948..380591028cb8f4b3a05cd0c4b7a62deeb6af1a3c 100644 (file)
@@ -38,9 +38,6 @@
 
 #define GB(x) ((uint64_t)(x) * 1024 * 1024 * 1024)
 
-/* Amount of extra memory space we add to the e820 ranges */
-struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata;
-
 /* Number of pages released from the initial allocation. */
 unsigned long xen_released_pages;
 
@@ -64,18 +61,6 @@ static struct {
 } xen_remap_buf __initdata __aligned(PAGE_SIZE);
 static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY;
 
-/*
- * The maximum amount of extra memory compared to the base size.  The
- * main scaling factor is the size of struct page.  At extreme ratios
- * of base:extra, all the base memory can be filled with page
- * structures for the extra memory, leaving no space for anything
- * else.
- *
- * 10x seems like a reasonable balance between scaling flexibility and
- * leaving a practically usable system.
- */
-#define EXTRA_MEM_RATIO                (10)
-
 static bool xen_512gb_limit __initdata = IS_ENABLED(CONFIG_XEN_512GB);
 
 static void __init xen_parse_512gb(void)
@@ -96,35 +81,6 @@ static void __init xen_parse_512gb(void)
        xen_512gb_limit = val;
 }
 
-static void __init xen_add_extra_mem(unsigned long start_pfn,
-                                    unsigned long n_pfns)
-{
-       int i;
-
-       /*
-        * No need to check for zero size, should happen rarely and will only
-        * write a new entry regarded to be unused due to zero size.
-        */
-       for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
-               /* Add new region. */
-               if (xen_extra_mem[i].n_pfns == 0) {
-                       xen_extra_mem[i].start_pfn = start_pfn;
-                       xen_extra_mem[i].n_pfns = n_pfns;
-                       break;
-               }
-               /* Append to existing region. */
-               if (xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns ==
-                   start_pfn) {
-                       xen_extra_mem[i].n_pfns += n_pfns;
-                       break;
-               }
-       }
-       if (i == XEN_EXTRA_MEM_MAX_REGIONS)
-               printk(KERN_WARNING "Warning: not enough extra memory regions\n");
-
-       memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns));
-}
-
 static void __init xen_del_extra_mem(unsigned long start_pfn,
                                     unsigned long n_pfns)
 {
index a87ab36889e76cd41892a25538b37f3ca98b500e..79cf93f2c92f1d4aac6d62f4edf0ec084557da51 100644 (file)
@@ -163,4 +163,18 @@ void xen_hvm_post_suspend(int suspend_cancelled);
 static inline void xen_hvm_post_suspend(int suspend_cancelled) {}
 #endif
 
+/*
+ * The maximum amount of extra memory compared to the base size.  The
+ * main scaling factor is the size of struct page.  At extreme ratios
+ * of base:extra, all the base memory can be filled with page
+ * structures for the extra memory, leaving no space for anything
+ * else.
+ *
+ * 10x seems like a reasonable balance between scaling flexibility and
+ * leaving a practically usable system.
+ */
+#define EXTRA_MEM_RATIO                (10)
+
+void xen_add_extra_mem(unsigned long start_pfn, unsigned long n_pfns);
+
 #endif /* XEN_OPS_H */
index e7adaaf1c21927a71d93e64817e22732fc72f2a3..7a5f611c3d2e3e83eb00be12b9131f49d8348f5e 100644 (file)
@@ -583,6 +583,9 @@ static void bd_finish_claiming(struct block_device *bdev, void *holder,
        mutex_unlock(&bdev->bd_holder_lock);
        bd_clear_claiming(whole, holder);
        mutex_unlock(&bdev_lock);
+
+       if (hops && hops->get_holder)
+               hops->get_holder(holder);
 }
 
 /**
@@ -605,6 +608,7 @@ EXPORT_SYMBOL(bd_abort_claiming);
 static void bd_end_claim(struct block_device *bdev, void *holder)
 {
        struct block_device *whole = bdev_whole(bdev);
+       const struct blk_holder_ops *hops = bdev->bd_holder_ops;
        bool unblock = false;
 
        /*
@@ -627,6 +631,9 @@ static void bd_end_claim(struct block_device *bdev, void *holder)
                whole->bd_holder = NULL;
        mutex_unlock(&bdev_lock);
 
+       if (hops && hops->put_holder)
+               hops->put_holder(holder);
+
        /*
         * If this was the last claim, remove holder link and unblock evpoll if
         * it was a write holder.
index 44661c2e30ca5de9387d4c09202a588b6f57e64f..2903ce19f15cfa5d2c04a193a8352ddcfdceac12 100644 (file)
@@ -1497,6 +1497,9 @@ endif
 if PPC
 source "arch/powerpc/crypto/Kconfig"
 endif
+if RISCV
+source "arch/riscv/crypto/Kconfig"
+endif
 if S390
 source "arch/s390/crypto/Kconfig"
 endif
index d305716635855e6eef9331bf5357fc4e68cff333..cb7e1114e8ebe2df99d783cd795956384997f0bf 100644 (file)
@@ -7,9 +7,10 @@
 #include "speakup.h"
 #include "spk_priv.h"
 
-static int misc_registered;
+static int synth_registered, synthu_registered;
 static int dev_opened;
 
+/* Latin1 version */
 static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
                                  size_t nbytes, loff_t *ppos)
 {
@@ -34,6 +35,98 @@ static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
        return (ssize_t)nbytes;
 }
 
+/* UTF-8 version */
+static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer,
+                                  size_t nbytes, loff_t *ppos)
+{
+       size_t count = nbytes, want;
+       const char __user *ptr = buffer;
+       size_t bytes;
+       unsigned long flags;
+       unsigned char buf[256];
+       u16 ubuf[256];
+       size_t in, in2, out;
+
+       if (!synth)
+               return -ENODEV;
+
+       want = 1;
+       while (count >= want) {
+               /* Copy some UTF-8 piece from userland */
+               bytes = min(count, sizeof(buf));
+               if (copy_from_user(buf, ptr, bytes))
+                       return -EFAULT;
+
+               /* Convert to u16 */
+               for (in = 0, out = 0; in < bytes; in++) {
+                       unsigned char c = buf[in];
+                       int nbytes = 8 - fls(c ^ 0xff);
+                       u32 value;
+
+                       switch (nbytes) {
+                       case 8: /* 0xff */
+                       case 7: /* 0xfe */
+                       case 1: /* 0x80 */
+                               /* Invalid, drop */
+                               goto drop;
+
+                       case 0:
+                               /* ASCII, copy */
+                               ubuf[out++] = c;
+                               continue;
+
+                       default:
+                               /* 2..6-byte UTF-8 */
+
+                               if (bytes - in < nbytes) {
+                                       /* We don't have it all yet, stop here
+                                        * and wait for the rest
+                                        */
+                                       bytes = in;
+                                       want = nbytes;
+                                       continue;
+                               }
+
+                               /* First byte */
+                               value = c & ((1u << (7 - nbytes)) - 1);
+
+                               /* Other bytes */
+                               for (in2 = 2; in2 <= nbytes; in2++) {
+                                       c = buf[in + 1];
+                                       if ((c & 0xc0) != 0x80) {
+                                               /* Invalid, drop the head */
+                                               want = 1;
+                                               goto drop;
+                                       }
+                                       value = (value << 6) | (c & 0x3f);
+                                       in++;
+                               }
+
+                               if (value < 0x10000)
+                                       ubuf[out++] = value;
+                               want = 1;
+                               break;
+                       }
+drop:
+                       /* empty statement */;
+               }
+
+               count -= bytes;
+               ptr += bytes;
+
+               /* And speak this up */
+               if (out) {
+                       spin_lock_irqsave(&speakup_info.spinlock, flags);
+                       for (in = 0; in < out; in++)
+                               synth_buffer_add(ubuf[in]);
+                       synth_start();
+                       spin_unlock_irqrestore(&speakup_info.spinlock, flags);
+               }
+       }
+
+       return (ssize_t)(nbytes - count);
+}
+
 static ssize_t speakup_file_read(struct file *fp, char __user *buf,
                                 size_t nbytes, loff_t *ppos)
 {
@@ -62,31 +155,57 @@ static const struct file_operations synth_fops = {
        .release = speakup_file_release,
 };
 
+static const struct file_operations synthu_fops = {
+       .read = speakup_file_read,
+       .write = speakup_file_writeu,
+       .open = speakup_file_open,
+       .release = speakup_file_release,
+};
+
 static struct miscdevice synth_device = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = "synth",
        .fops = &synth_fops,
 };
 
+static struct miscdevice synthu_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "synthu",
+       .fops = &synthu_fops,
+};
+
 void speakup_register_devsynth(void)
 {
-       if (misc_registered != 0)
-               return;
-/* zero it so if register fails, deregister will not ref invalid ptrs */
-       if (misc_register(&synth_device)) {
-               pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
-       } else {
-               pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
-                       MISC_MAJOR, synth_device.minor);
-               misc_registered = 1;
+       if (!synth_registered) {
+               if (misc_register(&synth_device)) {
+                       pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
+               } else {
+                       pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
+                               MISC_MAJOR, synth_device.minor);
+                       synth_registered = 1;
+               }
+       }
+       if (!synthu_registered) {
+               if (misc_register(&synthu_device)) {
+                       pr_warn("Couldn't initialize miscdevice /dev/synthu.\n");
+               } else {
+                       pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n",
+                               MISC_MAJOR, synthu_device.minor);
+                       synthu_registered = 1;
+               }
        }
 }
 
 void speakup_unregister_devsynth(void)
 {
-       if (!misc_registered)
-               return;
-       pr_info("speakup: unregistering synth device /dev/synth\n");
-       misc_deregister(&synth_device);
-       misc_registered = 0;
+       if (synth_registered) {
+               pr_info("speakup: unregistering synth device /dev/synth\n");
+               misc_deregister(&synth_device);
+               synth_registered = 0;
+       }
+       if (synthu_registered) {
+               pr_info("speakup: unregistering synth device /dev/synthu\n");
+               misc_deregister(&synthu_device);
+               synthu_registered = 0;
+       }
 }
index eea2a2fa4f0159af7ece0add14d5b23100f6d49f..45f90610313382cac117da4cbe93d1d782a96054 100644 (file)
@@ -208,8 +208,10 @@ void spk_do_flush(void)
        wake_up_process(speakup_task);
 }
 
-void synth_write(const char *buf, size_t count)
+void synth_write(const char *_buf, size_t count)
 {
+       const unsigned char *buf = (const unsigned char *) _buf;
+
        while (count--)
                synth_buffer_add(*buf++);
        synth_start();
index c645bb453f3b7fdf16fa228c30d53d7809ea24a8..ff1689bb3124dd53a56b275bf2d3075cfa6d9423 100644 (file)
@@ -286,7 +286,7 @@ config ACPI_CPPC_LIB
 
 config ACPI_PROCESSOR
        tristate "Processor"
-       depends on X86 || ARM64 || LOONGARCH
+       depends on X86 || ARM64 || LOONGARCH || RISCV
        select ACPI_PROCESSOR_IDLE
        select ACPI_CPU_FREQ_PSS if X86 || LOONGARCH
        select THERMAL
@@ -460,7 +460,6 @@ config ACPI_BGRT
 
 config ACPI_REDUCED_HARDWARE_ONLY
        bool "Hardware-reduced ACPI support only" if EXPERT
-       def_bool n
        help
          This config item changes the way the ACPI code is built.  When this
          option is selected, the kernel will use a specialized version of
index a89bdbe0018442f0c7d57dc6d920f078c4078128..a7c00ef78086cf17a9ce72eae63b23a2b93e5b55 100644 (file)
@@ -380,6 +380,8 @@ static int dock_in_progress(struct dock_station *ds)
 
 /**
  * handle_eject_request - handle an undock request checking for error conditions
+ * @ds: The dock station to undock.
+ * @event: The ACPI event number associated with the undock request.
  *
  * Check to make sure the dock device is still present, then undock and
  * hotremove all the devices that may need removing.
index 8b3b126e0b940bd1492c759c6f267acd6d0f1dc6..86b0925f612d98b91f4801591768dc88aa9ae88d 100644 (file)
@@ -1,2 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-y  += rhct.o
+obj-y                                  += rhct.o
+obj-$(CONFIG_ACPI_PROCESSOR_IDLE)      += cpuidle.o
+obj-$(CONFIG_ACPI_CPPC_LIB)            += cppc.o
diff --git a/drivers/acpi/riscv/cppc.c b/drivers/acpi/riscv/cppc.c
new file mode 100644 (file)
index 0000000..4cdff38
--- /dev/null
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implement CPPC FFH helper routines for RISC-V.
+ *
+ * Copyright (C) 2024 Ventana Micro Systems Inc.
+ */
+
+#include <acpi/cppc_acpi.h>
+#include <asm/csr.h>
+#include <asm/sbi.h>
+
+#define SBI_EXT_CPPC 0x43505043
+
+/* CPPC interfaces defined in SBI spec */
+#define SBI_CPPC_PROBE                 0x0
+#define SBI_CPPC_READ                  0x1
+#define SBI_CPPC_READ_HI               0x2
+#define SBI_CPPC_WRITE                 0x3
+
+/* RISC-V FFH definitions from RISC-V FFH spec */
+#define FFH_CPPC_TYPE(r)               (((r) & GENMASK_ULL(63, 60)) >> 60)
+#define FFH_CPPC_SBI_REG(r)            ((r) & GENMASK(31, 0))
+#define FFH_CPPC_CSR_NUM(r)            ((r) & GENMASK(11, 0))
+
+#define FFH_CPPC_SBI                   0x1
+#define FFH_CPPC_CSR                   0x2
+
+struct sbi_cppc_data {
+       u64 val;
+       u32 reg;
+       struct sbiret ret;
+};
+
+static bool cppc_ext_present;
+
+static int __init sbi_cppc_init(void)
+{
+       if (sbi_spec_version >= sbi_mk_version(2, 0) &&
+           sbi_probe_extension(SBI_EXT_CPPC) > 0) {
+               pr_info("SBI CPPC extension detected\n");
+               cppc_ext_present = true;
+       } else {
+               pr_info("SBI CPPC extension NOT detected!!\n");
+               cppc_ext_present = false;
+       }
+
+       return 0;
+}
+device_initcall(sbi_cppc_init);
+
+static void sbi_cppc_read(void *read_data)
+{
+       struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
+
+       data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ,
+                             data->reg, 0, 0, 0, 0, 0);
+}
+
+static void sbi_cppc_write(void *write_data)
+{
+       struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
+
+       data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE,
+                             data->reg, data->val, 0, 0, 0, 0);
+}
+
+static void cppc_ffh_csr_read(void *read_data)
+{
+       struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
+
+       switch (data->reg) {
+       /* Support only TIME CSR for now */
+       case CSR_TIME:
+               data->ret.value = csr_read(CSR_TIME);
+               data->ret.error = 0;
+               break;
+       default:
+               data->ret.error = -EINVAL;
+               break;
+       }
+}
+
+static void cppc_ffh_csr_write(void *write_data)
+{
+       struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
+
+       data->ret.error = -EINVAL;
+}
+
+/*
+ * Refer to drivers/acpi/cppc_acpi.c for the description of the functions
+ * below.
+ */
+bool cpc_ffh_supported(void)
+{
+       return true;
+}
+
+int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
+{
+       struct sbi_cppc_data data;
+
+       if (WARN_ON_ONCE(irqs_disabled()))
+               return -EPERM;
+
+       if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
+               if (!cppc_ext_present)
+                       return -EINVAL;
+
+               data.reg = FFH_CPPC_SBI_REG(reg->address);
+
+               smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
+
+               *val = data.ret.value;
+
+               return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
+       } else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
+               data.reg = FFH_CPPC_CSR_NUM(reg->address);
+
+               smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
+
+               *val = data.ret.value;
+
+               return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
+       }
+
+       return -EINVAL;
+}
+
+int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
+{
+       struct sbi_cppc_data data;
+
+       if (WARN_ON_ONCE(irqs_disabled()))
+               return -EPERM;
+
+       if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
+               if (!cppc_ext_present)
+                       return -EINVAL;
+
+               data.reg = FFH_CPPC_SBI_REG(reg->address);
+               data.val = val;
+
+               smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
+
+               return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
+       } else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
+               data.reg = FFH_CPPC_CSR_NUM(reg->address);
+               data.val = val;
+
+               smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
+
+               return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
+       }
+
+       return -EINVAL;
+}
diff --git a/drivers/acpi/riscv/cpuidle.c b/drivers/acpi/riscv/cpuidle.c
new file mode 100644 (file)
index 0000000..624f9bb
--- /dev/null
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024, Ventana Micro Systems Inc
+ *     Author: Sunil V L <sunilvl@ventanamicro.com>
+ *
+ */
+
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpuidle.h>
+#include <linux/suspend.h>
+#include <asm/cpuidle.h>
+#include <asm/sbi.h>
+#include <asm/suspend.h>
+
+#define RISCV_FFH_LPI_TYPE_MASK        GENMASK_ULL(63, 60)
+#define RISCV_FFH_LPI_RSVD_MASK        GENMASK_ULL(59, 32)
+
+#define RISCV_FFH_LPI_TYPE_SBI BIT_ULL(60)
+
+static int acpi_cpu_init_idle(unsigned int cpu)
+{
+       int i;
+       struct acpi_lpi_state *lpi;
+       struct acpi_processor *pr = per_cpu(processors, cpu);
+
+       if (unlikely(!pr || !pr->flags.has_lpi))
+               return -EINVAL;
+
+       if (!riscv_sbi_hsm_is_supported())
+               return -ENODEV;
+
+       if (pr->power.count <= 1)
+               return -ENODEV;
+
+       for (i = 1; i < pr->power.count; i++) {
+               u32 state;
+
+               lpi = &pr->power.lpi_states[i];
+
+               /*
+                * Validate Entry Method as per FFH spec.
+                * bits[63:60] should be 0x1
+                * bits[59:32] should be 0x0
+                * bits[31:0] represent a SBI power_state
+                */
+               if (((lpi->address & RISCV_FFH_LPI_TYPE_MASK) != RISCV_FFH_LPI_TYPE_SBI) ||
+                   (lpi->address & RISCV_FFH_LPI_RSVD_MASK)) {
+                       pr_warn("Invalid LPI entry method %#llx\n", lpi->address);
+                       return -EINVAL;
+               }
+
+               state = lpi->address;
+               if (!riscv_sbi_suspend_state_is_valid(state)) {
+                       pr_warn("Invalid SBI power state %#x\n", state);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+int acpi_processor_ffh_lpi_probe(unsigned int cpu)
+{
+       return acpi_cpu_init_idle(cpu);
+}
+
+int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+{
+       u32 state = lpi->address;
+
+       if (state & SBI_HSM_SUSP_NON_RET_BIT)
+               return CPU_PM_CPU_IDLE_ENTER_PARAM(riscv_sbi_hart_suspend,
+                                                  lpi->index,
+                                                  state);
+       else
+               return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(riscv_sbi_hart_suspend,
+                                                            lpi->index,
+                                                            state);
+}
index 728acfeb774d8327bc24108c2401bc46920c8d0c..889f1c1a1fa92da3e89861fa206610db8ced888d 100644 (file)
@@ -502,6 +502,7 @@ static void acpi_pm_finish(void)
 
 /**
  * acpi_pm_start - Start system PM transition.
+ * @acpi_state: The target ACPI power state to transition to.
  */
 static void acpi_pm_start(u32 acpi_state)
 {
@@ -540,8 +541,9 @@ static u32 acpi_suspend_states[] = {
 };
 
 /**
- *     acpi_suspend_begin - Set the target system sleep state to the state
- *             associated with given @pm_state, if supported.
+ * acpi_suspend_begin - Set the target system sleep state to the state
+ *     associated with given @pm_state, if supported.
+ * @pm_state: The target system power management state.
  */
 static int acpi_suspend_begin(suspend_state_t pm_state)
 {
@@ -671,10 +673,11 @@ static const struct platform_suspend_ops acpi_suspend_ops = {
 };
 
 /**
- *     acpi_suspend_begin_old - Set the target system sleep state to the
- *             state associated with given @pm_state, if supported, and
- *             execute the _PTS control method.  This function is used if the
- *             pre-ACPI 2.0 suspend ordering has been requested.
+ * acpi_suspend_begin_old - Set the target system sleep state to the
+ *     state associated with given @pm_state, if supported, and
+ *     execute the _PTS control method.  This function is used if the
+ *     pre-ACPI 2.0 suspend ordering has been requested.
+ * @pm_state: The target suspend state for the system.
  */
 static int acpi_suspend_begin_old(suspend_state_t pm_state)
 {
@@ -967,10 +970,11 @@ static const struct platform_hibernation_ops acpi_hibernation_ops = {
 };
 
 /**
- *     acpi_hibernation_begin_old - Set the target system sleep state to
- *             ACPI_STATE_S4 and execute the _PTS control method.  This
- *             function is used if the pre-ACPI 2.0 suspend ordering has been
- *             requested.
+ * acpi_hibernation_begin_old - Set the target system sleep state to
+ *     ACPI_STATE_S4 and execute the _PTS control method.  This
+ *     function is used if the pre-ACPI 2.0 suspend ordering has been
+ *     requested.
+ * @stage: The power management event message.
  */
 static int acpi_hibernation_begin_old(pm_message_t stage)
 {
index e0e4dc38b6920737c2d9ec432664d0b160834de8..2e1f261ec5c8950ae5164925fc8e72b51fad36c2 100644 (file)
@@ -925,7 +925,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
                int i;
 
                for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
-                       unsigned long page_addr;
                        bool on_lru;
 
                        if (!alloc->pages[i].page_ptr)
@@ -933,7 +932,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
 
                        on_lru = list_lru_del_obj(&binder_freelist,
                                                  &alloc->pages[i].lru);
-                       page_addr = alloc->buffer + i * PAGE_SIZE;
                        binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
                                     "%s: %d: page %d %s\n",
                                     __func__, alloc->pid, i,
index 78570684ff68f9f3895c37469a18ac0414bc80ff..562302e2e57ce5a2651575ad1620b1725d654f6a 100644 (file)
@@ -669,19 +669,6 @@ MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets");
 static void ahci_pci_save_initial_config(struct pci_dev *pdev,
                                         struct ahci_host_priv *hpriv)
 {
-       if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA) {
-               switch (pdev->device) {
-               case 0x1166:
-                       dev_info(&pdev->dev, "ASM1166 has only six ports\n");
-                       hpriv->saved_port_map = 0x3f;
-                       break;
-               case 0x1064:
-                       dev_info(&pdev->dev, "ASM1064 has only four ports\n");
-                       hpriv->saved_port_map = 0xf;
-                       break;
-               }
-       }
-
        if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
                dev_info(&pdev->dev, "JMB361 has only one port\n");
                hpriv->saved_port_map = 1;
index 7dbf14a1d915779e0237b996f495b49faaa3e5a6..741497324d78ae02afb124f50fa33acc857126d2 100644 (file)
@@ -751,7 +751,7 @@ static int __component_add(struct device *dev, const struct component_ops *ops,
  * component_bind_all(). See also &struct component_ops.
  *
  * @subcomponent must be nonzero and is used to differentiate between multiple
- * components registerd on the same device @dev. These components are match
+ * components registered on the same device @dev. These components are match
  * using component_match_add_typed().
  *
  * The component needs to be unregistered at driver unload/disconnect by
@@ -781,7 +781,7 @@ EXPORT_SYMBOL_GPL(component_add_typed);
  * The component needs to be unregistered at driver unload/disconnect by
  * calling component_del().
  *
- * See also component_add_typed() for a variant that allows multipled different
+ * See also component_add_typed() for a variant that allows multiple different
  * components on the same device.
  */
 int component_add(struct device *dev, const struct component_ops *ops)
index 9828da9b933cb7511756d15ec8be2ebbd14f9e44..b93f3c5716aeeaa001651962f0af2c73bdfd5685 100644 (file)
@@ -92,12 +92,13 @@ static int __fwnode_link_add(struct fwnode_handle *con,
        return 0;
 }
 
-int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup)
+int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,
+                   u8 flags)
 {
        int ret;
 
        mutex_lock(&fwnode_link_lock);
-       ret = __fwnode_link_add(con, sup, 0);
+       ret = __fwnode_link_add(con, sup, flags);
        mutex_unlock(&fwnode_link_lock);
        return ret;
 }
@@ -1011,7 +1012,8 @@ static struct fwnode_handle *fwnode_links_check_suppliers(
                return NULL;
 
        list_for_each_entry(link, &fwnode->suppliers, c_hook)
-               if (!(link->flags & FWLINK_FLAG_CYCLE))
+               if (!(link->flags &
+                     (FWLINK_FLAG_CYCLE | FWLINK_FLAG_IGNORE)))
                        return link->supplier;
 
        return NULL;
@@ -1871,6 +1873,7 @@ static void fw_devlink_unblock_consumers(struct device *dev)
        device_links_write_unlock();
 }
 
+#define get_dev_from_fwnode(fwnode)    get_device((fwnode)->dev)
 
 static bool fwnode_init_without_drv(struct fwnode_handle *fwnode)
 {
@@ -1901,6 +1904,63 @@ static bool fwnode_ancestor_init_without_drv(struct fwnode_handle *fwnode)
        return false;
 }
 
+/**
+ * fwnode_is_ancestor_of - Test if @ancestor is ancestor of @child
+ * @ancestor: Firmware which is tested for being an ancestor
+ * @child: Firmware which is tested for being the child
+ *
+ * A node is considered an ancestor of itself too.
+ *
+ * Return: true if @ancestor is an ancestor of @child. Otherwise, returns false.
+ */
+static bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor,
+                                 const struct fwnode_handle *child)
+{
+       struct fwnode_handle *parent;
+
+       if (IS_ERR_OR_NULL(ancestor))
+               return false;
+
+       if (child == ancestor)
+               return true;
+
+       fwnode_for_each_parent_node(child, parent) {
+               if (parent == ancestor) {
+                       fwnode_handle_put(parent);
+                       return true;
+               }
+       }
+       return false;
+}
+
+/**
+ * fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
+ * @fwnode: firmware node
+ *
+ * Given a firmware node (@fwnode), this function finds its closest ancestor
+ * firmware node that has a corresponding struct device and returns that struct
+ * device.
+ *
+ * The caller is responsible for calling put_device() on the returned device
+ * pointer.
+ *
+ * Return: a pointer to the device of the @fwnode's closest ancestor.
+ */
+static struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode)
+{
+       struct fwnode_handle *parent;
+       struct device *dev;
+
+       fwnode_for_each_parent_node(fwnode, parent) {
+               dev = get_dev_from_fwnode(parent);
+               if (dev) {
+                       fwnode_handle_put(parent);
+                       return dev;
+               }
+       }
+       return NULL;
+}
+
 /**
  * __fw_devlink_relax_cycles - Relax and mark dependency cycles.
  * @con: Potential consumer device.
@@ -1962,6 +2022,9 @@ static bool __fw_devlink_relax_cycles(struct device *con,
        }
 
        list_for_each_entry(link, &sup_handle->suppliers, c_hook) {
+               if (link->flags & FWLINK_FLAG_IGNORE)
+                       continue;
+
                if (__fw_devlink_relax_cycles(con, link->supplier)) {
                        __fwnode_link_cycle(link);
                        ret = true;
@@ -2040,6 +2103,9 @@ static int fw_devlink_create_devlink(struct device *con,
        int ret = 0;
        u32 flags;
 
+       if (link->flags & FWLINK_FLAG_IGNORE)
+               return 0;
+
        if (con->fwnode == link->consumer)
                flags = fw_devlink_get_flags(link->flags);
        else
index f5a6bffce5188090a6f0be2775e74ffd85ffdf59..56fba44ba391adb432ca0b85e552b3ee95ddbad6 100644 (file)
@@ -366,7 +366,7 @@ static int cpu_uevent(const struct device *dev, struct kobj_uevent_env *env)
 }
 #endif
 
-struct bus_type cpu_subsys = {
+const struct bus_type cpu_subsys = {
        .name = "cpu",
        .dev_name = "cpu",
        .match = cpu_subsys_match,
index 85152537dbf12d005236cf18c721c51f62a5ebd8..83d352394fdf48756180cdf1bb25cf1db9bc5113 100644 (file)
@@ -313,7 +313,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
 
        mutex_lock(&deferred_probe_mutex);
        list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe)
-               dev_info(p->device, "deferred probe pending: %s", p->deferred_probe_reason ?: "(reason unknown)\n");
+               dev_warn(p->device, "deferred probe pending: %s", p->deferred_probe_reason ?: "(reason unknown)\n");
        mutex_unlock(&deferred_probe_mutex);
 
        fw_devlink_probing_done();
@@ -397,13 +397,12 @@ bool device_is_bound(struct device *dev)
 static void driver_bound(struct device *dev)
 {
        if (device_is_bound(dev)) {
-               pr_warn("%s: device %s already bound\n",
-                       __func__, kobject_name(&dev->kobj));
+               dev_warn(dev, "%s: device already bound\n", __func__);
                return;
        }
 
-       pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
-                __func__, dev_name(dev));
+       dev_dbg(dev, "driver: '%s': %s: bound to device\n", dev->driver->name,
+               __func__);
 
        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
        device_links_driver_bound(dev);
@@ -587,13 +586,13 @@ static int call_driver_probe(struct device *dev, struct device_driver *drv)
                break;
        case -ENODEV:
        case -ENXIO:
-               pr_debug("%s: probe of %s rejects match %d\n",
-                        drv->name, dev_name(dev), ret);
+               dev_dbg(dev, "probe with driver %s rejects match %d\n",
+                       drv->name, ret);
                break;
        default:
                /* driver matched but the probe failed */
-               pr_warn("%s: probe of %s failed with error %d\n",
-                       drv->name, dev_name(dev), ret);
+               dev_err(dev, "probe with driver %s failed with error %d\n",
+                       drv->name, ret);
                break;
        }
 
@@ -620,8 +619,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
        if (link_ret == -EPROBE_DEFER)
                return link_ret;
 
-       pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
-                drv->bus->name, __func__, drv->name, dev_name(dev));
+       dev_dbg(dev, "bus: '%s': %s: probing driver %s with device\n",
+               drv->bus->name, __func__, drv->name);
        if (!list_empty(&dev->devres_head)) {
                dev_crit(dev, "Resources present before probing\n");
                ret = -EBUSY;
@@ -644,8 +643,7 @@ re_probe:
 
        ret = driver_sysfs_add(dev);
        if (ret) {
-               pr_err("%s: driver_sysfs_add(%s) failed\n",
-                      __func__, dev_name(dev));
+               dev_err(dev, "%s: driver_sysfs_add failed\n", __func__);
                goto sysfs_failed;
        }
 
@@ -706,8 +704,8 @@ re_probe:
                dev->pm_domain->sync(dev);
 
        driver_bound(dev);
-       pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
-                drv->bus->name, __func__, dev_name(dev), drv->name);
+       dev_dbg(dev, "bus: '%s': %s: bound device to driver %s\n",
+               drv->bus->name, __func__, drv->name);
        goto done;
 
 dev_sysfs_state_synced_failed:
@@ -786,8 +784,8 @@ static int __driver_probe_device(struct device_driver *drv, struct device *dev)
                return -EBUSY;
 
        dev->can_match = true;
-       pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
-                drv->bus->name, __func__, dev_name(dev), drv->name);
+       dev_dbg(dev, "bus: '%s': %s: matched device with driver %s\n",
+               drv->bus->name, __func__, drv->name);
 
        pm_runtime_get_suppliers(dev);
        if (dev->parent)
index ea28102d421ebf2d3d611d77547816e48368ab5c..da8ca01d011c3f3694a381e1c98d0b3a8301663b 100644 (file)
@@ -551,12 +551,16 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
                                                       file_size_ptr,
                                                       READING_FIRMWARE);
                if (rc < 0) {
-                       if (rc != -ENOENT)
-                               dev_warn(device, "loading %s failed with error %d\n",
-                                        path, rc);
-                       else
-                               dev_dbg(device, "loading %s failed for no such file or directory.\n",
-                                        path);
+                       if (!(fw_priv->opt_flags & FW_OPT_NO_WARN)) {
+                               if (rc != -ENOENT)
+                                       dev_warn(device,
+                                                "loading %s failed with error %d\n",
+                                                path, rc);
+                               else
+                                       dev_dbg(device,
+                                               "loading %s failed for no such file or directory.\n",
+                                               path);
+                       }
                        continue;
                }
                size = rc;
index 0d01890160f3f4d0bc9bae5af2c49d44e522954c..11f5fdf65b9ef604ab574e476a1a09f89af24552 100644 (file)
@@ -174,8 +174,8 @@ static int platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,
        if (!datap)
                return -ENOMEM;
 
-       datap->devid = ida_simple_get(&platform_msi_devid_ida,
-                                     0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
+       datap->devid = ida_alloc_max(&platform_msi_devid_ida,
+                                    (1 << DEV_ID_SHIFT) - 1, GFP_KERNEL);
        if (datap->devid < 0) {
                err = datap->devid;
                kfree(datap);
@@ -193,7 +193,7 @@ static void platform_msi_free_priv_data(struct device *dev)
        struct platform_msi_priv_data *data = dev->msi.data->platform_data;
 
        dev->msi.data->platform_data = NULL;
-       ida_simple_remove(&platform_msi_devid_ida, data->devid);
+       ida_free(&platform_msi_devid_ida, data->devid);
        kfree(data);
 }
 
index a1b01ab4205280df05759c5139e49b34f6f64a82..7324a704a9a118322df02b061380fdb0fa3cdc21 100644 (file)
@@ -7,15 +7,16 @@
  *          Mika Westerberg <mika.westerberg@linux.intel.com>
  */
 
-#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
 #include <linux/export.h>
-#include <linux/kernel.h>
+#include <linux/kconfig.h>
 #include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_graph.h>
-#include <linux/of_irq.h>
 #include <linux/property.h>
 #include <linux/phy.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
 
 struct fwnode_handle *__dev_fwnode(struct device *dev)
 {
@@ -699,34 +700,6 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode)
 }
 EXPORT_SYMBOL_GPL(fwnode_get_next_parent);
 
-/**
- * fwnode_get_next_parent_dev - Find device of closest ancestor fwnode
- * @fwnode: firmware node
- *
- * Given a firmware node (@fwnode), this function finds its closest ancestor
- * firmware node that has a corresponding struct device and returns that struct
- * device.
- *
- * The caller is responsible for calling put_device() on the returned device
- * pointer.
- *
- * Return: a pointer to the device of the @fwnode's closest ancestor.
- */
-struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode)
-{
-       struct fwnode_handle *parent;
-       struct device *dev;
-
-       fwnode_for_each_parent_node(fwnode, parent) {
-               dev = get_dev_from_fwnode(parent);
-               if (dev) {
-                       fwnode_handle_put(parent);
-                       return dev;
-               }
-       }
-       return NULL;
-}
-
 /**
  * fwnode_count_parents - Return the number of parents a node has
  * @fwnode: The node the parents of which are to be counted
@@ -773,34 +746,6 @@ struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode,
 }
 EXPORT_SYMBOL_GPL(fwnode_get_nth_parent);
 
-/**
- * fwnode_is_ancestor_of - Test if @ancestor is ancestor of @child
- * @ancestor: Firmware which is tested for being an ancestor
- * @child: Firmware which is tested for being the child
- *
- * A node is considered an ancestor of itself too.
- *
- * Return: true if @ancestor is an ancestor of @child. Otherwise, returns false.
- */
-bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor, const struct fwnode_handle *child)
-{
-       struct fwnode_handle *parent;
-
-       if (IS_ERR_OR_NULL(ancestor))
-               return false;
-
-       if (child == ancestor)
-               return true;
-
-       fwnode_for_each_parent_node(child, parent) {
-               if (parent == ancestor) {
-                       fwnode_handle_put(parent);
-                       return true;
-               }
-       }
-       return false;
-}
-
 /**
  * fwnode_get_next_child_node - Return the next child node handle for a node
  * @fwnode: Firmware node to find the next child node for.
index 36512fb75a201c1a1ab5aa68b694667b56b96036..eb6eb25b343bafaa9c03f881b98a528305fa6093 100644 (file)
@@ -6,10 +6,21 @@
  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
  */
 
+#include <linux/container_of.h>
 #include <linux/device.h>
-#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/kobject.h>
+#include <linux/kstrtox.h>
+#include <linux/list.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
 
 #include "base.h"
 
index 1b399ec8c07d1e7027a759051b18187dde83ab1e..25c9d85667f1a258ce4e4b003b6526b41257b02f 100644 (file)
@@ -2787,7 +2787,6 @@ do_request:
                pending = set_next_request();
                spin_unlock_irq(&floppy_lock);
                if (!pending) {
-                       do_floppy = NULL;
                        unlock_fdc();
                        return;
                }
index 3c84fcbda01aa3791aac96c97a6fba9ea6d211ce..e6bc4a73c9fc33ee7645ad903b991e4bf05e686c 100644 (file)
@@ -383,8 +383,8 @@ static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
        }
 }
 
-static ssize_t btmtkuart_receive_buf(struct serdev_device *serdev,
-                                    const u8 *data, size_t count)
+static size_t btmtkuart_receive_buf(struct serdev_device *serdev,
+                                   const u8 *data, size_t count)
 {
        struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
 
index 0b93c2ff29e49a10b6fbac2336388bc4ceea1214..9d0c7e278114b229f7cc2155e7cc57a2cbfa9c54 100644 (file)
@@ -1285,8 +1285,8 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = {
        { NXP_RECV_FW_REQ_V3,   .recv = nxp_recv_fw_req_v3 },
 };
 
-static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev,
-                                    const u8 *data, size_t count)
+static size_t btnxpuart_receive_buf(struct serdev_device *serdev,
+                                   const u8 *data, size_t count)
 {
        struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
 
index 214fff876eae50e8ef88b7a4df44a3c76fdff240..85c0d9b68f5f76f5274f2ba049c9eaa949274381 100644 (file)
@@ -271,8 +271,8 @@ static void hci_uart_write_wakeup(struct serdev_device *serdev)
  *
  * Return: number of processed bytes
  */
-static ssize_t hci_uart_receive_buf(struct serdev_device *serdev,
-                                   const u8 *data, size_t count)
+static size_t hci_uart_receive_buf(struct serdev_device *serdev,
+                                  const u8 *data, size_t count)
 {
        struct hci_uart *hu = serdev_device_get_drvdata(serdev);
 
index b6dfe4340da2cbfc9af162f56e9621ffb0c481f6..65ae758f3194366bd614df7a3acc485f6d5697ce 100644 (file)
@@ -96,6 +96,20 @@ static const int gisb_offsets_bcm7400[] = {
        [ARB_ERR_CAP_MASTER]    = 0x0d8,
 };
 
+static const int gisb_offsets_bcm74165[] = {
+       [ARB_TIMER]             = 0x008,
+       [ARB_BP_CAP_CLR]        = 0x044,
+       [ARB_BP_CAP_HI_ADDR]    = -1,
+       [ARB_BP_CAP_ADDR]       = 0x048,
+       [ARB_BP_CAP_STATUS]     = 0x058,
+       [ARB_BP_CAP_MASTER]     = 0x05c,
+       [ARB_ERR_CAP_CLR]       = 0x038,
+       [ARB_ERR_CAP_HI_ADDR]   = -1,
+       [ARB_ERR_CAP_ADDR]      = 0x020,
+       [ARB_ERR_CAP_STATUS]    = 0x030,
+       [ARB_ERR_CAP_MASTER]    = 0x034,
+};
+
 static const int gisb_offsets_bcm7435[] = {
        [ARB_TIMER]             = 0x00c,
        [ARB_BP_CAP_CLR]        = 0x014,
@@ -393,6 +407,7 @@ static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
        { .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },
        { .compatible = "brcm,bcm7278-gisb-arb", .data = gisb_offsets_bcm7278 },
        { .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 },
+       { .compatible = "brcm,bcm74165-gisb-arb", .data = gisb_offsets_bcm74165 },
        { },
 };
 
index f794b9c8049e20f5395b7a743cb3adea912f63a5..dda340aaed95a5573a2ec776ca712e11a1ed0b52 100644 (file)
@@ -297,30 +297,30 @@ struct mhi_ring_element {
        __le32 dword[2];
 };
 
+#define MHI_STATE_LIST                         \
+       mhi_state(RESET,        "RESET")        \
+       mhi_state(READY,        "READY")        \
+       mhi_state(M0,           "M0")           \
+       mhi_state(M1,           "M1")           \
+       mhi_state(M2,           "M2")           \
+       mhi_state(M3,           "M3")           \
+       mhi_state(M3_FAST,      "M3_FAST")      \
+       mhi_state(BHI,          "BHI")          \
+       mhi_state_end(SYS_ERR,  "SYS ERROR")
+
+#undef mhi_state
+#undef mhi_state_end
+
+#define mhi_state(a, b)                case MHI_STATE_##a: return b;
+#define mhi_state_end(a, b)    case MHI_STATE_##a: return b;
+
 static inline const char *mhi_state_str(enum mhi_state state)
 {
        switch (state) {
-       case MHI_STATE_RESET:
-               return "RESET";
-       case MHI_STATE_READY:
-               return "READY";
-       case MHI_STATE_M0:
-               return "M0";
-       case MHI_STATE_M1:
-               return "M1";
-       case MHI_STATE_M2:
-               return "M2";
-       case MHI_STATE_M3:
-               return "M3";
-       case MHI_STATE_M3_FAST:
-               return "M3 FAST";
-       case MHI_STATE_BHI:
-               return "BHI";
-       case MHI_STATE_SYS_ERR:
-               return "SYS ERROR";
+       MHI_STATE_LIST
        default:
                return "Unknown state";
        }
-};
+}
 
 #endif /* _MHI_COMMON_H */
index 65fc1d738bec2671b6f0d08fb30e714c81df1167..f8f674adf1d4053d894c237aeae808b7a4977f3d 100644 (file)
@@ -1149,8 +1149,9 @@ int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl)
        mhi_ep_mmio_mask_interrupts(mhi_cntrl);
        mhi_ep_mmio_init(mhi_cntrl);
 
-       mhi_cntrl->mhi_event = kzalloc(mhi_cntrl->event_rings * (sizeof(*mhi_cntrl->mhi_event)),
-                                       GFP_KERNEL);
+       mhi_cntrl->mhi_event = kcalloc(mhi_cntrl->event_rings,
+                                      sizeof(*mhi_cntrl->mhi_event),
+                                      GFP_KERNEL);
        if (!mhi_cntrl->mhi_event)
                return -ENOMEM;
 
@@ -1496,7 +1497,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
        mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item",
                                                        sizeof(struct mhi_ep_ring_item), 0,
                                                        0, NULL);
-       if (!mhi_cntrl->ev_ring_el_cache) {
+       if (!mhi_cntrl->ring_item_cache) {
                ret = -ENOMEM;
                goto err_destroy_tre_buf_cache;
        }
index edc0ec5a0933980a69b6fd329e00982b6653fd5c..dedd29ca8db355ec0c1b9673f5c8a7f606451d83 100644 (file)
@@ -395,7 +395,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
        void *buf;
        dma_addr_t dma_addr;
        size_t size, fw_sz;
-       int i, ret;
+       int ret;
 
        if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
                dev_err(dev, "Device MHI is not in valid state\n");
@@ -408,15 +408,6 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
        if (ret)
                dev_err(dev, "Could not capture serial number via BHI\n");
 
-       for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) {
-               ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i),
-                                  &mhi_cntrl->oem_pk_hash[i]);
-               if (ret) {
-                       dev_err(dev, "Could not capture OEM PK HASH via BHI\n");
-                       break;
-               }
-       }
-
        /* wait for ready on pass through or any other execution environment */
        if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee))
                goto fw_load_ready_state;
index 65ceac1837f9a1a0a133715fafad3cf8d490d309..44f934981de82a31d99826ee9ed231d0df2b7fde 100644 (file)
 #include <linux/wait.h>
 #include "internal.h"
 
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
 static DEFINE_IDA(mhi_controller_ida);
 
+#undef mhi_ee
+#undef mhi_ee_end
+
+#define mhi_ee(a, b)           [MHI_EE_##a] = b,
+#define mhi_ee_end(a, b)       [MHI_EE_##a] = b,
+
 const char * const mhi_ee_str[MHI_EE_MAX] = {
-       [MHI_EE_PBL] = "PRIMARY BOOTLOADER",
-       [MHI_EE_SBL] = "SECONDARY BOOTLOADER",
-       [MHI_EE_AMSS] = "MISSION MODE",
-       [MHI_EE_RDDM] = "RAMDUMP DOWNLOAD MODE",
-       [MHI_EE_WFW] = "WLAN FIRMWARE",
-       [MHI_EE_PTHRU] = "PASS THROUGH",
-       [MHI_EE_EDL] = "EMERGENCY DOWNLOAD",
-       [MHI_EE_FP] = "FLASH PROGRAMMER",
-       [MHI_EE_DISABLE_TRANSITION] = "DISABLE",
-       [MHI_EE_NOT_SUPPORTED] = "NOT SUPPORTED",
+       MHI_EE_LIST
 };
 
+#undef dev_st_trans
+#undef dev_st_trans_end
+
+#define dev_st_trans(a, b)     [DEV_ST_TRANSITION_##a] = b,
+#define dev_st_trans_end(a, b) [DEV_ST_TRANSITION_##a] = b,
+
 const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX] = {
-       [DEV_ST_TRANSITION_PBL] = "PBL",
-       [DEV_ST_TRANSITION_READY] = "READY",
-       [DEV_ST_TRANSITION_SBL] = "SBL",
-       [DEV_ST_TRANSITION_MISSION_MODE] = "MISSION MODE",
-       [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER",
-       [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR",
-       [DEV_ST_TRANSITION_DISABLE] = "DISABLE",
+       DEV_ST_TRANSITION_LIST
 };
 
+#undef ch_state_type
+#undef ch_state_type_end
+
+#define ch_state_type(a, b)    [MHI_CH_STATE_TYPE_##a] = b,
+#define ch_state_type_end(a, b)        [MHI_CH_STATE_TYPE_##a] = b,
+
 const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = {
-       [MHI_CH_STATE_TYPE_RESET] = "RESET",
-       [MHI_CH_STATE_TYPE_STOP] = "STOP",
-       [MHI_CH_STATE_TYPE_START] = "START",
+       MHI_CH_STATE_TYPE_LIST
 };
 
+#undef mhi_pm_state
+#undef mhi_pm_state_end
+
+#define mhi_pm_state(a, b)     [MHI_PM_STATE_##a] = b,
+#define mhi_pm_state_end(a, b) [MHI_PM_STATE_##a] = b,
+
 static const char * const mhi_pm_state_str[] = {
-       [MHI_PM_STATE_DISABLE] = "DISABLE",
-       [MHI_PM_STATE_POR] = "POWER ON RESET",
-       [MHI_PM_STATE_M0] = "M0",
-       [MHI_PM_STATE_M2] = "M2",
-       [MHI_PM_STATE_M3_ENTER] = "M?->M3",
-       [MHI_PM_STATE_M3] = "M3",
-       [MHI_PM_STATE_M3_EXIT] = "M3->M0",
-       [MHI_PM_STATE_FW_DL_ERR] = "Firmware Download Error",
-       [MHI_PM_STATE_SYS_ERR_DETECT] = "SYS ERROR Detect",
-       [MHI_PM_STATE_SYS_ERR_PROCESS] = "SYS ERROR Process",
-       [MHI_PM_STATE_SHUTDOWN_PROCESS] = "SHUTDOWN Process",
-       [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect",
+       MHI_PM_STATE_LIST
 };
 
 const char *to_mhi_pm_state_str(u32 state)
@@ -97,11 +96,19 @@ static ssize_t oem_pk_hash_show(struct device *dev,
 {
        struct mhi_device *mhi_dev = to_mhi_device(dev);
        struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
-       int i, cnt = 0;
+       u32 hash_segment[MHI_MAX_OEM_PK_HASH_SEGMENTS];
+       int i, cnt = 0, ret;
 
-       for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++)
-               cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n",
-                               i, mhi_cntrl->oem_pk_hash[i]);
+       for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++) {
+               ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i), &hash_segment[i]);
+               if (ret) {
+                       dev_err(dev, "Could not capture OEM PK HASH\n");
+                       return ret;
+               }
+       }
+
+       for (i = 0; i < MHI_MAX_OEM_PK_HASH_SEGMENTS; i++)
+               cnt += sysfs_emit_at(buf, cnt, "OEMPKHASH[%d]: 0x%x\n", i, hash_segment[i]);
 
        return cnt;
 }
@@ -907,7 +914,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
        struct mhi_chan *mhi_chan;
        struct mhi_cmd *mhi_cmd;
        struct mhi_device *mhi_dev;
-       u32 soc_info;
        int ret, i;
 
        if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs ||
@@ -982,17 +988,6 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,
                mhi_cntrl->unmap_single = mhi_unmap_single_no_bb;
        }
 
-       /* Read the MHI device info */
-       ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs,
-                          SOC_HW_VERSION_OFFS, &soc_info);
-       if (ret)
-               goto err_destroy_wq;
-
-       mhi_cntrl->family_number = FIELD_GET(SOC_HW_VERSION_FAM_NUM_BMSK, soc_info);
-       mhi_cntrl->device_number = FIELD_GET(SOC_HW_VERSION_DEV_NUM_BMSK, soc_info);
-       mhi_cntrl->major_version = FIELD_GET(SOC_HW_VERSION_MAJOR_VER_BMSK, soc_info);
-       mhi_cntrl->minor_version = FIELD_GET(SOC_HW_VERSION_MINOR_VER_BMSK, soc_info);
-
        mhi_cntrl->index = ida_alloc(&mhi_controller_ida, GFP_KERNEL);
        if (mhi_cntrl->index < 0) {
                ret = mhi_cntrl->index;
index 30ac415a3000f687367689ece738ed48d70677e9..5fe49311b8eb466f848a6dbdeb964998340f619a 100644 (file)
@@ -15,12 +15,6 @@ extern struct bus_type mhi_bus_type;
 #define MHI_SOC_RESET_REQ_OFFSET                       0xb0
 #define MHI_SOC_RESET_REQ                              BIT(0)
 
-#define SOC_HW_VERSION_OFFS                            0x224
-#define SOC_HW_VERSION_FAM_NUM_BMSK                    GENMASK(31, 28)
-#define SOC_HW_VERSION_DEV_NUM_BMSK                    GENMASK(27, 16)
-#define SOC_HW_VERSION_MAJOR_VER_BMSK                  GENMASK(15, 8)
-#define SOC_HW_VERSION_MINOR_VER_BMSK                  GENMASK(7, 0)
-
 struct mhi_ctxt {
        struct mhi_event_ctxt *er_ctxt;
        struct mhi_chan_ctxt *chan_ctxt;
@@ -42,6 +36,11 @@ enum mhi_ch_state_type {
        MHI_CH_STATE_TYPE_MAX,
 };
 
+#define MHI_CH_STATE_TYPE_LIST                         \
+       ch_state_type(RESET,            "RESET")        \
+       ch_state_type(STOP,             "STOP")         \
+       ch_state_type_end(START,        "START")
+
 extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX];
 #define TO_CH_STATE_TYPE_STR(state) (((state) >= MHI_CH_STATE_TYPE_MAX) ? \
                                     "INVALID_STATE" : \
@@ -50,6 +49,18 @@ extern const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX];
 #define MHI_INVALID_BRSTMODE(mode) (mode != MHI_DB_BRST_DISABLE && \
                                    mode != MHI_DB_BRST_ENABLE)
 
+#define MHI_EE_LIST                                            \
+       mhi_ee(PBL,                     "PRIMARY BOOTLOADER")   \
+       mhi_ee(SBL,                     "SECONDARY BOOTLOADER") \
+       mhi_ee(AMSS,                    "MISSION MODE")         \
+       mhi_ee(RDDM,                    "RAMDUMP DOWNLOAD MODE")\
+       mhi_ee(WFW,                     "WLAN FIRMWARE")        \
+       mhi_ee(PTHRU,                   "PASS THROUGH")         \
+       mhi_ee(EDL,                     "EMERGENCY DOWNLOAD")   \
+       mhi_ee(FP,                      "FLASH PROGRAMMER")     \
+       mhi_ee(DISABLE_TRANSITION,      "DISABLE")              \
+       mhi_ee_end(NOT_SUPPORTED,       "NOT SUPPORTED")
+
 extern const char * const mhi_ee_str[MHI_EE_MAX];
 #define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \
                             "INVALID_EE" : mhi_ee_str[ee])
@@ -72,6 +83,15 @@ enum dev_st_transition {
        DEV_ST_TRANSITION_MAX,
 };
 
+#define DEV_ST_TRANSITION_LIST                                 \
+       dev_st_trans(PBL,               "PBL")                  \
+       dev_st_trans(READY,             "READY")                \
+       dev_st_trans(SBL,               "SBL")                  \
+       dev_st_trans(MISSION_MODE,      "MISSION MODE")         \
+       dev_st_trans(FP,                "FLASH PROGRAMMER")     \
+       dev_st_trans(SYS_ERR,           "SYS ERROR")            \
+       dev_st_trans_end(DISABLE,       "DISABLE")
+
 extern const char * const dev_state_tran_str[DEV_ST_TRANSITION_MAX];
 #define TO_DEV_STATE_TRANS_STR(state) (((state) >= DEV_ST_TRANSITION_MAX) ? \
                                "INVALID_STATE" : dev_state_tran_str[state])
@@ -88,11 +108,27 @@ enum mhi_pm_state {
        MHI_PM_STATE_FW_DL_ERR,
        MHI_PM_STATE_SYS_ERR_DETECT,
        MHI_PM_STATE_SYS_ERR_PROCESS,
+       MHI_PM_STATE_SYS_ERR_FAIL,
        MHI_PM_STATE_SHUTDOWN_PROCESS,
        MHI_PM_STATE_LD_ERR_FATAL_DETECT,
        MHI_PM_STATE_MAX
 };
 
+#define MHI_PM_STATE_LIST                                                      \
+       mhi_pm_state(DISABLE,                   "DISABLE")                      \
+       mhi_pm_state(POR,                       "POWER ON RESET")               \
+       mhi_pm_state(M0,                        "M0")                           \
+       mhi_pm_state(M2,                        "M2")                           \
+       mhi_pm_state(M3_ENTER,                  "M?->M3")                       \
+       mhi_pm_state(M3,                        "M3")                           \
+       mhi_pm_state(M3_EXIT,                   "M3->M0")                       \
+       mhi_pm_state(FW_DL_ERR,                 "Firmware Download Error")      \
+       mhi_pm_state(SYS_ERR_DETECT,            "SYS ERROR Detect")             \
+       mhi_pm_state(SYS_ERR_PROCESS,           "SYS ERROR Process")            \
+       mhi_pm_state(SYS_ERR_FAIL,              "SYS ERROR Failure")            \
+       mhi_pm_state(SHUTDOWN_PROCESS,          "SHUTDOWN Process")             \
+       mhi_pm_state_end(LD_ERR_FATAL_DETECT,   "Linkdown or Error Fatal Detect")
+
 #define MHI_PM_DISABLE                                 BIT(0)
 #define MHI_PM_POR                                     BIT(1)
 #define MHI_PM_M0                                      BIT(2)
@@ -104,14 +140,16 @@ enum mhi_pm_state {
 #define MHI_PM_FW_DL_ERR                               BIT(7)
 #define MHI_PM_SYS_ERR_DETECT                          BIT(8)
 #define MHI_PM_SYS_ERR_PROCESS                         BIT(9)
-#define MHI_PM_SHUTDOWN_PROCESS                                BIT(10)
+#define MHI_PM_SYS_ERR_FAIL                            BIT(10)
+#define MHI_PM_SHUTDOWN_PROCESS                                BIT(11)
 /* link not accessible */
-#define MHI_PM_LD_ERR_FATAL_DETECT                     BIT(11)
+#define MHI_PM_LD_ERR_FATAL_DETECT                     BIT(12)
 
 #define MHI_REG_ACCESS_VALID(pm_state)                 ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \
                                                MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \
                                                MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \
-                                               MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR)))
+                                               MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS |  \
+                                               MHI_PM_FW_DL_ERR)))
 #define MHI_PM_IN_ERROR_STATE(pm_state)                        (pm_state >= MHI_PM_FW_DL_ERR)
 #define MHI_PM_IN_FATAL_STATE(pm_state)                        (pm_state == MHI_PM_LD_ERR_FATAL_DETECT)
 #define MHI_DB_ACCESS_VALID(mhi_cntrl)                 (mhi_cntrl->pm_state & mhi_cntrl->db_access)
index abb561db9ae1d556be5f9e393e7af562f74754d0..15d657af9b5b8685bfa0a70b0c4dd2c498c3bf06 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include "internal.h"
+#include "trace.h"
 
 int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
                              void __iomem *base, u32 offset, u32 *out)
@@ -493,11 +494,8 @@ irqreturn_t mhi_intvec_threaded_handler(int irq_number, void *priv)
 
        state = mhi_get_mhi_state(mhi_cntrl);
        ee = mhi_get_exec_env(mhi_cntrl);
-       dev_dbg(dev, "local ee: %s state: %s device ee: %s state: %s\n",
-               TO_MHI_EXEC_STR(mhi_cntrl->ee),
-               mhi_state_str(mhi_cntrl->dev_state),
-               TO_MHI_EXEC_STR(ee), mhi_state_str(state));
 
+       trace_mhi_intvec_states(mhi_cntrl, ee, state);
        if (state == MHI_STATE_SYS_ERR) {
                dev_dbg(dev, "System error detected\n");
                pm_state = mhi_tryset_pm_state(mhi_cntrl,
@@ -838,6 +836,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
        while (dev_rp != local_rp) {
                enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp);
 
+               trace_mhi_ctrl_event(mhi_cntrl, local_rp);
+
                switch (type) {
                case MHI_PKT_TYPE_BW_REQ_EVENT:
                {
@@ -1003,6 +1003,8 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
        while (dev_rp != local_rp && event_quota > 0) {
                enum mhi_pkt_type type = MHI_TRE_GET_EV_TYPE(local_rp);
 
+               trace_mhi_data_event(mhi_cntrl, local_rp);
+
                chan = MHI_TRE_GET_EV_CHID(local_rp);
 
                WARN_ON(chan >= mhi_cntrl->max_chan);
@@ -1243,6 +1245,7 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
        mhi_tre->dword[0] = MHI_TRE_DATA_DWORD0(info->len);
        mhi_tre->dword[1] = MHI_TRE_DATA_DWORD1(bei, eot, eob, chain);
 
+       trace_mhi_gen_tre(mhi_cntrl, mhi_chan, mhi_tre);
        /* increment WP */
        mhi_add_ring_element(mhi_cntrl, tre_ring);
        mhi_add_ring_element(mhi_cntrl, buf_ring);
@@ -1337,9 +1340,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl,
        enum mhi_cmd_type cmd = MHI_CMD_NOP;
        int ret;
 
-       dev_dbg(dev, "%d: Updating channel state to: %s\n", mhi_chan->chan,
-               TO_CH_STATE_TYPE_STR(to_state));
-
+       trace_mhi_channel_command_start(mhi_cntrl, mhi_chan, to_state, TPS("Updating"));
        switch (to_state) {
        case MHI_CH_STATE_TYPE_RESET:
                write_lock_irq(&mhi_chan->lock);
@@ -1406,9 +1407,7 @@ static int mhi_update_channel_state(struct mhi_controller *mhi_cntrl,
                write_unlock_irq(&mhi_chan->lock);
        }
 
-       dev_dbg(dev, "%d: Channel state change to %s successful\n",
-               mhi_chan->chan, TO_CH_STATE_TYPE_STR(to_state));
-
+       trace_mhi_channel_command_end(mhi_cntrl, mhi_chan, to_state, TPS("Updated"));
 exit_channel_update:
        mhi_cntrl->runtime_put(mhi_cntrl);
        mhi_device_put(mhi_cntrl->mhi_dev);
index cd6cd14b3d29b17c0a9ce78ef40a902686d26a48..51639bfcfec70835b65d4864ddcc6e7937bb64d0 100644 (file)
@@ -538,7 +538,7 @@ static struct mhi_event_config mhi_telit_fn980_hw_v1_events[] = {
        MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101)
 };
 
-static struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
+static const struct mhi_controller_config modem_telit_fn980_hw_v1_config = {
        .max_channels = 128,
        .timeout_ms = 20000,
        .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v1_channels),
index a2f2feef14768a83ad2d0f6f2f7f5db1cd027311..8b40d3f01accdaf3b6604ef4c70696759224d8b2 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include "internal.h"
+#include "trace.h"
 
 /*
  * Not all MHI state transitions are synchronous. Transitions like Linkdown,
  *     M0 <--> M0
  *     M0 -> FW_DL_ERR
  *     M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0
- * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
+ * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS
+ *     SYS_ERR_PROCESS -> SYS_ERR_FAIL
+ *     SYS_ERR_FAIL -> SYS_ERR_DETECT
+ *     SYS_ERR_PROCESS --> POR
  * L2: SHUTDOWN_PROCESS -> LD_ERR_FATAL_DETECT
  *     SHUTDOWN_PROCESS -> DISABLE
  * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
@@ -93,7 +97,12 @@ static const struct mhi_pm_transitions dev_state_transitions[] = {
        },
        {
                MHI_PM_SYS_ERR_PROCESS,
-               MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS |
+               MHI_PM_POR | MHI_PM_SYS_ERR_FAIL | MHI_PM_SHUTDOWN_PROCESS |
+               MHI_PM_LD_ERR_FATAL_DETECT
+       },
+       {
+               MHI_PM_SYS_ERR_FAIL,
+               MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
                MHI_PM_LD_ERR_FATAL_DETECT
        },
        /* L2 States */
@@ -123,6 +132,7 @@ enum mhi_pm_state __must_check mhi_tryset_pm_state(struct mhi_controller *mhi_cn
        if (unlikely(!(dev_state_transitions[index].to_states & state)))
                return cur_state;
 
+       trace_mhi_tryset_pm_state(mhi_cntrl, state);
        mhi_cntrl->pm_state = state;
        return mhi_cntrl->pm_state;
 }
@@ -629,7 +639,13 @@ static void mhi_pm_sys_error_transition(struct mhi_controller *mhi_cntrl)
                                        !in_reset, timeout);
                if (!ret || in_reset) {
                        dev_err(dev, "Device failed to exit MHI Reset state\n");
-                       goto exit_sys_error_transition;
+                       write_lock_irq(&mhi_cntrl->pm_lock);
+                       cur_state = mhi_tryset_pm_state(mhi_cntrl,
+                                                       MHI_PM_SYS_ERR_FAIL);
+                       write_unlock_irq(&mhi_cntrl->pm_lock);
+                       /* Shutdown may have occurred, otherwise cleanup now */
+                       if (cur_state != MHI_PM_SYS_ERR_FAIL)
+                               goto exit_sys_error_transition;
                }
 
                /*
@@ -758,7 +774,6 @@ void mhi_pm_st_worker(struct work_struct *work)
        struct mhi_controller *mhi_cntrl = container_of(work,
                                                        struct mhi_controller,
                                                        st_worker);
-       struct device *dev = &mhi_cntrl->mhi_dev->dev;
 
        spin_lock_irq(&mhi_cntrl->transition_lock);
        list_splice_tail_init(&mhi_cntrl->transition_list, &head);
@@ -766,8 +781,8 @@ void mhi_pm_st_worker(struct work_struct *work)
 
        list_for_each_entry_safe(itr, tmp, &head, node) {
                list_del(&itr->node);
-               dev_dbg(dev, "Handling state transition: %s\n",
-                       TO_DEV_STATE_TRANS_STR(itr->state));
+
+               trace_mhi_pm_st_transition(mhi_cntrl, itr->state);
 
                switch (itr->state) {
                case DEV_ST_TRANSITION_PBL:
diff --git a/drivers/bus/mhi/host/trace.h b/drivers/bus/mhi/host/trace.h
new file mode 100644 (file)
index 0000000..368515d
--- /dev/null
@@ -0,0 +1,282 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mhi_host
+
+#if !defined(_TRACE_EVENT_MHI_HOST_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EVENT_MHI_HOST_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+#include "../common.h"
+#include "internal.h"
+
+#undef mhi_state
+#undef mhi_state_end
+
+#define mhi_state(a, b)                TRACE_DEFINE_ENUM(MHI_STATE_##a);
+#define mhi_state_end(a, b)    TRACE_DEFINE_ENUM(MHI_STATE_##a);
+
+MHI_STATE_LIST
+
+#undef mhi_state
+#undef mhi_state_end
+
+#define mhi_state(a, b)                { MHI_STATE_##a, b },
+#define mhi_state_end(a, b)    { MHI_STATE_##a, b }
+
+#undef mhi_pm_state
+#undef mhi_pm_state_end
+
+#define mhi_pm_state(a, b)             TRACE_DEFINE_ENUM(MHI_PM_STATE_##a);
+#define mhi_pm_state_end(a, b)         TRACE_DEFINE_ENUM(MHI_PM_STATE_##a);
+
+MHI_PM_STATE_LIST
+
+#undef mhi_pm_state
+#undef mhi_pm_state_end
+
+#define mhi_pm_state(a, b)             { MHI_PM_STATE_##a, b },
+#define mhi_pm_state_end(a, b)         { MHI_PM_STATE_##a, b }
+
+#undef mhi_ee
+#undef mhi_ee_end
+
+#define mhi_ee(a, b)                   TRACE_DEFINE_ENUM(MHI_EE_##a);
+#define mhi_ee_end(a, b)               TRACE_DEFINE_ENUM(MHI_EE_##a);
+
+MHI_EE_LIST
+
+#undef mhi_ee
+#undef mhi_ee_end
+
+#define mhi_ee(a, b)                   { MHI_EE_##a, b },
+#define mhi_ee_end(a, b)               { MHI_EE_##a, b }
+
+#undef ch_state_type
+#undef ch_state_type_end
+
+#define ch_state_type(a, b)            TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a);
+#define ch_state_type_end(a, b)                TRACE_DEFINE_ENUM(MHI_CH_STATE_TYPE_##a);
+
+MHI_CH_STATE_TYPE_LIST
+
+#undef ch_state_type
+#undef ch_state_type_end
+
+#define ch_state_type(a, b)            { MHI_CH_STATE_TYPE_##a, b },
+#define ch_state_type_end(a, b)                { MHI_CH_STATE_TYPE_##a, b }
+
+#undef dev_st_trans
+#undef dev_st_trans_end
+
+#define dev_st_trans(a, b)             TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a);
+#define dev_st_trans_end(a, b)         TRACE_DEFINE_ENUM(DEV_ST_TRANSITION_##a);
+
+DEV_ST_TRANSITION_LIST
+
+#undef dev_st_trans
+#undef dev_st_trans_end
+
+#define dev_st_trans(a, b)             { DEV_ST_TRANSITION_##a, b },
+#define dev_st_trans_end(a, b)         { DEV_ST_TRANSITION_##a, b }
+
+#define TPS(x) tracepoint_string(x)
+
+TRACE_EVENT(mhi_gen_tre,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
+                struct mhi_ring_element *mhi_tre),
+
+       TP_ARGS(mhi_cntrl, mhi_chan, mhi_tre),
+
+       TP_STRUCT__entry(
+               __string(name, mhi_cntrl->mhi_dev->name)
+               __field(int, ch_num)
+               __field(void *, wp)
+               __field(__le64, tre_ptr)
+               __field(__le32, dword0)
+               __field(__le32, dword1)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, mhi_cntrl->mhi_dev->name);
+               __entry->ch_num = mhi_chan->chan;
+               __entry->wp = mhi_tre;
+               __entry->tre_ptr = mhi_tre->ptr;
+               __entry->dword0 = mhi_tre->dword[0];
+               __entry->dword1 = mhi_tre->dword[1];
+       ),
+
+       TP_printk("%s: Chan: %d TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x\n",
+                 __get_str(name), __entry->ch_num, __entry->wp, __entry->tre_ptr,
+                 __entry->dword0, __entry->dword1)
+);
+
+TRACE_EVENT(mhi_intvec_states,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, int dev_ee, int dev_state),
+
+       TP_ARGS(mhi_cntrl, dev_ee, dev_state),
+
+       TP_STRUCT__entry(
+               __string(name, mhi_cntrl->mhi_dev->name)
+               __field(int, local_ee)
+               __field(int, state)
+               __field(int, dev_ee)
+               __field(int, dev_state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, mhi_cntrl->mhi_dev->name);
+               __entry->local_ee = mhi_cntrl->ee;
+               __entry->state = mhi_cntrl->dev_state;
+               __entry->dev_ee = dev_ee;
+               __entry->dev_state = dev_state;
+       ),
+
+       TP_printk("%s: Local EE: %s State: %s Device EE: %s Dev State: %s\n",
+                 __get_str(name),
+                 __print_symbolic(__entry->local_ee, MHI_EE_LIST),
+                 __print_symbolic(__entry->state, MHI_STATE_LIST),
+                 __print_symbolic(__entry->dev_ee, MHI_EE_LIST),
+                 __print_symbolic(__entry->dev_state, MHI_STATE_LIST))
+);
+
+TRACE_EVENT(mhi_tryset_pm_state,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, int pm_state),
+
+       TP_ARGS(mhi_cntrl, pm_state),
+
+       TP_STRUCT__entry(
+               __string(name, mhi_cntrl->mhi_dev->name)
+               __field(int, pm_state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, mhi_cntrl->mhi_dev->name);
+               if (pm_state)
+                       pm_state = __fls(pm_state);
+               __entry->pm_state = pm_state;
+       ),
+
+       TP_printk("%s: PM state: %s\n", __get_str(name),
+                 __print_symbolic(__entry->pm_state, MHI_PM_STATE_LIST))
+);
+
+DECLARE_EVENT_CLASS(mhi_process_event_ring,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp),
+
+       TP_ARGS(mhi_cntrl, rp),
+
+       TP_STRUCT__entry(
+               __string(name, mhi_cntrl->mhi_dev->name)
+               __field(__le32, dword0)
+               __field(__le32, dword1)
+               __field(int, state)
+               __field(__le64, ptr)
+               __field(void *, rp)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, mhi_cntrl->mhi_dev->name);
+               __entry->rp = rp;
+               __entry->ptr = rp->ptr;
+               __entry->dword0 = rp->dword[0];
+               __entry->dword1 = rp->dword[1];
+               __entry->state = MHI_TRE_GET_EV_STATE(rp);
+       ),
+
+       TP_printk("%s: TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x State: %s\n",
+                 __get_str(name), __entry->rp, __entry->ptr, __entry->dword0,
+                 __entry->dword1, __print_symbolic(__entry->state, MHI_STATE_LIST))
+);
+
+DEFINE_EVENT(mhi_process_event_ring, mhi_data_event,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp),
+
+       TP_ARGS(mhi_cntrl, rp)
+);
+
+DEFINE_EVENT(mhi_process_event_ring, mhi_ctrl_event,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_ring_element *rp),
+
+       TP_ARGS(mhi_cntrl, rp)
+);
+
+DECLARE_EVENT_CLASS(mhi_update_channel_state,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state,
+                const char *reason),
+
+       TP_ARGS(mhi_cntrl, mhi_chan, state, reason),
+
+       TP_STRUCT__entry(
+               __string(name, mhi_cntrl->mhi_dev->name)
+               __field(int, ch_num)
+               __field(int, state)
+               __field(const char *, reason)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, mhi_cntrl->mhi_dev->name);
+               __entry->ch_num = mhi_chan->chan;
+               __entry->state = state;
+               __entry->reason = reason;
+       ),
+
+       TP_printk("%s: chan%d: %s state to: %s\n",
+                 __get_str(name),  __entry->ch_num, __entry->reason,
+                 __print_symbolic(__entry->state, MHI_CH_STATE_TYPE_LIST))
+);
+
+DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_start,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state,
+                const char *reason),
+
+       TP_ARGS(mhi_cntrl, mhi_chan, state, reason)
+);
+
+DEFINE_EVENT(mhi_update_channel_state, mhi_channel_command_end,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int state,
+                const char *reason),
+
+       TP_ARGS(mhi_cntrl, mhi_chan, state, reason)
+);
+
+TRACE_EVENT(mhi_pm_st_transition,
+
+       TP_PROTO(struct mhi_controller *mhi_cntrl, int state),
+
+       TP_ARGS(mhi_cntrl, state),
+
+       TP_STRUCT__entry(
+               __string(name, mhi_cntrl->mhi_dev->name)
+               __field(int, state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, mhi_cntrl->mhi_dev->name);
+               __entry->state = state;
+       ),
+
+       TP_printk("%s: Handling state transition: %s\n", __get_str(name),
+                 __print_symbolic(__entry->state, DEV_ST_TRANSITION_LIST))
+);
+
+#endif
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/bus/mhi/host
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
index 4fa932cb09150a3bdb15c6f78033a8e2cc6e541c..baf22a82c47a7ec9ee8dfbcd7029b718c0d21d1d 100644 (file)
@@ -39,45 +39,39 @@ struct ts_nbus {
 /*
  * request all gpios required by the bus.
  */
-static int ts_nbus_init_pdata(struct platform_device *pdev, struct ts_nbus
-               *ts_nbus)
+static int ts_nbus_init_pdata(struct platform_device *pdev,
+                             struct ts_nbus *ts_nbus)
 {
        ts_nbus->data = devm_gpiod_get_array(&pdev->dev, "ts,data",
                        GPIOD_OUT_HIGH);
-       if (IS_ERR(ts_nbus->data)) {
-               dev_err(&pdev->dev, "failed to retrieve ts,data-gpio from dts\n");
-               return PTR_ERR(ts_nbus->data);
-       }
+       if (IS_ERR(ts_nbus->data))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ts_nbus->data),
+                                    "failed to retrieve ts,data-gpio from dts\n");
 
        ts_nbus->csn = devm_gpiod_get(&pdev->dev, "ts,csn", GPIOD_OUT_HIGH);
-       if (IS_ERR(ts_nbus->csn)) {
-               dev_err(&pdev->dev, "failed to retrieve ts,csn-gpio from dts\n");
-               return PTR_ERR(ts_nbus->csn);
-       }
+       if (IS_ERR(ts_nbus->csn))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ts_nbus->csn),
+                             "failed to retrieve ts,csn-gpio from dts\n");
 
        ts_nbus->txrx = devm_gpiod_get(&pdev->dev, "ts,txrx", GPIOD_OUT_HIGH);
-       if (IS_ERR(ts_nbus->txrx)) {
-               dev_err(&pdev->dev, "failed to retrieve ts,txrx-gpio from dts\n");
-               return PTR_ERR(ts_nbus->txrx);
-       }
+       if (IS_ERR(ts_nbus->txrx))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ts_nbus->txrx),
+                                    "failed to retrieve ts,txrx-gpio from dts\n");
 
        ts_nbus->strobe = devm_gpiod_get(&pdev->dev, "ts,strobe", GPIOD_OUT_HIGH);
-       if (IS_ERR(ts_nbus->strobe)) {
-               dev_err(&pdev->dev, "failed to retrieve ts,strobe-gpio from dts\n");
-               return PTR_ERR(ts_nbus->strobe);
-       }
+       if (IS_ERR(ts_nbus->strobe))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ts_nbus->strobe),
+                                    "failed to retrieve ts,strobe-gpio from dts\n");
 
        ts_nbus->ale = devm_gpiod_get(&pdev->dev, "ts,ale", GPIOD_OUT_HIGH);
-       if (IS_ERR(ts_nbus->ale)) {
-               dev_err(&pdev->dev, "failed to retrieve ts,ale-gpio from dts\n");
-               return PTR_ERR(ts_nbus->ale);
-       }
+       if (IS_ERR(ts_nbus->ale))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ts_nbus->ale),
+                                    "failed to retrieve ts,ale-gpio from dts\n");
 
        ts_nbus->rdy = devm_gpiod_get(&pdev->dev, "ts,rdy", GPIOD_IN);
-       if (IS_ERR(ts_nbus->rdy)) {
-               dev_err(&pdev->dev, "failed to retrieve ts,rdy-gpio from dts\n");
-               return PTR_ERR(ts_nbus->rdy);
-       }
+       if (IS_ERR(ts_nbus->rdy))
+               return dev_err_probe(&pdev->dev, PTR_ERR(ts_nbus->rdy),
+                                    "failed to retrieve ts,rdy-gpio from dts\n");
 
        return 0;
 }
@@ -273,7 +267,7 @@ EXPORT_SYMBOL_GPL(ts_nbus_write);
 static int ts_nbus_probe(struct platform_device *pdev)
 {
        struct pwm_device *pwm;
-       struct pwm_args pargs;
+       struct pwm_state state;
        struct device *dev = &pdev->dev;
        struct ts_nbus *ts_nbus;
        int ret;
@@ -289,32 +283,24 @@ static int ts_nbus_probe(struct platform_device *pdev)
                return ret;
 
        pwm = devm_pwm_get(dev, NULL);
-       if (IS_ERR(pwm)) {
-               ret = PTR_ERR(pwm);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "unable to request PWM\n");
-               return ret;
-       }
+       if (IS_ERR(pwm))
+               return dev_err_probe(dev, PTR_ERR(pwm),
+                                    "unable to request PWM\n");
 
-       pwm_get_args(pwm, &pargs);
-       if (!pargs.period) {
-               dev_err(&pdev->dev, "invalid PWM period\n");
-               return -EINVAL;
-       }
+       pwm_init_state(pwm, &state);
+       if (!state.period)
+               return dev_err_probe(dev, -EINVAL, "invalid PWM period\n");
 
-       /*
-        * FIXME: pwm_apply_args() should be removed when switching to
-        * the atomic PWM API.
-        */
-       pwm_apply_args(pwm);
-       ret = pwm_config(pwm, pargs.period, pargs.period);
+       state.duty_cycle = state.period;
+       state.enabled = true;
+
+       ret = pwm_apply_state(pwm, &state);
        if (ret < 0)
-               return ret;
+               return dev_err_probe(dev, ret, "failed to configure PWM\n");
 
        /*
         * we can now start the FPGA and populate the peripherals.
         */
-       pwm_enable(pwm);
        ts_nbus->pwm = pwm;
 
        /*
@@ -324,7 +310,8 @@ static int ts_nbus_probe(struct platform_device *pdev)
 
        ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
        if (ret < 0)
-               return ret;
+               return dev_err_probe(dev, ret,
+                                    "failed to populate platform devices on bus\n");
 
        dev_info(dev, "initialized\n");
 
index 5d1ea482419f046e090f22ec81b37e3d0c237651..749a3295c2bdc130f4bc1929bc339fbc29de1046 100644 (file)
@@ -8,3 +8,7 @@
 ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS
 
 obj-$(CONFIG_CDX_BUS) += cdx.o controller/
+
+ifdef CONFIG_GENERIC_MSI_IRQ
+obj-$(CONFIG_CDX_BUS) += cdx_msi.o
+endif
index b74d76afccb6345c0b1bdff08f825979510f6968..236d381dc5f75d0d288010f942b745629efc18d6 100644 (file)
@@ -56,6 +56,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -302,8 +303,19 @@ static int cdx_probe(struct device *dev)
 {
        struct cdx_driver *cdx_drv = to_cdx_driver(dev->driver);
        struct cdx_device *cdx_dev = to_cdx_device(dev);
+       struct cdx_controller *cdx = cdx_dev->cdx;
        int error;
 
+       /*
+        * Setup MSI device data so that generic MSI alloc/free can
+        * be used by the device driver.
+        */
+       if (cdx->msi_domain) {
+               error = msi_setup_device_data(&cdx_dev->dev);
+               if (error)
+                       return error;
+       }
+
        error = cdx_drv->probe(cdx_dev);
        if (error) {
                dev_err_probe(dev, error, "%s failed\n", __func__);
@@ -787,6 +799,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
 
        /* Populate CDX dev params */
        cdx_dev->req_id = dev_params->req_id;
+       cdx_dev->msi_dev_id = dev_params->msi_dev_id;
        cdx_dev->vendor = dev_params->vendor;
        cdx_dev->device = dev_params->device;
        cdx_dev->subsystem_vendor = dev_params->subsys_vendor;
@@ -804,12 +817,19 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
        cdx_dev->dev.bus = &cdx_bus_type;
        cdx_dev->dev.dma_mask = &cdx_dev->dma_mask;
        cdx_dev->dev.release = cdx_device_release;
+       cdx_dev->msi_write_pending = false;
+       mutex_init(&cdx_dev->irqchip_lock);
 
        /* Set Name */
        dev_set_name(&cdx_dev->dev, "cdx-%02x:%02x",
                     ((cdx->id << CDX_CONTROLLER_ID_SHIFT) | (cdx_dev->bus_num & CDX_BUS_NUM_MASK)),
                     cdx_dev->dev_num);
 
+       if (cdx->msi_domain) {
+               cdx_dev->num_msi = dev_params->num_msi;
+               dev_set_msi_domain(&cdx_dev->dev, cdx->msi_domain);
+       }
+
        ret = device_add(&cdx_dev->dev);
        if (ret) {
                dev_err(&cdx_dev->dev,
index 300ad8be7a344dda7b1e3af8bf4ee87624f415e0..9c60c04dcf8778f2c688e969d9cac811ef7decdc 100644 (file)
@@ -25,6 +25,8 @@
  * @req_id: Requestor ID associated with CDX device
  * @class: Class of the CDX Device
  * @revision: Revision of the CDX device
+ * @msi_dev_id: MSI device ID associated with CDX device
+ * @num_msi: Number of MSI's supported by the device
  */
 struct cdx_dev_params {
        struct cdx_controller *cdx;
@@ -40,6 +42,8 @@ struct cdx_dev_params {
        u32 req_id;
        u32 class;
        u8 revision;
+       u32 msi_dev_id;
+       u32 num_msi;
 };
 
 /**
@@ -79,4 +83,12 @@ int cdx_device_add(struct cdx_dev_params *dev_params);
  */
 struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num);
 
+/**
+ * cdx_msi_domain_init - Init the CDX bus MSI domain.
+ * @dev: Device of the CDX bus controller
+ *
+ * Return: CDX MSI domain, NULL on failure
+ */
+struct irq_domain *cdx_msi_domain_init(struct device *dev);
+
 #endif /* _CDX_H_ */
diff --git a/drivers/cdx/cdx_msi.c b/drivers/cdx/cdx_msi.c
new file mode 100644 (file)
index 0000000..e55f171
--- /dev/null
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD CDX bus driver MSI support
+ *
+ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
+ */
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+#include <linux/cdx/cdx_bus.h>
+
+#include "cdx.h"
+
+static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
+{
+       struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
+       struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
+
+       /* We would not operate on msg here rather we wait for irq_bus_sync_unlock()
+        * to be called from preemptible task context.
+        */
+       msi_desc->msg = *msg;
+       cdx_dev->msi_write_pending = true;
+}
+
+static void cdx_msi_write_irq_lock(struct irq_data *irq_data)
+{
+       struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
+       struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
+
+       mutex_lock(&cdx_dev->irqchip_lock);
+}
+
+static void cdx_msi_write_irq_unlock(struct irq_data *irq_data)
+{
+       struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
+       struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
+       struct cdx_controller *cdx = cdx_dev->cdx;
+       struct cdx_device_config dev_config;
+
+       if (!cdx_dev->msi_write_pending) {
+               mutex_unlock(&cdx_dev->irqchip_lock);
+               return;
+       }
+
+       cdx_dev->msi_write_pending = false;
+       mutex_unlock(&cdx_dev->irqchip_lock);
+
+       dev_config.msi.msi_index = msi_desc->msi_index;
+       dev_config.msi.data = msi_desc->msg.data;
+       dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo;
+
+       /*
+        * dev_configure() is a controller callback which can interact with
+        * Firmware or other entities, and can sleep, so invoke this function
+        * outside of the mutex held region.
+        */
+       dev_config.type = CDX_DEV_MSI_CONF;
+       if (cdx->ops->dev_configure)
+               cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
+}
+
+int cdx_enable_msi(struct cdx_device *cdx_dev)
+{
+       struct cdx_controller *cdx = cdx_dev->cdx;
+       struct cdx_device_config dev_config;
+
+       dev_config.type = CDX_DEV_MSI_ENABLE;
+       dev_config.msi_enable = true;
+       if (cdx->ops->dev_configure) {
+               return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num,
+                                              &dev_config);
+       }
+
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(cdx_enable_msi);
+
+void cdx_disable_msi(struct cdx_device *cdx_dev)
+{
+       struct cdx_controller *cdx = cdx_dev->cdx;
+       struct cdx_device_config dev_config;
+
+       dev_config.type = CDX_DEV_MSI_ENABLE;
+       dev_config.msi_enable = false;
+       if (cdx->ops->dev_configure)
+               cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
+}
+EXPORT_SYMBOL_GPL(cdx_disable_msi);
+
+static struct irq_chip cdx_msi_irq_chip = {
+       .name                   = "CDX-MSI",
+       .irq_mask               = irq_chip_mask_parent,
+       .irq_unmask             = irq_chip_unmask_parent,
+       .irq_eoi                = irq_chip_eoi_parent,
+       .irq_set_affinity       = msi_domain_set_affinity,
+       .irq_write_msi_msg      = cdx_msi_write_msg,
+       .irq_bus_lock           = cdx_msi_write_irq_lock,
+       .irq_bus_sync_unlock    = cdx_msi_write_irq_unlock
+};
+
+/* Convert an msi_desc to a unique identifier within the domain. */
+static irq_hw_number_t cdx_domain_calc_hwirq(struct cdx_device *dev,
+                                            struct msi_desc *desc)
+{
+       return ((irq_hw_number_t)dev->msi_dev_id << 10) | desc->msi_index;
+}
+
+static void cdx_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+       arg->desc = desc;
+       arg->hwirq = cdx_domain_calc_hwirq(to_cdx_device(desc->dev), desc);
+}
+
+static int cdx_msi_prepare(struct irq_domain *msi_domain,
+                          struct device *dev,
+                          int nvec, msi_alloc_info_t *info)
+{
+       struct cdx_device *cdx_dev = to_cdx_device(dev);
+       struct device *parent = cdx_dev->cdx->dev;
+       struct msi_domain_info *msi_info;
+       u32 dev_id;
+       int ret;
+
+       /* Retrieve device ID from requestor ID using parent device */
+       ret = of_map_id(parent->of_node, cdx_dev->msi_dev_id, "msi-map", "msi-map-mask",
+                       NULL, &dev_id);
+       if (ret) {
+               dev_err(dev, "of_map_id failed for MSI: %d\n", ret);
+               return ret;
+       }
+
+#ifdef GENERIC_MSI_DOMAIN_OPS
+       /* Set the device Id to be passed to the GIC-ITS */
+       info->scratchpad[0].ul = dev_id;
+#endif
+
+       msi_info = msi_get_domain_info(msi_domain->parent);
+
+       return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
+}
+
+static struct msi_domain_ops cdx_msi_ops = {
+       .msi_prepare    = cdx_msi_prepare,
+       .set_desc       = cdx_msi_set_desc
+};
+
+static struct msi_domain_info cdx_msi_domain_info = {
+       .ops    = &cdx_msi_ops,
+       .chip   = &cdx_msi_irq_chip,
+       .flags  = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+                 MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS
+};
+
+struct irq_domain *cdx_msi_domain_init(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct fwnode_handle *fwnode_handle;
+       struct irq_domain *cdx_msi_domain;
+       struct device_node *parent_node;
+       struct irq_domain *parent;
+
+       fwnode_handle = of_node_to_fwnode(np);
+
+       parent_node = of_parse_phandle(np, "msi-map", 1);
+       if (!parent_node) {
+               dev_err(dev, "msi-map not present on cdx controller\n");
+               return NULL;
+       }
+
+       parent = irq_find_matching_fwnode(of_node_to_fwnode(parent_node), DOMAIN_BUS_NEXUS);
+       if (!parent || !msi_get_domain_info(parent)) {
+               dev_err(dev, "unable to locate ITS domain\n");
+               return NULL;
+       }
+
+       cdx_msi_domain = msi_create_irq_domain(fwnode_handle, &cdx_msi_domain_info, parent);
+       if (!cdx_msi_domain) {
+               dev_err(dev, "unable to create CDX-MSI domain\n");
+               return NULL;
+       }
+
+       dev_dbg(dev, "CDX-MSI domain created\n");
+
+       return cdx_msi_domain;
+}
+EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, CDX_BUS_CONTROLLER);
index 61bf17fbe43360cc0712a75025abb1d1371ac648..f8e729761aeed03302d6c625b74f5e54bfd1bcbf 100644 (file)
@@ -9,6 +9,7 @@ if CDX_BUS
 
 config CDX_CONTROLLER
        tristate "CDX bus controller"
+       select GENERIC_MSI_IRQ
        select REMOTEPROC
        select RPMSG
        help
index 85fe4b1c4e5ee54dbc0f2d432a9bdd24d8d6ab6a..112a1541de6d7ed68b74566c870ab5928b8a71a9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/cdx/cdx_bus.h>
+#include <linux/irqdomain.h>
 
 #include "cdx_controller.h"
 #include "../cdx.h"
@@ -60,9 +61,19 @@ static int cdx_configure_device(struct cdx_controller *cdx,
                                u8 bus_num, u8 dev_num,
                                struct cdx_device_config *dev_config)
 {
+       u16 msi_index;
        int ret = 0;
+       u32 data;
+       u64 addr;
 
        switch (dev_config->type) {
+       case CDX_DEV_MSI_CONF:
+               msi_index = dev_config->msi.msi_index;
+               data = dev_config->msi.data;
+               addr = dev_config->msi.addr;
+
+               ret = cdx_mcdi_write_msi(cdx->priv, bus_num, dev_num, msi_index, addr, data);
+               break;
        case CDX_DEV_RESET_CONF:
                ret = cdx_mcdi_reset_device(cdx->priv, bus_num, dev_num);
                break;
@@ -70,6 +81,9 @@ static int cdx_configure_device(struct cdx_controller *cdx,
                ret = cdx_mcdi_bus_master_enable(cdx->priv, bus_num, dev_num,
                                                 dev_config->bus_master_enable);
                break;
+       case CDX_DEV_MSI_ENABLE:
+               ret = cdx_mcdi_msi_enable(cdx->priv, bus_num, dev_num, dev_config->msi_enable);
+               break;
        default:
                ret = -EINVAL;
        }
@@ -178,6 +192,14 @@ static int xlnx_cdx_probe(struct platform_device *pdev)
        cdx->priv = cdx_mcdi;
        cdx->ops = &cdx_ops;
 
+       /* Create MSI domain */
+       cdx->msi_domain = cdx_msi_domain_init(&pdev->dev);
+       if (!cdx->msi_domain) {
+               dev_err(&pdev->dev, "cdx_msi_domain_init() failed");
+               ret = -ENODEV;
+               goto cdx_msi_fail;
+       }
+
        ret = cdx_setup_rpmsg(pdev);
        if (ret) {
                if (ret != -EPROBE_DEFER)
@@ -189,6 +211,8 @@ static int xlnx_cdx_probe(struct platform_device *pdev)
        return 0;
 
 cdx_rpmsg_fail:
+       irq_domain_remove(cdx->msi_domain);
+cdx_msi_fail:
        kfree(cdx);
 cdx_alloc_fail:
        cdx_mcdi_finish(cdx_mcdi);
@@ -205,6 +229,7 @@ static int xlnx_cdx_remove(struct platform_device *pdev)
 
        cdx_destroy_rpmsg(pdev);
 
+       irq_domain_remove(cdx->msi_domain);
        kfree(cdx);
 
        cdx_mcdi_finish(cdx_mcdi);
index 2de019406b577f5e51b37e13e2082a5728c3d6c4..832a44af963ef3575a992f564ab432883e5d3c06 100644 (file)
 #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_OFST                 84
 #define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID_LEN                  4
 
+/* MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2 msgresponse */
+#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN                            92
+/* Requester ID used by device for GIC ITS DeviceID */
+#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_OFST       88
+#define MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID_LEN                4
+
 /***********************************/
 /*
  * MC_CMD_CDX_BUS_DOWN
 #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_LBN      2
 #define MC_CMD_CDX_DEVICE_CONTROL_GET_OUT_MMIO_REGIONS_ENABLE_WIDTH    1
 
+/***********************************/
+/*
+ * MC_CMD_CDX_DEVICE_WRITE_MSI_MSG
+ * Populates the MSI message to be used by the hardware to raise the specified
+ * interrupt vector. Versal-net implementation specific limitations are that
+ * only 4 CDX devices with MSI interrupt capability are supported and all
+ * vectors within a device must use the same write address. The command will
+ * return EINVAL if any of these limitations is violated.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG                                        0x9
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_MSGSET                         0x9
+#undef MC_CMD_0x9_PRIVILEGE_CTG
+
+#define MC_CMD_0x9_PRIVILEGE_CTG SRIOV_CTG_ADMIN
+
+/* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN msgrequest */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN                         28
+/* Device bus number, in range 0 to BUS_COUNT-1 */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_OFST                    0
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_BUS_LEN                     4
+/* Device number relative to the bus, in range 0 to DEVICE_COUNT-1 for that bus */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_OFST                 4
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE_LEN                  4
+/*
+ * Device-relative MSI vector number. Must be < MSI_COUNT reported for the
+ * device.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_OFST             8
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR_LEN              4
+/* Reserved (alignment) */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_OFST               12
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_RESERVED_LEN                        4
+/*
+ * MSI address to be used by the hardware. Typically, on ARM systems this
+ * address is translated by the IOMMU (if enabled) and it is the responsibility
+ * of the entity managing the IOMMU (APU kernel) to supply the correct IOVA
+ * here.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_OFST            16
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LEN             8
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_OFST         16
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LEN          4
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_LBN          128
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_LO_WIDTH                32
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_OFST         20
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LEN          4
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_LBN          160
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS_HI_WIDTH                32
+/*
+ * MSI data to be used by the hardware. On versal-net, only the lower 16-bits
+ * are used, the remaining bits are ignored and should be set to zero.
+ */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_OFST               24
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA_LEN                        4
+
+/* MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT msgresponse */
+#define MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_OUT_LEN                                0
+
 /***********************************/
 /* MC_CMD_V2_EXTN - Encapsulation for a v2 extended command */
 #define MC_CMD_V2_EXTN                                 0x7f
index b1f53094638934697920088068e4f95a850f1afe..885c69e6ebe5b61da7c205ba282e00581b2cacc6 100644 (file)
@@ -49,7 +49,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
                            u8 bus_num, u8 dev_num,
                            struct cdx_dev_params *dev_params)
 {
-       MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN);
+       MCDI_DECLARE_BUF(outbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN);
        MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_IN_LEN);
        struct resource *res = &dev_params->res[0];
        size_t outlen;
@@ -64,7 +64,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
        if (ret)
                return ret;
 
-       if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_LEN)
+       if (outlen != MC_CMD_CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_LEN)
                return -EIO;
 
        dev_params->bus_num = bus_num;
@@ -73,6 +73,9 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
        req_id = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_REQUESTER_ID);
        dev_params->req_id = req_id;
 
+       dev_params->msi_dev_id = MCDI_DWORD(outbuf,
+                                           CDX_BUS_GET_DEVICE_CONFIG_OUT_V2_REQUESTER_DEVICE_ID);
+
        dev_params->res_count = 0;
        if (MCDI_QWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MMIO_REGION0_SIZE) != 0) {
                res[dev_params->res_count].start =
@@ -127,6 +130,7 @@ int cdx_mcdi_get_dev_config(struct cdx_mcdi *cdx,
        dev_params->class = MCDI_DWORD(outbuf,
                                       CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_CLASS) & 0xFFFFFF;
        dev_params->revision = MCDI_BYTE(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_DEVICE_REVISION);
+       dev_params->num_msi = MCDI_DWORD(outbuf, CDX_BUS_GET_DEVICE_CONFIG_OUT_MSI_COUNT);
 
        return 0;
 }
@@ -155,6 +159,24 @@ int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num)
        return ret;
 }
 
+int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num,
+                      u32 msi_vector, u64 msi_address, u32 msi_data)
+{
+       MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG_IN_LEN);
+       int ret;
+
+       MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_BUS, bus_num);
+       MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_DEVICE, dev_num);
+       MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_VECTOR, msi_vector);
+       MCDI_SET_QWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_ADDRESS, msi_address);
+       MCDI_SET_DWORD(inbuf, CDX_DEVICE_WRITE_MSI_MSG_IN_MSI_DATA, msi_data);
+
+       ret = cdx_mcdi_rpc(cdx, MC_CMD_CDX_DEVICE_WRITE_MSI_MSG, inbuf, sizeof(inbuf),
+                          NULL, 0, NULL);
+
+       return ret;
+}
+
 int cdx_mcdi_reset_device(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num)
 {
        MCDI_DECLARE_BUF(inbuf, MC_CMD_CDX_DEVICE_RESET_IN_LEN);
@@ -226,3 +248,10 @@ int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num,
        return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable,
                        MC_CMD_CDX_DEVICE_CONTROL_SET_IN_BUS_MASTER_ENABLE_LBN);
 }
+
+int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num,
+                       u8 dev_num, bool enable)
+{
+       return cdx_mcdi_ctrl_flag_set(cdx, bus_num, dev_num, enable,
+                       MC_CMD_CDX_DEVICE_CONTROL_SET_IN_MSI_ENABLE_LBN);
+}
index 258a5462fbe34cc13beffc142e654e5ecdd556e5..b9942affdc6b2d9e0ab3f427f8f97ad113e88415 100644 (file)
@@ -65,6 +65,26 @@ int cdx_mcdi_bus_enable(struct cdx_mcdi *cdx, u8 bus_num);
  */
 int cdx_mcdi_bus_disable(struct cdx_mcdi *cdx, u8 bus_num);
 
+/**
+ * cdx_mcdi_write_msi - Write MSI configuration for CDX device
+ * @cdx: pointer to MCDI interface.
+ * @bus_num: Bus number.
+ * @dev_num: Device number.
+ * @msi_vector: Device-relative MSI vector number.
+ *     Must be < MSI_COUNT reported for the device.
+ * @msi_address: MSI address to be used by the hardware. Typically, on ARM
+ *     systems this address is translated by the IOMMU (if enabled) and
+ *     it is the responsibility of the entity managing the IOMMU (APU kernel)
+ *     to supply the correct IOVA here.
+ * @msi_data: MSI data to be used by the hardware. On versal-net, only the
+ *     lower 16-bits are used, the remaining bits are ignored and should be
+ *     set to zero.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int cdx_mcdi_write_msi(struct cdx_mcdi *cdx, u8 bus_num, u8 dev_num,
+                      u32 msi_vector, u64 msi_address, u32 msi_data);
+
 /**
  * cdx_mcdi_reset_device - Reset cdx device represented by bus_num:dev_num
  * @cdx: pointer to MCDI interface.
@@ -89,4 +109,17 @@ int cdx_mcdi_reset_device(struct cdx_mcdi *cdx,
 int cdx_mcdi_bus_master_enable(struct cdx_mcdi *cdx, u8 bus_num,
                               u8 dev_num, bool enable);
 
+/**
+ * cdx_mcdi_msi_enable - Enable/Disable MSIs for cdx device represented
+ *                      by bus_num:dev_num
+ * @cdx: pointer to MCDI interface.
+ * @bus_num: Bus number.
+ * @dev_num: Device number.
+ * @enable: Enable msi's if set, disable otherwise.
+ *
+ * Return: 0 on success, <0 on failure
+ */
+int cdx_mcdi_msi_enable(struct cdx_mcdi *cdx, u8 bus_num,
+                       u8 dev_num, bool enable);
+
 #endif /* CDX_MCDI_FUNCTIONS_H */
index 9c90b1d2c0366b854e45fe7403ebacef7c13e28f..d51fc8321d411ce60281a1be71f2e3a01022907f 100644 (file)
@@ -87,7 +87,6 @@ struct hpets {
        struct hpets *hp_next;
        struct hpet __iomem *hp_hpet;
        unsigned long hp_hpet_phys;
-       struct clocksource *hp_clocksource;
        unsigned long long hp_tick_freq;
        unsigned long hp_delta;
        unsigned int hp_ntimer;
index 019cf6079cecd61f96f03603f27aa526e75077ba..4f6c3cb8aa4138e6948d7b5971595d0dd4de07b7 100644 (file)
@@ -636,11 +636,11 @@ static int hwicap_setup(struct platform_device *pdev, int id,
                retval = -ENOMEM;
                goto failed;
        }
-       dev_set_drvdata(dev, (void *)drvdata);
+       dev_set_drvdata(dev, drvdata);
 
        drvdata->base_address = devm_platform_ioremap_resource(pdev, 0);
-       if (!drvdata->base_address) {
-               retval = -ENODEV;
+       if (IS_ERR(drvdata->base_address)) {
+               retval = PTR_ERR(drvdata->base_address);
                goto failed;
        }
 
index e5372e45d2118bd668e4b9b4d7f73c9f66a21b2f..8802e2a6fd20b779dfafa1708ad25cb109327843 100644 (file)
@@ -64,19 +64,17 @@ static int xilly_drv_probe(struct platform_device *op)
        return xillybus_endpoint_discovery(endpoint);
 }
 
-static int xilly_drv_remove(struct platform_device *op)
+static void xilly_drv_remove(struct platform_device *op)
 {
        struct device *dev = &op->dev;
        struct xilly_endpoint *endpoint = dev_get_drvdata(dev);
 
        xillybus_endpoint_remove(endpoint);
-
-       return 0;
 }
 
 static struct platform_driver xillybus_platform_driver = {
        .probe = xilly_drv_probe,
-       .remove = xilly_drv_remove,
+       .remove_new = xilly_drv_remove,
        .driver = {
                .name = xillyname,
                .of_match_table = xillybus_of_match,
index 93183287c58db78cad885de7ae96a058705da817..43514e6f3b78001a64984e75ba3bd55d8740fdae 100644 (file)
@@ -376,14 +376,9 @@ static void __init of_omap2_apll_setup(struct device_node *node)
        }
        clk_hw->fixed_rate = val;
 
-       if (of_property_read_u32(node, "ti,bit-shift", &val)) {
-               pr_err("%pOFn missing bit-shift\n", node);
-               goto cleanup;
-       }
-
-       clk_hw->enable_bit = val;
-       ad->enable_mask = 0x3 << val;
-       ad->autoidle_mask = 0x3 << val;
+       clk_hw->enable_bit = ti_clk_get_legacy_bit_shift(node);
+       ad->enable_mask = 0x3 << clk_hw->enable_bit;
+       ad->autoidle_mask = 0x3 << clk_hw->enable_bit;
 
        if (of_property_read_u32(node, "ti,idlest-shift", &val)) {
                pr_err("%pOFn missing idlest-shift\n", node);
index 1862958ab412ccd06695dc64c94891b837f819f9..f2117fef7c7d66e9ff7cfecbd63e814c99550d3e 100644 (file)
@@ -7,6 +7,7 @@
  * Tero Kristo <t-kristo@ti.com>
  */
 
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
@@ -15,6 +16,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/list.h>
+#include <linux/minmax.h>
 #include <linux/regmap.h>
 #include <linux/string_helpers.h>
 #include <linux/memblock.h>
@@ -114,20 +116,26 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops)
 
 /*
  * Eventually we could standardize to using '_' for clk-*.c files to follow the
- * TRM naming and leave out the tmp name here.
+ * TRM naming.
  */
 static struct device_node *ti_find_clock_provider(struct device_node *from,
                                                  const char *name)
 {
+       char *tmp __free(kfree) = NULL;
        struct device_node *np;
        bool found = false;
        const char *n;
-       char *tmp;
+       char *p;
 
        tmp = kstrdup_and_replace(name, '-', '_', GFP_KERNEL);
        if (!tmp)
                return NULL;
 
+       /* Ignore a possible address for the node name */
+       p = strchr(tmp, '@');
+       if (p)
+               *p = '\0';
+
        /* Node named "clock" with "clock-output-names" */
        for_each_of_allnodes_from(from, np) {
                if (of_property_read_string_index(np, "clock-output-names",
@@ -140,7 +148,6 @@ static struct device_node *ti_find_clock_provider(struct device_node *from,
                        break;
                }
        }
-       kfree(tmp);
 
        if (found) {
                of_node_put(from);
@@ -148,7 +155,7 @@ static struct device_node *ti_find_clock_provider(struct device_node *from,
        }
 
        /* Fall back to using old node name base provider name */
-       return of_find_node_by_name(from, name);
+       return of_find_node_by_name(from, tmp);
 }
 
 /**
@@ -301,8 +308,9 @@ int __init ti_clk_retry_init(struct device_node *node, void *user,
 int ti_clk_get_reg_addr(struct device_node *node, int index,
                        struct clk_omap_reg *reg)
 {
-       u32 val;
-       int i;
+       u32 clksel_addr, val;
+       bool is_clksel = false;
+       int i, err;
 
        for (i = 0; i < CLK_MAX_MEMMAPS; i++) {
                if (clocks_node_ptr[i] == node->parent)
@@ -318,21 +326,62 @@ int ti_clk_get_reg_addr(struct device_node *node, int index,
 
        reg->index = i;
 
-       if (of_property_read_u32_index(node, "reg", index, &val)) {
-               if (of_property_read_u32_index(node->parent, "reg",
-                                              index, &val)) {
-                       pr_err("%pOFn or parent must have reg[%d]!\n",
-                              node, index);
+       if (of_device_is_compatible(node->parent, "ti,clksel")) {
+               err = of_property_read_u32_index(node->parent, "reg", index, &clksel_addr);
+               if (err) {
+                       pr_err("%pOFn parent clksel must have reg[%d]!\n", node, index);
                        return -EINVAL;
                }
+               is_clksel = true;
        }
 
+       err = of_property_read_u32_index(node, "reg", index, &val);
+       if (err && is_clksel) {
+               /* Legacy clksel with no reg and a possible ti,bit-shift property */
+               reg->offset = clksel_addr;
+               reg->bit = ti_clk_get_legacy_bit_shift(node);
+               reg->ptr = NULL;
+
+               return 0;
+       }
+
+       /* Updated clksel clock with a proper reg property */
+       if (is_clksel) {
+               reg->offset = clksel_addr;
+               reg->bit = val;
+               reg->ptr = NULL;
+               return 0;
+       }
+
+       /* Other clocks that may or may not have ti,bit-shift property  */
        reg->offset = val;
+       reg->bit = ti_clk_get_legacy_bit_shift(node);
        reg->ptr = NULL;
 
        return 0;
 }
 
+/**
+ * ti_clk_get_legacy_bit_shift - get bit shift for a clock register
+ * @node: device node for the clock
+ *
+ * Gets the clock register bit shift using the legacy ti,bit-shift
+ * property. Only needed for legacy clock, and can be eventually
+ * dropped once all the composite clocks use a clksel node with a
+ * proper reg property.
+ */
+int ti_clk_get_legacy_bit_shift(struct device_node *node)
+{
+       int err;
+       u32 val;
+
+       err = of_property_read_u32(node, "ti,bit-shift", &val);
+       if (!err && in_range(val, 0, 32))
+               return val;
+
+       return 0;
+}
+
 void ti_clk_latch(struct clk_omap_reg *reg, s8 shift)
 {
        u32 latch;
index 16a9f7c2280a57016a55373d8d706c331974ece1..2de7acea1ea0503790754a5d4b9bcfe42da701d3 100644 (file)
@@ -216,6 +216,7 @@ int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
 
 int ti_clk_get_reg_addr(struct device_node *node, int index,
                        struct clk_omap_reg *reg);
+int ti_clk_get_legacy_bit_shift(struct device_node *node);
 void ti_dt_clocks_register(struct ti_dt_clk *oclks);
 int ti_clk_retry_init(struct device_node *node, void *user,
                      ti_of_clk_init_cb_t func);
index 5d5bb123ba9494c01e918e69e377784890c1edd5..ade99ab6cfa9b18e5bcfb616273b5c06637035c1 100644 (file)
@@ -477,10 +477,7 @@ static int __init ti_clk_divider_populate(struct device_node *node,
        if (ret)
                return ret;
 
-       if (!of_property_read_u32(node, "ti,bit-shift", &val))
-               div->shift = val;
-       else
-               div->shift = 0;
+       div->shift = div->reg.bit;
 
        if (!of_property_read_u32(node, "ti,latch-bit", &val))
                div->latch = val;
index 8e477d50d0fdbfabc67ec4bfbe162864a1559ad5..a9febd6356b826cf3b853f2426acc82d6a2562c7 100644 (file)
@@ -132,7 +132,6 @@ static void __init _of_ti_gate_clk_setup(struct device_node *node,
        struct clk_omap_reg reg;
        const char *name;
        u8 enable_bit = 0;
-       u32 val;
        u32 flags = 0;
        u8 clk_gate_flags = 0;
 
@@ -140,8 +139,7 @@ static void __init _of_ti_gate_clk_setup(struct device_node *node,
                if (ti_clk_get_reg_addr(node, 0, &reg))
                        return;
 
-               if (!of_property_read_u32(node, "ti,bit-shift", &val))
-                       enable_bit = val;
+               enable_bit = reg.bit;
        }
 
        if (of_clk_get_parent_count(node) != 1) {
@@ -170,7 +168,6 @@ _of_ti_composite_gate_clk_setup(struct device_node *node,
                                const struct clk_hw_omap_ops *hw_ops)
 {
        struct clk_hw_omap *gate;
-       u32 val = 0;
 
        gate = kzalloc(sizeof(*gate), GFP_KERNEL);
        if (!gate)
@@ -179,9 +176,7 @@ _of_ti_composite_gate_clk_setup(struct device_node *node,
        if (ti_clk_get_reg_addr(node, 0, &gate->enable_reg))
                goto cleanup;
 
-       of_property_read_u32(node, "ti,bit-shift", &val);
-
-       gate->enable_bit = val;
+       gate->enable_bit = gate->enable_reg.bit;
        gate->ops = hw_ops;
 
        if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE))
index 172301c646f85a62b400f7993caa86ff53cd0425..3eb35c87c0ed5e706ff0f7761f74c179758a847d 100644 (file)
@@ -66,13 +66,11 @@ static void __init _of_ti_interface_clk_setup(struct device_node *node,
        struct clk_omap_reg reg;
        u8 enable_bit = 0;
        const char *name;
-       u32 val;
 
        if (ti_clk_get_reg_addr(node, 0, &reg))
                return;
 
-       if (!of_property_read_u32(node, "ti,bit-shift", &val))
-               enable_bit = val;
+       enable_bit = reg.bit;
 
        parent_name = of_clk_get_parent_name(node, 0);
        if (!parent_name) {
index 1ebafa386be6150be385ad9172b682eacc9c109b..216d85d6aac6c5e2adf3bfa3d7beed3299afe66a 100644 (file)
@@ -189,7 +189,7 @@ static void of_mux_clk_setup(struct device_node *node)
        if (ti_clk_get_reg_addr(node, 0, &reg))
                goto cleanup;
 
-       of_property_read_u32(node, "ti,bit-shift", &shift);
+       shift = reg.bit;
 
        of_property_read_u32(node, "ti,latch-bit", &latch);
 
@@ -252,7 +252,6 @@ static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
 {
        struct clk_omap_mux *mux;
        unsigned int num_parents;
-       u32 val;
 
        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
        if (!mux)
@@ -261,8 +260,7 @@ static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
        if (ti_clk_get_reg_addr(node, 0, &mux->reg))
                goto cleanup;
 
-       if (!of_property_read_u32(node, "ti,bit-shift", &val))
-               mux->shift = val;
+       mux->shift = mux->reg.bit;
 
        if (of_property_read_bool(node, "ti,index-starts-at-one"))
                mux->flags |= CLK_MUX_INDEX_ONE;
index 44a61dc6f93208c897f1379cbb1371191d29d7b4..ab1c8c2b66b887a8149d1dbc1d6d41428e22c7e9 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/bitfield.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/cpu.h>
 #define GT_CONTROL_COMP_ENABLE         BIT(1)  /* banked */
 #define GT_CONTROL_IRQ_ENABLE          BIT(2)  /* banked */
 #define GT_CONTROL_AUTO_INC            BIT(3)  /* banked */
-#define GT_CONTROL_PRESCALER_SHIFT      8
-#define GT_CONTROL_PRESCALER_MAX        0xF
-#define GT_CONTROL_PRESCALER_MASK       (GT_CONTROL_PRESCALER_MAX << \
-                                        GT_CONTROL_PRESCALER_SHIFT)
+#define GT_CONTROL_PRESCALER_MASK      GENMASK(15, 8)
 
 #define GT_INT_STATUS  0x0c
 #define GT_INT_STATUS_EVENT_FLAG       BIT(0)
@@ -52,7 +50,8 @@
  */
 static void __iomem *gt_base;
 static struct notifier_block gt_clk_rate_change_nb;
-static u32 gt_psv_new, gt_psv_bck, gt_target_rate;
+static u32 gt_psv_new, gt_psv_bck;
+static unsigned long gt_target_rate;
 static int gt_ppi;
 static struct clock_event_device __percpu *gt_evt;
 
@@ -88,7 +87,7 @@ static u64 gt_counter_read(void)
        return _gt_counter_read();
 }
 
-/**
+/*
  * To ensure that updates to comparator value register do not set the
  * Interrupt Status Register proceed as follows:
  * 1. Clear the Comp Enable bit in the Timer Control Register.
@@ -247,7 +246,7 @@ static void gt_write_presc(u32 psv)
 
        reg = readl(gt_base + GT_CONTROL);
        reg &= ~GT_CONTROL_PRESCALER_MASK;
-       reg |= psv << GT_CONTROL_PRESCALER_SHIFT;
+       reg |= FIELD_PREP(GT_CONTROL_PRESCALER_MASK, psv);
        writel(reg, gt_base + GT_CONTROL);
 }
 
@@ -256,8 +255,7 @@ static u32 gt_read_presc(void)
        u32 reg;
 
        reg = readl(gt_base + GT_CONTROL);
-       reg &= GT_CONTROL_PRESCALER_MASK;
-       return reg >> GT_CONTROL_PRESCALER_SHIFT;
+       return FIELD_GET(GT_CONTROL_PRESCALER_MASK, reg);
 }
 
 static void __init gt_delay_timer_init(void)
@@ -272,9 +270,9 @@ static int __init gt_clocksource_init(void)
        writel(0, gt_base + GT_COUNTER0);
        writel(0, gt_base + GT_COUNTER1);
        /* set prescaler and enable timer on all the cores */
-       writel(((CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) <<
-               GT_CONTROL_PRESCALER_SHIFT)
-              GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+       writel(FIELD_PREP(GT_CONTROL_PRESCALER_MASK,
+                         CONFIG_ARM_GT_INITIAL_PRESCALER_VAL - 1) |
+              GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
 
 #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
        sched_clock_register(gt_sched_clock_read, 64, gt_target_rate);
@@ -290,18 +288,17 @@ static int gt_clk_rate_change_cb(struct notifier_block *nb,
        switch (event) {
        case PRE_RATE_CHANGE:
        {
-               int psv;
-
-               psv = DIV_ROUND_CLOSEST(ndata->new_rate,
-                                       gt_target_rate);
+               unsigned long psv;
 
-               if (abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR)
+               psv = DIV_ROUND_CLOSEST(ndata->new_rate, gt_target_rate);
+               if (!psv ||
+                   abs(gt_target_rate - (ndata->new_rate / psv)) > MAX_F_ERR)
                        return NOTIFY_BAD;
 
                psv--;
 
                /* prescaler within legal range? */
-               if (psv < 0 || psv > GT_CONTROL_PRESCALER_MAX)
+               if (!FIELD_FIT(GT_CONTROL_PRESCALER_MASK, psv))
                        return NOTIFY_BAD;
 
                /*
@@ -411,7 +408,7 @@ static int __init global_timer_of_register(struct device_node *np)
        err = gt_clocksource_init();
        if (err)
                goto out_irq;
-       
+
        err = cpuhp_setup_state(CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
                                "clockevents/arm/global_timer:starting",
                                gt_starting_cpu, gt_dying_cpu);
index 8ff7cd4e20bb1132af3bdc0c0ef79f038294f941..b2a080647e413226b83d11b0416310b2fa82f804 100644 (file)
@@ -81,14 +81,14 @@ static int hv_ce_set_next_event(unsigned long delta,
 
        current_tick = hv_read_reference_counter();
        current_tick += delta;
-       hv_set_register(HV_REGISTER_STIMER0_COUNT, current_tick);
+       hv_set_msr(HV_MSR_STIMER0_COUNT, current_tick);
        return 0;
 }
 
 static int hv_ce_shutdown(struct clock_event_device *evt)
 {
-       hv_set_register(HV_REGISTER_STIMER0_COUNT, 0);
-       hv_set_register(HV_REGISTER_STIMER0_CONFIG, 0);
+       hv_set_msr(HV_MSR_STIMER0_COUNT, 0);
+       hv_set_msr(HV_MSR_STIMER0_CONFIG, 0);
        if (direct_mode_enabled && stimer0_irq >= 0)
                disable_percpu_irq(stimer0_irq);
 
@@ -119,7 +119,7 @@ static int hv_ce_set_oneshot(struct clock_event_device *evt)
                timer_cfg.direct_mode = 0;
                timer_cfg.sintx = stimer0_message_sint;
        }
-       hv_set_register(HV_REGISTER_STIMER0_CONFIG, timer_cfg.as_uint64);
+       hv_set_msr(HV_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
        return 0;
 }
 
@@ -372,11 +372,11 @@ static __always_inline u64 read_hv_clock_msr(void)
         * is set to 0 when the partition is created and is incremented in 100
         * nanosecond units.
         *
-        * Use hv_raw_get_register() because this function is used from
-        * noinstr. Notable; while HV_REGISTER_TIME_REF_COUNT is a synthetic
+        * Use hv_raw_get_msr() because this function is used from
+        * noinstr. Notable; while HV_MSR_TIME_REF_COUNT is a synthetic
         * register it doesn't need the GHCB path.
         */
-       return hv_raw_get_register(HV_REGISTER_TIME_REF_COUNT);
+       return hv_raw_get_msr(HV_MSR_TIME_REF_COUNT);
 }
 
 /*
@@ -439,9 +439,9 @@ static void suspend_hv_clock_tsc(struct clocksource *arg)
        union hv_reference_tsc_msr tsc_msr;
 
        /* Disable the TSC page */
-       tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+       tsc_msr.as_uint64 = hv_get_msr(HV_MSR_REFERENCE_TSC);
        tsc_msr.enable = 0;
-       hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
+       hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 }
 
 
@@ -450,10 +450,10 @@ static void resume_hv_clock_tsc(struct clocksource *arg)
        union hv_reference_tsc_msr tsc_msr;
 
        /* Re-enable the TSC page */
-       tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+       tsc_msr.as_uint64 = hv_get_msr(HV_MSR_REFERENCE_TSC);
        tsc_msr.enable = 1;
        tsc_msr.pfn = tsc_pfn;
-       hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
+       hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 }
 
 #ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK
@@ -555,14 +555,14 @@ static void __init hv_init_tsc_clocksource(void)
         * thus TSC clocksource will work even without the real TSC page
         * mapped.
         */
-       tsc_msr.as_uint64 = hv_get_register(HV_REGISTER_REFERENCE_TSC);
+       tsc_msr.as_uint64 = hv_get_msr(HV_MSR_REFERENCE_TSC);
        if (hv_root_partition)
                tsc_pfn = tsc_msr.pfn;
        else
                tsc_pfn = HVPFN_DOWN(virt_to_phys(tsc_page));
        tsc_msr.enable = 1;
        tsc_msr.pfn = tsc_pfn;
-       hv_set_register(HV_REGISTER_REFERENCE_TSC, tsc_msr.as_uint64);
+       hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64);
 
        clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
 
index 9a55e733ae995dc6d734e9eb14dee295cd59b230..09fd292eb83df06d5ba32ec7e1c1671e42be5217 100644 (file)
@@ -131,7 +131,7 @@ static int clint_timer_starting_cpu(unsigned int cpu)
        struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu);
 
        ce->cpumask = cpumask_of(cpu);
-       clockevents_config_and_register(ce, clint_timer_freq, 100, 0x7fffffff);
+       clockevents_config_and_register(ce, clint_timer_freq, 100, ULONG_MAX);
 
        enable_percpu_irq(clint_timer_irq,
                          irq_get_trigger_type(clint_timer_irq));
index 6a878d227a13b59a7eca83468402cc0117a5eef6..489e69169ed4e3d31cae8e6931afa015b224b84d 100644 (file)
@@ -258,9 +258,8 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *ced = dev_id;
        struct imx_timer *imxtm = to_imx_timer(ced);
-       uint32_t tstat;
 
-       tstat = readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat);
+       readl_relaxed(imxtm->base + imxtm->gpt->reg_tstat);
 
        imxtm->gpt->gpt_irq_acknowledge(imxtm);
 
index 5a7a951c4efcdf187e73e2190b27dcea943f97bc..44525813be1e285713eb32166de21e78f2bf2e50 100644 (file)
@@ -4,48 +4,62 @@
 
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
+#include <linux/slab.h>
 
 #include "timer-of.h"
 
 #define CMP_OFFSET     0x10000
+#define RD_OFFSET      0x20000
 
 #define CNTCV_LO       0x8
 #define CNTCV_HI       0xc
 #define CMPCV_LO       (CMP_OFFSET + 0x20)
 #define CMPCV_HI       (CMP_OFFSET + 0x24)
 #define CMPCR          (CMP_OFFSET + 0x2c)
+#define CNTCV_LO_IMX95 (RD_OFFSET + 0x8)
+#define CNTCV_HI_IMX95 (RD_OFFSET + 0xc)
 
 #define SYS_CTR_EN             0x1
 #define SYS_CTR_IRQ_MASK       0x2
 
 #define SYS_CTR_CLK_DIV                0x3
 
-static void __iomem *sys_ctr_base __ro_after_init;
-static u32 cmpcr __ro_after_init;
+struct sysctr_private {
+       u32 cmpcr;
+       u32 lo_off;
+       u32 hi_off;
+};
 
-static void sysctr_timer_enable(bool enable)
+static void sysctr_timer_enable(struct clock_event_device *evt, bool enable)
 {
-       writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR);
+       struct timer_of *to = to_timer_of(evt);
+       struct sysctr_private *priv = to->private_data;
+       void __iomem *base = timer_of_base(to);
+
+       writel(enable ? priv->cmpcr | SYS_CTR_EN : priv->cmpcr, base + CMPCR);
 }
 
-static void sysctr_irq_acknowledge(void)
+static void sysctr_irq_acknowledge(struct clock_event_device *evt)
 {
        /*
         * clear the enable bit(EN =0) will clear
         * the status bit(ISTAT = 0), then the interrupt
         * signal will be negated(acknowledged).
         */
-       sysctr_timer_enable(false);
+       sysctr_timer_enable(evt, false);
 }
 
-static inline u64 sysctr_read_counter(void)
+static inline u64 sysctr_read_counter(struct clock_event_device *evt)
 {
+       struct timer_of *to = to_timer_of(evt);
+       struct sysctr_private *priv = to->private_data;
+       void __iomem *base = timer_of_base(to);
        u32 cnt_hi, tmp_hi, cnt_lo;
 
        do {
-               cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
-               cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO);
-               tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
+               cnt_hi = readl_relaxed(base + priv->hi_off);
+               cnt_lo = readl_relaxed(base + priv->lo_off);
+               tmp_hi = readl_relaxed(base + priv->hi_off);
        } while (tmp_hi != cnt_hi);
 
        return  ((u64) cnt_hi << 32) | cnt_lo;
@@ -54,22 +68,24 @@ static inline u64 sysctr_read_counter(void)
 static int sysctr_set_next_event(unsigned long delta,
                                 struct clock_event_device *evt)
 {
+       struct timer_of *to = to_timer_of(evt);
+       void __iomem *base = timer_of_base(to);
        u32 cmp_hi, cmp_lo;
        u64 next;
 
-       sysctr_timer_enable(false);
+       sysctr_timer_enable(evt, false);
 
-       next = sysctr_read_counter();
+       next = sysctr_read_counter(evt);
 
        next += delta;
 
        cmp_hi = (next >> 32) & 0x00fffff;
        cmp_lo = next & 0xffffffff;
 
-       writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI);
-       writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO);
+       writel_relaxed(cmp_hi, base + CMPCV_HI);
+       writel_relaxed(cmp_lo, base + CMPCV_LO);
 
-       sysctr_timer_enable(true);
+       sysctr_timer_enable(evt, true);
 
        return 0;
 }
@@ -81,7 +97,7 @@ static int sysctr_set_state_oneshot(struct clock_event_device *evt)
 
 static int sysctr_set_state_shutdown(struct clock_event_device *evt)
 {
-       sysctr_timer_enable(false);
+       sysctr_timer_enable(evt, false);
 
        return 0;
 }
@@ -90,7 +106,7 @@ static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
 {
        struct clock_event_device *evt = dev_id;
 
-       sysctr_irq_acknowledge();
+       sysctr_irq_acknowledge(evt);
 
        evt->event_handler(evt);
 
@@ -117,34 +133,75 @@ static struct timer_of to_sysctr = {
        },
 };
 
-static void __init sysctr_clockevent_init(void)
+static int __init __sysctr_timer_init(struct device_node *np)
 {
+       struct sysctr_private *priv;
+       void __iomem *base;
+       int ret;
+
+       priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ret = timer_of_init(np, &to_sysctr);
+       if (ret) {
+               kfree(priv);
+               return ret;
+       }
+
+       if (!of_property_read_bool(np, "nxp,no-divider")) {
+               /* system counter clock is divided by 3 internally */
+               to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV;
+       }
+
        to_sysctr.clkevt.cpumask = cpu_possible_mask;
+       to_sysctr.private_data = priv;
+
+       base = timer_of_base(&to_sysctr);
+       priv->cmpcr = readl(base + CMPCR) & ~SYS_CTR_EN;
+
+       return 0;
+}
+
+static int __init sysctr_timer_init(struct device_node *np)
+{
+       struct sysctr_private *priv;
+       int ret;
+
+       ret = __sysctr_timer_init(np);
+       if (ret)
+               return ret;
+
+       priv = to_sysctr.private_data;
+       priv->lo_off = CNTCV_LO;
+       priv->hi_off = CNTCV_HI;
 
        clockevents_config_and_register(&to_sysctr.clkevt,
                                        timer_of_rate(&to_sysctr),
                                        0xff, 0x7fffffff);
+
+       return 0;
 }
 
-static int __init sysctr_timer_init(struct device_node *np)
+static int __init sysctr_timer_imx95_init(struct device_node *np)
 {
-       int ret = 0;
+       struct sysctr_private *priv;
+       int ret;
 
-       ret = timer_of_init(np, &to_sysctr);
+       ret = __sysctr_timer_init(np);
        if (ret)
                return ret;
 
-       if (!of_property_read_bool(np, "nxp,no-divider")) {
-               /* system counter clock is divided by 3 internally */
-               to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV;
-       }
-
-       sys_ctr_base = timer_of_base(&to_sysctr);
-       cmpcr = readl(sys_ctr_base + CMPCR);
-       cmpcr &= ~SYS_CTR_EN;
+       priv = to_sysctr.private_data;
+       priv->lo_off = CNTCV_LO_IMX95;
+       priv->hi_off = CNTCV_HI_IMX95;
 
-       sysctr_clockevent_init();
+       clockevents_config_and_register(&to_sysctr.clkevt,
+                                       timer_of_rate(&to_sysctr),
+                                       0xff, 0x7fffffff);
 
        return 0;
 }
+
 TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);
+TIMER_OF_DECLARE(sysctr_timer_imx95, "nxp,imx95-sysctr-timer", sysctr_timer_imx95_init);
index e66dcbd6656658dd32f913189fceebda87e8ccbf..48ce50c5f5e68eeec9de696476d424dd5b2c00d0 100644 (file)
@@ -108,13 +108,16 @@ static int riscv_timer_starting_cpu(unsigned int cpu)
 {
        struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu);
 
+       /* Clear timer interrupt */
+       riscv_clock_event_stop();
+
        ce->cpumask = cpumask_of(cpu);
        ce->irq = riscv_clock_event_irq;
        if (riscv_timer_cannot_wake_cpu)
                ce->features |= CLOCK_EVT_FEAT_C3STOP;
        if (static_branch_likely(&riscv_sstc_available))
                ce->rating = 450;
-       clockevents_config_and_register(ce, riscv_timebase, 100, 0x7fffffff);
+       clockevents_config_and_register(ce, riscv_timebase, 100, ULONG_MAX);
 
        enable_percpu_irq(riscv_clock_event_irq,
                          irq_get_trigger_type(riscv_clock_event_irq));
index c9a753f96ba12d50930ab242bec5eb5bce79fcfc..0a4ea3288bfbea7040c07dfe91e69f44da8cc8dd 100644 (file)
@@ -73,7 +73,7 @@ static void stm32_timer_of_bits_set(struct timer_of *to, int bits)
  * Accessor helper to get the number of bits in the timer-of private
  * structure.
  *
- * Returns an integer corresponding to the number of bits.
+ * Returns: an integer corresponding to the number of bits.
  */
 static int stm32_timer_of_bits_get(struct timer_of *to)
 {
@@ -177,7 +177,7 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 }
 
 /**
- * stm32_timer_width - Sort out the timer width (32/16)
+ * stm32_timer_set_width - Sort out the timer width (32/16)
  * @to: a pointer to a timer-of structure
  *
  * Write the 32-bit max value and read/return the result. If the timer
index 59b0be482f32c668065ffd78c2e23ada53266748..a86529a707370d3ee5412191d432b71231677d60 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
  * timer-ti-32k.c - OMAP2 32k Timer Support
  *
  * Copyright (C) 2009 Nokia Corporation
index 5d5b9174f88a9de4f9c783eab9e4ddb1cd5fc444..49944ce1f813530f713b498073b8427b76d723e9 100644 (file)
@@ -177,7 +177,6 @@ static int das08_ai_insn_read(struct comedi_device *dev,
        int ret;
 
        chan = CR_CHAN(insn->chanspec);
-       range = CR_RANGE(insn->chanspec);
 
        /* clear crap */
        inb(dev->iobase + DAS08_AI_LSB_REG);
index 35efb53d5492a3c87cca82790345d202f10993dc..94e55c40970a6cf94e7356896ec427e93bd3000e 100644 (file)
@@ -302,4 +302,33 @@ config QORIQ_CPUFREQ
          which are capable of changing the CPU's frequency dynamically.
 
 endif
+
+config ACPI_CPPC_CPUFREQ
+       tristate "CPUFreq driver based on the ACPI CPPC spec"
+       depends on ACPI_PROCESSOR
+       depends on ARM || ARM64 || RISCV
+       select ACPI_CPPC_LIB
+       help
+         This adds a CPUFreq driver which uses CPPC methods
+         as described in the ACPIv5.1 spec. CPPC stands for
+         Collaborative Processor Performance Controls. It
+         is based on an abstract continuous scale of CPU
+         performance values which allows the remote power
+         processor to flexibly optimize for power and
+         performance. CPPC relies on power management firmware
+         support for its operation.
+
+         If in doubt, say N.
+
+config ACPI_CPPC_CPUFREQ_FIE
+       bool "Frequency Invariance support for CPPC cpufreq driver"
+       depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
+       depends on ARM || ARM64 || RISCV
+       default y
+       help
+         This extends frequency invariance support in the CPPC cpufreq driver,
+         by using CPPC delivered and reference performance counters.
+
+         If in doubt, say N.
+
 endmenu
index a0ebad77666e305ad0c47a7473832d1a60d082fb..96b404ce829f31738af74c48b97619737b3e0992 100644 (file)
@@ -3,32 +3,6 @@
 # ARM CPU Frequency scaling drivers
 #
 
-config ACPI_CPPC_CPUFREQ
-       tristate "CPUFreq driver based on the ACPI CPPC spec"
-       depends on ACPI_PROCESSOR
-       select ACPI_CPPC_LIB
-       help
-         This adds a CPUFreq driver which uses CPPC methods
-         as described in the ACPIv5.1 spec. CPPC stands for
-         Collaborative Processor Performance Controls. It
-         is based on an abstract continuous scale of CPU
-         performance values which allows the remote power
-         processor to flexibly optimize for power and
-         performance. CPPC relies on power management firmware
-         support for its operation.
-
-         If in doubt, say N.
-
-config ACPI_CPPC_CPUFREQ_FIE
-       bool "Frequency Invariance support for CPPC cpufreq driver"
-       depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
-       default y
-       help
-         This extends frequency invariance support in the CPPC cpufreq driver,
-         by using CPPC delivered and reference performance counters.
-
-         If in doubt, say N.
-
 config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
        tristate "Allwinner nvmem based SUN50I CPUFreq driver"
        depends on ARCH_SUNXI
index 8bd6e5e8f121ce89fdc80af0caa66fd6944ef593..2d83bbc65dd0bd69c8b035790ddc1217ddde9fb4 100644 (file)
@@ -208,7 +208,7 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
        if (!priv)
                return -ENOMEM;
 
-       if (!alloc_cpumask_var(&priv->cpus, GFP_KERNEL))
+       if (!zalloc_cpumask_var(&priv->cpus, GFP_KERNEL))
                return -ENOMEM;
 
        cpumask_set_cpu(cpu, priv->cpus);
index f6f8d7f450e7f5fbab2a7b11a67864c78f621f72..66e10a19d76abc3476282c69060c0cac4a815084 100644 (file)
@@ -653,14 +653,16 @@ static ssize_t store_local_boost(struct cpufreq_policy *policy,
        if (policy->boost_enabled == enable)
                return count;
 
+       policy->boost_enabled = enable;
+
        cpus_read_lock();
        ret = cpufreq_driver->set_boost(policy, enable);
        cpus_read_unlock();
 
-       if (ret)
+       if (ret) {
+               policy->boost_enabled = !policy->boost_enabled;
                return ret;
-
-       policy->boost_enabled = enable;
+       }
 
        return count;
 }
@@ -1428,6 +1430,9 @@ static int cpufreq_online(unsigned int cpu)
                        goto out_free_policy;
                }
 
+               /* Let the per-policy boost flag mirror the cpufreq_driver boost during init */
+               policy->boost_enabled = cpufreq_boost_enabled() && policy_has_boost_freq(policy);
+
                /*
                 * The initialization has succeeded and the policy is online.
                 * If there is a problem with its frequency table, take it
@@ -2769,11 +2774,12 @@ int cpufreq_boost_trigger_state(int state)
 
        cpus_read_lock();
        for_each_active_policy(policy) {
+               policy->boost_enabled = state;
                ret = cpufreq_driver->set_boost(policy, state);
-               if (ret)
+               if (ret) {
+                       policy->boost_enabled = !policy->boost_enabled;
                        goto err_reset_state;
-
-               policy->boost_enabled = state;
+               }
        }
        cpus_read_unlock();
 
index c4d4643b6ca6507ca85b134ecadcd0f1e0d82a5b..c17dc51a5a022d4b85558f69f3c21ec27ec2ba00 100644 (file)
@@ -40,7 +40,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
        cpufreq_for_each_valid_entry(pos, table) {
                freq = pos->frequency;
 
-               if (!cpufreq_boost_enabled()
+               if ((!cpufreq_boost_enabled() || !policy->boost_enabled)
                    && (pos->flags & CPUFREQ_BOOST_FREQ))
                        continue;
 
index 0b483bd0d3ca6c5ca1668c6d87d431888ca26df1..3b4f6bfb2f4cf3ee2184948d2b991e3d5f196153 100644 (file)
@@ -30,6 +30,7 @@ struct scmi_data {
 
 static struct scmi_protocol_handle *ph;
 static const struct scmi_perf_proto_ops *perf_ops;
+static struct cpufreq_driver scmi_cpufreq_driver;
 
 static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
 {
@@ -167,6 +168,12 @@ scmi_get_rate_limit(u32 domain, bool has_fast_switch)
        return rate_limit;
 }
 
+static struct freq_attr *scmi_cpufreq_hw_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+       NULL,
+};
+
 static int scmi_cpufreq_init(struct cpufreq_policy *policy)
 {
        int ret, nr_opp, domain;
@@ -276,6 +283,17 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
        policy->transition_delay_us =
                scmi_get_rate_limit(domain, policy->fast_switch_possible);
 
+       if (policy_has_boost_freq(policy)) {
+               ret = cpufreq_enable_boost_support();
+               if (ret) {
+                       dev_warn(cpu_dev, "failed to enable boost: %d\n", ret);
+                       goto out_free_opp;
+               } else {
+                       scmi_cpufreq_hw_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs;
+                       scmi_cpufreq_driver.boost_enabled = true;
+               }
+       }
+
        return 0;
 
 out_free_opp:
@@ -334,7 +352,7 @@ static struct cpufreq_driver scmi_cpufreq_driver = {
                  CPUFREQ_NEED_INITIAL_FREQ_CHECK |
                  CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
-       .attr   = cpufreq_generic_attr,
+       .attr   = scmi_cpufreq_hw_attr,
        .target_index   = scmi_cpufreq_set_target,
        .fast_switch    = scmi_cpufreq_fast_switch,
        .get    = scmi_cpufreq_get_rate,
index e8094fc92491ebd2754c7cf89223ee5f658529d4..a6e123dfe394d8a6b50063cee9bdf4fdf8ad1b48 100644 (file)
@@ -73,26 +73,6 @@ static inline bool sbi_is_domain_state_available(void)
        return data->available;
 }
 
-static int sbi_suspend_finisher(unsigned long suspend_type,
-                               unsigned long resume_addr,
-                               unsigned long opaque)
-{
-       struct sbiret ret;
-
-       ret = sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_SUSPEND,
-                       suspend_type, resume_addr, opaque, 0, 0, 0);
-
-       return (ret.error) ? sbi_err_map_linux_errno(ret.error) : 0;
-}
-
-static int sbi_suspend(u32 state)
-{
-       if (state & SBI_HSM_SUSP_NON_RET_BIT)
-               return cpu_suspend(state, sbi_suspend_finisher);
-       else
-               return sbi_suspend_finisher(state, 0, 0);
-}
-
 static __cpuidle int sbi_cpuidle_enter_state(struct cpuidle_device *dev,
                                             struct cpuidle_driver *drv, int idx)
 {
@@ -100,9 +80,9 @@ static __cpuidle int sbi_cpuidle_enter_state(struct cpuidle_device *dev,
        u32 state = states[idx];
 
        if (state & SBI_HSM_SUSP_NON_RET_BIT)
-               return CPU_PM_CPU_IDLE_ENTER_PARAM(sbi_suspend, idx, state);
+               return CPU_PM_CPU_IDLE_ENTER_PARAM(riscv_sbi_hart_suspend, idx, state);
        else
-               return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(sbi_suspend,
+               return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(riscv_sbi_hart_suspend,
                                                             idx, state);
 }
 
@@ -133,7 +113,7 @@ static __cpuidle int __sbi_enter_domain_idle_state(struct cpuidle_device *dev,
        else
                state = states[idx];
 
-       ret = sbi_suspend(state) ? -1 : idx;
+       ret = riscv_sbi_hart_suspend(state) ? -1 : idx;
 
        ct_cpuidle_exit();
 
@@ -206,17 +186,6 @@ static const struct of_device_id sbi_cpuidle_state_match[] = {
        { },
 };
 
-static bool sbi_suspend_state_is_valid(u32 state)
-{
-       if (state > SBI_HSM_SUSPEND_RET_DEFAULT &&
-           state < SBI_HSM_SUSPEND_RET_PLATFORM)
-               return false;
-       if (state > SBI_HSM_SUSPEND_NON_RET_DEFAULT &&
-           state < SBI_HSM_SUSPEND_NON_RET_PLATFORM)
-               return false;
-       return true;
-}
-
 static int sbi_dt_parse_state_node(struct device_node *np, u32 *state)
 {
        int err = of_property_read_u32(np, "riscv,sbi-suspend-param", state);
@@ -226,7 +195,7 @@ static int sbi_dt_parse_state_node(struct device_node *np, u32 *state)
                return err;
        }
 
-       if (!sbi_suspend_state_is_valid(*state)) {
+       if (!riscv_sbi_suspend_state_is_valid(*state)) {
                pr_warn("Invalid SBI suspend state %#x\n", *state);
                return -EINVAL;
        }
@@ -607,16 +576,8 @@ static int __init sbi_cpuidle_init(void)
        int ret;
        struct platform_device *pdev;
 
-       /*
-        * The SBI HSM suspend function is only available when:
-        * 1) SBI version is 0.3 or higher
-        * 2) SBI HSM extension is available
-        */
-       if ((sbi_spec_version < sbi_mk_version(0, 3)) ||
-           !sbi_probe_extension(SBI_EXT_HSM)) {
-               pr_info("HSM suspend not available\n");
+       if (!riscv_sbi_hsm_is_supported())
                return 0;
-       }
 
        ret = platform_driver_register(&sbi_cpuidle_driver);
        if (ret)
index bdf117a33744be2db0468e869226ac8d45ef7a16..e5f13260fc524d848f602ca43818929615d97c1d 100644 (file)
@@ -646,18 +646,18 @@ u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *memdev, u64 dpa);
 
 TRACE_EVENT(cxl_poison,
 
-       TP_PROTO(struct cxl_memdev *cxlmd, struct cxl_region *region,
+       TP_PROTO(struct cxl_memdev *cxlmd, struct cxl_region *cxlr,
                 const struct cxl_poison_record *record, u8 flags,
                 __le64 overflow_ts, enum cxl_poison_trace_type trace_type),
 
-       TP_ARGS(cxlmd, region, record, flags, overflow_ts, trace_type),
+       TP_ARGS(cxlmd, cxlr, record, flags, overflow_ts, trace_type),
 
        TP_STRUCT__entry(
                __string(memdev, dev_name(&cxlmd->dev))
                __string(host, dev_name(cxlmd->dev.parent))
                __field(u64, serial)
                __field(u8, trace_type)
-               __string(region, region)
+               __string(region, cxlr ? dev_name(&cxlr->dev) : "")
                __field(u64, overflow_ts)
                __field(u64, hpa)
                __field(u64, dpa)
@@ -677,10 +677,10 @@ TRACE_EVENT(cxl_poison,
                __entry->source = cxl_poison_record_source(record);
                __entry->trace_type = trace_type;
                __entry->flags = flags;
-               if (region) {
-                       __assign_str(region, dev_name(&region->dev));
-                       memcpy(__entry->uuid, &region->params.uuid, 16);
-                       __entry->hpa = cxl_trace_hpa(region, cxlmd,
+               if (cxlr) {
+                       __assign_str(region, dev_name(&cxlr->dev));
+                       memcpy(__entry->uuid, &cxlr->params.uuid, 16);
+                       __entry->hpa = cxl_trace_hpa(cxlr, cxlmd,
                                                     __entry->dpa);
                } else {
                        __assign_str(region, "");
index 69c46935ffc78cef0c01bc2cffb352ef00d30207..2d9fa6011945d88bae6ba24f74ef8a2ff1b2ea84 100644 (file)
@@ -123,7 +123,7 @@ static int dio_bus_match(struct device *dev, struct device_driver *drv)
 }
 
 
-struct bus_type dio_bus_type = {
+const struct bus_type dio_bus_type = {
        .name   = "dio",
        .match  = dio_bus_match,
        .probe  = dio_device_probe,
index c0976f6268d3292206e7dcba40fd487837e633ba..e6cdb905eeaca70aec09132606d66996d5b87579 100644 (file)
@@ -322,7 +322,8 @@ static ssize_t show_immediate(struct device *dev,
        if (value < 0)
                return -ENOENT;
 
-       return sysfs_emit(buf, "0x%06x\n", value);
+       // Note that this function is also called by init_fw_attribute_group() with NULL pointer.
+       return buf ? sysfs_emit(buf, "0x%06x\n", value) : 0;
 }
 
 #define IMMEDIATE_ATTR(name, key)                              \
@@ -334,6 +335,8 @@ static ssize_t show_text_leaf(struct device *dev,
        struct config_rom_attribute *attr =
                container_of(dattr, struct config_rom_attribute, attr);
        const u32 *directories[] = {NULL, NULL};
+       size_t bufsize;
+       char dummy_buf[2];
        int i, ret = -ENOENT;
 
        down_read(&fw_device_rwsem);
@@ -355,9 +358,16 @@ static ssize_t show_text_leaf(struct device *dev,
                }
        }
 
+       // Note that this function is also called by init_fw_attribute_group() with NULL pointer.
+       if (buf) {
+               bufsize = PAGE_SIZE - 1;
+       } else {
+               buf = dummy_buf;
+               bufsize = 1;
+       }
+
        for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) {
-               int result = fw_csr_string(directories[i], attr->key, buf,
-                                          PAGE_SIZE - 1);
+               int result = fw_csr_string(directories[i], attr->key, buf, bufsize);
                // Detected.
                if (result >= 0) {
                        ret = result;
@@ -366,7 +376,7 @@ static ssize_t show_text_leaf(struct device *dev,
                        // in the root directory follows to the directory entry for vendor ID
                        // instead of the immediate value for vendor ID.
                        result = fw_csr_string(directories[i], CSR_DIRECTORY | attr->key, buf,
-                                              PAGE_SIZE - 1);
+                                              bufsize);
                        if (result >= 0)
                                ret = result;
                }
index 8e832d1ad8251eed9e4007a566eb6a70d8af548d..345fff167b52f5e1b87ced8cd854e96702e0734d 100644 (file)
@@ -871,6 +871,9 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
                else
                        freq = dom->opp[idx].indicative_freq * dom->mult_factor;
 
+               /* All OPPs above the sustained frequency are treated as turbo */
+               data.turbo = freq > dom->sustained_freq_khz * 1000;
+
                data.level = dom->opp[idx].perf;
                data.freq = freq;
 
index f80a9af3d16e94de51e4f124ec4ff40a43eaa31a..d18a1a5de14495aa639ae5888beb1986421da663 100644 (file)
@@ -252,7 +252,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
        if (si->lfb_depth != 32)
                return -ENODEV;
 
-       font = get_default_font(xres, yres, -1, -1);
+       font = get_default_font(xres, yres, NULL, NULL);
        if (!font)
                return -ENODEV;
 
index 456d0e5eaf78b595a66c622103b719e0fd2d3a69..cc807ed35aedf7737a3585b3b5153408364d2765 100644 (file)
@@ -336,7 +336,7 @@ static int efifb_add_links(struct fwnode_handle *fwnode)
        if (!sup_np)
                return 0;
 
-       fwnode_link_add(fwnode, of_fwnode_handle(sup_np));
+       fwnode_link_add(fwnode, of_fwnode_handle(sup_np), 0);
        of_node_put(sup_np);
 
        return 0;
index 79789f0563f6a3df89f396e12299bd1a2a3452ce..9bc45357e1a803aed2a60b7c5b98b429aed2a79e 100644 (file)
@@ -3,6 +3,7 @@
  * Xilinx Zynq MPSoC Firmware layer
  *
  *  Copyright (C) 2014-2022 Xilinx, Inc.
+ *  Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
  *
  *  Michal Simek <michal.simek@amd.com>
  *  Davorin Mista <davorin.mista@aggios.com>
@@ -1384,6 +1385,30 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out)
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_aes_engine);
 
+/**
+ * zynqmp_pm_efuse_access - Provides access to efuse memory.
+ * @address:   Address of the efuse params structure
+ * @out:               Returned output value
+ *
+ * Return:     Returns status, either success or error code.
+ */
+int zynqmp_pm_efuse_access(const u64 address, u32 *out)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       if (!out)
+               return -EINVAL;
+
+       ret = zynqmp_pm_invoke_fn(PM_EFUSE_ACCESS, ret_payload, 2,
+                                 upper_32_bits(address),
+                                 lower_32_bits(address));
+       *out = ret_payload[1];
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_efuse_access);
+
 /**
  * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash
  * @address:   Address of the data/ Address of output buffer where
index e6d12fbab653fb9a5fb622497e284ddd553223b3..094ee97ea26cb18db87490c8205f4cb095426f57 100644 (file)
@@ -327,7 +327,7 @@ static struct attribute *dfl_dev_attrs[] = {
 };
 ATTRIBUTE_GROUPS(dfl_dev);
 
-static struct bus_type dfl_bus_type = {
+static const struct bus_type dfl_bus_type = {
        .name           = "dfl",
        .match          = dfl_bus_match,
        .probe          = dfl_bus_probe,
index a024be2b84e2913d0be7b3621c21080dd5583793..79c473b3c7c3d5aa4ff1a824dbc7737a49528305 100644 (file)
@@ -30,7 +30,7 @@ int fpga_bridge_enable(struct fpga_bridge *bridge)
 {
        dev_dbg(&bridge->dev, "enable\n");
 
-       if (bridge->br_ops && bridge->br_ops->enable_set)
+       if (bridge->br_ops->enable_set)
                return bridge->br_ops->enable_set(bridge, 1);
 
        return 0;
@@ -48,7 +48,7 @@ int fpga_bridge_disable(struct fpga_bridge *bridge)
 {
        dev_dbg(&bridge->dev, "disable\n");
 
-       if (bridge->br_ops && bridge->br_ops->enable_set)
+       if (bridge->br_ops->enable_set)
                return bridge->br_ops->enable_set(bridge, 0);
 
        return 0;
@@ -296,7 +296,7 @@ static ssize_t state_show(struct device *dev,
        struct fpga_bridge *bridge = to_fpga_bridge(dev);
        int state = 1;
 
-       if (bridge->br_ops && bridge->br_ops->enable_show) {
+       if (bridge->br_ops->enable_show) {
                state = bridge->br_ops->enable_show(bridge);
                if (state < 0)
                        return state;
@@ -401,7 +401,7 @@ void fpga_bridge_unregister(struct fpga_bridge *bridge)
         * If the low level driver provides a method for putting bridge into
         * a desired state upon unregister, do it.
         */
-       if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove)
+       if (bridge->br_ops->fpga_bridge_remove)
                bridge->br_ops->fpga_bridge_remove(bridge);
 
        device_unregister(&bridge->dev);
index baa956494e79f0aa3651d5c0ab2e550f2337aff3..0e43bf6294f878aa83ab64d8c0b6b4ce3d09b93b 100644 (file)
@@ -80,7 +80,7 @@ static const struct gnss_operations gnss_serial_gnss_ops = {
        .write_raw      = gnss_serial_write_raw,
 };
 
-static ssize_t gnss_serial_receive_buf(struct serdev_device *serdev,
+static size_t gnss_serial_receive_buf(struct serdev_device *serdev,
                                       const u8 *buf, size_t count)
 {
        struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
index 6801a8fb20401a484aba805be4fe1c0f0ca8e940..79375d14bbb6732e3676c4e8dc8e20c41bbf2c15 100644 (file)
@@ -160,7 +160,7 @@ static const struct gnss_operations sirf_gnss_ops = {
        .write_raw      = sirf_write_raw,
 };
 
-static ssize_t sirf_receive_buf(struct serdev_device *serdev,
+static size_t sirf_receive_buf(struct serdev_device *serdev,
                                const u8 *buf, size_t count)
 {
        struct sirf_data *data = serdev_device_get_drvdata(serdev);
index 182ed8f67850033a41ae1bad8c1b5ea0620ebb9d..5a0c476361c300273d0c6cf27306b14c59679cbe 100644 (file)
@@ -68,6 +68,7 @@ config DRM_USE_DYNAMIC_DEBUG
 config DRM_KUNIT_TEST_HELPERS
        tristate
        depends on DRM && KUNIT
+       select DRM_KMS_HELPER
        help
          KUnit Helpers for KMS drivers.
 
@@ -80,7 +81,6 @@ config DRM_KUNIT_TEST
        select DRM_EXEC
        select DRM_EXPORT_FOR_TESTS if m
        select DRM_GEM_SHMEM_HELPER
-       select DRM_KMS_HELPER
        select DRM_KUNIT_TEST_HELPERS
        select DRM_LIB_RANDOM
        select PRIME_NUMBERS
index f5f2945711be0c215d6a812d217c402616fc1cef..35dd6effa9a34a1be9ce83f83ab7915a38f6b4e8 100644 (file)
@@ -146,7 +146,7 @@ int amdgpu_amdkfd_drm_client_create(struct amdgpu_device *adev)
 {
        int ret;
 
-       if (!adev->kfd.init_complete)
+       if (!adev->kfd.init_complete || adev->kfd.client.dev)
                return 0;
 
        ret = drm_client_init(&adev->ddev, &adev->kfd.client, "kfd",
index 14dc9d2d8d53ad0e4085fb137b42d9b2967f3b33..df58a6a1a67ec51f1bb81ff1bd8364be8a46cc13 100644 (file)
@@ -2869,14 +2869,16 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
 
        mutex_lock(&process_info->lock);
 
-       drm_exec_init(&exec, 0, 0);
+       drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0);
        drm_exec_until_all_locked(&exec) {
                list_for_each_entry(peer_vm, &process_info->vm_list_head,
                                    vm_list_node) {
                        ret = amdgpu_vm_lock_pd(peer_vm, &exec, 2);
                        drm_exec_retry_on_contention(&exec);
-                       if (unlikely(ret))
+                       if (unlikely(ret)) {
+                               pr_err("Locking VM PD failed, ret: %d\n", ret);
                                goto ttm_reserve_fail;
+                       }
                }
 
                /* Reserve all BOs and page tables/directory. Add all BOs from
@@ -2889,8 +2891,10 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
                        gobj = &mem->bo->tbo.base;
                        ret = drm_exec_prepare_obj(&exec, gobj, 1);
                        drm_exec_retry_on_contention(&exec);
-                       if (unlikely(ret))
+                       if (unlikely(ret)) {
+                               pr_err("drm_exec_prepare_obj failed, ret: %d\n", ret);
                                goto ttm_reserve_fail;
+                       }
                }
        }
 
@@ -2950,8 +2954,10 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu *
         * validations above would invalidate DMABuf imports again.
         */
        ret = process_validate_vms(process_info, &exec.ticket);
-       if (ret)
+       if (ret) {
+               pr_debug("Validating VMs failed, ret: %d\n", ret);
                goto validate_map_fail;
+       }
 
        /* Update mappings not managed by KFD */
        list_for_each_entry(peer_vm, &process_info->vm_list_head,
index 1e9454e6e4cb4edaccd731b415a049ea83cff45f..5dc24c971b41f0a93c7463fbbf397d33e08c5563 100644 (file)
@@ -4040,10 +4040,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
         * early on during init and before calling to RREG32.
         */
        adev->reset_domain = amdgpu_reset_create_reset_domain(SINGLE_DEVICE, "amdgpu-reset-dev");
-       if (!adev->reset_domain) {
-               r = -ENOMEM;
-               goto unmap_memory;
-       }
+       if (!adev->reset_domain)
+               return -ENOMEM;
 
        /* detect hw virtualization here */
        amdgpu_detect_virtualization(adev);
@@ -4053,7 +4051,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        r = amdgpu_device_get_job_timeout_settings(adev);
        if (r) {
                dev_err(adev->dev, "invalid lockup_timeout parameter syntax\n");
-               goto unmap_memory;
+               return r;
        }
 
        amdgpu_device_set_mcbp(adev);
@@ -4061,12 +4059,12 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        /* early init functions */
        r = amdgpu_device_ip_early_init(adev);
        if (r)
-               goto unmap_memory;
+               return r;
 
        /* Get rid of things like offb */
        r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver);
        if (r)
-               goto unmap_memory;
+               return r;
 
        /* Enable TMZ based on IP_VERSION */
        amdgpu_gmc_tmz_set(adev);
@@ -4076,7 +4074,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        if (adev->gmc.xgmi.supported) {
                r = adev->gfxhub.funcs->get_xgmi_info(adev);
                if (r)
-                       goto unmap_memory;
+                       return r;
        }
 
        /* enable PCIE atomic ops */
@@ -4345,8 +4343,6 @@ release_ras_con:
 failed:
        amdgpu_vf_error_trans_all(adev);
 
-unmap_memory:
-       iounmap(adev->rmmio);
        return r;
 }
 
index 15b188aaf681805af714f0ee6d8d660e70ed81d3..80b9642f2bc4f25c69e9f30c70138f073e0c6cd2 100644 (file)
@@ -2479,8 +2479,11 @@ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work)
        }
        for (i = 0; i < mgpu_info.num_dgpu; i++) {
                adev = mgpu_info.gpu_ins[i].adev;
-               if (!adev->kfd.init_complete)
+               if (!adev->kfd.init_complete) {
+                       kgd2kfd_init_zone_device(adev);
                        amdgpu_amdkfd_device_init(adev);
+                       amdgpu_amdkfd_drm_client_create(adev);
+               }
                amdgpu_ttm_set_buffer_funcs_status(adev, true);
        }
 }
index f8b48fd93108cecc0ef75a358323c89274df2815..55d5508987ffe57979bbec08203ff85675a1031a 100644 (file)
@@ -687,7 +687,7 @@ int amdgpu_gfx_enable_kgq(struct amdgpu_device *adev, int xcc_id)
        r = amdgpu_ring_test_helper(kiq_ring);
        spin_unlock(&kiq->ring_lock);
        if (r)
-               DRM_ERROR("KCQ enable failed\n");
+               DRM_ERROR("KGQ enable failed\n");
 
        return r;
 }
index 55b65fc04b651ee36196b038e7dda5b82e6e2051..431ec72655ec80f42d6f7f01e7c3fe1191b18f26 100644 (file)
@@ -129,13 +129,25 @@ static const struct mmu_interval_notifier_ops amdgpu_hmm_hsa_ops = {
  */
 int amdgpu_hmm_register(struct amdgpu_bo *bo, unsigned long addr)
 {
+       int r;
+
        if (bo->kfd_bo)
-               return mmu_interval_notifier_insert(&bo->notifier, current->mm,
+               r = mmu_interval_notifier_insert(&bo->notifier, current->mm,
                                                    addr, amdgpu_bo_size(bo),
                                                    &amdgpu_hmm_hsa_ops);
-       return mmu_interval_notifier_insert(&bo->notifier, current->mm, addr,
-                                           amdgpu_bo_size(bo),
-                                           &amdgpu_hmm_gfx_ops);
+       else
+               r = mmu_interval_notifier_insert(&bo->notifier, current->mm, addr,
+                                                       amdgpu_bo_size(bo),
+                                                       &amdgpu_hmm_gfx_ops);
+       if (r)
+               /*
+                * Make sure amdgpu_hmm_unregister() doesn't call
+                * mmu_interval_notifier_remove() when the notifier isn't properly
+                * initialized.
+                */
+               bo->notifier.mm = NULL;
+
+       return r;
 }
 
 /**
index 3c2b1413058bb790c3aa3da792934200a967ec29..94b310fdb719d4c09717e0829b2c40adeae1b8d4 100644 (file)
@@ -1830,6 +1830,10 @@ static int psp_hdcp_initialize(struct psp_context *psp)
        if (amdgpu_sriov_vf(psp->adev))
                return 0;
 
+       /* bypass hdcp initialization if dmu is harvested */
+       if (!amdgpu_device_has_display_hardware(psp->adev))
+               return 0;
+
        if (!psp->hdcp_context.context.bin_desc.size_bytes ||
            !psp->hdcp_context.context.bin_desc.start_addr) {
                dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n");
@@ -1862,6 +1866,9 @@ int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
        if (amdgpu_sriov_vf(psp->adev))
                return 0;
 
+       if (!psp->hdcp_context.context.initialized)
+               return 0;
+
        return psp_ta_invoke(psp, ta_cmd_id, &psp->hdcp_context.context);
 }
 
@@ -1897,6 +1904,10 @@ static int psp_dtm_initialize(struct psp_context *psp)
        if (amdgpu_sriov_vf(psp->adev))
                return 0;
 
+       /* bypass dtm initialization if dmu is harvested */
+       if (!amdgpu_device_has_display_hardware(psp->adev))
+               return 0;
+
        if (!psp->dtm_context.context.bin_desc.size_bytes ||
            !psp->dtm_context.context.bin_desc.start_addr) {
                dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n");
@@ -1929,6 +1940,9 @@ int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
        if (amdgpu_sriov_vf(psp->adev))
                return 0;
 
+       if (!psp->dtm_context.context.initialized)
+               return 0;
+
        return psp_ta_invoke(psp, ta_cmd_id, &psp->dtm_context.context);
 }
 
@@ -2063,6 +2077,10 @@ static int psp_securedisplay_initialize(struct psp_context *psp)
        if (amdgpu_sriov_vf(psp->adev))
                return 0;
 
+       /* bypass securedisplay initialization if dmu is harvested */
+       if (!amdgpu_device_has_display_hardware(psp->adev))
+               return 0;
+
        if (!psp->securedisplay_context.context.bin_desc.size_bytes ||
            !psp->securedisplay_context.context.bin_desc.start_addr) {
                dev_info(psp->adev->dev, "SECUREDISPLAY: securedisplay ta ucode is not available\n");
index 8722beba494e563fd45c3e2f3cfba05a7f9d38e8..fc418e670fdae27b699bdbefce8051ab128ab76c 100644 (file)
@@ -864,6 +864,7 @@ static void amdgpu_ttm_gart_bind(struct amdgpu_device *adev,
                amdgpu_gart_bind(adev, gtt->offset, ttm->num_pages,
                                 gtt->ttm.dma_address, flags);
        }
+       gtt->bound = true;
 }
 
 /*
index b2535023764f494d7ae91a3d0fa15cc89080200b..9c514a606a2f4d7da4697c8fb14e604f239216fc 100644 (file)
@@ -60,6 +60,7 @@
 #define FIRMWARE_VCN4_0_4              "amdgpu/vcn_4_0_4.bin"
 #define FIRMWARE_VCN4_0_5              "amdgpu/vcn_4_0_5.bin"
 #define FIRMWARE_VCN4_0_6              "amdgpu/vcn_4_0_6.bin"
+#define FIRMWARE_VCN4_0_6_1            "amdgpu/vcn_4_0_6_1.bin"
 #define FIRMWARE_VCN5_0_0              "amdgpu/vcn_5_0_0.bin"
 
 MODULE_FIRMWARE(FIRMWARE_RAVEN);
@@ -85,6 +86,7 @@ MODULE_FIRMWARE(FIRMWARE_VCN4_0_3);
 MODULE_FIRMWARE(FIRMWARE_VCN4_0_4);
 MODULE_FIRMWARE(FIRMWARE_VCN4_0_5);
 MODULE_FIRMWARE(FIRMWARE_VCN4_0_6);
+MODULE_FIRMWARE(FIRMWARE_VCN4_0_6_1);
 MODULE_FIRMWARE(FIRMWARE_VCN5_0_0);
 
 static void amdgpu_vcn_idle_work_handler(struct work_struct *work);
@@ -93,14 +95,22 @@ int amdgpu_vcn_early_init(struct amdgpu_device *adev)
 {
        char ucode_prefix[30];
        char fw_name[40];
-       int r;
+       int r, i;
 
-       amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix));
-       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
-       r = amdgpu_ucode_request(adev, &adev->vcn.fw, fw_name);
-       if (r)
-               amdgpu_ucode_release(&adev->vcn.fw);
+       for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+               amdgpu_ucode_ip_version_decode(adev, UVD_HWIP, ucode_prefix, sizeof(ucode_prefix));
+               snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
+               if (amdgpu_ip_version(adev, UVD_HWIP, 0) ==  IP_VERSION(4, 0, 6) &&
+                       i == 1) {
+                       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_%d.bin", ucode_prefix, i);
+               }
 
+               r = amdgpu_ucode_request(adev, &adev->vcn.fw[i], fw_name);
+               if (r) {
+                       amdgpu_ucode_release(&adev->vcn.fw[i]);
+                       return r;
+               }
+       }
        return r;
 }
 
@@ -141,7 +151,7 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev)
                }
        }
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[0]->data;
        adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version);
 
        /* Bit 20-23, it is encode major and non-zero for new naming convention.
@@ -256,9 +266,10 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)
 
                for (i = 0; i < adev->vcn.num_enc_rings; ++i)
                        amdgpu_ring_fini(&adev->vcn.inst[j].ring_enc[i]);
+
+               amdgpu_ucode_release(&adev->vcn.fw[j]);
        }
 
-       amdgpu_ucode_release(&adev->vcn.fw);
        mutex_destroy(&adev->vcn.vcn1_jpeg1_workaround);
        mutex_destroy(&adev->vcn.vcn_pg_lock);
 
@@ -354,11 +365,12 @@ int amdgpu_vcn_resume(struct amdgpu_device *adev)
                        const struct common_firmware_header *hdr;
                        unsigned int offset;
 
-                       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+                       hdr = (const struct common_firmware_header *)adev->vcn.fw[i]->data;
                        if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) {
                                offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
                                if (drm_dev_enter(adev_to_drm(adev), &idx)) {
-                                       memcpy_toio(adev->vcn.inst[i].cpu_addr, adev->vcn.fw->data + offset,
+                                       memcpy_toio(adev->vcn.inst[i].cpu_addr,
+                                                   adev->vcn.fw[i]->data + offset,
                                                    le32_to_cpu(hdr->ucode_size_bytes));
                                        drm_dev_exit(idx);
                                }
@@ -1043,11 +1055,11 @@ void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev)
        if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
                const struct common_firmware_header *hdr;
 
-               hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
-
                for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
                        if (adev->vcn.harvest_config & (1 << i))
                                continue;
+
+                       hdr = (const struct common_firmware_header *)adev->vcn.fw[i]->data;
                        /* currently only support 2 FW instances */
                        if (i >= 2) {
                                dev_info(adev->dev, "More then 2 VCN FW instances!\n");
@@ -1055,7 +1067,7 @@ void amdgpu_vcn_setup_ucode(struct amdgpu_device *adev)
                        }
                        idx = AMDGPU_UCODE_ID_VCN + i;
                        adev->firmware.ucode[idx].ucode_id = idx;
-                       adev->firmware.ucode[idx].fw = adev->vcn.fw;
+                       adev->firmware.ucode[idx].fw = adev->vcn.fw[i];
                        adev->firmware.fw_size +=
                                ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE);
 
index 1985f71b4373b8bac2c40f19894587725c163b3c..a418393d89ec91acda8400622b7d8915bc89c968 100644 (file)
@@ -306,7 +306,7 @@ struct amdgpu_vcn_ras {
 struct amdgpu_vcn {
        unsigned                fw_version;
        struct delayed_work     idle_work;
-       const struct firmware   *fw;    /* VCN firmware */
+       const struct firmware   *fw[AMDGPU_MAX_VCN_INSTANCES];  /* VCN firmware */
        unsigned                num_enc_rings;
        enum amd_powergating_state cur_state;
        bool                    indirect_sram;
index 70c5cc80ecdc009f3f9e434d5847b0a8736c7ddc..7a65a2b128ec4372c5e6c219c70b9ab110b869fc 100644 (file)
@@ -575,9 +575,6 @@ static unsigned int vpe_ring_init_cond_exec(struct amdgpu_ring *ring,
 {
        unsigned int ret;
 
-       if (ring->adev->vpe.collaborate_mode)
-               return ~0;
-
        amdgpu_ring_write(ring, VPE_CMD_HEADER(VPE_CMD_OPCODE_COND_EXE, 0));
        amdgpu_ring_write(ring, lower_32_bits(addr));
        amdgpu_ring_write(ring, upper_32_bits(addr));
index 904b9ff5ead2f5d1823689e826b3dd01688851e9..f90905ef32c76d62c3d490445b71388e9e0dc6bb 100644 (file)
@@ -3657,6 +3657,9 @@ static void gfx_v10_0_init_spm_golden_registers(struct amdgpu_device *adev)
 
 static void gfx_v10_0_init_golden_registers(struct amdgpu_device *adev)
 {
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        switch (amdgpu_ip_version(adev, GC_HWIP, 0)) {
        case IP_VERSION(10, 1, 10):
                soc15_program_register_sequence(adev,
@@ -4982,7 +4985,8 @@ static void gfx_v10_0_constants_init(struct amdgpu_device *adev)
        u32 tmp;
        int i;
 
-       WREG32_FIELD15(GC, 0, GRBM_CNTL, READ_TIMEOUT, 0xff);
+       if (!amdgpu_sriov_vf(adev))
+               WREG32_FIELD15(GC, 0, GRBM_CNTL, READ_TIMEOUT, 0xff);
 
        gfx_v10_0_setup_rb(adev);
        gfx_v10_0_get_cu_info(adev, &adev->gfx.cu_info);
@@ -7163,7 +7167,7 @@ static int gfx_v10_0_hw_init(void *handle)
        if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 0))
                gfx_v10_3_program_pbb_mode(adev);
 
-       if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0))
+       if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0) && !amdgpu_sriov_vf(adev))
                gfx_v10_3_set_power_brake_sequence(adev);
 
        return r;
index cd0e8a321e460476d36e4c5b82922b7b2ab3cadb..17509f32f61a4f32b7fff17aeeba6369bdce5689 100644 (file)
@@ -155,6 +155,9 @@ static void gfxhub_v2_1_init_system_aperture_regs(struct amdgpu_device *adev)
 {
        uint64_t value;
 
+       if (amdgpu_sriov_vf(adev))
+               return;
+
        /* Program the AGP BAR */
        WREG32_SOC15(GC, 0, mmGCMC_VM_AGP_BASE, 0);
        WREG32_SOC15(GC, 0, mmGCMC_VM_AGP_BOT, adev->gmc.agp_start >> 24);
index 16fe428c0722d2577212bfdc4f95554214d68c52..7aed96fa10a9d20bb3e856982e48c7de828cf4ff 100644 (file)
@@ -418,6 +418,12 @@ static u32 ih_v7_0_get_wptr(struct amdgpu_device *adev,
        tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
+
+       /* Unset the CLEAR_OVERFLOW bit immediately so new overflows
+        * can be detected.
+        */
+       tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0);
+       WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
 out:
        return (wptr & ih->ptr_mask);
 }
index b3961968c10c4cf84ac76090431b2e9f712e586c..238ea40c245002a6b5af170f564793ee2077f3f7 100644 (file)
@@ -99,16 +99,15 @@ mmhub_v3_3_print_l2_protection_fault_status(struct amdgpu_device *adev,
        switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) {
        case IP_VERSION(3, 3, 0):
        case IP_VERSION(3, 3, 1):
-               mmhub_cid = mmhub_client_ids_v3_3[cid][rw];
+               mmhub_cid = cid < ARRAY_SIZE(mmhub_client_ids_v3_3) ?
+                           mmhub_client_ids_v3_3[cid][rw] :
+                           cid == 0x140 ? "UMSCH" : NULL;
                break;
        default:
                mmhub_cid = NULL;
                break;
        }
 
-       if (!mmhub_cid && cid == 0x140)
-               mmhub_cid = "UMSCH";
-
        dev_err(adev->dev, "\t Faulty UTCL2 client ID: %s (0x%x)\n",
                mmhub_cid ? mmhub_cid : "unknown", cid);
        dev_err(adev->dev, "\t MORE_FAULTS: 0x%lx\n",
index 2d904ee72701af9f90f518bfa732d821a0a3b5ad..34237a1b1f2e45c40989c2070bdc0ae071ee0c4b 100644 (file)
@@ -431,16 +431,11 @@ static void sdma_v4_4_2_inst_gfx_stop(struct amdgpu_device *adev,
        struct amdgpu_ring *sdma[AMDGPU_MAX_SDMA_INSTANCES];
        u32 doorbell_offset, doorbell;
        u32 rb_cntl, ib_cntl;
-       int i, unset = 0;
+       int i;
 
        for_each_inst(i, inst_mask) {
                sdma[i] = &adev->sdma.instance[i].ring;
 
-               if ((adev->mman.buffer_funcs_ring == sdma[i]) && unset != 1) {
-                       amdgpu_ttm_set_buffer_funcs_status(adev, false);
-                       unset = 1;
-               }
-
                rb_cntl = RREG32_SDMA(i, regSDMA_GFX_RB_CNTL);
                rb_cntl = REG_SET_FIELD(rb_cntl, SDMA_GFX_RB_CNTL, RB_ENABLE, 0);
                WREG32_SDMA(i, regSDMA_GFX_RB_CNTL, rb_cntl);
@@ -487,20 +482,10 @@ static void sdma_v4_4_2_inst_rlc_stop(struct amdgpu_device *adev,
 static void sdma_v4_4_2_inst_page_stop(struct amdgpu_device *adev,
                                       uint32_t inst_mask)
 {
-       struct amdgpu_ring *sdma[AMDGPU_MAX_SDMA_INSTANCES];
        u32 rb_cntl, ib_cntl;
        int i;
-       bool unset = false;
 
        for_each_inst(i, inst_mask) {
-               sdma[i] = &adev->sdma.instance[i].page;
-
-               if ((adev->mman.buffer_funcs_ring == sdma[i]) &&
-                       (!unset)) {
-                       amdgpu_ttm_set_buffer_funcs_status(adev, false);
-                       unset = true;
-               }
-
                rb_cntl = RREG32_SDMA(i, regSDMA_PAGE_RB_CNTL);
                rb_cntl = REG_SET_FIELD(rb_cntl, SDMA_PAGE_RB_CNTL,
                                        RB_ENABLE, 0);
@@ -950,13 +935,7 @@ static int sdma_v4_4_2_inst_start(struct amdgpu_device *adev,
                        r = amdgpu_ring_test_helper(page);
                        if (r)
                                return r;
-
-                       if (adev->mman.buffer_funcs_ring == page)
-                               amdgpu_ttm_set_buffer_funcs_status(adev, true);
                }
-
-               if (adev->mman.buffer_funcs_ring == ring)
-                       amdgpu_ttm_set_buffer_funcs_status(adev, true);
        }
 
        return r;
index 25ba27151ac0f29498665e86cd7ec0c3b04a31b3..aaceecd558cf9693bc16a528d3be4430be80d5b4 100644 (file)
@@ -304,7 +304,7 @@ static int vcn_v1_0_resume(void *handle)
  */
 static void vcn_v1_0_mc_resume_spg_mode(struct amdgpu_device *adev)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[0]->size + 4);
        uint32_t offset;
 
        /* cache window 0: fw */
@@ -371,7 +371,7 @@ static void vcn_v1_0_mc_resume_spg_mode(struct amdgpu_device *adev)
 
 static void vcn_v1_0_mc_resume_dpg_mode(struct amdgpu_device *adev)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[0]->size + 4);
        uint32_t offset;
 
        /* cache window 0: fw */
index 18794394c5a052b26ef009647616a8aba92efd9a..e357d8cf0c01540ca3f986b88e2a6e1892df6a34 100644 (file)
@@ -330,7 +330,7 @@ static int vcn_v2_0_resume(void *handle)
  */
 static void vcn_v2_0_mc_resume(struct amdgpu_device *adev)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[0]->size + 4);
        uint32_t offset;
 
        if (amdgpu_sriov_vf(adev))
@@ -386,7 +386,7 @@ static void vcn_v2_0_mc_resume(struct amdgpu_device *adev)
 
 static void vcn_v2_0_mc_resume_dpg_mode(struct amdgpu_device *adev, bool indirect)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[0]->size + 4);
        uint32_t offset;
 
        /* cache window 0: fw */
@@ -1878,7 +1878,7 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev)
 
                init_table += header->vcn_table_offset;
 
-               size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+               size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[0]->size + 4);
 
                MMSCH_V2_0_INSERT_DIRECT_RD_MOD_WT(
                        SOC15_REG_OFFSET(UVD, i, mmUVD_STATUS),
index aba403d718065776392dd4e159c1dac5878e232b..1cd8a94b0fbc2319f86f352b3fa6638ec7545d7c 100644 (file)
@@ -414,13 +414,15 @@ static int vcn_v2_5_resume(void *handle)
  */
 static void vcn_v2_5_mc_resume(struct amdgpu_device *adev)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size;
        uint32_t offset;
        int i;
 
        for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
                if (adev->vcn.harvest_config & (1 << i))
                        continue;
+
+               size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[i]->size + 4);
                /* cache window 0: fw */
                if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
                        WREG32_SOC15(VCN, i, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW,
@@ -469,7 +471,7 @@ static void vcn_v2_5_mc_resume(struct amdgpu_device *adev)
 
 static void vcn_v2_5_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_idx, bool indirect)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[inst_idx]->size + 4);
        uint32_t offset;
 
        /* cache window 0: fw */
@@ -1240,7 +1242,7 @@ static int vcn_v2_5_sriov_start(struct amdgpu_device *adev)
                        SOC15_REG_OFFSET(VCN, i, mmUVD_STATUS),
                        ~UVD_STATUS__UVD_BUSY, UVD_STATUS__UVD_BUSY);
 
-               size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+               size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[i]->size + 4);
                /* mc resume*/
                if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
                        MMSCH_V1_0_INSERT_DIRECT_WT(
index e02af4de521c6f93c3dd57fa08457edfb2d237eb..8f82fb887e9c20c293b1390bb90c58ea9ff8ceea 100644 (file)
@@ -449,7 +449,7 @@ static int vcn_v3_0_resume(void *handle)
  */
 static void vcn_v3_0_mc_resume(struct amdgpu_device *adev, int inst)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[inst]->size + 4);
        uint32_t offset;
 
        /* cache window 0: fw */
@@ -499,7 +499,7 @@ static void vcn_v3_0_mc_resume(struct amdgpu_device *adev, int inst)
 
 static void vcn_v3_0_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_idx, bool indirect)
 {
-       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+       uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[inst_idx]->size + 4);
        uint32_t offset;
 
        /* cache window 0: fw */
@@ -1332,7 +1332,7 @@ static int vcn_v3_0_start_sriov(struct amdgpu_device *adev)
                        mmUVD_STATUS),
                        ~UVD_STATUS__UVD_BUSY, UVD_STATUS__UVD_BUSY);
 
-               cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+               cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[i]->size + 4);
 
                if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
                        MMSCH_V3_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, i,
index 8ab01ae919d2e36c8ff1c2226227c173223247be..832d15f7b5f61c0f22a3bf7779cca8108e0087e4 100644 (file)
@@ -382,7 +382,7 @@ static void vcn_v4_0_mc_resume(struct amdgpu_device *adev, int inst)
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
@@ -442,7 +442,7 @@ static void vcn_v4_0_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_idx
 {
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst_idx]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
@@ -1289,7 +1289,7 @@ static int vcn_v4_0_start_sriov(struct amdgpu_device *adev)
                        regUVD_STATUS),
                        ~UVD_STATUS__UVD_BUSY, UVD_STATUS__UVD_BUSY);
 
-               cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+               cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[i]->size + 4);
 
                if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
                        MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, i,
index 810bbfccd6f2eacb0269e554bbfe66b014919c42..203fa988322bdd93a009a2d21a42eb42217d6996 100644 (file)
@@ -332,7 +332,7 @@ static void vcn_v4_0_3_mc_resume(struct amdgpu_device *adev, int inst_idx)
        uint32_t offset, size, vcn_inst;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst_idx]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        vcn_inst = GET_INST(VCN, inst_idx);
@@ -407,7 +407,7 @@ static void vcn_v4_0_3_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_i
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst_idx]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
@@ -894,7 +894,7 @@ static int vcn_v4_0_3_start_sriov(struct amdgpu_device *adev)
                MMSCH_V4_0_INSERT_DIRECT_RD_MOD_WT(SOC15_REG_OFFSET(VCN, 0, regUVD_STATUS),
                        ~UVD_STATUS__UVD_BUSY, UVD_STATUS__UVD_BUSY);
 
-               cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4);
+               cache_size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw[i]->size + 4);
 
                if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
                        MMSCH_V4_0_INSERT_DIRECT_WT(SOC15_REG_OFFSET(VCN, 0,
index 0468955338b755f636e60f2943a7719b5e82bd77..501e53e69f2a0ca94076cd5616fbea1646ca4af1 100644 (file)
@@ -45,7 +45,7 @@
 #define mmUVD_DPG_LMA_DATA_BASE_IDX                                    regUVD_DPG_LMA_DATA_BASE_IDX
 
 #define VCN_VID_SOC_ADDRESS_2_0                                                0x1fb00
-#define VCN1_VID_SOC_ADDRESS_3_0                                       0x48300
+#define VCN1_VID_SOC_ADDRESS_3_0                                       (0x48300 + 0x38000)
 
 #define VCN_HARVEST_MMSCH                                                      0
 
@@ -329,7 +329,7 @@ static void vcn_v4_0_5_mc_resume(struct amdgpu_device *adev, int inst)
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
@@ -390,7 +390,7 @@ static void vcn_v4_0_5_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_i
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst_idx]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
@@ -486,7 +486,8 @@ static void vcn_v4_0_5_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_i
 
        /* VCN global tiling registers */
        WREG32_SOC15_DPG_MODE(inst_idx, SOC15_DPG_MODE_OFFSET(
-               VCN, 0, regUVD_GFX10_ADDR_CONFIG), adev->gfx.config.gb_addr_config, 0, indirect);
+               VCN, inst_idx, regUVD_GFX10_ADDR_CONFIG),
+               adev->gfx.config.gb_addr_config, 0, indirect);
 }
 
 /**
@@ -911,7 +912,6 @@ static int vcn_v4_0_5_start_dpg_mode(struct amdgpu_device *adev, int inst_idx, b
                VCN, inst_idx, regUVD_MASTINT_EN),
                UVD_MASTINT_EN__VCPU_EN_MASK, 0, indirect);
 
-
        if (indirect)
                amdgpu_vcn_psp_update_sram(adev, inst_idx, 0);
 
index d6ee9958ba5fccb758715b8d6ff71cf5e2c7f6f0..bc60c554eb32960e166833d899094dbbb3442ad0 100644 (file)
@@ -290,7 +290,7 @@ static void vcn_v5_0_0_mc_resume(struct amdgpu_device *adev, int inst)
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
@@ -351,7 +351,7 @@ static void vcn_v5_0_0_mc_resume_dpg_mode(struct amdgpu_device *adev, int inst_i
        uint32_t offset, size;
        const struct common_firmware_header *hdr;
 
-       hdr = (const struct common_firmware_header *)adev->vcn.fw->data;
+       hdr = (const struct common_firmware_header *)adev->vcn.fw[inst_idx]->data;
        size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
 
        /* cache window 0: fw */
index 1c9c6096e28fb335ab9a9c90751a2cfd96b4b5dc..2851719d7121612b64842f3da8e84cf82d073454 100644 (file)
@@ -1767,6 +1767,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        if (amdgpu_dc_debug_mask & DC_FORCE_SUBVP_MCLK_SWITCH)
                adev->dm.dc->debug.force_subvp_mclk_switch = true;
 
+       if (amdgpu_dc_debug_mask & DC_ENABLE_DML2)
+               adev->dm.dc->debug.using_dml2 = true;
+
        adev->dm.dc->debug.visual_confirm = amdgpu_dc_visual_confirm;
 
        /* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
@@ -11271,18 +11274,24 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
        if (!adev->dm.freesync_module)
                goto update;
 
-       if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT
-               || sink->sink_signal == SIGNAL_TYPE_EDP) {
+       if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
+                    sink->sink_signal == SIGNAL_TYPE_EDP)) {
                bool edid_check_required = false;
 
-               if (edid) {
-                       edid_check_required = is_dp_capable_without_timing_msa(
-                                               adev->dm.dc,
-                                               amdgpu_dm_connector);
+               if (is_dp_capable_without_timing_msa(adev->dm.dc,
+                                                    amdgpu_dm_connector)) {
+                       if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) {
+                               freesync_capable = true;
+                               amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq;
+                               amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq;
+                       } else {
+                               edid_check_required = edid->version > 1 ||
+                                                     (edid->version == 1 &&
+                                                      edid->revision > 1);
+                       }
                }
 
-               if (edid_check_required == true && (edid->version > 1 ||
-                  (edid->version == 1 && edid->revision > 1))) {
+               if (edid_check_required) {
                        for (i = 0; i < 4; i++) {
 
                                timing  = &edid->detailed_timings[i];
index 668f05c8654ef0f3d7e9d5989e76f802aa23247b..bec252e1dd27a98263b5bd3299cc3dfd8ed089e9 100644 (file)
@@ -216,6 +216,16 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base)
        if (clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz > 1950)
                clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz = 1950;
 
+       /* DPPCLK */
+       dcn32_init_single_clock(clk_mgr, PPCLK_DPPCLK,
+                       &clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz,
+                       &num_entries_per_clk->num_dppclk_levels);
+       num_levels = num_entries_per_clk->num_dppclk_levels;
+       clk_mgr_base->bw_params->dc_mode_limit.dppclk_mhz = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DPPCLK);
+       //HW recommends limit of 1950 MHz in display clock for all DCN3.2.x
+       if (clk_mgr_base->bw_params->dc_mode_limit.dppclk_mhz > 1950)
+               clk_mgr_base->bw_params->dc_mode_limit.dppclk_mhz = 1950;
+
        if (num_entries_per_clk->num_dcfclk_levels &&
                        num_entries_per_clk->num_dtbclk_levels &&
                        num_entries_per_clk->num_dispclk_levels)
@@ -240,6 +250,10 @@ void dcn32_init_clocks(struct clk_mgr *clk_mgr_base)
                                        = khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz);
        }
 
+       for (i = 0; i < num_levels; i++)
+               if (clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz > 1950)
+                       clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz = 1950;
+
        /* Get UCLK, update bounding box */
        clk_mgr_base->funcs->get_memclk_states_from_smu(clk_mgr_base);
 
index 5211c1c0f3c0cf0968cae6c168750dc34d7a0e9a..e7dc128f6284b45846f4eff707d3f052dab7b108 100644 (file)
@@ -1302,6 +1302,54 @@ static void disable_vbios_mode_if_required(
        }
 }
 
+/**
+ * wait_for_blank_complete - wait for all active OPPs to finish pending blank
+ * pattern updates
+ *
+ * @dc: [in] dc reference
+ * @context: [in] hardware context in use
+ */
+static void wait_for_blank_complete(struct dc *dc,
+               struct dc_state *context)
+{
+       struct pipe_ctx *opp_head;
+       struct dce_hwseq *hws = dc->hwseq;
+       int i;
+
+       if (!hws->funcs.wait_for_blank_complete)
+               return;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               opp_head = &context->res_ctx.pipe_ctx[i];
+
+               if (!resource_is_pipe_type(opp_head, OPP_HEAD) ||
+                               dc_state_get_pipe_subvp_type(context, opp_head) == SUBVP_PHANTOM)
+                       continue;
+
+               hws->funcs.wait_for_blank_complete(opp_head->stream_res.opp);
+       }
+}
+
+static void wait_for_odm_update_pending_complete(struct dc *dc, struct dc_state *context)
+{
+       struct pipe_ctx *otg_master;
+       struct timing_generator *tg;
+       int i;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               otg_master = &context->res_ctx.pipe_ctx[i];
+               if (!resource_is_pipe_type(otg_master, OTG_MASTER) ||
+                               dc_state_get_pipe_subvp_type(context, otg_master) == SUBVP_PHANTOM)
+                       continue;
+               tg = otg_master->stream_res.tg;
+               if (tg->funcs->wait_odm_doublebuffer_pending_clear)
+                       tg->funcs->wait_odm_doublebuffer_pending_clear(tg);
+       }
+
+       /* ODM update may require to reprogram blank pattern for each OPP */
+       wait_for_blank_complete(dc, context);
+}
+
 static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context)
 {
        int i;
@@ -1993,6 +2041,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
                context->stream_count == 0) {
                /* Must wait for no flips to be pending before doing optimize bw */
                wait_for_no_pipes_pending(dc, context);
+               /*
+                * optimized dispclk depends on ODM setup. Need to wait for ODM
+                * update pending complete before optimizing bandwidth.
+                */
+               wait_for_odm_update_pending_complete(dc, context);
                /* pplib is notified if disp_num changed */
                dc->hwss.optimize_bandwidth(dc, context);
                /* Need to do otg sync again as otg could be out of sync due to otg
@@ -3270,6 +3323,9 @@ static bool dc_dmub_should_send_dirty_rect_cmd(struct dc *dc, struct dc_stream_s
        if (stream->link->replay_settings.config.replay_supported)
                return true;
 
+       if (stream->ctx->dce_version >= DCN_VERSION_3_5 && stream->abm_level)
+               return true;
+
        return false;
 }
 
@@ -3493,7 +3549,7 @@ static void commit_planes_for_stream_fast(struct dc *dc,
                top_pipe_to_program->stream->update_flags.raw = 0;
 }
 
-static void wait_for_outstanding_hw_updates(struct dc *dc, const struct dc_state *dc_context)
+static void wait_for_outstanding_hw_updates(struct dc *dc, struct dc_state *dc_context)
 {
 /*
  * This function calls HWSS to wait for any potentially double buffered
@@ -3531,6 +3587,7 @@ static void wait_for_outstanding_hw_updates(struct dc *dc, const struct dc_state
                        }
                }
        }
+       wait_for_odm_update_pending_complete(dc, dc_context);
 }
 
 static void commit_planes_for_stream(struct dc *dc,
@@ -4844,22 +4901,16 @@ void dc_exit_ips_for_hw_access(struct dc *dc)
 
 bool dc_dmub_is_ips_idle_state(struct dc *dc)
 {
-       uint32_t idle_state = 0;
-
        if (dc->debug.disable_idle_power_optimizations)
                return false;
 
        if (!dc->caps.ips_support || (dc->config.disable_ips == DMUB_IPS_DISABLE_ALL))
                return false;
 
-       if (dc->hwss.get_idle_state)
-               idle_state = dc->hwss.get_idle_state(dc);
-
-       if (!(idle_state & DMUB_IPS1_ALLOW_MASK) ||
-               !(idle_state & DMUB_IPS2_ALLOW_MASK))
-               return true;
+       if (!dc->ctx->dmub_srv)
+               return false;
 
-       return false;
+       return dc->ctx->dmub_srv->idle_allowed;
 }
 
 /* set min and max memory clock to lowest and highest DPM level, respectively */
index 180ac47868c22a68c1af47096db95ecf6b11994c..5cc7f8da209c599f7585e8f10e499ef2118f34ff 100644 (file)
@@ -334,7 +334,8 @@ static void dc_state_free(struct kref *kref)
 
 void dc_state_release(struct dc_state *state)
 {
-       kref_put(&state->refcount, dc_state_free);
+       if (state != NULL)
+               kref_put(&state->refcount, dc_state_free);
 }
 /*
  * dc_state_add_stream() - Add a new dc_stream_state to a dc_state.
index 9900dda2eef5cd2e44e6dbd008cd411194d107af..be2ac5c442a480f868a53667433384a452c65b66 100644 (file)
@@ -1085,9 +1085,9 @@ struct replay_settings {
        /* SMU optimization is enabled */
        bool replay_smu_opt_enable;
        /* Current Coasting vtotal */
-       uint16_t coasting_vtotal;
+       uint32_t coasting_vtotal;
        /* Coasting vtotal table */
-       uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM];
+       uint32_t coasting_vtotal_table[PR_COASTING_TYPE_NUM];
        /* Maximum link off frame count */
        enum replay_link_off_frame_count_level link_off_frame_count_level;
        /* Replay pseudo vtotal for abm + ips on full screen video which can improve ips residency */
index 48a40dcc7050bd597ed7e5b7d645b0764db2c572..5838a11efd00c4e6cfce8b3d86e9c43413ae4374 100644 (file)
@@ -384,6 +384,7 @@ static const struct opp_funcs dcn10_opp_funcs = {
                .opp_set_disp_pattern_generator = NULL,
                .opp_program_dpg_dimensions = NULL,
                .dpg_is_blanked = NULL,
+               .dpg_is_pending = NULL,
                .opp_destroy = opp1_destroy
 };
 
index 0784d01986610d6be0407ff97318483191ead832..fbf1b6370eb23af3820fa092393229296a49a843 100644 (file)
@@ -337,6 +337,19 @@ bool opp2_dpg_is_blanked(struct output_pixel_processor *opp)
                (double_buffer_pending == 0);
 }
 
+bool opp2_dpg_is_pending(struct output_pixel_processor *opp)
+{
+       struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp);
+       uint32_t double_buffer_pending;
+       uint32_t dpg_en;
+
+       REG_GET(DPG_CONTROL, DPG_EN, &dpg_en);
+
+       REG_GET(DPG_STATUS, DPG_DOUBLE_BUFFER_PENDING, &double_buffer_pending);
+
+       return (dpg_en == 1 && double_buffer_pending == 1);
+}
+
 void opp2_program_left_edge_extra_pixel (
                struct output_pixel_processor *opp,
                bool count)
@@ -363,6 +376,7 @@ static struct opp_funcs dcn20_opp_funcs = {
                .opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator,
                .opp_program_dpg_dimensions = opp2_program_dpg_dimensions,
                .dpg_is_blanked = opp2_dpg_is_blanked,
+               .dpg_is_pending = opp2_dpg_is_pending,
                .opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
                .opp_destroy = opp1_destroy,
                .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
index 3ab221bdd27dd24c40d5db6977c31d77e7667b14..8f186abd558db45a09dc92776e0b627fb1e0958b 100644 (file)
@@ -159,6 +159,8 @@ void opp2_program_dpg_dimensions(
 
 bool opp2_dpg_is_blanked(struct output_pixel_processor *opp);
 
+bool opp2_dpg_is_pending(struct output_pixel_processor *opp);
+
 void opp2_dpg_set_blank_color(
                struct output_pixel_processor *opp,
                const struct tg_color *color);
index 8e77db46a4090147217ab58f1795c7bc24030a39..6a71ba3dfc6327969d8f973913fee9c80d6aa387 100644 (file)
@@ -50,6 +50,7 @@ static struct opp_funcs dcn201_opp_funcs = {
                .opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator,
                .opp_program_dpg_dimensions = opp2_program_dpg_dimensions,
                .dpg_is_blanked = opp2_dpg_is_blanked,
+               .dpg_is_pending = opp2_dpg_is_pending,
                .opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
                .opp_destroy = opp1_destroy,
                .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
index 87760600e154dad46e911e28f0b2937e6e012602..f98def6c8c2d23fc630f2c3d873335f5ad31c4ef 100644 (file)
@@ -782,3 +782,9 @@ void dcn32_update_dml_pipes_odm_policy_based_on_context(struct dc *dc, struct dc
                pipe_cnt++;
        }
 }
+
+void dcn32_override_min_req_dcfclk(struct dc *dc, struct dc_state *context)
+{
+       if (dcn32_subvp_in_use(dc, context) && context->bw_ctx.bw.dcn.clk.dcfclk_khz <= MIN_SUBVP_DCFCLK_KHZ)
+               context->bw_ctx.bw.dcn.clk.dcfclk_khz = MIN_SUBVP_DCFCLK_KHZ;
+}
index b49e1dc9d8ba5154385d4fc396a9c243ec5cfb79..a0a65e0991041d90904c516c7279c5b8aa76967c 100644 (file)
@@ -623,6 +623,7 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
                 * - Not TMZ surface
                 */
                if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) &&
+                               !(pipe->stream->timing.pix_clk_100hz / 10000 > DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ) &&
                                (!dcn32_is_psr_capable(pipe) || (context->stream_count == 1 && dc->caps.dmub_caps.subvp_psr)) &&
                                dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_NONE &&
                                (refresh_rate < 120 || dcn32_allow_subvp_high_refresh_rate(dc, context, pipe)) &&
index 1ba6933d2b3617aa6d275647d17320dd0755ae69..17a58f41fc6a8501a4cf998507d9b89f68d0fcc1 100644 (file)
@@ -824,13 +824,25 @@ static struct scaler_data get_scaler_data_for_plane(const struct dc_plane_state
 
 static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned int location, const struct dc_stream_state *in)
 {
+       dml_uint_t width, height;
+
+       if (in->timing.h_addressable > 3840)
+               width = 3840;
+       else
+               width = in->timing.h_addressable;       // 4K max
+
+       if (in->timing.v_addressable > 2160)
+               height = 2160;
+       else
+               height = in->timing.v_addressable;      // 4K max
+
        out->CursorBPP[location] = dml_cur_32bit;
        out->CursorWidth[location] = 256;
 
        out->GPUVMMinPageSizeKBytes[location] = 256;
 
-       out->ViewportWidth[location] = in->timing.h_addressable;
-       out->ViewportHeight[location] = in->timing.v_addressable;
+       out->ViewportWidth[location] = width;
+       out->ViewportHeight[location] = height;
        out->ViewportStationary[location] = false;
        out->ViewportWidthChroma[location] = 0;
        out->ViewportHeightChroma[location] = 0;
@@ -849,7 +861,7 @@ static void populate_dummy_dml_plane_cfg(struct dml_plane_cfg_st *out, unsigned
        out->HTapsChroma[location] = 0;
        out->VTapsChroma[location] = 0;
        out->SourceScan[location] = dml_rotation_0;
-       out->ScalerRecoutWidth[location] = in->timing.h_addressable;
+       out->ScalerRecoutWidth[location] = width;
 
        out->LBBitPerPixel[location] = 57;
 
index 2a58a7687bdb5779db6c639d3cbf2277aaf231ae..72cca367062e163be2dbe41f7af452c515467a54 100644 (file)
@@ -703,13 +703,8 @@ static inline struct dml2_context *dml2_allocate_memory(void)
        return (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL);
 }
 
-bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
+static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
 {
-       // Allocate Mode Lib Ctx
-       *dml2 = dml2_allocate_memory();
-
-       if (!(*dml2))
-               return false;
 
        // Store config options
        (*dml2)->config = *config;
@@ -737,9 +732,18 @@ bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options
        initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc);
 
        initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states);
+}
+
+bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2)
+{
+       // Allocate Mode Lib Ctx
+       *dml2 = dml2_allocate_memory();
+
+       if (!(*dml2))
+               return false;
+
+       dml2_init(in_dc, config, dml2);
 
-       /*Initialize DML20 instance which calls dml2_core_create, and core_dcn3_populate_informative*/
-       //dml2_initialize_instance(&(*dml_ctx)->v20.dml_init);
        return true;
 }
 
@@ -779,3 +783,11 @@ bool dml2_create_copy(struct dml2_context **dst_dml2,
 
        return true;
 }
+
+void dml2_reinit(const struct dc *in_dc,
+                                const struct dml2_configuration_options *config,
+                                struct dml2_context **dml2)
+{
+
+       dml2_init(in_dc, config, dml2);
+}
index ee0eb184eb6d7ea23bec303133cfaa76dc40854a..cc662d682fd4de03f475dfcb59ee68541c09b44c 100644 (file)
@@ -214,6 +214,9 @@ void dml2_copy(struct dml2_context *dst_dml2,
        struct dml2_context *src_dml2);
 bool dml2_create_copy(struct dml2_context **dst_dml2,
        struct dml2_context *src_dml2);
+void dml2_reinit(const struct dc *in_dc,
+                                const struct dml2_configuration_options *config,
+                                struct dml2_context **dml2);
 
 /*
  * dml2_validate - Determines if a display configuration is supported or not.
index c55d5155ecb9c0bd44d35af712c8bb27aac715c4..8b3536c380b8de70f500edef2c91f0169690cd3f 100644 (file)
@@ -1498,6 +1498,11 @@ static void dcn20_detect_pipe_changes(struct dc_state *old_state,
                return;
        }
 
+       if (resource_is_pipe_type(new_pipe, OTG_MASTER) &&
+                       resource_is_odm_topology_changed(new_pipe, old_pipe))
+               /* Detect odm changes */
+               new_pipe->update_flags.bits.odm = 1;
+
        /* Exit on unchanged, unused pipe */
        if (!old_pipe->plane_state && !new_pipe->plane_state)
                return;
@@ -1551,10 +1556,6 @@ static void dcn20_detect_pipe_changes(struct dc_state *old_state,
 
        /* Detect top pipe only changes */
        if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {
-               /* Detect odm changes */
-               if (resource_is_odm_topology_changed(new_pipe, old_pipe))
-                       new_pipe->update_flags.bits.odm = 1;
-
                /* Detect global sync changes */
                if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset
                                || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start
@@ -1999,19 +2000,20 @@ void dcn20_program_front_end_for_ctx(
        DC_LOGGER_INIT(dc->ctx->logger);
        unsigned int prev_hubp_count = 0;
        unsigned int hubp_count = 0;
+       struct pipe_ctx *pipe;
 
        if (resource_is_pipe_topology_changed(dc->current_state, context))
                resource_log_pipe_topology_update(dc, context);
 
        if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
                for (i = 0; i < dc->res_pool->pipe_count; i++) {
-                       struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+                       pipe = &context->res_ctx.pipe_ctx[i];
 
-                       if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->plane_state) {
-                               ASSERT(!pipe_ctx->plane_state->triplebuffer_flips);
+                       if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->plane_state) {
+                               ASSERT(!pipe->plane_state->triplebuffer_flips);
                                /*turn off triple buffer for full update*/
                                dc->hwss.program_triplebuffer(
-                                               dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
+                                               dc, pipe, pipe->plane_state->triplebuffer_flips);
                        }
                }
        }
@@ -2085,12 +2087,22 @@ void dcn20_program_front_end_for_ctx(
                        DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
                }
 
+       /* update ODM for blanked OTG master pipes */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe = &context->res_ctx.pipe_ctx[i];
+               if (resource_is_pipe_type(pipe, OTG_MASTER) &&
+                               !resource_is_pipe_type(pipe, DPP_PIPE) &&
+                               pipe->update_flags.bits.odm &&
+                               hws->funcs.update_odm)
+                       hws->funcs.update_odm(dc, context, pipe);
+       }
+
        /*
         * Program all updated pipes, order matters for mpcc setup. Start with
         * top pipe and program all pipes that follow in order
         */
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
-               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+               pipe = &context->res_ctx.pipe_ctx[i];
 
                if (pipe->plane_state && !pipe->top_pipe) {
                        while (pipe) {
@@ -2129,17 +2141,6 @@ void dcn20_program_front_end_for_ctx(
                        context->stream_status[0].plane_count > 1) {
                        pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
                }
-
-               /* when dynamic ODM is active, pipes must be reconfigured when all planes are
-                * disabled, as some transitions will leave software and hardware state
-                * mismatched.
-                */
-               if (dc->debug.enable_single_display_2to1_odm_policy &&
-                       pipe->stream &&
-                       pipe->update_flags.bits.disable &&
-                       !pipe->prev_odm_pipe &&
-                       hws->funcs.update_odm)
-                       hws->funcs.update_odm(dc, context, pipe);
        }
 }
 
@@ -2451,7 +2452,7 @@ bool dcn20_wait_for_blank_complete(
        int counter;
 
        for (counter = 0; counter < 1000; counter++) {
-               if (opp->funcs->dpg_is_blanked(opp))
+               if (!opp->funcs->dpg_is_pending(opp))
                        break;
 
                udelay(100);
@@ -2462,7 +2463,7 @@ bool dcn20_wait_for_blank_complete(
                return false;
        }
 
-       return true;
+       return opp->funcs->dpg_is_blanked(opp);
 }
 
 bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
index 7e6b7f2a6dc9ea799c3a4b0a23b5d3e4c6d26b17..8bc3d01537bbd493d08d294b2a8d88104c95b21c 100644 (file)
@@ -812,10 +812,20 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
        if (pipe_ctx == NULL)
                return;
 
-       if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL)
+       if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) {
                pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
                                pipe_ctx->stream_res.stream_enc,
                                enable);
+
+               /* Wait for two frame to make sure AV mute is sent out */
+               if (enable) {
+                       pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+                       pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+                       pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+                       pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
+                       pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
+               }
+       }
 }
 
 void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
index aa36d7a56ca8c3b6f3cd47e67455ba67549bf73b..c0b526cf178654f1c9fedb95e08831e965a911a7 100644 (file)
@@ -1156,6 +1156,13 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                        dsc->funcs->dsc_disconnect(dsc);
                }
        }
+
+       if (!resource_is_pipe_type(pipe_ctx, DPP_PIPE))
+               /*
+                * blank pattern is generated by OPP, reprogram blank pattern
+                * due to OPP count change
+                */
+               dc->hwseq->funcs.blank_pixel_data(dc, pipe_ctx, true);
 }
 
 unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
@@ -1778,3 +1785,26 @@ void dcn32_prepare_bandwidth(struct dc *dc,
                context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
        }
 }
+
+void dcn32_interdependent_update_lock(struct dc *dc,
+               struct dc_state *context, bool lock)
+{
+       unsigned int i;
+       struct pipe_ctx *pipe;
+       struct timing_generator *tg;
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe = &context->res_ctx.pipe_ctx[i];
+               tg = pipe->stream_res.tg;
+
+               if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
+                               !tg->funcs->is_tg_enabled(tg) ||
+                               dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)
+                       continue;
+
+               if (lock)
+                       dc->hwss.pipe_control_lock(dc, pipe, true);
+               else
+                       dc->hwss.pipe_control_lock(dc, pipe, false);
+       }
+}
index 069e20bc87c0a75af028168253219fc9343b1af3..f55c11fc56ec7a7a3d86cff32269a89fb6c5a3d5 100644 (file)
@@ -129,4 +129,6 @@ bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc,
 void dcn32_prepare_bandwidth(struct dc *dc,
        struct dc_state *context);
 
+void dcn32_interdependent_update_lock(struct dc *dc,
+               struct dc_state *context, bool lock);
 #endif /* __DC_HWSS_DCN32_H__ */
index 2b073123d3ede2eb16ae766af9a285511fc6e8ea..67d661dbd5b7c7c20673424102b139c8df47d9be 100644 (file)
@@ -58,7 +58,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .disable_plane = dcn20_disable_plane,
        .disable_pixel_data = dcn20_disable_pixel_data,
        .pipe_control_lock = dcn20_pipe_control_lock,
-       .interdependent_update_lock = dcn10_lock_all_pipes,
+       .interdependent_update_lock = dcn32_interdependent_update_lock,
        .cursor_lock = dcn10_cursor_lock,
        .prepare_bandwidth = dcn32_prepare_bandwidth,
        .optimize_bandwidth = dcn20_optimize_bandwidth,
index aee5372e292c5a691c9b6f2d8a45ef31e823889d..d89c92370d5b3a773f524ccfdeeb3d0d5691af63 100644 (file)
@@ -337,6 +337,9 @@ struct opp_funcs {
        bool (*dpg_is_blanked)(
                        struct output_pixel_processor *opp);
 
+       bool (*dpg_is_pending)(struct output_pixel_processor *opp);
+
+
        void (*opp_dpg_set_blank_color)(
                        struct output_pixel_processor *opp,
                        const struct tg_color *color);
index d98d72f35be5bd3eb28f8db759c6f8848bf5fa85..ffad8fe16c54dc2447f5846c8788387e024c5d71 100644 (file)
@@ -331,6 +331,7 @@ struct timing_generator_funcs {
 
        void (*init_odm)(struct timing_generator *tg);
        void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg);
+       void (*wait_odm_doublebuffer_pending_clear)(struct timing_generator *tg);
 };
 
 #endif
index 26fe81f213da55d39aa7edbb387328192d42685b..bf29fc58ea6a62af45d0643b497cc54a779c0a8b 100644 (file)
@@ -285,12 +285,12 @@ struct link_service {
                        enum replay_FW_Message_type msg,
                        union dmub_replay_cmd_set *cmd_data);
        bool (*edp_set_coasting_vtotal)(
-                       struct dc_link *link, uint16_t coasting_vtotal);
+                       struct dc_link *link, uint32_t coasting_vtotal);
        bool (*edp_replay_residency)(const struct dc_link *link,
                        unsigned int *residency, const bool is_start,
                        const bool is_alpm);
        bool (*edp_set_replay_power_opt_and_coasting_vtotal)(struct dc_link *link,
-                       const unsigned int *power_opts, uint16_t coasting_vtotal);
+                       const unsigned int *power_opts, uint32_t coasting_vtotal);
 
        bool (*edp_wait_for_t12)(struct dc_link *link);
        bool (*edp_is_ilr_optimization_required)(struct dc_link *link,
index acfbbc638cc647668ad6cfa86625e18b294ceb82..3baa2bdd6dd652c919f46529d244ce89b4c9c65c 100644 (file)
@@ -1034,7 +1034,7 @@ bool edp_send_replay_cmd(struct dc_link *link,
        return true;
 }
 
-bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal)
+bool edp_set_coasting_vtotal(struct dc_link *link, uint32_t coasting_vtotal)
 {
        struct dc *dc = link->ctx->dc;
        struct dmub_replay *replay = dc->res_pool->replay;
@@ -1073,7 +1073,7 @@ bool edp_replay_residency(const struct dc_link *link,
 }
 
 bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
-       const unsigned int *power_opts, uint16_t coasting_vtotal)
+       const unsigned int *power_opts, uint32_t coasting_vtotal)
 {
        struct dc  *dc = link->ctx->dc;
        struct dmub_replay *replay = dc->res_pool->replay;
index 34e521af7bb482260539bcf66821741531ab17af..a158c6234d4225e6f665a8082ad351e5ad809d16 100644 (file)
@@ -59,12 +59,12 @@ bool edp_setup_replay(struct dc_link *link,
 bool edp_send_replay_cmd(struct dc_link *link,
                        enum replay_FW_Message_type msg,
                        union dmub_replay_cmd_set *cmd_data);
-bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal);
+bool edp_set_coasting_vtotal(struct dc_link *link, uint32_t coasting_vtotal);
 bool edp_replay_residency(const struct dc_link *link,
        unsigned int *residency, const bool is_start, const bool is_alpm);
 bool edp_get_replay_state(const struct dc_link *link, uint64_t *state);
 bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
-       const unsigned int *power_opts, uint16_t coasting_vtotal);
+       const unsigned int *power_opts, uint32_t coasting_vtotal);
 bool edp_wait_for_t12(struct dc_link *link);
 bool edp_is_ilr_optimization_required(struct dc_link *link,
        struct dc_crtc_timing *crtc_timing);
index ab81594a7fadcc0ea6eecb148ddc264202a1c0df..6c2e84d3967fc552a6a5ee346d5731cfdd920098 100644 (file)
@@ -557,7 +557,8 @@ struct dcn_optc_registers {
        type OTG_CRC_DATA_STREAM_SPLIT_MODE;\
        type OTG_CRC_DATA_FORMAT;\
        type OTG_V_TOTAL_LAST_USED_BY_DRR;\
-       type OTG_DRR_TIMING_DBUF_UPDATE_PENDING;
+       type OTG_DRR_TIMING_DBUF_UPDATE_PENDING;\
+       type OTG_H_TIMING_DIV_MODE_DB_UPDATE_PENDING;
 
 #define TG_REG_FIELD_LIST_DCN3_2(type) \
        type OTG_H_TIMING_DIV_MODE_MANUAL;
index 82349354332548e160494c23bee15acaa18b7630..f07a4c7e48bc23ed0d2351aef46ef38907ee265f 100644 (file)
@@ -122,6 +122,13 @@ void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combi
        }
 }
 
+void optc32_wait_odm_doublebuffer_pending_clear(struct timing_generator *tg)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(tg);
+
+       REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, OTG_H_TIMING_DIV_MODE_DB_UPDATE_PENDING, 0, 2, 50000);
+}
+
 void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
@@ -345,6 +352,7 @@ static struct timing_generator_funcs dcn32_tg_funcs = {
                .set_odm_bypass = optc32_set_odm_bypass,
                .set_odm_combine = optc32_set_odm_combine,
                .get_odm_combine_segments = optc32_get_odm_combine_segments,
+               .wait_odm_doublebuffer_pending_clear = optc32_wait_odm_doublebuffer_pending_clear,
                .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode,
                .get_optc_source = optc2_get_optc_source,
                .set_out_mux = optc3_set_out_mux,
index 8ce3b178cab06513fffc93bf3ef9b84d288f505b..0c2c14695561961212aff800f100ac7160d04ad3 100644 (file)
@@ -183,5 +183,6 @@ void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool man
 void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments);
 void optc32_set_odm_bypass(struct timing_generator *optc,
                const struct dc_crtc_timing *dc_crtc_timing);
+void optc32_wait_odm_doublebuffer_pending_clear(struct timing_generator *tg);
 
 #endif /* __DC_OPTC_DCN32_H__ */
index 3f3951f3ba9834eb5ba4a9599a9f34051ed87f50..ce1754cc1f4631bcb800891ab7bd74ad52a36a69 100644 (file)
@@ -1771,6 +1771,7 @@ static bool dml1_validate(struct dc *dc, struct dc_state *context, bool fast_val
        dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
 
        dcn32_override_min_req_memclk(dc, context);
+       dcn32_override_min_req_dcfclk(dc, context);
 
        BW_VAL_TRACE_END_WATERMARKS();
 
@@ -1930,6 +1931,8 @@ static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw
 {
        DC_FP_START();
        dcn32_update_bw_bounding_box_fpu(dc, bw_params);
+       if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2)
+               dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2);
        DC_FP_END();
 }
 
index 0c87b0fabba7d96ff38180900e41f1438419912c..2258c5c7212d86902b4352fbf0fe3da01b524c78 100644 (file)
@@ -42,6 +42,7 @@
 #define SUBVP_ACTIVE_MARGIN_LIST_LEN 2
 #define DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ 1800
 #define DCN3_2_VMIN_DISPCLK_HZ 717000000
+#define MIN_SUBVP_DCFCLK_KHZ 400000
 
 #define TO_DCN32_RES_POOL(pool)\
        container_of(pool, struct dcn32_resource_pool, base)
@@ -181,6 +182,8 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int
 
 void dcn32_update_dml_pipes_odm_policy_based_on_context(struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes);
 
+void dcn32_override_min_req_dcfclk(struct dc *dc, struct dc_state *context);
+
 /* definitions for run time init of reg offsets */
 
 /* CLK SRC */
index b356fed1726d92dea75ac98f5669896cb4dcca80..296a0a8e71459f79f8478569287bd11dcae50cad 100644 (file)
@@ -1581,6 +1581,8 @@ static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b
 {
        DC_FP_START();
        dcn321_update_bw_bounding_box_fpu(dc, bw_params);
+       if (dc->debug.using_dml2 && dc->current_state && dc->current_state->bw_ctx.dml2)
+               dml2_reinit(dc, &dc->dml2_options, &dc->current_state->bw_ctx.dml2);
        DC_FP_END();
 }
 
index a529e369b2ace9b8e28254e0a36cd02106ccab84..af3fe8bb0728b114a735faddfb68ae38360af334 100644 (file)
@@ -3238,6 +3238,14 @@ struct dmub_cmd_replay_set_coasting_vtotal_data {
         * Currently the support is only for 0 or 1
         */
        uint8_t panel_inst;
+       /**
+        * 16-bit value dicated by driver that indicates the coasting vtotal high byte part.
+        */
+       uint16_t coasting_vtotal_high;
+       /**
+        * Explicit padding to 4 byte boundary.
+        */
+       uint8_t pad[2];
 };
 
 /**
index 8c137d7c032e1ffa5d4e2ac288424ba4edba3008..7c9805705fd3804f15c4d297dbeceb6cf05656de 100644 (file)
@@ -513,6 +513,9 @@ enum mod_hdcp_status mod_hdcp_hdcp2_create_session(struct mod_hdcp *hdcp)
        hdcp_cmd = (struct ta_hdcp_shared_memory *)psp->hdcp_context.context.mem_context.shared_buf;
        memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory));
 
+       if (!display)
+               return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
+
        hdcp_cmd->in_msg.hdcp2_create_session_v2.display_handle = display->index;
 
        if (hdcp->connection.link.adjust.hdcp2.force_type == MOD_HDCP_FORCE_TYPE_0)
index e304e8435fb8f1c5e29428f72c20a6097fb57697..2a3698fd2dc242e6927d1c9c399197f1ccb3f40c 100644 (file)
@@ -975,7 +975,7 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link,
 
 void set_replay_coasting_vtotal(struct dc_link *link,
        enum replay_coasting_vtotal_type type,
-       uint16_t vtotal)
+       uint32_t vtotal)
 {
        link->replay_settings.coasting_vtotal_table[type] = vtotal;
 }
index bef4815e1703d78cdebc6f49bc160932d08c5272..ff7e6f3cd6be230b95755188043e76b8041db121 100644 (file)
@@ -56,7 +56,7 @@ bool dmub_init_abm_config(struct resource_pool *res_pool,
 void init_replay_config(struct dc_link *link, struct replay_config *pr_config);
 void set_replay_coasting_vtotal(struct dc_link *link,
        enum replay_coasting_vtotal_type type,
-       uint16_t vtotal);
+       uint32_t vtotal);
 void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal);
 void calculate_replay_link_off_frame_count(struct dc_link *link,
        uint16_t vtotal, uint16_t htotal);
index 1d96eb274d72d462de9330166a01d1acc881b2ad..0c2d04f978ac92257d78a184786e48c837e38b7f 100644 (file)
@@ -1283,10 +1283,8 @@ static int arcturus_get_power_limit(struct smu_context *smu,
                                        uint32_t *max_power_limit,
                                        uint32_t *min_power_limit)
 {
-       struct smu_11_0_powerplay_table *powerplay_table =
-               (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
-       uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t power_limit;
 
        if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
                /* the last hope to figure out the ppt limit */
@@ -1302,26 +1300,10 @@ static int arcturus_get_power_limit(struct smu_context *smu,
                *current_power_limit = power_limit;
        if (default_power_limit)
                *default_power_limit = power_limit;
-
-       if (smu->od_enabled)
-               od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-       else
-               od_percent_upper = 0;
-
-       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-
-       dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
-                                                       od_percent_upper, od_percent_lower, power_limit);
-
-       if (max_power_limit) {
-               *max_power_limit = power_limit * (100 + od_percent_upper);
-               *max_power_limit /= 100;
-       }
-
-       if (min_power_limit) {
-               *min_power_limit = power_limit * (100 - od_percent_lower);
-               *min_power_limit /= 100;
-       }
+       if (max_power_limit)
+               *max_power_limit = power_limit;
+       if (min_power_limit)
+               *min_power_limit = power_limit;
 
        return 0;
 }
index ed189a3878ebe7199833e495f45417461897a93a..836b1df7992862614d017c0dd4d919f0f80a3965 100644 (file)
@@ -2339,7 +2339,7 @@ static int navi10_get_power_limit(struct smu_context *smu,
                (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
        struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
-       uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
 
        if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
                /* the last hope to figure out the ppt limit */
@@ -2356,13 +2356,16 @@ static int navi10_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled &&
-                   navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT))
-               od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
-       else
-               od_percent_upper = 0;
-
-       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+       if (powerplay_table) {
+               if (smu->od_enabled &&
+                           navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
+                       od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+               } else if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
+                       od_percent_upper = 0;
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
+               }
+       }
 
        dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
                                        od_percent_upper, od_percent_lower, power_limit);
index e2ad2b972ab0b3550d7aceb66e632eb372a0ffc5..1f18b61884f3f2ae8c3f4415b571329659b7a52c 100644 (file)
@@ -617,6 +617,12 @@ static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *s
        return throttler_status;
 }
 
+static bool sienna_cichlid_is_od_feature_supported(struct smu_11_0_7_overdrive_table *od_table,
+                                                  enum SMU_11_0_7_ODFEATURE_CAP cap)
+{
+       return od_table->cap[cap];
+}
+
 static int sienna_cichlid_get_power_limit(struct smu_context *smu,
                                          uint32_t *current_power_limit,
                                          uint32_t *default_power_limit,
@@ -625,7 +631,8 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu,
 {
        struct smu_11_0_7_powerplay_table *powerplay_table =
                (struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table;
-       uint32_t power_limit, od_percent_upper, od_percent_lower;
+       struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings;
+       uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
        uint16_t *table_member;
 
        GET_PPTABLE_MEMBER(SocketPowerLimitAc, &table_member);
@@ -640,12 +647,16 @@ static int sienna_cichlid_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled)
-               od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
-       else
-               od_percent_upper = 0;
-
-       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
+       if (powerplay_table) {
+               if (smu->od_enabled &&
+                               sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_POWER_LIMIT)) {
+                       od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
+               } else if ((sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_POWER_LIMIT))) {
+                       od_percent_upper = 0;
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
+               }
+       }
 
        dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
                                        od_percent_upper, od_percent_lower, power_limit);
@@ -1250,12 +1261,6 @@ static bool sienna_cichlid_is_support_fine_grained_dpm(struct smu_context *smu,
        return dpm_desc->SnapToDiscrete == 0;
 }
 
-static bool sienna_cichlid_is_od_feature_supported(struct smu_11_0_7_overdrive_table *od_table,
-                                                  enum SMU_11_0_7_ODFEATURE_CAP cap)
-{
-       return od_table->cap[cap];
-}
-
 static void sienna_cichlid_get_od_setting_range(struct smu_11_0_7_overdrive_table *od_table,
                                                enum SMU_11_0_7_ODSETTING_ID setting,
                                                uint32_t *min, uint32_t *max)
index 9b80f18ea6c359f279f050ee9f645b92dd43d057..9c03296f92cdd41c868406dfd861bf56a77c2e81 100644 (file)
@@ -2356,7 +2356,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
                (struct smu_13_0_0_powerplay_table *)table_context->power_play_table;
        PPTable_t *pptable = table_context->driver_pptable;
        SkuTable_t *skutable = &pptable->SkuTable;
-       uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
        uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
 
        if (smu_v13_0_get_current_power_limit(smu, &power_limit))
@@ -2369,12 +2369,16 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled)
-               od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
-       else
-               od_percent_upper = 0;
-
-       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+       if (powerplay_table) {
+               if (smu->od_enabled &&
+                               smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+                       od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+               } else if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+                       od_percent_upper = 0;
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+               }
+       }
 
        dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
                                        od_percent_upper, od_percent_lower, power_limit);
index 3dc7b60cb0754d0f62fd3cead74f1553071b8597..7318964f1f148fae680df028b0ae9c1cc74cb616 100644 (file)
@@ -2320,7 +2320,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
                (struct smu_13_0_7_powerplay_table *)table_context->power_play_table;
        PPTable_t *pptable = table_context->driver_pptable;
        SkuTable_t *skutable = &pptable->SkuTable;
-       uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0;
        uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
 
        if (smu_v13_0_get_current_power_limit(smu, &power_limit))
@@ -2333,12 +2333,16 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (smu->od_enabled)
-               od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
-       else
-               od_percent_upper = 0;
-
-       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
+       if (powerplay_table) {
+               if (smu->od_enabled &&
+                               (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT))) {
+                       od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
+               } else if (smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_PPT_BIT)) {
+                       od_percent_upper = 0;
+                       od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_7_ODSETTING_POWERPERCENTAGE]);
+               }
+       }
 
        dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
                                        od_percent_upper, od_percent_lower, power_limit);
index e7c4bef74aa46a37d0e1b4e87a78eee6f1c94b42..4b2ae27f0a57f2461a04f293a540c130a0fd17ee 100644 (file)
@@ -441,23 +441,21 @@ lt8912_connector_mode_valid(struct drm_connector *connector,
 static int lt8912_connector_get_modes(struct drm_connector *connector)
 {
        const struct drm_edid *drm_edid;
-       int ret = -1;
-       int num = 0;
        struct lt8912 *lt = connector_to_lt8912(connector);
        u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+       int ret, num;
 
        drm_edid = drm_bridge_edid_read(lt->hdmi_port, connector);
        drm_edid_connector_update(connector, drm_edid);
-       if (drm_edid) {
-               num = drm_edid_connector_add_modes(connector);
-       } else {
-               return ret;
-       }
+       if (!drm_edid)
+               return 0;
+
+       num = drm_edid_connector_add_modes(connector);
 
        ret = drm_display_info_set_bus_formats(&connector->display_info,
                                               &bus_format, 1);
-       if (ret)
-               num = ret;
+       if (ret < 0)
+               num = 0;
 
        drm_edid_free(drm_edid);
        return num;
index bcf8bccd86d6cc0a90f8bbba7a9cc76a64b3803b..f4f593ad8f79574604401eeb2bd819e5a3acbc7f 100644 (file)
@@ -294,8 +294,8 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
 static int lt9611uxc_connector_get_modes(struct drm_connector *connector)
 {
        struct lt9611uxc *lt9611uxc = connector_to_lt9611uxc(connector);
-       unsigned int count;
        const struct drm_edid *drm_edid;
+       int count;
 
        drm_edid = drm_bridge_edid_read(&lt9611uxc->bridge, connector);
        drm_edid_connector_update(connector, drm_edid);
index e814020bbcd3b3275d71174fe907c18ffeddefe0..cfbe020de54e0143162f7fea369a3bb458a50f13 100644 (file)
@@ -274,19 +274,24 @@ EXPORT_SYMBOL(drm_panel_disable);
  * The modes probed from the panel are automatically added to the connector
  * that the panel is attached to.
  *
- * Return: The number of modes available from the panel on success or a
- * negative error code on failure.
+ * Return: The number of modes available from the panel on success, or 0 on
+ * failure (no modes).
  */
 int drm_panel_get_modes(struct drm_panel *panel,
                        struct drm_connector *connector)
 {
        if (!panel)
-               return -EINVAL;
+               return 0;
 
-       if (panel->funcs && panel->funcs->get_modes)
-               return panel->funcs->get_modes(panel, connector);
+       if (panel->funcs && panel->funcs->get_modes) {
+               int num;
 
-       return -EOPNOTSUPP;
+               num = panel->funcs->get_modes(panel, connector);
+               if (num > 0)
+                       return num;
+       }
+
+       return 0;
 }
 EXPORT_SYMBOL(drm_panel_get_modes);
 
index 4d60cc810b577324f4c504ddadba2a23821fabd4..bf2dd1f46b6c4f17577c849a375114443a094a28 100644 (file)
@@ -422,6 +422,13 @@ static int drm_helper_probe_get_modes(struct drm_connector *connector)
 
        count = connector_funcs->get_modes(connector);
 
+       /* The .get_modes() callback should not return negative values. */
+       if (count < 0) {
+               drm_err(connector->dev, ".get_modes() returned %pe\n",
+                       ERR_PTR(count));
+               count = 0;
+       }
+
        /*
         * Fallback for when DDC probe failed in drm_get_edid() and thus skipped
         * override/firmware EDID.
index ca31bad6c5760dd9429df203a8a3d1c20d722a9f..f48c4343f4690f6dc288d1d8a1185a604d3c9152 100644 (file)
@@ -74,16 +74,15 @@ static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data,
 {
        struct exynos_dp_device *dp = to_dp(plat_data);
        struct drm_display_mode *mode;
-       int num_modes = 0;
 
        if (dp->plat_data.panel)
-               return num_modes;
+               return 0;
 
        mode = drm_mode_create(connector->dev);
        if (!mode) {
                DRM_DEV_ERROR(dp->dev,
                              "failed to create a new display mode.\n");
-               return num_modes;
+               return 0;
        }
 
        drm_display_mode_from_videomode(&dp->vm, mode);
@@ -94,7 +93,7 @@ static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data,
        drm_mode_set_name(mode);
        drm_mode_probed_add(connector, mode);
 
-       return num_modes + 1;
+       return 1;
 }
 
 static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
index 00382f28748ac0843653e1e1f1cf749590047468..f5bbba9ad225263ab72bc78aa696a6193794f1c6 100644 (file)
@@ -316,14 +316,14 @@ static int vidi_get_modes(struct drm_connector *connector)
         */
        if (!ctx->raw_edid) {
                DRM_DEV_DEBUG_KMS(ctx->dev, "raw_edid is null.\n");
-               return -EFAULT;
+               return 0;
        }
 
        edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
        edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
        if (!edid) {
                DRM_DEV_DEBUG_KMS(ctx->dev, "failed to allocate edid\n");
-               return -ENOMEM;
+               return 0;
        }
 
        drm_connector_update_edid_property(connector, edid);
index 43bed6cbaaea072e7c8860692739d4873a4d2c39..b1d02dec3774d095243597999359fde10fd9ad12 100644 (file)
@@ -887,11 +887,11 @@ static int hdmi_get_modes(struct drm_connector *connector)
        int ret;
 
        if (!hdata->ddc_adpt)
-               return -ENODEV;
+               return 0;
 
        edid = drm_get_edid(connector, hdata->ddc_adpt);
        if (!edid)
-               return -ENODEV;
+               return 0;
 
        hdata->dvi_mode = !connector->display_info.is_hdmi;
        DRM_DEV_DEBUG_KMS(hdata->dev, "%s : width[%d] x height[%d]\n",
index 99bdb833591ce1a44e14ae1df964d7166cfcf9e0..7862e7cefe02785b828d0e5769c4b511913f67c9 100644 (file)
@@ -411,7 +411,7 @@ TRACE_EVENT(intel_fbc_activate,
                           struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
                                                                         plane->pipe);
                           __assign_str(dev, __dev_name_kms(plane));
-                          __assign_str(name, plane->base.name)
+                          __assign_str(name, plane->base.name);
                           __entry->pipe = crtc->pipe;
                           __entry->frame = intel_crtc_get_vblank_counter(crtc);
                           __entry->scanline = intel_get_crtc_scanline(crtc);
@@ -438,7 +438,7 @@ TRACE_EVENT(intel_fbc_deactivate,
                           struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
                                                                         plane->pipe);
                           __assign_str(dev, __dev_name_kms(plane));
-                          __assign_str(name, plane->base.name)
+                          __assign_str(name, plane->base.name);
                           __entry->pipe = crtc->pipe;
                           __entry->frame = intel_crtc_get_vblank_counter(crtc);
                           __entry->scanline = intel_get_crtc_scanline(crtc);
@@ -465,7 +465,7 @@ TRACE_EVENT(intel_fbc_nuke,
                           struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
                                                                         plane->pipe);
                           __assign_str(dev, __dev_name_kms(plane));
-                          __assign_str(name, plane->base.name)
+                          __assign_str(name, plane->base.name);
                           __entry->pipe = crtc->pipe;
                           __entry->frame = intel_crtc_get_vblank_counter(crtc);
                           __entry->scanline = intel_get_crtc_scanline(crtc);
index 70349739dd89bed615e221fb00900fc4b53b496d..55dedd73f528c8842941a96f53eb82d4c2a863dc 100644 (file)
@@ -72,14 +72,14 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
                int ret;
 
                if (!mode)
-                       return -EINVAL;
+                       return 0;
 
                ret = of_get_drm_display_mode(np, &imxpd->mode,
                                              &imxpd->bus_flags,
                                              OF_USE_NATIVE_MODE);
                if (ret) {
                        drm_mode_destroy(connector->dev, mode);
-                       return ret;
+                       return 0;
                }
 
                drm_mode_copy(mode, &imxpd->mode);
index 56dcd25db1ce2c79b8a6be7c0ea684838e74e655..db8cbf6151129d63fd24e42626dfd10e4c84bb33 100644 (file)
@@ -1256,6 +1256,8 @@ out:
                        drm_vma_node_unmap(&nvbo->bo.base.vma_node,
                                           bdev->dev_mapping);
                        nouveau_ttm_io_mem_free_locked(drm, nvbo->bo.resource);
+                       nvbo->bo.resource->bus.offset = 0;
+                       nvbo->bo.resource->bus.addr = NULL;
                        goto retry;
                }
 
index 666eb93b1742ca5435cf0567e28e1664122bad8b..11b4c9c274a1a597cb3592019d873345c241d1cd 100644 (file)
@@ -41,7 +41,6 @@ r535_devinit_new(const struct nvkm_devinit_func *hw,
 
        rm->dtor = r535_devinit_dtor;
        rm->post = hw->post;
-       rm->disable = hw->disable;
 
        ret = nv50_devinit_new_(rm, device, type, inst, pdevinit);
        if (ret)
index a73a5b58979045b07468c1443940f87e1b151f67..9994cbd6f1c40c0c798498687f4f5d7168e883c5 100644 (file)
@@ -1430,6 +1430,10 @@ r535_gsp_msg_post_event(void *priv, u32 fn, void *repv, u32 repc)
 
 /**
  * r535_gsp_msg_run_cpu_sequencer() -- process I/O commands from the GSP
+ * @priv: gsp pointer
+ * @fn: function number (ignored)
+ * @repv: pointer to libos print RPC
+ * @repc: message size
  *
  * The GSP sequencer is a list of I/O commands that the GSP can send to
  * the driver to perform for various purposes.  The most common usage is to
@@ -1781,6 +1785,7 @@ static void create_pte_array(u64 *ptes, dma_addr_t addr, size_t size)
 
 /**
  * r535_gsp_libos_init() -- create the libos arguments structure
+ * @gsp: gsp pointer
  *
  * The logging buffers are byte queues that contain encoded printf-like
  * messages from GSP-RM.  They need to be decoded by a special application
@@ -1920,6 +1925,10 @@ nvkm_gsp_radix3_dtor(struct nvkm_gsp *gsp, struct nvkm_gsp_radix3 *rx3)
 
 /**
  * nvkm_gsp_radix3_sg - build a radix3 table from a S/G list
+ * @gsp: gsp pointer
+ * @sgt: S/G list to traverse
+ * @size: size of the image, in bytes
+ * @rx3: radix3 array to update
  *
  * The GSP uses a three-level page table, called radix3, to map the firmware.
  * Each 64-bit "pointer" in the table is either the bus address of an entry in
index 69001a3dc0df23380d4e5f3a3c973b9c73ba3065..2d1880c61b50d1316c3119c0d2fa2ac733d3396b 100644 (file)
@@ -166,7 +166,7 @@ sun4i_hdmi_connector_clock_valid(const struct drm_connector *connector,
                                 unsigned long long clock)
 {
        const struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector);
-       unsigned long diff = clock / 200; /* +-0.5% allowed by HDMI spec */
+       unsigned long diff = div_u64(clock, 200); /* +-0.5% allowed by HDMI spec */
        long rounded_rate;
 
        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
index 34f807ed1c315e3cb0cd53a59d34eb36c3bceec4..d8751ea2030329ccd1cc7ab4b72dd7b9fe63538f 100644 (file)
@@ -509,7 +509,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
        edid = drm_get_edid(connector, vc4_hdmi->ddc);
        cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid);
        if (!edid)
-               return -ENODEV;
+               return 0;
 
        drm_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
index 952496c6260dfb5c3e9f798137cd4737a4040acb..826c8b389672502dfebd6e89c6c1997bf8f0c9a2 100644 (file)
@@ -235,6 +235,29 @@ retry:
                        goto err_unlock_list;
        }
 
+       if (!args->num_batch_buffer) {
+               err = xe_vm_lock(vm, true);
+               if (err)
+                       goto err_unlock_list;
+
+               if (!xe_vm_in_lr_mode(vm)) {
+                       struct dma_fence *fence;
+
+                       fence = xe_sync_in_fence_get(syncs, num_syncs, q, vm);
+                       if (IS_ERR(fence)) {
+                               err = PTR_ERR(fence);
+                               goto err_unlock_list;
+                       }
+                       for (i = 0; i < num_syncs; i++)
+                               xe_sync_entry_signal(&syncs[i], NULL, fence);
+                       xe_exec_queue_last_fence_set(q, vm, fence);
+                       dma_fence_put(fence);
+               }
+
+               xe_vm_unlock(vm);
+               goto err_unlock_list;
+       }
+
        vm_exec.vm = &vm->gpuvm;
        vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
        if (xe_vm_in_lr_mode(vm)) {
@@ -254,24 +277,6 @@ retry:
                goto err_exec;
        }
 
-       if (!args->num_batch_buffer) {
-               if (!xe_vm_in_lr_mode(vm)) {
-                       struct dma_fence *fence;
-
-                       fence = xe_sync_in_fence_get(syncs, num_syncs, q, vm);
-                       if (IS_ERR(fence)) {
-                               err = PTR_ERR(fence);
-                               goto err_exec;
-                       }
-                       for (i = 0; i < num_syncs; i++)
-                               xe_sync_entry_signal(&syncs[i], NULL, fence);
-                       xe_exec_queue_last_fence_set(q, vm, fence);
-                       dma_fence_put(fence);
-               }
-
-               goto err_exec;
-       }
-
        if (xe_exec_queue_is_lr(q) && xe_exec_queue_ring_full(q)) {
                err = -EWOULDBLOCK;     /* Aliased to -EAGAIN */
                skip_retry = true;
index 73c535193a984b385f65986c9b1c0d3b79f1f5b4..241c294270d9167f25d1898f8f590c7aabb06ca0 100644 (file)
@@ -69,7 +69,7 @@ static bool access_is_atomic(enum access_type access_type)
 static bool vma_is_valid(struct xe_tile *tile, struct xe_vma *vma)
 {
        return BIT(tile->id) & vma->tile_present &&
-               !(BIT(tile->id) & vma->usm.tile_invalidated);
+               !(BIT(tile->id) & vma->tile_invalidated);
 }
 
 static bool vma_matches(struct xe_vma *vma, u64 page_addr)
@@ -226,7 +226,7 @@ retry_userptr:
 
        if (xe_vma_is_userptr(vma))
                ret = xe_vma_userptr_check_repin(to_userptr_vma(vma));
-       vma->usm.tile_invalidated &= ~BIT(tile->id);
+       vma->tile_invalidated &= ~BIT(tile->id);
 
 unlock_dma_resv:
        drm_exec_fini(&exec);
index 4ddc55527f9ab3e632635c5f920d4f4420df1255..846f14507d5ff2ed47ff8c0c4dac573e584ade89 100644 (file)
@@ -468,7 +468,7 @@ DEFINE_EVENT(xe_vma, xe_vma_userptr_invalidate,
             TP_ARGS(vma)
 );
 
-DEFINE_EVENT(xe_vma, xe_vma_usm_invalidate,
+DEFINE_EVENT(xe_vma, xe_vma_invalidate,
             TP_PROTO(struct xe_vma *vma),
             TP_ARGS(vma)
 );
index d28260351af2e330c16dbbf94609f19b285d1806..f88faef4142bde018f336d33d3e2eed726a4bc29 100644 (file)
@@ -708,6 +708,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
        int err = 0;
        LIST_HEAD(tmp_evict);
 
+       xe_assert(vm->xe, !xe_vm_in_fault_mode(vm));
        lockdep_assert_held_write(&vm->lock);
 
        /* Collect invalidated userptrs */
@@ -724,11 +725,27 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
        list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list,
                                 userptr.repin_link) {
                err = xe_vma_userptr_pin_pages(uvma);
-               if (err < 0)
-                       return err;
+               if (err == -EFAULT) {
+                       list_del_init(&uvma->userptr.repin_link);
 
-               list_del_init(&uvma->userptr.repin_link);
-               list_move_tail(&uvma->vma.combined_links.rebind, &vm->rebind_list);
+                       /* Wait for pending binds */
+                       xe_vm_lock(vm, false);
+                       dma_resv_wait_timeout(xe_vm_resv(vm),
+                                             DMA_RESV_USAGE_BOOKKEEP,
+                                             false, MAX_SCHEDULE_TIMEOUT);
+
+                       err = xe_vm_invalidate_vma(&uvma->vma);
+                       xe_vm_unlock(vm);
+                       if (err)
+                               return err;
+               } else {
+                       if (err < 0)
+                               return err;
+
+                       list_del_init(&uvma->userptr.repin_link);
+                       list_move_tail(&uvma->vma.combined_links.rebind,
+                                      &vm->rebind_list);
+               }
        }
 
        return 0;
@@ -2024,7 +2041,7 @@ static int xe_vm_prefetch(struct xe_vm *vm, struct xe_vma *vma,
                        return err;
        }
 
-       if (vma->tile_mask != (vma->tile_present & ~vma->usm.tile_invalidated)) {
+       if (vma->tile_mask != (vma->tile_present & ~vma->tile_invalidated)) {
                return xe_vm_bind(vm, vma, q, xe_vma_bo(vma), syncs, num_syncs,
                                  true, first_op, last_op);
        } else {
@@ -3214,9 +3231,8 @@ int xe_vm_invalidate_vma(struct xe_vma *vma)
        u8 id;
        int ret;
 
-       xe_assert(xe, xe_vm_in_fault_mode(xe_vma_vm(vma)));
        xe_assert(xe, !xe_vma_is_null(vma));
-       trace_xe_vma_usm_invalidate(vma);
+       trace_xe_vma_invalidate(vma);
 
        /* Check that we don't race with page-table updates */
        if (IS_ENABLED(CONFIG_PROVE_LOCKING)) {
@@ -3254,7 +3270,7 @@ int xe_vm_invalidate_vma(struct xe_vma *vma)
                }
        }
 
-       vma->usm.tile_invalidated = vma->tile_mask;
+       vma->tile_invalidated = vma->tile_mask;
 
        return 0;
 }
index 79b5cab57711995a6dc3938f5269d73efddee95e..ae5fb565f6bf48d52e29c811a8333793e4e128fd 100644 (file)
@@ -84,11 +84,8 @@ struct xe_vma {
                struct work_struct destroy_work;
        };
 
-       /** @usm: unified shared memory state */
-       struct {
-               /** @tile_invalidated: VMA has been invalidated */
-               u8 tile_invalidated;
-       } usm;
+       /** @tile_invalidated: VMA has been invalidated */
+       u8 tile_invalidated;
 
        /** @tile_mask: Tile mask of where to create binding for this VMA */
        u8 tile_mask;
index 079cc283a18667b4eb0dcbf3fa021d1db09d7b32..c5f6b5a5d1176e516b4dd23db45ce736e04bb5d0 100644 (file)
@@ -111,8 +111,10 @@ void xe_vram_freq_sysfs_init(struct xe_tile *tile)
                return;
 
        kobj = kobject_create_and_add("memory", tile->sysfs);
-       if (!kobj)
+       if (!kobj) {
                drm_warn(&xe->drm, "failed to add memory directory, err: %d\n", -ENOMEM);
+               return;
+       }
 
        err = sysfs_create_group(kobj, &freq_group_attrs);
        if (err) {
index 84660729538b95cb8624080490025a68cba4fa54..a6e1cca06172f52d6f35b05da94642dbc3221ee4 100644 (file)
@@ -166,7 +166,7 @@ static const struct dev_pm_ops gb_bundle_pm_ops = {
        SET_RUNTIME_PM_OPS(gb_bundle_suspend, gb_bundle_resume, gb_bundle_idle)
 };
 
-struct device_type greybus_bundle_type = {
+const struct device_type greybus_bundle_type = {
        .name =         "greybus_bundle",
        .release =      gb_bundle_release,
        .pm =           &gb_bundle_pm_ops,
index 359a2584197397dc5351fa0f01b1c3ac5a79444f..b5cf49d09df229c79dda7efe78015a009d01bf6b 100644 (file)
@@ -436,7 +436,7 @@ static void gb_control_release(struct device *dev)
        kfree(control);
 }
 
-struct device_type greybus_control_type = {
+const struct device_type greybus_control_type = {
        .name =         "greybus_control",
        .release =      gb_control_release,
 };
index 5714be7404707b767da8d7dc7b6ad19a57769410..95c09d4f3a8695108b9b9a88ca862bc614bb7e13 100644 (file)
@@ -27,6 +27,36 @@ int greybus_disabled(void)
 }
 EXPORT_SYMBOL_GPL(greybus_disabled);
 
+static int is_gb_host_device(const struct device *dev)
+{
+       return dev->type == &greybus_hd_type;
+}
+
+static int is_gb_module(const struct device *dev)
+{
+       return dev->type == &greybus_module_type;
+}
+
+static int is_gb_interface(const struct device *dev)
+{
+       return dev->type == &greybus_interface_type;
+}
+
+static int is_gb_control(const struct device *dev)
+{
+       return dev->type == &greybus_control_type;
+}
+
+static int is_gb_bundle(const struct device *dev)
+{
+       return dev->type == &greybus_bundle_type;
+}
+
+static int is_gb_svc(const struct device *dev)
+{
+       return dev->type == &greybus_svc_type;
+}
+
 static bool greybus_match_one_id(struct gb_bundle *bundle,
                                 const struct greybus_bundle_id *id)
 {
@@ -155,7 +185,7 @@ static void greybus_shutdown(struct device *dev)
        }
 }
 
-struct bus_type greybus_bus_type = {
+const struct bus_type greybus_bus_type = {
        .name =         "greybus",
        .match =        greybus_match_device,
        .uevent =       greybus_uevent,
index e89cca015095552ab04d98ccf144f0835a152aa1..1ee78d0d90b4d46b78d5876917c45a21966e9aff 100644 (file)
@@ -513,16 +513,16 @@ static int es2_cport_allocate(struct gb_host_device *hd, int cport_id,
 
        if (cport_id < 0) {
                ida_start = 0;
-               ida_end = hd->num_cports;
+               ida_end = hd->num_cports - 1;
        } else if (cport_id < hd->num_cports) {
                ida_start = cport_id;
-               ida_end = cport_id + 1;
+               ida_end = cport_id;
        } else {
                dev_err(&hd->dev, "cport %d not available\n", cport_id);
                return -EINVAL;
        }
 
-       return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
+       return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL);
 }
 
 static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
@@ -535,7 +535,7 @@ static void es2_cport_release(struct gb_host_device *hd, u16 cport_id)
                return;
        }
 
-       ida_simple_remove(&hd->cport_id_map, cport_id);
+       ida_free(&hd->cport_id_map, cport_id);
 }
 
 static int cport_enable(struct gb_host_device *hd, u16 cport_id,
index c3e90025064bdec9ac5cf7de150d708fbecae03a..33f8fad70260a45c6d0042871c9b4e3dff293bb5 100644 (file)
@@ -271,7 +271,7 @@ static void hdlc_rx_frame(struct gb_beagleplay *bg)
        }
 }
 
-static ssize_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count)
+static size_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count)
 {
        size_t i;
        u8 c;
@@ -331,8 +331,8 @@ static void hdlc_deinit(struct gb_beagleplay *bg)
        flush_work(&bg->tx_work);
 }
 
-static ssize_t gb_tty_receive(struct serdev_device *sd, const u8 *data,
-                             size_t count)
+static size_t gb_tty_receive(struct serdev_device *sd, const u8 *data,
+                            size_t count)
 {
        struct gb_beagleplay *bg = serdev_device_get_drvdata(sd);
 
index 72b21bf2d7d36a85cbfd05d261d760fa37f16205..5de98d9177f151103aecb17ce97f421838c3c3f7 100644 (file)
@@ -50,7 +50,7 @@ int gb_hd_cport_reserve(struct gb_host_device *hd, u16 cport_id)
        struct ida *id_map = &hd->cport_id_map;
        int ret;
 
-       ret = ida_simple_get(id_map, cport_id, cport_id + 1, GFP_KERNEL);
+       ret = ida_alloc_range(id_map, cport_id, cport_id, GFP_KERNEL);
        if (ret < 0) {
                dev_err(&hd->dev, "failed to reserve cport %u\n", cport_id);
                return ret;
@@ -64,7 +64,7 @@ void gb_hd_cport_release_reserved(struct gb_host_device *hd, u16 cport_id)
 {
        struct ida *id_map = &hd->cport_id_map;
 
-       ida_simple_remove(id_map, cport_id);
+       ida_free(id_map, cport_id);
 }
 EXPORT_SYMBOL_GPL(gb_hd_cport_release_reserved);
 
@@ -80,16 +80,16 @@ int gb_hd_cport_allocate(struct gb_host_device *hd, int cport_id,
 
        if (cport_id < 0) {
                ida_start = 0;
-               ida_end = hd->num_cports;
+               ida_end = hd->num_cports - 1;
        } else if (cport_id < hd->num_cports) {
                ida_start = cport_id;
-               ida_end = cport_id + 1;
+               ida_end = cport_id;
        } else {
                dev_err(&hd->dev, "cport %d not available\n", cport_id);
                return -EINVAL;
        }
 
-       return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
+       return ida_alloc_range(id_map, ida_start, ida_end, GFP_KERNEL);
 }
 
 /* Locking: Caller guarantees serialisation */
@@ -100,7 +100,7 @@ void gb_hd_cport_release(struct gb_host_device *hd, u16 cport_id)
                return;
        }
 
-       ida_simple_remove(&hd->cport_id_map, cport_id);
+       ida_free(&hd->cport_id_map, cport_id);
 }
 
 static void gb_hd_release(struct device *dev)
@@ -111,12 +111,12 @@ static void gb_hd_release(struct device *dev)
 
        if (hd->svc)
                gb_svc_put(hd->svc);
-       ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
+       ida_free(&gb_hd_bus_id_map, hd->bus_id);
        ida_destroy(&hd->cport_id_map);
        kfree(hd);
 }
 
-struct device_type greybus_hd_type = {
+const struct device_type greybus_hd_type = {
        .name           = "greybus_host_device",
        .release        = gb_hd_release,
 };
@@ -162,7 +162,7 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
        if (!hd)
                return ERR_PTR(-ENOMEM);
 
-       ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL);
+       ret = ida_alloc_min(&gb_hd_bus_id_map, 1, GFP_KERNEL);
        if (ret < 0) {
                kfree(hd);
                return ERR_PTR(ret);
index 9ec949a438ef6752607a5ac2708294f12879ce64..fd58a86b0888dba7772400fd67a9d200a5071e2c 100644 (file)
@@ -131,9 +131,8 @@ static int gb_interface_route_create(struct gb_interface *intf)
        int ret;
 
        /* Allocate an interface device id. */
-       ret = ida_simple_get(&svc->device_id_map,
-                            GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1,
-                            GFP_KERNEL);
+       ret = ida_alloc_range(&svc->device_id_map, GB_SVC_DEVICE_ID_MIN,
+                             GB_SVC_DEVICE_ID_MAX, GFP_KERNEL);
        if (ret < 0) {
                dev_err(&intf->dev, "failed to allocate device id: %d\n", ret);
                return ret;
@@ -165,7 +164,7 @@ err_svc_id_free:
         * XXX anymore.
         */
 err_ida_remove:
-       ida_simple_remove(&svc->device_id_map, device_id);
+       ida_free(&svc->device_id_map, device_id);
 
        return ret;
 }
@@ -178,7 +177,7 @@ static void gb_interface_route_destroy(struct gb_interface *intf)
                return;
 
        gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id);
-       ida_simple_remove(&svc->device_id_map, intf->device_id);
+       ida_free(&svc->device_id_map, intf->device_id);
        intf->device_id = GB_INTERFACE_DEVICE_ID_BAD;
 }
 
@@ -765,7 +764,7 @@ static const struct dev_pm_ops gb_interface_pm_ops = {
                           gb_interface_runtime_idle)
 };
 
-struct device_type greybus_interface_type = {
+const struct device_type greybus_interface_type = {
        .name =         "greybus_interface",
        .release =      gb_interface_release,
        .pm =           &gb_interface_pm_ops,
index 36f77f9e1d7439eaf9c16e871a3fd28a6a218bf5..7f7153a1dd602c1e7cf0bfb887009808c919ebf0 100644 (file)
@@ -81,7 +81,7 @@ static void gb_module_release(struct device *dev)
        kfree(module);
 }
 
-struct device_type greybus_module_type = {
+const struct device_type greybus_module_type = {
        .name           = "greybus_module",
        .release        = gb_module_release,
 };
index 0d7e749174a48c65eeb0c5918f68ed75b2726613..4256467fcd35976e011a5f226be38387ce9199b7 100644 (file)
@@ -1305,7 +1305,7 @@ static void gb_svc_release(struct device *dev)
        kfree(svc);
 }
 
-struct device_type greybus_svc_type = {
+const struct device_type greybus_svc_type = {
        .name           = "greybus_svc",
        .release        = gb_svc_release,
 };
index 00242107d62e02ccca5b033ae12e5e2538df7696..862c47b191afe85b7aaf18fde71d46c8ec4c852b 100644 (file)
@@ -16,6 +16,7 @@ config HYPERV
 config HYPERV_VTL_MODE
        bool "Enable Linux to boot in VTL context"
        depends on X86_64 && HYPERV
+       depends on SMP
        default n
        help
          Virtual Secure Mode (VSM) is a set of hypervisor capabilities and
index 51e5018ac9b26cb682ff21cc3cd23461a632658d..a8ad728354cb097621db497cd48251861a0f1016 100644 (file)
@@ -270,7 +270,7 @@ void hv_synic_enable_regs(unsigned int cpu)
        union hv_synic_scontrol sctrl;
 
        /* Setup the Synic's message page */
-       simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP);
+       simp.as_uint64 = hv_get_msr(HV_MSR_SIMP);
        simp.simp_enabled = 1;
 
        if (ms_hyperv.paravisor_present || hv_root_partition) {
@@ -286,10 +286,10 @@ void hv_synic_enable_regs(unsigned int cpu)
                        >> HV_HYP_PAGE_SHIFT;
        }
 
-       hv_set_register(HV_REGISTER_SIMP, simp.as_uint64);
+       hv_set_msr(HV_MSR_SIMP, simp.as_uint64);
 
        /* Setup the Synic's event page */
-       siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
+       siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP);
        siefp.siefp_enabled = 1;
 
        if (ms_hyperv.paravisor_present || hv_root_partition) {
@@ -305,13 +305,12 @@ void hv_synic_enable_regs(unsigned int cpu)
                        >> HV_HYP_PAGE_SHIFT;
        }
 
-       hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64);
+       hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64);
 
        /* Setup the shared SINT. */
        if (vmbus_irq != -1)
                enable_percpu_irq(vmbus_irq, 0);
-       shared_sint.as_uint64 = hv_get_register(HV_REGISTER_SINT0 +
-                                       VMBUS_MESSAGE_SINT);
+       shared_sint.as_uint64 = hv_get_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT);
 
        shared_sint.vector = vmbus_interrupt;
        shared_sint.masked = false;
@@ -326,14 +325,13 @@ void hv_synic_enable_regs(unsigned int cpu)
 #else
        shared_sint.auto_eoi = 0;
 #endif
-       hv_set_register(HV_REGISTER_SINT0 + VMBUS_MESSAGE_SINT,
-                               shared_sint.as_uint64);
+       hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
 
        /* Enable the global synic bit */
-       sctrl.as_uint64 = hv_get_register(HV_REGISTER_SCONTROL);
+       sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL);
        sctrl.enable = 1;
 
-       hv_set_register(HV_REGISTER_SCONTROL, sctrl.as_uint64);
+       hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
 }
 
 int hv_synic_init(unsigned int cpu)
@@ -357,17 +355,15 @@ void hv_synic_disable_regs(unsigned int cpu)
        union hv_synic_siefp siefp;
        union hv_synic_scontrol sctrl;
 
-       shared_sint.as_uint64 = hv_get_register(HV_REGISTER_SINT0 +
-                                       VMBUS_MESSAGE_SINT);
+       shared_sint.as_uint64 = hv_get_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT);
 
        shared_sint.masked = 1;
 
        /* Need to correctly cleanup in the case of SMP!!! */
        /* Disable the interrupt */
-       hv_set_register(HV_REGISTER_SINT0 + VMBUS_MESSAGE_SINT,
-                               shared_sint.as_uint64);
+       hv_set_msr(HV_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
 
-       simp.as_uint64 = hv_get_register(HV_REGISTER_SIMP);
+       simp.as_uint64 = hv_get_msr(HV_MSR_SIMP);
        /*
         * In Isolation VM, sim and sief pages are allocated by
         * paravisor. These pages also will be used by kdump
@@ -382,9 +378,9 @@ void hv_synic_disable_regs(unsigned int cpu)
                simp.base_simp_gpa = 0;
        }
 
-       hv_set_register(HV_REGISTER_SIMP, simp.as_uint64);
+       hv_set_msr(HV_MSR_SIMP, simp.as_uint64);
 
-       siefp.as_uint64 = hv_get_register(HV_REGISTER_SIEFP);
+       siefp.as_uint64 = hv_get_msr(HV_MSR_SIEFP);
        siefp.siefp_enabled = 0;
 
        if (ms_hyperv.paravisor_present || hv_root_partition) {
@@ -394,12 +390,12 @@ void hv_synic_disable_regs(unsigned int cpu)
                siefp.base_siefp_gpa = 0;
        }
 
-       hv_set_register(HV_REGISTER_SIEFP, siefp.as_uint64);
+       hv_set_msr(HV_MSR_SIEFP, siefp.as_uint64);
 
        /* Disable the global synic bit */
-       sctrl.as_uint64 = hv_get_register(HV_REGISTER_SCONTROL);
+       sctrl.as_uint64 = hv_get_msr(HV_MSR_SCONTROL);
        sctrl.enable = 0;
-       hv_set_register(HV_REGISTER_SCONTROL, sctrl.as_uint64);
+       hv_set_msr(HV_MSR_SCONTROL, sctrl.as_uint64);
 
        if (vmbus_irq != -1)
                disable_percpu_irq(vmbus_irq);
index 0285a74363b3d11e35b2e29aa86e1861e1900f00..dde3f9b6871af9eb68f1cd8931651a0250943fe0 100644 (file)
 #include <linux/sched/task_stack.h>
 #include <linux/panic_notifier.h>
 #include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/efi.h>
 #include <linux/kdebug.h>
 #include <linux/kmsg_dump.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/dma-map-ops.h>
 #include <linux/set_memory.h>
@@ -227,19 +230,19 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper,
         * contain the size of the panic data in that page. Rest of the
         * registers are no-op when the NOTIFY_MSG flag is set.
         */
-       hv_set_register(HV_REGISTER_CRASH_P0, 0);
-       hv_set_register(HV_REGISTER_CRASH_P1, 0);
-       hv_set_register(HV_REGISTER_CRASH_P2, 0);
-       hv_set_register(HV_REGISTER_CRASH_P3, virt_to_phys(hv_panic_page));
-       hv_set_register(HV_REGISTER_CRASH_P4, bytes_written);
+       hv_set_msr(HV_MSR_CRASH_P0, 0);
+       hv_set_msr(HV_MSR_CRASH_P1, 0);
+       hv_set_msr(HV_MSR_CRASH_P2, 0);
+       hv_set_msr(HV_MSR_CRASH_P3, virt_to_phys(hv_panic_page));
+       hv_set_msr(HV_MSR_CRASH_P4, bytes_written);
 
        /*
         * Let Hyper-V know there is crash data available along with
         * the panic message.
         */
-       hv_set_register(HV_REGISTER_CRASH_CTL,
-                       (HV_CRASH_CTL_CRASH_NOTIFY |
-                        HV_CRASH_CTL_CRASH_NOTIFY_MSG));
+       hv_set_msr(HV_MSR_CRASH_CTL,
+                  (HV_CRASH_CTL_CRASH_NOTIFY |
+                   HV_CRASH_CTL_CRASH_NOTIFY_MSG));
 }
 
 static struct kmsg_dumper hv_kmsg_dumper = {
@@ -278,6 +281,14 @@ static void hv_kmsg_dump_register(void)
 int __init hv_common_init(void)
 {
        int i;
+       union hv_hypervisor_version_info version;
+
+       /* Get information about the Hyper-V host version */
+       if (!hv_get_hypervisor_version(&version))
+               pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
+                       version.major_version, version.minor_version,
+                       version.build_number, version.service_number,
+                       version.service_pack, version.service_branch);
 
        if (hv_is_isolation_supported())
                sysctl_record_panic_msg = 0;
@@ -310,7 +321,7 @@ int __init hv_common_init(void)
                 * Register for panic kmsg callback only if the right
                 * capability is supported by the hypervisor.
                 */
-               hyperv_crash_ctl = hv_get_register(HV_REGISTER_CRASH_CTL);
+               hyperv_crash_ctl = hv_get_msr(HV_MSR_CRASH_CTL);
                if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG)
                        hv_kmsg_dump_register();
 
@@ -347,6 +358,72 @@ int __init hv_common_init(void)
        return 0;
 }
 
+void __init ms_hyperv_late_init(void)
+{
+       struct acpi_table_header *header;
+       acpi_status status;
+       u8 *randomdata;
+       u32 length, i;
+
+       /*
+        * Seed the Linux random number generator with entropy provided by
+        * the Hyper-V host in ACPI table OEM0.
+        */
+       if (!IS_ENABLED(CONFIG_ACPI))
+               return;
+
+       status = acpi_get_table("OEM0", 0, &header);
+       if (ACPI_FAILURE(status) || !header)
+               return;
+
+       /*
+        * Since the "OEM0" table name is for OEM specific usage, verify
+        * that what we're seeing purports to be from Microsoft.
+        */
+       if (strncmp(header->oem_table_id, "MICROSFT", 8))
+               goto error;
+
+       /*
+        * Ensure the length is reasonable. Requiring at least 8 bytes and
+        * no more than 4K bytes is somewhat arbitrary and just protects
+        * against a malformed table. Hyper-V currently provides 64 bytes,
+        * but allow for a change in a later version.
+        */
+       if (header->length < sizeof(*header) + 8 ||
+           header->length > sizeof(*header) + SZ_4K)
+               goto error;
+
+       length = header->length - sizeof(*header);
+       randomdata = (u8 *)(header + 1);
+
+       pr_debug("Hyper-V: Seeding rng with %d random bytes from ACPI table OEM0\n",
+                       length);
+
+       add_bootloader_randomness(randomdata, length);
+
+       /*
+        * To prevent the seed data from being visible in /sys/firmware/acpi,
+        * zero out the random data in the ACPI table and fixup the checksum.
+        * The zero'ing is done out of an abundance of caution in avoiding
+        * potential security risks to the rng. Similarly, reset the table
+        * length to just the header size so that a subsequent kexec doesn't
+        * try to use the zero'ed out random data.
+        */
+       for (i = 0; i < length; i++) {
+               header->checksum += randomdata[i];
+               randomdata[i] = 0;
+       }
+
+       for (i = 0; i < sizeof(header->length); i++)
+               header->checksum += ((u8 *)&header->length)[i];
+       header->length = sizeof(*header);
+       for (i = 0; i < sizeof(header->length); i++)
+               header->checksum -= ((u8 *)&header->length)[i];
+
+error:
+       acpi_put_table(header);
+}
+
 /*
  * Hyper-V specific initialization and die code for
  * individual CPUs that is common across all architectures.
@@ -409,7 +486,7 @@ int hv_common_cpu_init(unsigned int cpu)
                *inputarg = mem;
        }
 
-       msr_vp_index = hv_get_register(HV_REGISTER_VP_INDEX);
+       msr_vp_index = hv_get_msr(HV_MSR_VP_INDEX);
 
        hv_vp_index[cpu] = msr_vp_index;
 
@@ -506,7 +583,7 @@ EXPORT_SYMBOL_GPL(hv_is_hibernation_supported);
  */
 static u64 __hv_read_ref_counter(void)
 {
-       return hv_get_register(HV_REGISTER_TIME_REF_COUNT);
+       return hv_get_msr(HV_MSR_TIME_REF_COUNT);
 }
 
 u64 (*hv_read_reference_counter)(void) = __hv_read_ref_counter;
index 7f7965f3d187884d87a2a822c3479485e17cec62..4cb17603a8289b259e64dc6a5be215cb1e1a8a57 100644 (file)
@@ -2359,10 +2359,9 @@ static int vmbus_platform_driver_probe(struct platform_device *pdev)
                return vmbus_acpi_add(pdev);
 }
 
-static int vmbus_platform_driver_remove(struct platform_device *pdev)
+static void vmbus_platform_driver_remove(struct platform_device *pdev)
 {
        vmbus_mmio_remove();
-       return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -2542,7 +2541,7 @@ static const struct dev_pm_ops vmbus_bus_pm = {
 
 static struct platform_driver vmbus_platform_driver = {
        .probe = vmbus_platform_driver_probe,
-       .remove = vmbus_platform_driver_remove,
+       .remove_new = vmbus_platform_driver_remove,
        .driver = {
                .name = "vmbus",
                .acpi_match_table = ACPI_PTR(vmbus_acpi_device_ids),
index a9fd9ca45f2a893a37386f6c3256c67e0e4525c1..27b47b8623c09cca9c3d8da8cd6bf38f27f28f14 100644 (file)
@@ -74,17 +74,12 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = {
 
 static int omap_hwspinlock_probe(struct platform_device *pdev)
 {
-       struct device_node *node = pdev->dev.of_node;
        struct hwspinlock_device *bank;
-       struct hwspinlock *hwlock;
        void __iomem *io_base;
        int num_locks, i, ret;
        /* Only a single hwspinlock block device is supported */
        int base_id = 0;
 
-       if (!node)
-               return -ENODEV;
-
        io_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(io_base))
                return PTR_ERR(io_base);
@@ -93,10 +88,10 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
         * make sure the module is enabled and clocked before reading
         * the module SYSSTATUS register
         */
-       pm_runtime_enable(&pdev->dev);
+       devm_pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret < 0)
-               goto runtime_err;
+               return ret;
 
        /* Determine number of locks */
        i = readl(io_base + SYSSTATUS_OFFSET);
@@ -108,55 +103,24 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
         */
        ret = pm_runtime_put(&pdev->dev);
        if (ret < 0)
-               goto runtime_err;
+               return ret;
 
        /* one of the four lsb's must be set, and nothing else */
-       if (hweight_long(i & 0xf) != 1 || i > 8) {
-               ret = -EINVAL;
-               goto runtime_err;
-       }
+       if (hweight_long(i & 0xf) != 1 || i > 8)
+               return -EINVAL;
 
        num_locks = i * 32; /* actual number of locks in this device */
 
        bank = devm_kzalloc(&pdev->dev, struct_size(bank, lock, num_locks),
                            GFP_KERNEL);
-       if (!bank) {
-               ret = -ENOMEM;
-               goto runtime_err;
-       }
-
-       platform_set_drvdata(pdev, bank);
+       if (!bank)
+               return -ENOMEM;
 
-       for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
-               hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
+       for (i = 0; i < num_locks; i++)
+               bank->lock[i].priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
 
-       ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
+       return devm_hwspin_lock_register(&pdev->dev, bank, &omap_hwspinlock_ops,
                                                base_id, num_locks);
-       if (ret)
-               goto runtime_err;
-
-       dev_dbg(&pdev->dev, "Registered %d locks with HwSpinlock core\n",
-               num_locks);
-
-       return 0;
-
-runtime_err:
-       pm_runtime_disable(&pdev->dev);
-       return ret;
-}
-
-static void omap_hwspinlock_remove(struct platform_device *pdev)
-{
-       struct hwspinlock_device *bank = platform_get_drvdata(pdev);
-       int ret;
-
-       ret = hwspin_lock_unregister(bank);
-       if (ret) {
-               dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
-               return;
-       }
-
-       pm_runtime_disable(&pdev->dev);
 }
 
 static const struct of_device_id omap_hwspinlock_of_match[] = {
@@ -169,7 +133,6 @@ MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match);
 
 static struct platform_driver omap_hwspinlock_driver = {
        .probe          = omap_hwspinlock_probe,
-       .remove_new     = omap_hwspinlock_remove,
        .driver         = {
                .name   = "omap_hwspinlock",
                .of_match_table = omap_hwspinlock_of_match,
index 995d3b2c76df2d08c9ae26e7c5747621f71ac278..4ba478211b318ea5305f9f98dda40a041759f09f 100644 (file)
@@ -2,6 +2,26 @@
 #
 # Makefile for CoreSight drivers.
 #
+
+# Current W=1 warnings
+subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter
+subdir-ccflags-y += -Wmissing-declarations
+subdir-ccflags-y += -Wmissing-format-attribute
+subdir-ccflags-y += -Wmissing-prototypes
+subdir-ccflags-y += -Wold-style-definition
+subdir-ccflags-y += -Wmissing-include-dirs
+subdir-ccflags-y += -Wno-sign-compare
+condflags := \
+       $(call cc-option, -Wrestrict)                           \
+       $(call cc-option, -Wunused-but-set-variable)            \
+       $(call cc-option, -Wunused-const-variable)              \
+       $(call cc-option, -Wpacked-not-aligned)                 \
+       $(call cc-option, -Wformat-overflow)                    \
+       $(call cc-option, -Wformat-truncation)                  \
+       $(call cc-option, -Wstringop-overflow)                  \
+       $(call cc-option, -Wstringop-truncation)
+subdir-ccflags-y += $(condflags)
+
 obj-$(CONFIG_CORESIGHT) += coresight.o
 coresight-y := coresight-core.o  coresight-etm-perf.o coresight-platform.o \
                coresight-sysfs.o coresight-syscfg.o coresight-config.o \
index 84b31184252bb2f127e35b61e41e5cd43e554153..e794f2e145fad35a3fc835ea2d50b580d8889966 100644 (file)
@@ -9,6 +9,7 @@
 /* ETMv4 includes and features */
 #if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X)
 #include "coresight-etm4x-cfg.h"
+#include "coresight-cfg-preload.h"
 
 /* preload configurations and features */
 
index d7f0e231feb993458c375caae733279451432ca4..b83613e342891bf43b97ebeef87fcfa894fe1487 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/types.h>
 #include <linux/device.h>
 #include <linux/io.h>
-#include <linux/idr.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/slab.h>
 #include "coresight-priv.h"
 #include "coresight-syscfg.h"
 
-static DEFINE_MUTEX(coresight_mutex);
-static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
-
 /*
- * Use IDR to map the hash of the source's device name
- * to the pointer of path for the source. The idr is for
- * the sources which aren't associated with CPU.
+ * Mutex used to lock all sysfs enable and disable actions and loading and
+ * unloading devices by the Coresight core.
  */
-static DEFINE_IDR(path_idr);
+DEFINE_MUTEX(coresight_mutex);
+static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
 
 /**
  * struct coresight_node - elements of a path, from source to sink
@@ -45,12 +41,6 @@ struct coresight_node {
        struct list_head link;
 };
 
-/*
- * When operating Coresight drivers from the sysFS interface, only a single
- * path can exist from a tracer (associated to a CPU) to a sink.
- */
-static DEFINE_PER_CPU(struct list_head *, tracer_path);
-
 /*
  * When losing synchronisation a new barrier packet needs to be inserted at the
  * beginning of the data collected in a buffer.  That way the decoder knows that
@@ -61,34 +51,6 @@ EXPORT_SYMBOL_GPL(coresight_barrier_pkt);
 
 static const struct cti_assoc_op *cti_assoc_ops;
 
-ssize_t coresight_simple_show_pair(struct device *_dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
-       struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
-       u64 val;
-
-       pm_runtime_get_sync(_dev->parent);
-       val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
-       pm_runtime_put_sync(_dev->parent);
-       return sysfs_emit(buf, "0x%llx\n", val);
-}
-EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
-
-ssize_t coresight_simple_show32(struct device *_dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
-       struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
-       u64 val;
-
-       pm_runtime_get_sync(_dev->parent);
-       val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
-       pm_runtime_put_sync(_dev->parent);
-       return sysfs_emit(buf, "0x%llx\n", val);
-}
-EXPORT_SYMBOL_GPL(coresight_simple_show32);
-
 void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
 {
        cti_assoc_ops = cti_op;
@@ -279,42 +241,18 @@ EXPORT_SYMBOL_GPL(coresight_add_helper);
 static int coresight_enable_sink(struct coresight_device *csdev,
                                 enum cs_mode mode, void *data)
 {
-       int ret;
-
-       /*
-        * We need to make sure the "new" session is compatible with the
-        * existing "mode" of operation.
-        */
-       if (!sink_ops(csdev)->enable)
-               return -EINVAL;
-
-       ret = sink_ops(csdev)->enable(csdev, mode, data);
-       if (ret)
-               return ret;
-
-       csdev->enable = true;
-
-       return 0;
+       return sink_ops(csdev)->enable(csdev, mode, data);
 }
 
 static void coresight_disable_sink(struct coresight_device *csdev)
 {
-       int ret;
-
-       if (!sink_ops(csdev)->disable)
-               return;
-
-       ret = sink_ops(csdev)->disable(csdev);
-       if (ret)
-               return;
-       csdev->enable = false;
+       sink_ops(csdev)->disable(csdev);
 }
 
 static int coresight_enable_link(struct coresight_device *csdev,
                                 struct coresight_device *parent,
                                 struct coresight_device *child)
 {
-       int ret = 0;
        int link_subtype;
        struct coresight_connection *inconn, *outconn;
 
@@ -330,21 +268,13 @@ static int coresight_enable_link(struct coresight_device *csdev,
        if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT && IS_ERR(outconn))
                return PTR_ERR(outconn);
 
-       if (link_ops(csdev)->enable) {
-               ret = link_ops(csdev)->enable(csdev, inconn, outconn);
-               if (!ret)
-                       csdev->enable = true;
-       }
-
-       return ret;
+       return link_ops(csdev)->enable(csdev, inconn, outconn);
 }
 
 static void coresight_disable_link(struct coresight_device *csdev,
                                   struct coresight_device *parent,
                                   struct coresight_device *child)
 {
-       int i;
-       int link_subtype;
        struct coresight_connection *inconn, *outconn;
 
        if (!parent || !child)
@@ -352,49 +282,9 @@ static void coresight_disable_link(struct coresight_device *csdev,
 
        inconn = coresight_find_out_connection(parent, csdev);
        outconn = coresight_find_out_connection(csdev, child);
-       link_subtype = csdev->subtype.link_subtype;
 
-       if (link_ops(csdev)->disable) {
-               link_ops(csdev)->disable(csdev, inconn, outconn);
-       }
-
-       if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_MERG) {
-               for (i = 0; i < csdev->pdata->nr_inconns; i++)
-                       if (atomic_read(&csdev->pdata->in_conns[i]->dest_refcnt) !=
-                           0)
-                               return;
-       } else if (link_subtype == CORESIGHT_DEV_SUBTYPE_LINK_SPLIT) {
-               for (i = 0; i < csdev->pdata->nr_outconns; i++)
-                       if (atomic_read(&csdev->pdata->out_conns[i]->src_refcnt) !=
-                           0)
-                               return;
-       } else {
-               if (atomic_read(&csdev->refcnt) != 0)
-                       return;
-       }
-
-       csdev->enable = false;
-}
-
-int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
-                           void *data)
-{
-       int ret;
-
-       if (!csdev->enable) {
-               if (source_ops(csdev)->enable) {
-                       ret = source_ops(csdev)->enable(csdev, data, mode);
-                       if (ret)
-                               return ret;
-               }
-               csdev->enable = true;
-       }
-
-       atomic_inc(&csdev->refcnt);
-
-       return 0;
+       link_ops(csdev)->disable(csdev, inconn, outconn);
 }
-EXPORT_SYMBOL_GPL(coresight_enable_source);
 
 static bool coresight_is_helper(struct coresight_device *csdev)
 {
@@ -404,29 +294,12 @@ static bool coresight_is_helper(struct coresight_device *csdev)
 static int coresight_enable_helper(struct coresight_device *csdev,
                                   enum cs_mode mode, void *data)
 {
-       int ret;
-
-       if (!helper_ops(csdev)->enable)
-               return 0;
-       ret = helper_ops(csdev)->enable(csdev, mode, data);
-       if (ret)
-               return ret;
-
-       csdev->enable = true;
-       return 0;
+       return helper_ops(csdev)->enable(csdev, mode, data);
 }
 
 static void coresight_disable_helper(struct coresight_device *csdev)
 {
-       int ret;
-
-       if (!helper_ops(csdev)->disable)
-               return;
-
-       ret = helper_ops(csdev)->disable(csdev, NULL);
-       if (ret)
-               return;
-       csdev->enable = false;
+       helper_ops(csdev)->disable(csdev, NULL);
 }
 
 static void coresight_disable_helpers(struct coresight_device *csdev)
@@ -441,25 +314,20 @@ static void coresight_disable_helpers(struct coresight_device *csdev)
        }
 }
 
-/**
- *  coresight_disable_source - Drop the reference count by 1 and disable
- *  the device if there are no users left.
- *
- *  @csdev: The coresight device to disable
- *  @data: Opaque data to pass on to the disable function of the source device.
- *         For example in perf mode this is a pointer to the struct perf_event.
+/*
+ * Helper function to call source_ops(csdev)->disable and also disable the
+ * helpers.
  *
- *  Returns true if the device has been disabled.
+ * There is an imbalance between coresight_enable_path() and
+ * coresight_disable_path(). Enabling also enables the source's helpers as part
+ * of the path, but disabling always skips the first item in the path (which is
+ * the source), so sources and their helpers don't get disabled as part of that
+ * function and we need the extra step here.
  */
-bool coresight_disable_source(struct coresight_device *csdev, void *data)
+void coresight_disable_source(struct coresight_device *csdev, void *data)
 {
-       if (atomic_dec_return(&csdev->refcnt) == 0) {
-               if (source_ops(csdev)->disable)
-                       source_ops(csdev)->disable(csdev, data);
-               coresight_disable_helpers(csdev);
-               csdev->enable = false;
-       }
-       return !csdev->enable;
+       source_ops(csdev)->disable(csdev, data);
+       coresight_disable_helpers(csdev);
 }
 EXPORT_SYMBOL_GPL(coresight_disable_source);
 
@@ -484,7 +352,7 @@ static void coresight_disable_path_from(struct list_head *path,
                /*
                 * ETF devices are tricky... They can be a link or a sink,
                 * depending on how they are configured.  If an ETF has been
-                * "activated" it will be configured as a sink, otherwise
+                * selected as a sink it will be configured as a sink, otherwise
                 * go ahead with the link configuration.
                 */
                if (type == CORESIGHT_DEV_TYPE_LINKSINK)
@@ -562,7 +430,7 @@ int coresight_enable_path(struct list_head *path, enum cs_mode mode,
                /*
                 * ETF devices are tricky... They can be a link or a sink,
                 * depending on how they are configured.  If an ETF has been
-                * "activated" it will be configured as a sink, otherwise
+                * selected as a sink it will be configured as a sink, otherwise
                 * go ahead with the link configuration.
                 */
                if (type == CORESIGHT_DEV_TYPE_LINKSINK)
@@ -619,48 +487,6 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
        return csdev;
 }
 
-static struct coresight_device *
-coresight_find_enabled_sink(struct coresight_device *csdev)
-{
-       int i;
-       struct coresight_device *sink = NULL;
-
-       if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
-            csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
-            csdev->activated)
-               return csdev;
-
-       /*
-        * Recursively explore each port found on this element.
-        */
-       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
-               struct coresight_device *child_dev;
-
-               child_dev = csdev->pdata->out_conns[i]->dest_dev;
-               if (child_dev)
-                       sink = coresight_find_enabled_sink(child_dev);
-               if (sink)
-                       return sink;
-       }
-
-       return NULL;
-}
-
-/**
- * coresight_get_enabled_sink - returns the first enabled sink using
- * connection based search starting from the source reference
- *
- * @source: Coresight source device reference
- */
-struct coresight_device *
-coresight_get_enabled_sink(struct coresight_device *source)
-{
-       if (!source)
-               return NULL;
-
-       return coresight_find_enabled_sink(source);
-}
-
 static int coresight_sink_by_id(struct device *dev, const void *data)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
@@ -794,11 +620,10 @@ static void coresight_drop_device(struct coresight_device *csdev)
  * @sink:      The final sink we want in this path.
  * @path:      The list to add devices to.
  *
- * The tree of Coresight device is traversed until an activated sink is
- * found.  From there the sink is added to the list along with all the
- * devices that led to that point - the end result is a list from source
- * to sink. In that list the source is the first device and the sink the
- * last one.
+ * The tree of Coresight device is traversed until @sink is found.
+ * From there the sink is added to the list along with all the devices that led
+ * to that point - the end result is a list from source to sink. In that list
+ * the source is the first device and the sink the last one.
  */
 static int _coresight_build_path(struct coresight_device *csdev,
                                 struct coresight_device *sink,
@@ -808,7 +633,7 @@ static int _coresight_build_path(struct coresight_device *csdev,
        bool found = false;
        struct coresight_node *node;
 
-       /* An activated sink has been found.  Enqueue the element */
+       /* The sink has been found.  Enqueue the element */
        if (csdev == sink)
                goto out;
 
@@ -1072,269 +897,6 @@ static void coresight_clear_default_sink(struct coresight_device *csdev)
        }
 }
 
-/** coresight_validate_source - make sure a source has the right credentials
- *  @csdev:    the device structure for a source.
- *  @function: the function this was called from.
- *
- * Assumes the coresight_mutex is held.
- */
-static int coresight_validate_source(struct coresight_device *csdev,
-                                    const char *function)
-{
-       u32 type, subtype;
-
-       type = csdev->type;
-       subtype = csdev->subtype.source_subtype;
-
-       if (type != CORESIGHT_DEV_TYPE_SOURCE) {
-               dev_err(&csdev->dev, "wrong device type in %s\n", function);
-               return -EINVAL;
-       }
-
-       if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
-           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
-           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
-           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
-               dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int coresight_enable(struct coresight_device *csdev)
-{
-       int cpu, ret = 0;
-       struct coresight_device *sink;
-       struct list_head *path;
-       enum coresight_dev_subtype_source subtype;
-       u32 hash;
-
-       subtype = csdev->subtype.source_subtype;
-
-       mutex_lock(&coresight_mutex);
-
-       ret = coresight_validate_source(csdev, __func__);
-       if (ret)
-               goto out;
-
-       if (csdev->enable) {
-               /*
-                * There could be multiple applications driving the software
-                * source. So keep the refcount for each such user when the
-                * source is already enabled.
-                */
-               if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
-                       atomic_inc(&csdev->refcnt);
-               goto out;
-       }
-
-       sink = coresight_get_enabled_sink(csdev);
-       if (!sink) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       path = coresight_build_path(csdev, sink);
-       if (IS_ERR(path)) {
-               pr_err("building path(s) failed\n");
-               ret = PTR_ERR(path);
-               goto out;
-       }
-
-       ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
-       if (ret)
-               goto err_path;
-
-       ret = coresight_enable_source(csdev, CS_MODE_SYSFS, NULL);
-       if (ret)
-               goto err_source;
-
-       switch (subtype) {
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
-               /*
-                * When working from sysFS it is important to keep track
-                * of the paths that were created so that they can be
-                * undone in 'coresight_disable()'.  Since there can only
-                * be a single session per tracer (when working from sysFS)
-                * a per-cpu variable will do just fine.
-                */
-               cpu = source_ops(csdev)->cpu_id(csdev);
-               per_cpu(tracer_path, cpu) = path;
-               break;
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
-               /*
-                * Use the hash of source's device name as ID
-                * and map the ID to the pointer of the path.
-                */
-               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
-               ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
-               if (ret)
-                       goto err_source;
-               break;
-       default:
-               /* We can't be here */
-               break;
-       }
-
-out:
-       mutex_unlock(&coresight_mutex);
-       return ret;
-
-err_source:
-       coresight_disable_path(path);
-
-err_path:
-       coresight_release_path(path);
-       goto out;
-}
-EXPORT_SYMBOL_GPL(coresight_enable);
-
-void coresight_disable(struct coresight_device *csdev)
-{
-       int cpu, ret;
-       struct list_head *path = NULL;
-       u32 hash;
-
-       mutex_lock(&coresight_mutex);
-
-       ret = coresight_validate_source(csdev, __func__);
-       if (ret)
-               goto out;
-
-       if (!csdev->enable || !coresight_disable_source(csdev, NULL))
-               goto out;
-
-       switch (csdev->subtype.source_subtype) {
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
-               cpu = source_ops(csdev)->cpu_id(csdev);
-               path = per_cpu(tracer_path, cpu);
-               per_cpu(tracer_path, cpu) = NULL;
-               break;
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
-       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
-               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
-               /* Find the path by the hash. */
-               path = idr_find(&path_idr, hash);
-               if (path == NULL) {
-                       pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
-                       goto out;
-               }
-               idr_remove(&path_idr, hash);
-               break;
-       default:
-               /* We can't be here */
-               break;
-       }
-
-       coresight_disable_path(path);
-       coresight_release_path(path);
-
-out:
-       mutex_unlock(&coresight_mutex);
-}
-EXPORT_SYMBOL_GPL(coresight_disable);
-
-static ssize_t enable_sink_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->activated);
-}
-
-static ssize_t enable_sink_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t size)
-{
-       int ret;
-       unsigned long val;
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       ret = kstrtoul(buf, 10, &val);
-       if (ret)
-               return ret;
-
-       if (val)
-               csdev->activated = true;
-       else
-               csdev->activated = false;
-
-       return size;
-
-}
-static DEVICE_ATTR_RW(enable_sink);
-
-static ssize_t enable_source_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->enable);
-}
-
-static ssize_t enable_source_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       int ret = 0;
-       unsigned long val;
-       struct coresight_device *csdev = to_coresight_device(dev);
-
-       ret = kstrtoul(buf, 10, &val);
-       if (ret)
-               return ret;
-
-       if (val) {
-               ret = coresight_enable(csdev);
-               if (ret)
-                       return ret;
-       } else {
-               coresight_disable(csdev);
-       }
-
-       return size;
-}
-static DEVICE_ATTR_RW(enable_source);
-
-static struct attribute *coresight_sink_attrs[] = {
-       &dev_attr_enable_sink.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(coresight_sink);
-
-static struct attribute *coresight_source_attrs[] = {
-       &dev_attr_enable_source.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(coresight_source);
-
-static struct device_type coresight_dev_type[] = {
-       {
-               .name = "sink",
-               .groups = coresight_sink_groups,
-       },
-       {
-               .name = "link",
-       },
-       {
-               .name = "linksink",
-               .groups = coresight_sink_groups,
-       },
-       {
-               .name = "source",
-               .groups = coresight_source_groups,
-       },
-       {
-               .name = "helper",
-       }
-};
-/* Ensure the enum matches the names and groups */
-static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
-
 static void coresight_device_release(struct device *dev)
 {
        struct coresight_device *csdev = to_coresight_device(dev);
@@ -1799,7 +1361,7 @@ done:
 }
 EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
 
-struct bus_type coresight_bustype = {
+const struct bus_type coresight_bustype = {
        .name   = "coresight",
 };
 
index 3999d0a2cb6026d1d2315299045e87e2d18ae056..e805617020d06a9d23b11b53540021cba0deb71e 100644 (file)
@@ -974,7 +974,7 @@ static const struct amba_id cti_ids[] = {
        CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */
        CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */
        CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 MODULE_DEVICE_TABLE(amba, cti_ids);
index fa80039e0821f095b954d445e913c8f516cef4f4..3aab182b562f1009dd86713b05d640f6c3c72a26 100644 (file)
@@ -76,7 +76,6 @@ DEFINE_CORESIGHT_DEVLIST(etb_devs, "etb");
  * @pid:       Process ID of the process being monitored by the session
  *             that is using this component.
  * @buf:       area of memory where ETB buffer content gets sent.
- * @mode:      this ETB is being used.
  * @buffer_depth: size of @buf.
  * @trigger_cntr: amount of words to store after a trigger.
  */
@@ -89,7 +88,6 @@ struct etb_drvdata {
        local_t                 reading;
        pid_t                   pid;
        u8                      *buf;
-       u32                     mode;
        u32                     buffer_depth;
        u32                     trigger_cntr;
 };
@@ -150,20 +148,20 @@ static int etb_enable_sysfs(struct coresight_device *csdev)
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't messup with perf sessions. */
-       if (drvdata->mode == CS_MODE_PERF) {
+       if (coresight_get_mode(csdev) == CS_MODE_PERF) {
                ret = -EBUSY;
                goto out;
        }
 
-       if (drvdata->mode == CS_MODE_DISABLED) {
+       if (coresight_get_mode(csdev) == CS_MODE_DISABLED) {
                ret = etb_enable_hw(drvdata);
                if (ret)
                        goto out;
 
-               drvdata->mode = CS_MODE_SYSFS;
+               coresight_set_mode(csdev, CS_MODE_SYSFS);
        }
 
-       atomic_inc(&csdev->refcnt);
+       csdev->refcnt++;
 out:
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
        return ret;
@@ -181,7 +179,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* No need to continue if the component is already in used by sysFS. */
-       if (drvdata->mode == CS_MODE_SYSFS) {
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
                ret = -EBUSY;
                goto out;
        }
@@ -199,7 +197,7 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
         * use for this session.
         */
        if (drvdata->pid == pid) {
-               atomic_inc(&csdev->refcnt);
+               csdev->refcnt++;
                goto out;
        }
 
@@ -216,8 +214,8 @@ static int etb_enable_perf(struct coresight_device *csdev, void *data)
        if (!ret) {
                /* Associate with monitored process. */
                drvdata->pid = pid;
-               drvdata->mode = CS_MODE_PERF;
-               atomic_inc(&csdev->refcnt);
+               coresight_set_mode(drvdata->csdev, CS_MODE_PERF);
+               csdev->refcnt++;
        }
 
 out:
@@ -356,17 +354,18 @@ static int etb_disable(struct coresight_device *csdev)
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
-       if (atomic_dec_return(&csdev->refcnt)) {
+       csdev->refcnt--;
+       if (csdev->refcnt) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                return -EBUSY;
        }
 
        /* Complain if we (somehow) got out of sync */
-       WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+       WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
        etb_disable_hw(drvdata);
        /* Dissociate from monitored process. */
        drvdata->pid = -1;
-       drvdata->mode = CS_MODE_DISABLED;
+       coresight_set_mode(csdev, CS_MODE_DISABLED);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        dev_dbg(&csdev->dev, "ETB disabled\n");
@@ -447,7 +446,7 @@ static unsigned long etb_update_buffer(struct coresight_device *csdev,
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't do anything if another tracer is using this sink */
-       if (atomic_read(&csdev->refcnt) != 1)
+       if (csdev->refcnt != 1)
                goto out;
 
        __etb_disable_hw(drvdata);
@@ -589,7 +588,7 @@ static void etb_dump(struct etb_drvdata *drvdata)
        unsigned long flags;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
-       if (drvdata->mode == CS_MODE_SYSFS) {
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
                __etb_disable_hw(drvdata);
                etb_dump_hw(drvdata);
                __etb_enable_hw(drvdata);
@@ -837,7 +836,7 @@ static const struct amba_id etb_ids[] = {
                .id     = 0x000bb907,
                .mask   = 0x000fffff,
        },
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 MODULE_DEVICE_TABLE(amba, etb_ids);
index a52cfcce25d6ddef4ee48eac1f049f7b13143b50..c0c60e6a1703e3fd23ce85d8bc1ac63c242381d4 100644 (file)
@@ -589,7 +589,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
                return;
 
        /* stop tracer */
-       source_ops(csdev)->disable(csdev, event);
+       coresight_disable_source(csdev, event);
 
        /* tell the core */
        event->hw.state = PERF_HES_STOPPED;
index 9a0d08b092ae7f5a26a515d89428be4c00f1cac1..e02c3ea972c9286506bac2d198a712a8a1f970d4 100644 (file)
@@ -215,7 +215,6 @@ struct etm_config {
  * @port_size: port size as reported by ETMCR bit 4-6 and 21.
  * @arch:      ETM/PTM version number.
  * @use_cpu14: true if management registers need to be accessed via CP14.
- * @mode:      this tracer's mode, i.e sysFS, Perf or disabled.
  * @sticky_enable: true if ETM base configuration has been done.
  * @boot_enable:true if we should start tracing at boot time.
  * @os_unlock: true if access to management registers is allowed.
@@ -238,7 +237,6 @@ struct etm_drvdata {
        int                             port_size;
        u8                              arch;
        bool                            use_cp14;
-       local_t                         mode;
        bool                            sticky_enable;
        bool                            boot_enable;
        bool                            os_unlock;
index 116a91d90ac20a86ba7650b6b2f466ce5e1fa7e2..9d5c1391ffb12472cf8c756133bb7628bfbf95c3 100644 (file)
@@ -115,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata)
  *
  * Basically the same as @coresight_timeout except for the register access
  * method where we have to account for CP14 configurations.
-
+ *
  * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
  * TIMEOUT_US has elapsed, which ever happens first.
  */
@@ -556,14 +556,12 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
                      enum cs_mode mode)
 {
        int ret;
-       u32 val;
        struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
-       val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
-
-       /* Someone is already using the tracer */
-       if (val)
+       if (!coresight_take_mode(csdev, mode)) {
+               /* Someone is already using the tracer */
                return -EBUSY;
+       }
 
        switch (mode) {
        case CS_MODE_SYSFS:
@@ -578,7 +576,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
 
        /* The tracer didn't start */
        if (ret)
-               local_set(&drvdata->mode, CS_MODE_DISABLED);
+               coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
 
        return ret;
 }
@@ -672,14 +670,13 @@ static void etm_disable(struct coresight_device *csdev,
                        struct perf_event *event)
 {
        enum cs_mode mode;
-       struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        /*
         * For as long as the tracer isn't disabled another entity can't
         * change its status.  As such we can read the status here without
         * fearing it will change under us.
         */
-       mode = local_read(&drvdata->mode);
+       mode = coresight_get_mode(csdev);
 
        switch (mode) {
        case CS_MODE_DISABLED:
@@ -696,7 +693,7 @@ static void etm_disable(struct coresight_device *csdev,
        }
 
        if (mode)
-               local_set(&drvdata->mode, CS_MODE_DISABLED);
+               coresight_set_mode(csdev, CS_MODE_DISABLED);
 }
 
 static const struct coresight_ops_source etm_source_ops = {
@@ -715,7 +712,7 @@ static int etm_online_cpu(unsigned int cpu)
                return 0;
 
        if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
-               coresight_enable(etmdrvdata[cpu]->csdev);
+               coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
        return 0;
 }
 
@@ -730,7 +727,7 @@ static int etm_starting_cpu(unsigned int cpu)
                etmdrvdata[cpu]->os_unlock = true;
        }
 
-       if (local_read(&etmdrvdata[cpu]->mode))
+       if (coresight_get_mode(etmdrvdata[cpu]->csdev))
                etm_enable_hw(etmdrvdata[cpu]);
        spin_unlock(&etmdrvdata[cpu]->spinlock);
        return 0;
@@ -742,7 +739,7 @@ static int etm_dying_cpu(unsigned int cpu)
                return 0;
 
        spin_lock(&etmdrvdata[cpu]->spinlock);
-       if (local_read(&etmdrvdata[cpu]->mode))
+       if (coresight_get_mode(etmdrvdata[cpu]->csdev))
                etm_disable_hw(etmdrvdata[cpu]);
        spin_unlock(&etmdrvdata[cpu]->spinlock);
        return 0;
@@ -925,7 +922,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        dev_info(&drvdata->csdev->dev,
                 "%s initialized\n", (char *)coresight_get_uci_data(id));
        if (boot_enable) {
-               coresight_enable(drvdata->csdev);
+               coresight_enable_sysfs(drvdata->csdev);
                drvdata->boot_enable = true;
        }
 
@@ -1003,7 +1000,7 @@ static const struct amba_id etm_ids[] = {
        CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"),
        /* PTM 1.1 Qualcomm */
        CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"),
-       { 0, 0},
+       { 0, 0, NULL},
 };
 
 MODULE_DEVICE_TABLE(amba, etm_ids);
index 2f271b7fb048cf00153ca61fac5c8b2c26056a0f..68c644be9813bec8d7bd3b68af54d681d9954465 100644 (file)
@@ -722,7 +722,7 @@ static ssize_t cntr_val_show(struct device *dev,
        struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        struct etm_config *config = &drvdata->config;
 
-       if (!local_read(&drvdata->mode)) {
+       if (!coresight_get_mode(drvdata->csdev)) {
                spin_lock(&drvdata->spinlock);
                for (i = 0; i < drvdata->nr_cntr; i++)
                        ret += sprintf(buf, "counter %d: %x\n",
@@ -941,7 +941,7 @@ static ssize_t seq_curr_state_show(struct device *dev,
        struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        struct etm_config *config = &drvdata->config;
 
-       if (!local_read(&drvdata->mode)) {
+       if (!coresight_get_mode(drvdata->csdev)) {
                val = config->seq_curr_state;
                goto out;
        }
index ce1995a2827f01bbe164eaa95a845e9707254364..c2ca4a02dfce1fc792c42364289f2868f6f25bcf 100644 (file)
@@ -840,14 +840,11 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
                       enum cs_mode mode)
 {
        int ret;
-       u32 val;
-       struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
-       val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
 
-       /* Someone is already using the tracer */
-       if (val)
+       if (!coresight_take_mode(csdev, mode)) {
+               /* Someone is already using the tracer */
                return -EBUSY;
+       }
 
        switch (mode) {
        case CS_MODE_SYSFS:
@@ -862,7 +859,7 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event,
 
        /* The tracer didn't start */
        if (ret)
-               local_set(&drvdata->mode, CS_MODE_DISABLED);
+               coresight_set_mode(csdev, CS_MODE_DISABLED);
 
        return ret;
 }
@@ -1004,14 +1001,13 @@ static void etm4_disable(struct coresight_device *csdev,
                         struct perf_event *event)
 {
        enum cs_mode mode;
-       struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        /*
         * For as long as the tracer isn't disabled another entity can't
         * change its status.  As such we can read the status here without
         * fearing it will change under us.
         */
-       mode = local_read(&drvdata->mode);
+       mode = coresight_get_mode(csdev);
 
        switch (mode) {
        case CS_MODE_DISABLED:
@@ -1025,7 +1021,7 @@ static void etm4_disable(struct coresight_device *csdev,
        }
 
        if (mode)
-               local_set(&drvdata->mode, CS_MODE_DISABLED);
+               coresight_set_mode(csdev, CS_MODE_DISABLED);
 }
 
 static const struct coresight_ops_source etm4_source_ops = {
@@ -1200,6 +1196,7 @@ static void etm4_init_arch_data(void *info)
        struct etm4_init_arg *init_arg = info;
        struct etmv4_drvdata *drvdata;
        struct csdev_access *csa;
+       struct device *dev = init_arg->dev;
        int i;
 
        drvdata = dev_get_drvdata(init_arg->dev);
@@ -1213,6 +1210,10 @@ static void etm4_init_arch_data(void *info)
        if (!etm4_init_csdev_access(drvdata, csa))
                return;
 
+       if (!csa->io_mem ||
+           fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
+               drvdata->skip_power_up = true;
+
        /* Detect the support for OS Lock before we actually use it */
        etm_detect_os_lock(drvdata, csa);
 
@@ -1650,7 +1651,7 @@ static int etm4_online_cpu(unsigned int cpu)
                return etm4_probe_cpu(cpu);
 
        if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
-               coresight_enable(etmdrvdata[cpu]->csdev);
+               coresight_enable_sysfs(etmdrvdata[cpu]->csdev);
        return 0;
 }
 
@@ -1663,7 +1664,7 @@ static int etm4_starting_cpu(unsigned int cpu)
        if (!etmdrvdata[cpu]->os_unlock)
                etm4_os_unlock(etmdrvdata[cpu]);
 
-       if (local_read(&etmdrvdata[cpu]->mode))
+       if (coresight_get_mode(etmdrvdata[cpu]->csdev))
                etm4_enable_hw(etmdrvdata[cpu]);
        spin_unlock(&etmdrvdata[cpu]->spinlock);
        return 0;
@@ -1675,7 +1676,7 @@ static int etm4_dying_cpu(unsigned int cpu)
                return 0;
 
        spin_lock(&etmdrvdata[cpu]->spinlock);
-       if (local_read(&etmdrvdata[cpu]->mode))
+       if (coresight_get_mode(etmdrvdata[cpu]->csdev))
                etm4_disable_hw(etmdrvdata[cpu]);
        spin_unlock(&etmdrvdata[cpu]->spinlock);
        return 0;
@@ -1833,7 +1834,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
         * Save and restore the ETM Trace registers only if
         * the ETM is active.
         */
-       if (local_read(&drvdata->mode) && drvdata->save_state)
+       if (coresight_get_mode(drvdata->csdev) && drvdata->save_state)
                ret = __etm4_cpu_save(drvdata);
        return ret;
 }
@@ -2040,11 +2041,6 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
        if (!drvdata->arch)
                return -EINVAL;
 
-       /* TRCPDCR is not accessible with system instructions. */
-       if (!desc.access.io_mem ||
-           fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
-               drvdata->skip_power_up = true;
-
        major = ETM_ARCH_MAJOR_VERSION(drvdata->arch);
        minor = ETM_ARCH_MINOR_VERSION(drvdata->arch);
 
@@ -2098,7 +2094,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
                 drvdata->cpu, type_name, major, minor);
 
        if (boot_enable) {
-               coresight_enable(drvdata->csdev);
+               coresight_enable_sysfs(drvdata->csdev);
                drvdata->boot_enable = true;
        }
 
@@ -2390,7 +2386,7 @@ static const struct of_device_id etm4_sysreg_match[] = {
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id etm4x_acpi_ids[] = {
-       {"ARMHC500", 0}, /* ARM CoreSight ETM4x */
+       {"ARMHC500", 0, 0, 0}, /* ARM CoreSight ETM4x */
        {}
 };
 MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids);
index da17b6c49b0f1ae8467b9de7e2b6249c0a832bd3..9ea678bc2e8e5503b014d26ce058ea3960731999 100644 (file)
@@ -1016,7 +1016,6 @@ struct etmv4_drvdata {
        void __iomem                    *base;
        struct coresight_device         *csdev;
        spinlock_t                      spinlock;
-       local_t                         mode;
        int                             cpu;
        u8                              arch;
        u8                              nr_pe;
index a5b1fc787766a0eaea9733374a1288817ec63c24..ef1a0abfee4e912f62e66cac5fc92d3a72ab6e29 100644 (file)
@@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(of, static_funnel_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id static_funnel_ids[] = {
-       {"ARMHC9FE", 0},
+       {"ARMHC9FE", 0, 0, 0},
        {},
 };
 
@@ -391,7 +391,7 @@ static const struct amba_id dynamic_funnel_ids[] = {
                .id     = 0x000bb9eb,
                .mask   = 0x000fffff,
        },
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids);
index 767076e07970117c890af346a48b8246ce92a246..eb365236f9a976a77c48b34c6e36f404ed098512 100644 (file)
@@ -12,6 +12,9 @@
 #include <linux/coresight.h>
 #include <linux/pm_runtime.h>
 
+extern struct mutex coresight_mutex;
+extern struct device_type coresight_dev_type[];
+
 /*
  * Coresight management registers (0xf00-0xfcc)
  * 0xfa0 - 0xfa4: Management   registers in PFTv1.0
@@ -130,8 +133,6 @@ void coresight_disable_path(struct list_head *path);
 int coresight_enable_path(struct list_head *path, enum cs_mode mode,
                          void *sink_data);
 struct coresight_device *coresight_get_sink(struct list_head *path);
-struct coresight_device *
-coresight_get_enabled_sink(struct coresight_device *source);
 struct coresight_device *coresight_get_sink_by_id(u32 id);
 struct coresight_device *
 coresight_find_default_sink(struct coresight_device *csdev);
@@ -231,8 +232,6 @@ void coresight_add_helper(struct coresight_device *csdev,
 
 void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
 struct coresight_device *coresight_get_percpu_sink(int cpu);
-int coresight_enable_source(struct coresight_device *csdev, enum cs_mode mode,
-                           void *data);
-bool coresight_disable_source(struct coresight_device *csdev, void *data);
+void coresight_disable_source(struct coresight_device *csdev, void *data);
 
 #endif
index 91d93060dda5355c3de3fcf04498918547f8c584..73452d9dc13b261f2766b38a99c5aa3fce020744 100644 (file)
@@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, static_replicator_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id static_replicator_acpi_ids[] = {
-       {"ARMHC985", 0}, /* ARM CoreSight Static Replicator */
+       {"ARMHC985", 0, 0, 0}, /* ARM CoreSight Static Replicator */
        {}
 };
 
index a1c27c901ad17bb26af078f0628e315716f29142..974d37e5f94c0284ae626e29074f2c903e8b3df5 100644 (file)
@@ -119,7 +119,6 @@ DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm");
  * @spinlock:          only one at a time pls.
  * @chs:               the channels accociated to this STM.
  * @stm:               structure associated to the generic STM interface.
- * @mode:              this tracer's mode (enum cs_mode), i.e sysFS, or disabled.
  * @traceid:           value of the current ID for this component.
  * @write_bytes:       Maximus bytes this STM can write at a time.
  * @stmsper:           settings for register STMSPER.
@@ -136,7 +135,6 @@ struct stm_drvdata {
        spinlock_t              spinlock;
        struct channel_space    chs;
        struct stm_data         stm;
-       local_t                 mode;
        u8                      traceid;
        u32                     write_bytes;
        u32                     stmsper;
@@ -195,17 +193,15 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
 static int stm_enable(struct coresight_device *csdev, struct perf_event *event,
                      enum cs_mode mode)
 {
-       u32 val;
        struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        if (mode != CS_MODE_SYSFS)
                return -EINVAL;
 
-       val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode);
-
-       /* Someone is already using the tracer */
-       if (val)
+       if (!coresight_take_mode(csdev, mode)) {
+               /* Someone is already using the tracer */
                return -EBUSY;
+       }
 
        pm_runtime_get_sync(csdev->dev.parent);
 
@@ -266,7 +262,7 @@ static void stm_disable(struct coresight_device *csdev,
         * change its status.  As such we can read the status here without
         * fearing it will change under us.
         */
-       if (local_read(&drvdata->mode) == CS_MODE_SYSFS) {
+       if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
                spin_lock(&drvdata->spinlock);
                stm_disable_hw(drvdata);
                spin_unlock(&drvdata->spinlock);
@@ -276,7 +272,7 @@ static void stm_disable(struct coresight_device *csdev,
 
                pm_runtime_put(csdev->dev.parent);
 
-               local_set(&drvdata->mode, CS_MODE_DISABLED);
+               coresight_set_mode(csdev, CS_MODE_DISABLED);
                dev_dbg(&csdev->dev, "STM tracing disabled\n");
        }
 }
@@ -334,7 +330,7 @@ static int stm_generic_link(struct stm_data *stm_data,
        if (!drvdata || !drvdata->csdev)
                return -EINVAL;
 
-       return coresight_enable(drvdata->csdev);
+       return coresight_enable_sysfs(drvdata->csdev);
 }
 
 static void stm_generic_unlink(struct stm_data *stm_data,
@@ -345,7 +341,7 @@ static void stm_generic_unlink(struct stm_data *stm_data,
        if (!drvdata || !drvdata->csdev)
                return;
 
-       coresight_disable(drvdata->csdev);
+       coresight_disable_sysfs(drvdata->csdev);
 }
 
 static phys_addr_t
@@ -373,7 +369,7 @@ static long stm_generic_set_options(struct stm_data *stm_data,
 {
        struct stm_drvdata *drvdata = container_of(stm_data,
                                                   struct stm_drvdata, stm);
-       if (!(drvdata && local_read(&drvdata->mode)))
+       if (!(drvdata && coresight_get_mode(drvdata->csdev)))
                return -EINVAL;
 
        if (channel >= drvdata->numsp)
@@ -408,7 +404,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data,
                                                   struct stm_drvdata, stm);
        unsigned int stm_flags;
 
-       if (!(drvdata && local_read(&drvdata->mode)))
+       if (!(drvdata && coresight_get_mode(drvdata->csdev)))
                return -EACCES;
 
        if (channel >= drvdata->numsp)
@@ -515,7 +511,7 @@ static ssize_t port_select_show(struct device *dev,
        struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        unsigned long val;
 
-       if (!local_read(&drvdata->mode)) {
+       if (!coresight_get_mode(drvdata->csdev)) {
                val = drvdata->stmspscr;
        } else {
                spin_lock(&drvdata->spinlock);
@@ -541,7 +537,7 @@ static ssize_t port_select_store(struct device *dev,
        spin_lock(&drvdata->spinlock);
        drvdata->stmspscr = val;
 
-       if (local_read(&drvdata->mode)) {
+       if (coresight_get_mode(drvdata->csdev)) {
                CS_UNLOCK(drvdata->base);
                /* Process as per ARM's TRM recommendation */
                stmsper = readl_relaxed(drvdata->base + STMSPER);
@@ -562,7 +558,7 @@ static ssize_t port_enable_show(struct device *dev,
        struct stm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        unsigned long val;
 
-       if (!local_read(&drvdata->mode)) {
+       if (!coresight_get_mode(drvdata->csdev)) {
                val = drvdata->stmsper;
        } else {
                spin_lock(&drvdata->spinlock);
@@ -588,7 +584,7 @@ static ssize_t port_enable_store(struct device *dev,
        spin_lock(&drvdata->spinlock);
        drvdata->stmsper = val;
 
-       if (local_read(&drvdata->mode)) {
+       if (coresight_get_mode(drvdata->csdev)) {
                CS_UNLOCK(drvdata->base);
                writel_relaxed(drvdata->stmsper, drvdata->base + STMSPER);
                CS_LOCK(drvdata->base);
@@ -950,7 +946,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = {
 static const struct amba_id stm_ids[] = {
        CS_AMBA_ID_DATA(0x000bb962, "STM32"),
        CS_AMBA_ID_DATA(0x000bb963, "STM500"),
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 MODULE_DEVICE_TABLE(amba, stm_ids);
index dd78e9fcfc4dc991c0651e620187c8746068a325..f9444e2cb1d9f4bee3f412df3d1d81b75bc659d0 100644 (file)
  */
 
 #include <linux/device.h>
+#include <linux/idr.h>
 #include <linux/kernel.h>
 
 #include "coresight-priv.h"
 
+/*
+ * Use IDR to map the hash of the source's device name
+ * to the pointer of path for the source. The idr is for
+ * the sources which aren't associated with CPU.
+ */
+static DEFINE_IDR(path_idr);
+
+/*
+ * When operating Coresight drivers from the sysFS interface, only a single
+ * path can exist from a tracer (associated to a CPU) to a sink.
+ */
+static DEFINE_PER_CPU(struct list_head *, tracer_path);
+
+ssize_t coresight_simple_show_pair(struct device *_dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
+       struct cs_pair_attribute *cs_attr = container_of(attr, struct cs_pair_attribute, attr);
+       u64 val;
+
+       pm_runtime_get_sync(_dev->parent);
+       val = csdev_access_relaxed_read_pair(&csdev->access, cs_attr->lo_off, cs_attr->hi_off);
+       pm_runtime_put_sync(_dev->parent);
+       return sysfs_emit(buf, "0x%llx\n", val);
+}
+EXPORT_SYMBOL_GPL(coresight_simple_show_pair);
+
+ssize_t coresight_simple_show32(struct device *_dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = container_of(_dev, struct coresight_device, dev);
+       struct cs_off_attribute *cs_attr = container_of(attr, struct cs_off_attribute, attr);
+       u64 val;
+
+       pm_runtime_get_sync(_dev->parent);
+       val = csdev_access_relaxed_read32(&csdev->access, cs_attr->off);
+       pm_runtime_put_sync(_dev->parent);
+       return sysfs_emit(buf, "0x%llx\n", val);
+}
+EXPORT_SYMBOL_GPL(coresight_simple_show32);
+
+static int coresight_enable_source_sysfs(struct coresight_device *csdev,
+                                        enum cs_mode mode, void *data)
+{
+       int ret;
+
+       /*
+        * Comparison with CS_MODE_SYSFS works without taking any device
+        * specific spinlock because the truthyness of that comparison can only
+        * change with coresight_mutex held, which we already have here.
+        */
+       lockdep_assert_held(&coresight_mutex);
+       if (coresight_get_mode(csdev) != CS_MODE_SYSFS) {
+               ret = source_ops(csdev)->enable(csdev, data, mode);
+               if (ret)
+                       return ret;
+       }
+
+       csdev->refcnt++;
+
+       return 0;
+}
+
+/**
+ *  coresight_disable_source_sysfs - Drop the reference count by 1 and disable
+ *  the device if there are no users left.
+ *
+ *  @csdev: The coresight device to disable
+ *  @data: Opaque data to pass on to the disable function of the source device.
+ *         For example in perf mode this is a pointer to the struct perf_event.
+ *
+ *  Returns true if the device has been disabled.
+ */
+static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
+                                          void *data)
+{
+       lockdep_assert_held(&coresight_mutex);
+       if (coresight_get_mode(csdev) != CS_MODE_SYSFS)
+               return false;
+
+       csdev->refcnt--;
+       if (csdev->refcnt == 0) {
+               coresight_disable_source(csdev, data);
+               return true;
+       }
+       return false;
+}
+
+/**
+ * coresight_find_activated_sysfs_sink - returns the first sink activated via
+ * sysfs using connection based search starting from the source reference.
+ *
+ * @csdev: Coresight source device reference
+ */
+static struct coresight_device *
+coresight_find_activated_sysfs_sink(struct coresight_device *csdev)
+{
+       int i;
+       struct coresight_device *sink = NULL;
+
+       if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+            csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) &&
+            csdev->sysfs_sink_activated)
+               return csdev;
+
+       /*
+        * Recursively explore each port found on this element.
+        */
+       for (i = 0; i < csdev->pdata->nr_outconns; i++) {
+               struct coresight_device *child_dev;
+
+               child_dev = csdev->pdata->out_conns[i]->dest_dev;
+               if (child_dev)
+                       sink = coresight_find_activated_sysfs_sink(child_dev);
+               if (sink)
+                       return sink;
+       }
+
+       return NULL;
+}
+
+/** coresight_validate_source - make sure a source has the right credentials to
+ *  be used via sysfs.
+ *  @csdev:    the device structure for a source.
+ *  @function: the function this was called from.
+ *
+ * Assumes the coresight_mutex is held.
+ */
+static int coresight_validate_source_sysfs(struct coresight_device *csdev,
+                                    const char *function)
+{
+       u32 type, subtype;
+
+       type = csdev->type;
+       subtype = csdev->subtype.source_subtype;
+
+       if (type != CORESIGHT_DEV_TYPE_SOURCE) {
+               dev_err(&csdev->dev, "wrong device type in %s\n", function);
+               return -EINVAL;
+       }
+
+       if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
+           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
+           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
+           subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
+               dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int coresight_enable_sysfs(struct coresight_device *csdev)
+{
+       int cpu, ret = 0;
+       struct coresight_device *sink;
+       struct list_head *path;
+       enum coresight_dev_subtype_source subtype;
+       u32 hash;
+
+       subtype = csdev->subtype.source_subtype;
+
+       mutex_lock(&coresight_mutex);
+
+       ret = coresight_validate_source_sysfs(csdev, __func__);
+       if (ret)
+               goto out;
+
+       /*
+        * mode == SYSFS implies that it's already enabled. Don't look at the
+        * refcount to determine this because we don't claim the source until
+        * coresight_enable_source() so can still race with Perf mode which
+        * doesn't hold coresight_mutex.
+        */
+       if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
+               /*
+                * There could be multiple applications driving the software
+                * source. So keep the refcount for each such user when the
+                * source is already enabled.
+                */
+               if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+                       csdev->refcnt++;
+               goto out;
+       }
+
+       sink = coresight_find_activated_sysfs_sink(csdev);
+       if (!sink) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       path = coresight_build_path(csdev, sink);
+       if (IS_ERR(path)) {
+               pr_err("building path(s) failed\n");
+               ret = PTR_ERR(path);
+               goto out;
+       }
+
+       ret = coresight_enable_path(path, CS_MODE_SYSFS, NULL);
+       if (ret)
+               goto err_path;
+
+       ret = coresight_enable_source_sysfs(csdev, CS_MODE_SYSFS, NULL);
+       if (ret)
+               goto err_source;
+
+       switch (subtype) {
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
+               /*
+                * When working from sysFS it is important to keep track
+                * of the paths that were created so that they can be
+                * undone in 'coresight_disable()'.  Since there can only
+                * be a single session per tracer (when working from sysFS)
+                * a per-cpu variable will do just fine.
+                */
+               cpu = source_ops(csdev)->cpu_id(csdev);
+               per_cpu(tracer_path, cpu) = path;
+               break;
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+               /*
+                * Use the hash of source's device name as ID
+                * and map the ID to the pointer of the path.
+                */
+               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+               ret = idr_alloc_u32(&path_idr, path, &hash, hash, GFP_KERNEL);
+               if (ret)
+                       goto err_source;
+               break;
+       default:
+               /* We can't be here */
+               break;
+       }
+
+out:
+       mutex_unlock(&coresight_mutex);
+       return ret;
+
+err_source:
+       coresight_disable_path(path);
+
+err_path:
+       coresight_release_path(path);
+       goto out;
+}
+EXPORT_SYMBOL_GPL(coresight_enable_sysfs);
+
+void coresight_disable_sysfs(struct coresight_device *csdev)
+{
+       int cpu, ret;
+       struct list_head *path = NULL;
+       u32 hash;
+
+       mutex_lock(&coresight_mutex);
+
+       ret = coresight_validate_source_sysfs(csdev, __func__);
+       if (ret)
+               goto out;
+
+       if (!coresight_disable_source_sysfs(csdev, NULL))
+               goto out;
+
+       switch (csdev->subtype.source_subtype) {
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC:
+               cpu = source_ops(csdev)->cpu_id(csdev);
+               path = per_cpu(tracer_path, cpu);
+               per_cpu(tracer_path, cpu) = NULL;
+               break;
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
+       case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
+               hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
+               /* Find the path by the hash. */
+               path = idr_find(&path_idr, hash);
+               if (path == NULL) {
+                       pr_err("Path is not found for %s\n", dev_name(&csdev->dev));
+                       goto out;
+               }
+               idr_remove(&path_idr, hash);
+               break;
+       default:
+               /* We can't be here */
+               break;
+       }
+
+       coresight_disable_path(path);
+       coresight_release_path(path);
+
+out:
+       mutex_unlock(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_disable_sysfs);
+
+static ssize_t enable_sink_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", csdev->sysfs_sink_activated);
+}
+
+static ssize_t enable_sink_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t size)
+{
+       int ret;
+       unsigned long val;
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       csdev->sysfs_sink_activated = !!val;
+
+       return size;
+
+}
+static DEVICE_ATTR_RW(enable_sink);
+
+static ssize_t enable_source_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       guard(mutex)(&coresight_mutex);
+       return scnprintf(buf, PAGE_SIZE, "%u\n",
+                        coresight_get_mode(csdev) == CS_MODE_SYSFS);
+}
+
+static ssize_t enable_source_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+       int ret = 0;
+       unsigned long val;
+       struct coresight_device *csdev = to_coresight_device(dev);
+
+       ret = kstrtoul(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       if (val) {
+               ret = coresight_enable_sysfs(csdev);
+               if (ret)
+                       return ret;
+       } else {
+               coresight_disable_sysfs(csdev);
+       }
+
+       return size;
+}
+static DEVICE_ATTR_RW(enable_source);
+
+static struct attribute *coresight_sink_attrs[] = {
+       &dev_attr_enable_sink.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(coresight_sink);
+
+static struct attribute *coresight_source_attrs[] = {
+       &dev_attr_enable_source.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(coresight_source);
+
+struct device_type coresight_dev_type[] = {
+       [CORESIGHT_DEV_TYPE_SINK] = {
+               .name = "sink",
+               .groups = coresight_sink_groups,
+       },
+       [CORESIGHT_DEV_TYPE_LINK] = {
+               .name = "link",
+       },
+       [CORESIGHT_DEV_TYPE_LINKSINK] = {
+               .name = "linksink",
+               .groups = coresight_sink_groups,
+       },
+       [CORESIGHT_DEV_TYPE_SOURCE] = {
+               .name = "source",
+               .groups = coresight_source_groups,
+       },
+       [CORESIGHT_DEV_TYPE_HELPER] = {
+               .name = "helper",
+       }
+};
+/* Ensure the enum matches the names and groups */
+static_assert(ARRAY_SIZE(coresight_dev_type) == CORESIGHT_DEV_TYPE_MAX);
+
 /*
  * Connections group - links attribute.
  * Count of created links between coresight components in the group.
index 7ec5365e2b6429dcc3da499d7cef9ba2ab0967a5..72005b0c633e5cd2d7ecb5d3cd2064d975590372 100644 (file)
@@ -558,7 +558,7 @@ static void tmc_shutdown(struct amba_device *adev)
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
-       if (drvdata->mode == CS_MODE_DISABLED)
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_DISABLED)
                goto out;
 
        if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
@@ -594,7 +594,7 @@ static const struct amba_id tmc_ids[] = {
        CS_AMBA_ID(0x000bb9e9),
        /* Coresight SoC 600 TMC-ETF */
        CS_AMBA_ID(0x000bb9ea),
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 MODULE_DEVICE_TABLE(amba, tmc_ids);
index 7406b65e2cdda86d22118c52ef98c50b02d1fdcc..d4f641cd9de69488fe3d1c1dc9b5a9eafb55ed59 100644 (file)
@@ -89,7 +89,7 @@ static void __tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
         * When operating in sysFS mode the content of the buffer needs to be
         * read before the TMC is disabled.
         */
-       if (drvdata->mode == CS_MODE_SYSFS)
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
                tmc_etb_dump_hw(drvdata);
        tmc_disable_hw(drvdata);
 
@@ -205,8 +205,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
         * sink is already enabled no memory is needed and the HW need not be
         * touched.
         */
-       if (drvdata->mode == CS_MODE_SYSFS) {
-               atomic_inc(&csdev->refcnt);
+       if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
+               csdev->refcnt++;
                goto out;
        }
 
@@ -228,8 +228,8 @@ static int tmc_enable_etf_sink_sysfs(struct coresight_device *csdev)
 
        ret = tmc_etb_enable_hw(drvdata);
        if (!ret) {
-               drvdata->mode = CS_MODE_SYSFS;
-               atomic_inc(&csdev->refcnt);
+               coresight_set_mode(csdev, CS_MODE_SYSFS);
+               csdev->refcnt++;
        } else {
                /* Free up the buffer if we failed to enable */
                used = false;
@@ -262,7 +262,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
                 * No need to continue if the ETB/ETF is already operated
                 * from sysFS.
                 */
-               if (drvdata->mode == CS_MODE_SYSFS) {
+               if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
                        ret = -EBUSY;
                        break;
                }
@@ -284,7 +284,7 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
                 * use for this session.
                 */
                if (drvdata->pid == pid) {
-                       atomic_inc(&csdev->refcnt);
+                       csdev->refcnt++;
                        break;
                }
 
@@ -292,8 +292,8 @@ static int tmc_enable_etf_sink_perf(struct coresight_device *csdev, void *data)
                if (!ret) {
                        /* Associate with monitored process. */
                        drvdata->pid = pid;
-                       drvdata->mode = CS_MODE_PERF;
-                       atomic_inc(&csdev->refcnt);
+                       coresight_set_mode(csdev, CS_MODE_PERF);
+                       csdev->refcnt++;
                }
        } while (0);
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -338,17 +338,18 @@ static int tmc_disable_etf_sink(struct coresight_device *csdev)
                return -EBUSY;
        }
 
-       if (atomic_dec_return(&csdev->refcnt)) {
+       csdev->refcnt--;
+       if (csdev->refcnt) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                return -EBUSY;
        }
 
        /* Complain if we (somehow) got out of sync */
-       WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+       WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
        tmc_etb_disable_hw(drvdata);
        /* Dissociate from monitored process. */
        drvdata->pid = -1;
-       drvdata->mode = CS_MODE_DISABLED;
+       coresight_set_mode(csdev, CS_MODE_DISABLED);
 
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
@@ -371,15 +372,15 @@ static int tmc_enable_etf_link(struct coresight_device *csdev,
                return -EBUSY;
        }
 
-       if (atomic_read(&csdev->refcnt) == 0) {
+       if (csdev->refcnt == 0) {
                ret = tmc_etf_enable_hw(drvdata);
                if (!ret) {
-                       drvdata->mode = CS_MODE_SYSFS;
+                       coresight_set_mode(csdev, CS_MODE_SYSFS);
                        first_enable = true;
                }
        }
        if (!ret)
-               atomic_inc(&csdev->refcnt);
+               csdev->refcnt++;
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        if (first_enable)
@@ -401,9 +402,10 @@ static void tmc_disable_etf_link(struct coresight_device *csdev,
                return;
        }
 
-       if (atomic_dec_return(&csdev->refcnt) == 0) {
+       csdev->refcnt--;
+       if (csdev->refcnt == 0) {
                tmc_etf_disable_hw(drvdata);
-               drvdata->mode = CS_MODE_DISABLED;
+               coresight_set_mode(csdev, CS_MODE_DISABLED);
                last_disable = true;
        }
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
@@ -483,13 +485,13 @@ static unsigned long tmc_update_etf_buffer(struct coresight_device *csdev,
                return 0;
 
        /* This shouldn't happen */
-       if (WARN_ON_ONCE(drvdata->mode != CS_MODE_PERF))
+       if (WARN_ON_ONCE(coresight_get_mode(csdev) != CS_MODE_PERF))
                return 0;
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't do anything if another tracer is using this sink */
-       if (atomic_read(&csdev->refcnt) != 1)
+       if (csdev->refcnt != 1)
                goto out;
 
        CS_UNLOCK(drvdata->base);
@@ -629,7 +631,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
        }
 
        /* Don't interfere if operated from Perf */
-       if (drvdata->mode == CS_MODE_PERF) {
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_PERF) {
                ret = -EINVAL;
                goto out;
        }
@@ -641,7 +643,7 @@ int tmc_read_prepare_etb(struct tmc_drvdata *drvdata)
        }
 
        /* Disable the TMC if need be */
-       if (drvdata->mode == CS_MODE_SYSFS) {
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
                /* There is no point in reading a TMC in HW FIFO mode */
                mode = readl_relaxed(drvdata->base + TMC_MODE);
                if (mode != TMC_MODE_CIRCULAR_BUFFER) {
@@ -673,7 +675,7 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Re-enable the TMC if need be */
-       if (drvdata->mode == CS_MODE_SYSFS) {
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
                /* There is no point in reading a TMC in HW FIFO mode */
                mode = readl_relaxed(drvdata->base + TMC_MODE);
                if (mode != TMC_MODE_CIRCULAR_BUFFER) {
index af02ba5d5f15de7160421f8ba4d256907e4bd7dd..e75428fa1592a78780e7e7f05b47a88d2a79123c 100644 (file)
@@ -1143,7 +1143,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
         * When operating in sysFS mode the content of the buffer needs to be
         * read before the TMC is disabled.
         */
-       if (drvdata->mode == CS_MODE_SYSFS)
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
                tmc_etr_sync_sysfs_buf(drvdata);
 
        tmc_disable_hw(drvdata);
@@ -1189,7 +1189,7 @@ static struct etr_buf *tmc_etr_get_sysfs_buffer(struct coresight_device *csdev)
                spin_lock_irqsave(&drvdata->spinlock, flags);
        }
 
-       if (drvdata->reading || drvdata->mode == CS_MODE_PERF) {
+       if (drvdata->reading || coresight_get_mode(csdev) == CS_MODE_PERF) {
                ret = -EBUSY;
                goto out;
        }
@@ -1230,15 +1230,15 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
         * sink is already enabled no memory is needed and the HW need not be
         * touched, even if the buffer size has changed.
         */
-       if (drvdata->mode == CS_MODE_SYSFS) {
-               atomic_inc(&csdev->refcnt);
+       if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
+               csdev->refcnt++;
                goto out;
        }
 
        ret = tmc_etr_enable_hw(drvdata, sysfs_buf);
        if (!ret) {
-               drvdata->mode = CS_MODE_SYSFS;
-               atomic_inc(&csdev->refcnt);
+               coresight_set_mode(csdev, CS_MODE_SYSFS);
+               csdev->refcnt++;
        }
 
 out:
@@ -1564,7 +1564,7 @@ tmc_update_etr_buffer(struct coresight_device *csdev,
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* Don't do anything if another tracer is using this sink */
-       if (atomic_read(&csdev->refcnt) != 1) {
+       if (csdev->refcnt != 1) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                goto out;
        }
@@ -1652,7 +1652,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
 
        spin_lock_irqsave(&drvdata->spinlock, flags);
         /* Don't use this sink if it is already claimed by sysFS */
-       if (drvdata->mode == CS_MODE_SYSFS) {
+       if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
                rc = -EBUSY;
                goto unlock_out;
        }
@@ -1676,7 +1676,7 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
         * use for this session.
         */
        if (drvdata->pid == pid) {
-               atomic_inc(&csdev->refcnt);
+               csdev->refcnt++;
                goto unlock_out;
        }
 
@@ -1684,9 +1684,9 @@ static int tmc_enable_etr_sink_perf(struct coresight_device *csdev, void *data)
        if (!rc) {
                /* Associate with monitored process. */
                drvdata->pid = pid;
-               drvdata->mode = CS_MODE_PERF;
+               coresight_set_mode(csdev, CS_MODE_PERF);
                drvdata->perf_buf = etr_perf->etr_buf;
-               atomic_inc(&csdev->refcnt);
+               csdev->refcnt++;
        }
 
 unlock_out:
@@ -1719,17 +1719,18 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev)
                return -EBUSY;
        }
 
-       if (atomic_dec_return(&csdev->refcnt)) {
+       csdev->refcnt--;
+       if (csdev->refcnt) {
                spin_unlock_irqrestore(&drvdata->spinlock, flags);
                return -EBUSY;
        }
 
        /* Complain if we (somehow) got out of sync */
-       WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+       WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
        tmc_etr_disable_hw(drvdata);
        /* Dissociate from monitored process. */
        drvdata->pid = -1;
-       drvdata->mode = CS_MODE_DISABLED;
+       coresight_set_mode(csdev, CS_MODE_DISABLED);
        /* Reset perf specific data */
        drvdata->perf_buf = NULL;
 
@@ -1777,7 +1778,7 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata)
        }
 
        /* Disable the TMC if we are trying to read from a running session. */
-       if (drvdata->mode == CS_MODE_SYSFS)
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS)
                __tmc_etr_disable_hw(drvdata);
 
        drvdata->reading = true;
@@ -1799,7 +1800,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
        spin_lock_irqsave(&drvdata->spinlock, flags);
 
        /* RE-enable the TMC if need be */
-       if (drvdata->mode == CS_MODE_SYSFS) {
+       if (coresight_get_mode(drvdata->csdev) == CS_MODE_SYSFS) {
                /*
                 * The trace run will continue with the same allocated trace
                 * buffer. Since the tracer is still enabled drvdata::buf can't
index 8dcb426ac3e7aa259393ab2e550d4bf186dbbc46..cef979c897e62de087430d175e01b23ab6b06b05 100644 (file)
@@ -178,7 +178,6 @@ struct etr_buf {
  * @size:      trace buffer size for this TMC (common for all modes).
  * @max_burst_size: The maximum burst size that can be initiated by
  *             TMC-ETR on AXI bus.
- * @mode:      how this TMC is being used.
  * @config_type: TMC variant, must be of type @tmc_config_type.
  * @memwidth:  width of the memory interface databus, in bytes.
  * @trigger_cntr: amount of words to store after a trigger.
@@ -203,7 +202,6 @@ struct tmc_drvdata {
        u32                     len;
        u32                     size;
        u32                     max_burst_size;
-       u32                     mode;
        enum tmc_config_type    config_type;
        enum tmc_mem_intf_width memwidth;
        u32                     trigger_cntr;
index 5f82737c37bba5b063c8a80c86e78227b7759cc9..7739bc7adc449edcac598a29405c3cba02466e06 100644 (file)
@@ -18,6 +18,7 @@
 #include "coresight-priv.h"
 #include "coresight-tpda.h"
 #include "coresight-trace-id.h"
+#include "coresight-tpdm.h"
 
 DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
 
@@ -28,24 +29,59 @@ static bool coresight_device_is_tpdm(struct coresight_device *csdev)
                        CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
 }
 
+static void tpda_clear_element_size(struct coresight_device *csdev)
+{
+       struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+       drvdata->dsb_esize = 0;
+       drvdata->cmb_esize = 0;
+}
+
+static void tpda_set_element_size(struct tpda_drvdata *drvdata, u32 *val)
+{
+       /* Clear all relevant fields */
+       *val &= ~(TPDA_Pn_CR_DSBSIZE | TPDA_Pn_CR_CMBSIZE);
+
+       if (drvdata->dsb_esize == 64)
+               *val |= TPDA_Pn_CR_DSBSIZE;
+       else if (drvdata->dsb_esize == 32)
+               *val &= ~TPDA_Pn_CR_DSBSIZE;
+
+       if (drvdata->cmb_esize == 64)
+               *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x2);
+       else if (drvdata->cmb_esize == 32)
+               *val |= FIELD_PREP(TPDA_Pn_CR_CMBSIZE, 0x1);
+       else if (drvdata->cmb_esize == 8)
+               *val &= ~TPDA_Pn_CR_CMBSIZE;
+}
+
 /*
- * Read the DSB element size from the TPDM device
+ * Read the element size from the TPDM device. One TPDM must have at least one of the
+ * element size property.
  * Returns
- *    The dsb element size read from the devicetree if available.
- *    0 - Otherwise, with a warning once.
+ *    0 - The element size property is read
+ *    Others - Cannot read the property of the element size
  */
-static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
+static int tpdm_read_element_size(struct tpda_drvdata *drvdata,
+                                 struct coresight_device *csdev)
 {
-       int rc = 0;
-       u8 size = 0;
+       int rc = -EINVAL;
+       struct tpdm_drvdata *tpdm_data = dev_get_drvdata(csdev->dev.parent);
+
+       if (tpdm_has_dsb_dataset(tpdm_data)) {
+               rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
+                               "qcom,dsb-element-bits", &drvdata->dsb_esize);
+       }
+       if (tpdm_has_cmb_dataset(tpdm_data)) {
+               rc = fwnode_property_read_u32(dev_fwnode(csdev->dev.parent),
+                               "qcom,cmb-element-bits", &drvdata->cmb_esize);
+       }
 
-       rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent),
-                       "qcom,dsb-element-size", &size);
        if (rc)
                dev_warn_once(&csdev->dev,
-                       "Failed to read TPDM DSB Element size: %d\n", rc);
+                       "Failed to read TPDM Element size: %d\n", rc);
 
-       return size;
+       return rc;
 }
 
 /*
@@ -56,11 +92,12 @@ static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
  * Parameter "inport" is used to pass in the input port number
  * of TPDA, and it is set to -1 in the recursize call.
  */
-static int tpda_get_element_size(struct coresight_device *csdev,
+static int tpda_get_element_size(struct tpda_drvdata *drvdata,
+                                struct coresight_device *csdev,
                                 int inport)
 {
-       int dsb_size = -ENOENT;
-       int i, size;
+       int rc = 0;
+       int i;
        struct coresight_device *in;
 
        for (i = 0; i < csdev->pdata->nr_inconns; i++) {
@@ -69,30 +106,26 @@ static int tpda_get_element_size(struct coresight_device *csdev,
                        continue;
 
                /* Ignore the paths that do not match port */
-               if (inport > 0 &&
+               if (inport >= 0 &&
                    csdev->pdata->in_conns[i]->dest_port != inport)
                        continue;
 
                if (coresight_device_is_tpdm(in)) {
-                       size = tpdm_read_dsb_element_size(in);
+                       if (drvdata->dsb_esize || drvdata->cmb_esize)
+                               return -EEXIST;
+                       rc = tpdm_read_element_size(drvdata, in);
+                       if (rc)
+                               return rc;
                } else {
                        /* Recurse down the path */
-                       size = tpda_get_element_size(in, -1);
-               }
-
-               if (size < 0)
-                       return size;
-
-               if (dsb_size < 0) {
-                       /* Found a size, save it. */
-                       dsb_size = size;
-               } else {
-                       /* Found duplicate TPDMs */
-                       return -EEXIST;
+                       rc = tpda_get_element_size(drvdata, in, -1);
+                       if (rc)
+                               return rc;
                }
        }
 
-       return dsb_size;
+
+       return rc;
 }
 
 /* Settings pre enabling port control register */
@@ -109,37 +142,24 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
 static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
 {
        u32 val;
-       int size;
+       int rc;
 
        val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
-       /*
-        * Configure aggregator port n DSB data set element size
-        * Set the bit to 0 if the size is 32
-        * Set the bit to 1 if the size is 64
-        */
-       size = tpda_get_element_size(drvdata->csdev, port);
-       switch (size) {
-       case 32:
-               val &= ~TPDA_Pn_CR_DSBSIZE;
-               break;
-       case 64:
-               val |= TPDA_Pn_CR_DSBSIZE;
-               break;
-       case 0:
-               return -EEXIST;
-       case -EEXIST:
+       tpda_clear_element_size(drvdata->csdev);
+       rc = tpda_get_element_size(drvdata, drvdata->csdev, port);
+       if (!rc && (drvdata->dsb_esize || drvdata->cmb_esize)) {
+               tpda_set_element_size(drvdata, &val);
+               /* Enable the port */
+               val |= TPDA_Pn_CR_ENA;
+               writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+       } else if (rc == -EEXIST)
                dev_warn_once(&drvdata->csdev->dev,
-                       "Detected multiple TPDMs on port %d", -EEXIST);
-               return -EEXIST;
-       default:
-               return -EINVAL;
-       }
-
-       /* Enable the port */
-       val |= TPDA_Pn_CR_ENA;
-       writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+                             "Detected multiple TPDMs on port %d", port);
+       else
+               dev_warn_once(&drvdata->csdev->dev,
+                             "Didn't find TPDM element size");
 
-       return 0;
+       return rc;
 }
 
 static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
@@ -148,7 +168,12 @@ static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
 
        CS_UNLOCK(drvdata->base);
 
-       if (!drvdata->csdev->enable)
+       /*
+        * Only do pre-port enable for first port that calls enable when the
+        * device's main refcount is still 0
+        */
+       lockdep_assert_held(&drvdata->spinlock);
+       if (!drvdata->csdev->refcnt)
                tpda_enable_pre_port(drvdata);
 
        ret = tpda_enable_port(drvdata, port);
@@ -169,6 +194,7 @@ static int tpda_enable(struct coresight_device *csdev,
                ret = __tpda_enable(drvdata, in->dest_port);
                if (!ret) {
                        atomic_inc(&in->dest_refcnt);
+                       csdev->refcnt++;
                        dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
                }
        }
@@ -197,9 +223,10 @@ static void tpda_disable(struct coresight_device *csdev,
        struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        spin_lock(&drvdata->spinlock);
-       if (atomic_dec_return(&in->dest_refcnt) == 0)
+       if (atomic_dec_return(&in->dest_refcnt) == 0) {
                __tpda_disable(drvdata, in->dest_port);
-
+               csdev->refcnt--;
+       }
        spin_unlock(&drvdata->spinlock);
 
        dev_dbg(drvdata->dev, "TPDA inport %d disabled\n", in->dest_port);
@@ -300,7 +327,7 @@ static struct amba_id tpda_ids[] = {
                .id     = 0x000f0f00,
                .mask   = 0x000fff00,
        },
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 static struct amba_driver tpda_driver = {
index b3b38fd41b64bc84ceacff3926fe34341f8f1a25..c6af3d2da3efeaeef64ba9023f1c280583b542e6 100644 (file)
@@ -10,6 +10,8 @@
 #define TPDA_Pn_CR(n)          (0x004 + (n * 4))
 /* Aggregator port enable bit */
 #define TPDA_Pn_CR_ENA         BIT(0)
+/* Aggregator port CMB data set element size bit */
+#define TPDA_Pn_CR_CMBSIZE             GENMASK(7, 6)
 /* Aggregator port DSB data set element size bit */
 #define TPDA_Pn_CR_DSBSIZE             BIT(8)
 
@@ -25,6 +27,8 @@
  * @csdev:      component vitals needed by the framework.
  * @spinlock:   lock for the drvdata value.
  * @enable:     enable status of the component.
+ * @dsb_esize   Record the DSB element size.
+ * @cmb_esize   Record the CMB element size.
  */
 struct tpda_drvdata {
        void __iomem            *base;
@@ -32,6 +36,8 @@ struct tpda_drvdata {
        struct coresight_device *csdev;
        spinlock_t              spinlock;
        u8                      atid;
+       u32                     dsb_esize;
+       u32                     cmb_esize;
 };
 
 #endif  /* _CORESIGHT_CORESIGHT_TPDA_H */
index 97654aa4b772a07307f798ed93a79fb760960ed0..a9708ab0d4886c46043731314ca304790af4fc4d 100644 (file)
@@ -66,6 +66,31 @@ static ssize_t tpdm_simple_dataset_show(struct device *dev,
                        return -EINVAL;
                return sysfs_emit(buf, "0x%x\n",
                                drvdata->dsb->msr[tpdm_attr->idx]);
+       case CMB_TRIG_PATT:
+               if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+                       return -EINVAL;
+               return sysfs_emit(buf, "0x%x\n",
+                       drvdata->cmb->trig_patt[tpdm_attr->idx]);
+       case CMB_TRIG_PATT_MASK:
+               if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+                       return -EINVAL;
+               return sysfs_emit(buf, "0x%x\n",
+                       drvdata->cmb->trig_patt_mask[tpdm_attr->idx]);
+       case CMB_PATT:
+               if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+                       return -EINVAL;
+               return sysfs_emit(buf, "0x%x\n",
+                       drvdata->cmb->patt_val[tpdm_attr->idx]);
+       case CMB_PATT_MASK:
+               if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT)
+                       return -EINVAL;
+               return sysfs_emit(buf, "0x%x\n",
+                       drvdata->cmb->patt_mask[tpdm_attr->idx]);
+       case CMB_MSR:
+               if (tpdm_attr->idx >= drvdata->cmb_msr_num)
+                       return -EINVAL;
+               return sysfs_emit(buf, "0x%x\n",
+                               drvdata->cmb->msr[tpdm_attr->idx]);
        }
        return -EINVAL;
 }
@@ -77,67 +102,103 @@ static ssize_t tpdm_simple_dataset_store(struct device *dev,
                                         size_t size)
 {
        unsigned long val;
-       ssize_t ret = size;
+       ssize_t ret = -EINVAL;
 
        struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
        struct tpdm_dataset_attribute *tpdm_attr =
                container_of(attr, struct tpdm_dataset_attribute, attr);
 
        if (kstrtoul(buf, 0, &val))
-               return -EINVAL;
+               return ret;
 
-       spin_lock(&drvdata->spinlock);
+       guard(spinlock)(&drvdata->spinlock);
        switch (tpdm_attr->mem) {
        case DSB_TRIG_PATT:
-               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
                        drvdata->dsb->trig_patt[tpdm_attr->idx] = val;
-               else
-                       ret = -EINVAL;
+                       ret = size;
+               }
                break;
        case DSB_TRIG_PATT_MASK:
-               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
                        drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;
-               else
-                       ret = -EINVAL;
+                       ret = size;
+               }
                break;
        case DSB_PATT:
-               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
                        drvdata->dsb->patt_val[tpdm_attr->idx] = val;
-               else
-                       ret = -EINVAL;
+                       ret = size;
+               }
                break;
        case DSB_PATT_MASK:
-               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+               if (tpdm_attr->idx < TPDM_DSB_MAX_PATT) {
                        drvdata->dsb->patt_mask[tpdm_attr->idx] = val;
-               else
-                       ret = -EINVAL;
+                       ret = size;
+               }
                break;
        case DSB_MSR:
-               if (tpdm_attr->idx < drvdata->dsb_msr_num)
+               if (tpdm_attr->idx < drvdata->dsb_msr_num) {
                        drvdata->dsb->msr[tpdm_attr->idx] = val;
-               else
-                       ret = -EINVAL;
+                       ret = size;
+               }
+               break;
+       case CMB_TRIG_PATT:
+               if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+                       drvdata->cmb->trig_patt[tpdm_attr->idx] = val;
+                       ret = size;
+               }
+               break;
+       case CMB_TRIG_PATT_MASK:
+               if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+                       drvdata->cmb->trig_patt_mask[tpdm_attr->idx] = val;
+                       ret = size;
+               }
+               break;
+       case CMB_PATT:
+               if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+                       drvdata->cmb->patt_val[tpdm_attr->idx] = val;
+                       ret = size;
+               }
+               break;
+       case CMB_PATT_MASK:
+               if (tpdm_attr->idx < TPDM_CMB_MAX_PATT) {
+                       drvdata->cmb->patt_mask[tpdm_attr->idx] = val;
+                       ret = size;
+               }
+               break;
+       case CMB_MSR:
+               if (tpdm_attr->idx < drvdata->cmb_msr_num) {
+                       drvdata->cmb->msr[tpdm_attr->idx] = val;
+                       ret = size;
+               }
                break;
        default:
-               ret = -EINVAL;
+               break;
        }
-       spin_unlock(&drvdata->spinlock);
 
        return ret;
 }
 
-static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
+static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
+                                  struct attribute *attr, int n)
 {
-       return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
+       struct device *dev = kobj_to_dev(kobj);
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+       if (drvdata && tpdm_has_dsb_dataset(drvdata))
+               return attr->mode;
+
+       return 0;
 }
 
-static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
+static umode_t tpdm_cmb_is_visible(struct kobject *kobj,
                                   struct attribute *attr, int n)
 {
        struct device *dev = kobj_to_dev(kobj);
        struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
 
-       if (drvdata && tpdm_has_dsb_dataset(drvdata))
+       if (drvdata && tpdm_has_cmb_dataset(drvdata))
                return attr->mode;
 
        return 0;
@@ -159,6 +220,23 @@ static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
        return 0;
 }
 
+static umode_t tpdm_cmb_msr_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+       struct device_attribute *dev_attr =
+               container_of(attr, struct device_attribute, attr);
+       struct tpdm_dataset_attribute *tpdm_attr =
+               container_of(dev_attr, struct tpdm_dataset_attribute, attr);
+
+       if (tpdm_attr->idx < drvdata->cmb_msr_num)
+               return attr->mode;
+
+       return 0;
+}
+
 static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
 {
        if (tpdm_has_dsb_dataset(drvdata)) {
@@ -167,6 +245,9 @@ static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
                drvdata->dsb->trig_ts = true;
                drvdata->dsb->trig_type = false;
        }
+
+       if (drvdata->cmb)
+               memset(drvdata->cmb, 0, sizeof(struct cmb_dataset));
 }
 
 static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)
@@ -233,25 +314,27 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
 {
        u32 val, i;
 
+       if (!tpdm_has_dsb_dataset(drvdata))
+               return;
+
        for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
                writel_relaxed(drvdata->dsb->edge_ctrl[i],
-                          drvdata->base + TPDM_DSB_EDCR(i));
+                              drvdata->base + TPDM_DSB_EDCR(i));
        for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
                writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
-                          drvdata->base + TPDM_DSB_EDCMR(i));
+                              drvdata->base + TPDM_DSB_EDCMR(i));
        for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
                writel_relaxed(drvdata->dsb->patt_val[i],
-                          drvdata->base + TPDM_DSB_TPR(i));
+                              drvdata->base + TPDM_DSB_TPR(i));
                writel_relaxed(drvdata->dsb->patt_mask[i],
-                          drvdata->base + TPDM_DSB_TPMR(i));
+                              drvdata->base + TPDM_DSB_TPMR(i));
                writel_relaxed(drvdata->dsb->trig_patt[i],
-                          drvdata->base + TPDM_DSB_XPR(i));
+                              drvdata->base + TPDM_DSB_XPR(i));
                writel_relaxed(drvdata->dsb->trig_patt_mask[i],
-                          drvdata->base + TPDM_DSB_XPMR(i));
+                              drvdata->base + TPDM_DSB_XPMR(i));
        }
 
        set_dsb_tier(drvdata);
-
        set_dsb_msr(drvdata);
 
        val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
@@ -267,6 +350,76 @@ static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
        writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
 }
 
+static void set_cmb_tier(struct tpdm_drvdata *drvdata)
+{
+       u32 val;
+
+       val = readl_relaxed(drvdata->base + TPDM_CMB_TIER);
+
+       /* Clear all relevant fields */
+       val &= ~(TPDM_CMB_TIER_PATT_TSENAB | TPDM_CMB_TIER_TS_ALL |
+                TPDM_CMB_TIER_XTRIG_TSENAB);
+
+       /* Set pattern timestamp type and enablement */
+       if (drvdata->cmb->patt_ts)
+               val |= TPDM_CMB_TIER_PATT_TSENAB;
+
+       /* Set trigger timestamp */
+       if (drvdata->cmb->trig_ts)
+               val |= TPDM_CMB_TIER_XTRIG_TSENAB;
+
+       /* Set all timestamp enablement*/
+       if (drvdata->cmb->ts_all)
+               val |= TPDM_CMB_TIER_TS_ALL;
+
+       writel_relaxed(val, drvdata->base + TPDM_CMB_TIER);
+}
+
+static void set_cmb_msr(struct tpdm_drvdata *drvdata)
+{
+       int i;
+
+       for (i = 0; i < drvdata->cmb_msr_num; i++)
+               writel_relaxed(drvdata->cmb->msr[i],
+                          drvdata->base + TPDM_CMB_MSR(i));
+}
+
+static void tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
+{
+       u32 val, i;
+
+       if (!tpdm_has_cmb_dataset(drvdata))
+               return;
+
+       /* Configure pattern registers */
+       for (i = 0; i < TPDM_CMB_MAX_PATT; i++) {
+               writel_relaxed(drvdata->cmb->patt_val[i],
+                       drvdata->base + TPDM_CMB_TPR(i));
+               writel_relaxed(drvdata->cmb->patt_mask[i],
+                       drvdata->base + TPDM_CMB_TPMR(i));
+               writel_relaxed(drvdata->cmb->trig_patt[i],
+                       drvdata->base + TPDM_CMB_XPR(i));
+               writel_relaxed(drvdata->cmb->trig_patt_mask[i],
+                       drvdata->base + TPDM_CMB_XPMR(i));
+       }
+
+       set_cmb_tier(drvdata);
+       set_cmb_msr(drvdata);
+
+       val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
+       /*
+        * Set to 0 for continuous CMB collection mode,
+        * 1 for trace-on-change CMB collection mode.
+        */
+       if (drvdata->cmb->trace_mode)
+               val |= TPDM_CMB_CR_MODE;
+       else
+               val &= ~TPDM_CMB_CR_MODE;
+       /* Set the enable bit of CMB control register to 1 */
+       val |= TPDM_CMB_CR_ENA;
+       writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
+}
+
 /*
  * TPDM enable operations
  * The TPDM or Monitor serves as data collection component for various
@@ -279,8 +432,8 @@ static void __tpdm_enable(struct tpdm_drvdata *drvdata)
 {
        CS_UNLOCK(drvdata->base);
 
-       if (tpdm_has_dsb_dataset(drvdata))
-               tpdm_enable_dsb(drvdata);
+       tpdm_enable_dsb(drvdata);
+       tpdm_enable_cmb(drvdata);
 
        CS_LOCK(drvdata->base);
 }
@@ -308,19 +461,35 @@ static void tpdm_disable_dsb(struct tpdm_drvdata *drvdata)
 {
        u32 val;
 
+       if (!tpdm_has_dsb_dataset(drvdata))
+               return;
+
        /* Set the enable bit of DSB control register to 0 */
        val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
        val &= ~TPDM_DSB_CR_ENA;
        writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
 }
 
+static void tpdm_disable_cmb(struct tpdm_drvdata *drvdata)
+{
+       u32 val;
+
+       if (!tpdm_has_cmb_dataset(drvdata))
+               return;
+
+       val = readl_relaxed(drvdata->base + TPDM_CMB_CR);
+       /* Set the enable bit of CMB control register to 0 */
+       val &= ~TPDM_CMB_CR_ENA;
+       writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
+}
+
 /* TPDM disable operations */
 static void __tpdm_disable(struct tpdm_drvdata *drvdata)
 {
        CS_UNLOCK(drvdata->base);
 
-       if (tpdm_has_dsb_dataset(drvdata))
-               tpdm_disable_dsb(drvdata);
+       tpdm_disable_dsb(drvdata);
+       tpdm_disable_cmb(drvdata);
 
        CS_LOCK(drvdata->base);
 }
@@ -366,6 +535,12 @@ static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
                if (!drvdata->dsb)
                        return -ENOMEM;
        }
+       if (tpdm_has_cmb_dataset(drvdata) && (!drvdata->cmb)) {
+               drvdata->cmb = devm_kzalloc(drvdata->dev,
+                                               sizeof(*drvdata->cmb), GFP_KERNEL);
+               if (!drvdata->cmb)
+                       return -ENOMEM;
+       }
        tpdm_reset_datasets(drvdata);
 
        return 0;
@@ -577,9 +752,18 @@ static ssize_t enable_ts_show(struct device *dev,
                              char *buf)
 {
        struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+       struct tpdm_dataset_attribute *tpdm_attr =
+               container_of(attr, struct tpdm_dataset_attribute, attr);
+       ssize_t size = -EINVAL;
 
-       return sysfs_emit(buf, "%u\n",
-                        (unsigned int)drvdata->dsb->patt_ts);
+       if (tpdm_attr->mem == DSB_PATT)
+               size = sysfs_emit(buf, "%u\n",
+                                 (unsigned int)drvdata->dsb->patt_ts);
+       else if (tpdm_attr->mem == CMB_PATT)
+               size = sysfs_emit(buf, "%u\n",
+                                 (unsigned int)drvdata->cmb->patt_ts);
+
+       return size;
 }
 
 /*
@@ -591,17 +775,23 @@ static ssize_t enable_ts_store(struct device *dev,
                               size_t size)
 {
        struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+       struct tpdm_dataset_attribute *tpdm_attr =
+               container_of(attr, struct tpdm_dataset_attribute, attr);
        unsigned long val;
 
        if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
                return -EINVAL;
 
-       spin_lock(&drvdata->spinlock);
-       drvdata->dsb->patt_ts = !!val;
-       spin_unlock(&drvdata->spinlock);
+       guard(spinlock)(&drvdata->spinlock);
+       if (tpdm_attr->mem == DSB_PATT)
+               drvdata->dsb->patt_ts = !!val;
+       else if (tpdm_attr->mem == CMB_PATT)
+               drvdata->cmb->patt_ts = !!val;
+       else
+               return -EINVAL;
+
        return size;
 }
-static DEVICE_ATTR_RW(enable_ts);
 
 static ssize_t set_type_show(struct device *dev,
                             struct device_attribute *attr,
@@ -704,6 +894,96 @@ static ssize_t dsb_trig_ts_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(dsb_trig_ts);
 
+static ssize_t cmb_mode_show(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+       return sysfs_emit(buf, "%x\n", drvdata->cmb->trace_mode);
+
+}
+
+static ssize_t cmb_mode_store(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf,
+                             size_t size)
+{
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+       unsigned long trace_mode;
+
+       if (kstrtoul(buf, 0, &trace_mode) || (trace_mode & ~1UL))
+               return -EINVAL;
+
+       spin_lock(&drvdata->spinlock);
+       drvdata->cmb->trace_mode = trace_mode;
+       spin_unlock(&drvdata->spinlock);
+       return size;
+}
+static DEVICE_ATTR_RW(cmb_mode);
+
+static ssize_t cmb_ts_all_show(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+       return sysfs_emit(buf, "%u\n",
+                         (unsigned int)drvdata->cmb->ts_all);
+}
+
+static ssize_t cmb_ts_all_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf,
+                               size_t size)
+{
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+       unsigned long val;
+
+       if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+               return -EINVAL;
+
+       guard(spinlock)(&drvdata->spinlock);
+       if (val)
+               drvdata->cmb->ts_all = true;
+       else
+               drvdata->cmb->ts_all = false;
+
+       return size;
+}
+static DEVICE_ATTR_RW(cmb_ts_all);
+
+static ssize_t cmb_trig_ts_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+       return sysfs_emit(buf, "%u\n",
+                         (unsigned int)drvdata->cmb->trig_ts);
+}
+
+static ssize_t cmb_trig_ts_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf,
+                                size_t size)
+{
+       struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+       unsigned long val;
+
+       if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+               return -EINVAL;
+
+       guard(spinlock)(&drvdata->spinlock);
+       if (val)
+               drvdata->cmb->trig_ts = true;
+       else
+               drvdata->cmb->trig_ts = false;
+
+       return size;
+}
+static DEVICE_ATTR_RW(cmb_trig_ts);
+
 static struct attribute *tpdm_dsb_edge_attrs[] = {
        &dev_attr_ctrl_idx.attr,
        &dev_attr_ctrl_val.attr,
@@ -772,7 +1052,7 @@ static struct attribute *tpdm_dsb_patt_attrs[] = {
        DSB_PATT_MASK_ATTR(5),
        DSB_PATT_MASK_ATTR(6),
        DSB_PATT_MASK_ATTR(7),
-       &dev_attr_enable_ts.attr,
+       DSB_PATT_ENABLE_TS,
        &dev_attr_set_type.attr,
        NULL,
 };
@@ -813,6 +1093,59 @@ static struct attribute *tpdm_dsb_msr_attrs[] = {
        NULL,
 };
 
+static struct attribute *tpdm_cmb_trig_patt_attrs[] = {
+       CMB_TRIG_PATT_ATTR(0),
+       CMB_TRIG_PATT_ATTR(1),
+       CMB_TRIG_PATT_MASK_ATTR(0),
+       CMB_TRIG_PATT_MASK_ATTR(1),
+       NULL,
+};
+
+static struct attribute *tpdm_cmb_patt_attrs[] = {
+       CMB_PATT_ATTR(0),
+       CMB_PATT_ATTR(1),
+       CMB_PATT_MASK_ATTR(0),
+       CMB_PATT_MASK_ATTR(1),
+       CMB_PATT_ENABLE_TS,
+       NULL,
+};
+
+static struct attribute *tpdm_cmb_msr_attrs[] = {
+       CMB_MSR_ATTR(0),
+       CMB_MSR_ATTR(1),
+       CMB_MSR_ATTR(2),
+       CMB_MSR_ATTR(3),
+       CMB_MSR_ATTR(4),
+       CMB_MSR_ATTR(5),
+       CMB_MSR_ATTR(6),
+       CMB_MSR_ATTR(7),
+       CMB_MSR_ATTR(8),
+       CMB_MSR_ATTR(9),
+       CMB_MSR_ATTR(10),
+       CMB_MSR_ATTR(11),
+       CMB_MSR_ATTR(12),
+       CMB_MSR_ATTR(13),
+       CMB_MSR_ATTR(14),
+       CMB_MSR_ATTR(15),
+       CMB_MSR_ATTR(16),
+       CMB_MSR_ATTR(17),
+       CMB_MSR_ATTR(18),
+       CMB_MSR_ATTR(19),
+       CMB_MSR_ATTR(20),
+       CMB_MSR_ATTR(21),
+       CMB_MSR_ATTR(22),
+       CMB_MSR_ATTR(23),
+       CMB_MSR_ATTR(24),
+       CMB_MSR_ATTR(25),
+       CMB_MSR_ATTR(26),
+       CMB_MSR_ATTR(27),
+       CMB_MSR_ATTR(28),
+       CMB_MSR_ATTR(29),
+       CMB_MSR_ATTR(30),
+       CMB_MSR_ATTR(31),
+       NULL,
+};
+
 static struct attribute *tpdm_dsb_attrs[] = {
        &dev_attr_dsb_mode.attr,
        &dev_attr_dsb_trig_ts.attr,
@@ -820,6 +1153,13 @@ static struct attribute *tpdm_dsb_attrs[] = {
        NULL,
 };
 
+static struct attribute *tpdm_cmb_attrs[] = {
+       &dev_attr_cmb_mode.attr,
+       &dev_attr_cmb_ts_all.attr,
+       &dev_attr_cmb_trig_ts.attr,
+       NULL,
+};
+
 static struct attribute_group tpdm_dsb_attr_grp = {
        .attrs = tpdm_dsb_attrs,
        .is_visible = tpdm_dsb_is_visible,
@@ -849,6 +1189,29 @@ static struct attribute_group tpdm_dsb_msr_grp = {
        .name = "dsb_msr",
 };
 
+static struct attribute_group tpdm_cmb_attr_grp = {
+       .attrs = tpdm_cmb_attrs,
+       .is_visible = tpdm_cmb_is_visible,
+};
+
+static struct attribute_group tpdm_cmb_trig_patt_grp = {
+       .attrs = tpdm_cmb_trig_patt_attrs,
+       .is_visible = tpdm_cmb_is_visible,
+       .name = "cmb_trig_patt",
+};
+
+static struct attribute_group tpdm_cmb_patt_grp = {
+       .attrs = tpdm_cmb_patt_attrs,
+       .is_visible = tpdm_cmb_is_visible,
+       .name = "cmb_patt",
+};
+
+static struct attribute_group tpdm_cmb_msr_grp = {
+       .attrs = tpdm_cmb_msr_attrs,
+       .is_visible = tpdm_cmb_msr_is_visible,
+       .name = "cmb_msr",
+};
+
 static const struct attribute_group *tpdm_attr_grps[] = {
        &tpdm_attr_grp,
        &tpdm_dsb_attr_grp,
@@ -856,6 +1219,10 @@ static const struct attribute_group *tpdm_attr_grps[] = {
        &tpdm_dsb_trig_patt_grp,
        &tpdm_dsb_patt_grp,
        &tpdm_dsb_msr_grp,
+       &tpdm_cmb_attr_grp,
+       &tpdm_cmb_trig_patt_grp,
+       &tpdm_cmb_patt_grp,
+       &tpdm_cmb_msr_grp,
        NULL,
 };
 
@@ -894,6 +1261,10 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
                of_property_read_u32(drvdata->dev->of_node,
                           "qcom,dsb-msrs-num", &drvdata->dsb_msr_num);
 
+       if (drvdata && tpdm_has_cmb_dataset(drvdata))
+               of_property_read_u32(drvdata->dev->of_node,
+                          "qcom,cmb-msrs-num", &drvdata->cmb_msr_num);
+
        /* Set up coresight component description */
        desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
        if (!desc.name)
@@ -933,7 +1304,7 @@ static struct amba_id tpdm_ids[] = {
                .id = 0x000f0e00,
                .mask = 0x000fff00,
        },
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 static struct amba_driver tpdm_driver = {
index 4115b2a17b8d8a05a2f3c8f96e6029df2589e41f..e08d212642e351a3797d54f5d56c3b2196c9a23d 100644 (file)
@@ -9,6 +9,38 @@
 /* The max number of the datasets that TPDM supports */
 #define TPDM_DATASETS       7
 
+/* CMB Subunit Registers */
+#define TPDM_CMB_CR            (0xA00)
+/* CMB subunit timestamp insertion enable register */
+#define TPDM_CMB_TIER          (0xA04)
+/* CMB subunit timestamp pattern registers */
+#define TPDM_CMB_TPR(n)                (0xA08 + (n * 4))
+/* CMB subunit timestamp pattern mask registers */
+#define TPDM_CMB_TPMR(n)       (0xA10 + (n * 4))
+/* CMB subunit trigger pattern registers */
+#define TPDM_CMB_XPR(n)                (0xA18 + (n * 4))
+/* CMB subunit trigger pattern mask registers */
+#define TPDM_CMB_XPMR(n)       (0xA20 + (n * 4))
+/* CMB MSR register */
+#define TPDM_CMB_MSR(n)                (0xA80 + (n * 4))
+
+/* Enable bit for CMB subunit */
+#define TPDM_CMB_CR_ENA                BIT(0)
+/* Trace collection mode for CMB subunit */
+#define TPDM_CMB_CR_MODE       BIT(1)
+/* Timestamp control for pattern match */
+#define TPDM_CMB_TIER_PATT_TSENAB      BIT(0)
+/* CMB CTI timestamp request */
+#define TPDM_CMB_TIER_XTRIG_TSENAB     BIT(1)
+/* For timestamp fo all trace */
+#define TPDM_CMB_TIER_TS_ALL           BIT(2)
+
+/* Patten register number */
+#define TPDM_CMB_MAX_PATT              2
+
+/* MAX number of DSB MSR */
+#define TPDM_CMB_MAX_MSR 32
+
 /* DSB Subunit Registers */
 #define TPDM_DSB_CR            (0x780)
 #define TPDM_DSB_TIER          (0x784)
  *
  * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0
  * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0
+ * PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0
  */
 
 #define TPDM_PIDR0_DS_IMPDEF   BIT(0)
 #define TPDM_PIDR0_DS_DSB      BIT(1)
+#define TPDM_PIDR0_DS_CMB      BIT(2)
 
 #define TPDM_DSB_MAX_LINES     256
 /* MAX number of EDCR registers */
           }                                                            \
        })[0].attr.attr)
 
+#define tpdm_patt_enable_ts(name, mem)                         \
+       (&((struct tpdm_dataset_attribute[]) {                  \
+          {                                                    \
+               __ATTR(name, 0644, enable_ts_show,              \
+               enable_ts_store),               \
+               mem,                                            \
+               0,                                              \
+          }                                                    \
+       })[0].attr.attr)
+
 #define DSB_EDGE_CTRL_ATTR(nr)                                 \
                tpdm_simple_dataset_ro(edcr##nr,                \
                DSB_EDGE_CTRL, nr)
                tpdm_simple_dataset_rw(tpmr##nr,                \
                DSB_PATT_MASK, nr)
 
+#define DSB_PATT_ENABLE_TS                                     \
+               tpdm_patt_enable_ts(enable_ts,                  \
+               DSB_PATT)
+
 #define DSB_MSR_ATTR(nr)                                       \
                tpdm_simple_dataset_rw(msr##nr,                 \
                DSB_MSR, nr)
 
+#define CMB_TRIG_PATT_ATTR(nr)                                 \
+               tpdm_simple_dataset_rw(xpr##nr,                 \
+               CMB_TRIG_PATT, nr)
+
+#define CMB_TRIG_PATT_MASK_ATTR(nr)                            \
+               tpdm_simple_dataset_rw(xpmr##nr,                \
+               CMB_TRIG_PATT_MASK, nr)
+
+#define CMB_PATT_ATTR(nr)                                      \
+               tpdm_simple_dataset_rw(tpr##nr,                 \
+               CMB_PATT, nr)
+
+#define CMB_PATT_MASK_ATTR(nr)                                 \
+               tpdm_simple_dataset_rw(tpmr##nr,                \
+               CMB_PATT_MASK, nr)
+
+#define CMB_PATT_ENABLE_TS                                     \
+               tpdm_patt_enable_ts(enable_ts,                  \
+               CMB_PATT)
+
+#define CMB_MSR_ATTR(nr)                                       \
+               tpdm_simple_dataset_rw(msr##nr,                 \
+               CMB_MSR, nr)
+
 /**
  * struct dsb_dataset - specifics associated to dsb dataset
  * @mode:             DSB programming mode
@@ -173,6 +245,30 @@ struct dsb_dataset {
        bool                    trig_type;
 };
 
+/**
+ * struct cmb_dataset
+ * @trace_mode:       Dataset collection mode
+ * @patt_val:         Save value for pattern
+ * @patt_mask:        Save value for pattern mask
+ * @trig_patt:        Save value for trigger pattern
+ * @trig_patt_mask:   Save value for trigger pattern mask
+ * @msr               Save value for MSR
+ * @patt_ts:          Indicates if pattern match for timestamp is enabled.
+ * @trig_ts:          Indicates if CTI trigger for timestamp is enabled.
+ * @ts_all:           Indicates if timestamp is enabled for all packets.
+ */
+struct cmb_dataset {
+       u32                     trace_mode;
+       u32                     patt_val[TPDM_CMB_MAX_PATT];
+       u32                     patt_mask[TPDM_CMB_MAX_PATT];
+       u32                     trig_patt[TPDM_CMB_MAX_PATT];
+       u32                     trig_patt_mask[TPDM_CMB_MAX_PATT];
+       u32                     msr[TPDM_CMB_MAX_MSR];
+       bool                    patt_ts;
+       bool                    trig_ts;
+       bool                    ts_all;
+};
+
 /**
  * struct tpdm_drvdata - specifics associated to an TPDM component
  * @base:       memory mapped base address for this component.
@@ -182,7 +278,9 @@ struct dsb_dataset {
  * @enable:     enable status of the component.
  * @datasets:   The datasets types present of the TPDM.
  * @dsb         Specifics associated to TPDM DSB.
+ * @cmb         Specifics associated to TPDM CMB.
  * @dsb_msr_num Number of MSR supported by DSB TPDM
+ * @cmb_msr_num Number of MSR supported by CMB TPDM
  */
 
 struct tpdm_drvdata {
@@ -193,7 +291,9 @@ struct tpdm_drvdata {
        bool                    enable;
        unsigned long           datasets;
        struct dsb_dataset      *dsb;
+       struct cmb_dataset      *cmb;
        u32                     dsb_msr_num;
+       u32                     cmb_msr_num;
 };
 
 /* Enumerate members of various datasets */
@@ -205,6 +305,11 @@ enum dataset_mem {
        DSB_PATT,
        DSB_PATT_MASK,
        DSB_MSR,
+       CMB_TRIG_PATT,
+       CMB_TRIG_PATT_MASK,
+       CMB_PATT,
+       CMB_PATT_MASK,
+       CMB_MSR
 };
 
 /**
@@ -220,4 +325,13 @@ struct tpdm_dataset_attribute {
        u32 idx;
 };
 
+static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
+{
+       return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
+}
+
+static bool tpdm_has_cmb_dataset(struct tpdm_drvdata *drvdata)
+{
+       return (drvdata->datasets & TPDM_PIDR0_DS_CMB);
+}
 #endif  /* _CORESIGHT_CORESIGHT_TPDM_H */
index 59eac93fd6bb9eb6ce1fdb7fa83beaf0bf36cab4..29024f880fda7af029334d2a8e2588faeaa02c20 100644 (file)
@@ -58,6 +58,7 @@ struct tpiu_drvdata {
        void __iomem            *base;
        struct clk              *atclk;
        struct coresight_device *csdev;
+       spinlock_t              spinlock;
 };
 
 static void tpiu_enable_hw(struct csdev_access *csa)
@@ -72,8 +73,11 @@ static void tpiu_enable_hw(struct csdev_access *csa)
 static int tpiu_enable(struct coresight_device *csdev, enum cs_mode mode,
                       void *__unused)
 {
+       struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+       guard(spinlock)(&drvdata->spinlock);
        tpiu_enable_hw(&csdev->access);
-       atomic_inc(&csdev->refcnt);
+       csdev->refcnt++;
        dev_dbg(&csdev->dev, "TPIU enabled\n");
        return 0;
 }
@@ -96,7 +100,11 @@ static void tpiu_disable_hw(struct csdev_access *csa)
 
 static int tpiu_disable(struct coresight_device *csdev)
 {
-       if (atomic_dec_return(&csdev->refcnt))
+       struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+       guard(spinlock)(&drvdata->spinlock);
+       csdev->refcnt--;
+       if (csdev->refcnt)
                return -EBUSY;
 
        tpiu_disable_hw(&csdev->access);
@@ -132,6 +140,8 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
        if (!drvdata)
                return -ENOMEM;
 
+       spin_lock_init(&drvdata->spinlock);
+
        drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */
        if (!IS_ERR(drvdata->atclk)) {
                ret = clk_prepare_enable(drvdata->atclk);
@@ -218,7 +228,7 @@ static const struct amba_id tpiu_ids[] = {
                .id     = 0x000bb9e7,
                .mask   = 0x000fffff,
        },
-       { 0, 0},
+       { 0, 0, NULL },
 };
 
 MODULE_DEVICE_TABLE(amba, tpiu_ids);
index 10e886455b8b711e32de891fac9c025d243eaabb..f9ebf20c91e63df2d0d6b71c4182305fe3cc45c6 100644 (file)
@@ -103,7 +103,7 @@ static int smb_open(struct inode *inode, struct file *file)
        if (drvdata->reading)
                return -EBUSY;
 
-       if (atomic_read(&drvdata->csdev->refcnt))
+       if (drvdata->csdev->refcnt)
                return -EBUSY;
 
        smb_update_data_size(drvdata);
@@ -207,11 +207,11 @@ static void smb_enable_sysfs(struct coresight_device *csdev)
 {
        struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
 
-       if (drvdata->mode != CS_MODE_DISABLED)
+       if (coresight_get_mode(csdev) != CS_MODE_DISABLED)
                return;
 
        smb_enable_hw(drvdata);
-       drvdata->mode = CS_MODE_SYSFS;
+       coresight_set_mode(csdev, CS_MODE_SYSFS);
 }
 
 static int smb_enable_perf(struct coresight_device *csdev, void *data)
@@ -234,7 +234,7 @@ static int smb_enable_perf(struct coresight_device *csdev, void *data)
        if (drvdata->pid == -1) {
                smb_enable_hw(drvdata);
                drvdata->pid = pid;
-               drvdata->mode = CS_MODE_PERF;
+               coresight_set_mode(csdev, CS_MODE_PERF);
        }
 
        return 0;
@@ -253,7 +253,8 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
                return -EBUSY;
 
        /* Do nothing, the SMB is already enabled as other mode */
-       if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode)
+       if (coresight_get_mode(csdev) != CS_MODE_DISABLED &&
+           coresight_get_mode(csdev) != mode)
                return -EBUSY;
 
        switch (mode) {
@@ -270,7 +271,7 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
        if (ret)
                return ret;
 
-       atomic_inc(&csdev->refcnt);
+       csdev->refcnt++;
        dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
 
        return ret;
@@ -285,17 +286,18 @@ static int smb_disable(struct coresight_device *csdev)
        if (drvdata->reading)
                return -EBUSY;
 
-       if (atomic_dec_return(&csdev->refcnt))
+       csdev->refcnt--;
+       if (csdev->refcnt)
                return -EBUSY;
 
        /* Complain if we (somehow) got out of sync */
-       WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+       WARN_ON_ONCE(coresight_get_mode(csdev) == CS_MODE_DISABLED);
 
        smb_disable_hw(drvdata);
 
        /* Dissociate from the target process. */
        drvdata->pid = -1;
-       drvdata->mode = CS_MODE_DISABLED;
+       coresight_set_mode(csdev, CS_MODE_DISABLED);
        dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n");
 
        return 0;
@@ -380,7 +382,7 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
        guard(spinlock)(&drvdata->spinlock);
 
        /* Don't do anything if another tracer is using this sink. */
-       if (atomic_read(&csdev->refcnt) != 1)
+       if (csdev->refcnt != 1)
                return 0;
 
        smb_disable_hw(drvdata);
@@ -586,7 +588,7 @@ static void smb_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
-       {"HISI03A1", 0},
+       {"HISI03A1", 0, 0, 0},
        {}
 };
 MODULE_DEVICE_TABLE(acpi, ultrasoc_smb_acpi_match);
index 82a44c14a8829cd029c78979454e20efc8264b8f..a91d39cfccb8fcedabcd96c61fecaf9c193672ea 100644 (file)
@@ -109,7 +109,6 @@ struct smb_data_buffer {
  * @reading:   Synchronise user space access to SMB buffer.
  * @pid:       Process ID of the process being monitored by the
  *             session that is using this component.
- * @mode:      How this SMB is being used, perf mode or sysfs mode.
  */
 struct smb_drv_data {
        void __iomem *base;
@@ -119,7 +118,6 @@ struct smb_drv_data {
        spinlock_t spinlock;
        bool reading;
        pid_t pid;
-       enum cs_mode mode;
 };
 
 #endif
index c1b5fd2b89741d676a3571facd7a0c4dc3c080f7..4bf04a9778407acca7893172656d897ecd4c375a 100644 (file)
@@ -998,6 +998,9 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event)
        int ret;
        u32 val;
 
+       if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type)
+               return -ENOENT;
+
        if (event->cpu < 0) {
                dev_dbg(event->pmu->dev, "Per-task mode not supported\n");
                return -EOPNOTSUPP;
@@ -1006,9 +1009,6 @@ static int hisi_ptt_pmu_event_init(struct perf_event *event)
        if (event->attach_state & PERF_ATTACH_TASK)
                return -EOPNOTSUPP;
 
-       if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type)
-               return -ENOENT;
-
        ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config);
        if (ret < 0)
                return ret;
index b10574d42b7ac998bd73eb3ff9b38aaa68ca4b53..4f41a3c7824d062d7044777013a28ad25c5f324b 100644 (file)
@@ -6,21 +6,30 @@
  * I2C master mode controller driver, used in Nomadik 8815
  * and Ux500 platforms.
  *
+ * The Mobileye EyeQ5 platform is also supported; it uses
+ * the same Ux500/DB8500 IP block with two quirks:
+ *  - The memory bus only supports 32-bit accesses.
+ *  - A register must be configured for the I2C speed mode;
+ *    it is located in a shared register region called OLB.
+ *
  * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
  * Author: Sachin Verma <sachin.verma@st.com>
  */
-#include <linux/init.h>
-#include <linux/module.h>
 #include <linux/amba/bus.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/err.h>
+#include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/pm_runtime.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
 
 #define DRIVER_NAME "nmk-i2c"
 
 #define I2C_ICR                (0x038)
 
 /* Control registers */
-#define I2C_CR_PE              (0x1 << 0)      /* Peripheral Enable */
-#define I2C_CR_OM              (0x3 << 1)      /* Operating mode */
-#define I2C_CR_SAM             (0x1 << 3)      /* Slave addressing mode */
-#define I2C_CR_SM              (0x3 << 4)      /* Speed mode */
-#define I2C_CR_SGCM            (0x1 << 6)      /* Slave general call mode */
-#define I2C_CR_FTX             (0x1 << 7)      /* Flush Transmit */
-#define I2C_CR_FRX             (0x1 << 8)      /* Flush Receive */
-#define I2C_CR_DMA_TX_EN       (0x1 << 9)      /* DMA Tx enable */
-#define I2C_CR_DMA_RX_EN       (0x1 << 10)     /* DMA Rx Enable */
-#define I2C_CR_DMA_SLE         (0x1 << 11)     /* DMA sync. logic enable */
-#define I2C_CR_LM              (0x1 << 12)     /* Loopback mode */
-#define I2C_CR_FON             (0x3 << 13)     /* Filtering on */
-#define I2C_CR_FS              (0x3 << 15)     /* Force stop enable */
+#define I2C_CR_PE              BIT(0)          /* Peripheral Enable */
+#define I2C_CR_OM              GENMASK(2, 1)   /* Operating mode */
+#define I2C_CR_SAM             BIT(3)          /* Slave addressing mode */
+#define I2C_CR_SM              GENMASK(5, 4)   /* Speed mode */
+#define I2C_CR_SGCM            BIT(6)          /* Slave general call mode */
+#define I2C_CR_FTX             BIT(7)          /* Flush Transmit */
+#define I2C_CR_FRX             BIT(8)          /* Flush Receive */
+#define I2C_CR_DMA_TX_EN       BIT(9)          /* DMA Tx enable */
+#define I2C_CR_DMA_RX_EN       BIT(10)         /* DMA Rx Enable */
+#define I2C_CR_DMA_SLE         BIT(11)         /* DMA sync. logic enable */
+#define I2C_CR_LM              BIT(12)         /* Loopback mode */
+#define I2C_CR_FON             GENMASK(14, 13) /* Filtering on */
+#define I2C_CR_FS              GENMASK(16, 15) /* Force stop enable */
+
+/* Slave control register (SCR) */
+#define I2C_SCR_SLSU           GENMASK(31, 16) /* Slave data setup time */
 
 /* Master controller (MCR) register */
-#define I2C_MCR_OP             (0x1 << 0)      /* Operation */
-#define I2C_MCR_A7             (0x7f << 1)     /* 7-bit address */
-#define I2C_MCR_EA10           (0x7 << 8)      /* 10-bit Extended address */
-#define I2C_MCR_SB             (0x1 << 11)     /* Extended address */
-#define I2C_MCR_AM             (0x3 << 12)     /* Address type */
-#define I2C_MCR_STOP           (0x1 << 14)     /* Stop condition */
-#define I2C_MCR_LENGTH         (0x7ff << 15)   /* Transaction length */
+#define I2C_MCR_OP             BIT(0)          /* Operation */
+#define I2C_MCR_A7             GENMASK(7, 1)   /* 7-bit address */
+#define I2C_MCR_EA10           GENMASK(10, 8)  /* 10-bit Extended address */
+#define I2C_MCR_SB             BIT(11)         /* Extended address */
+#define I2C_MCR_AM             GENMASK(13, 12) /* Address type */
+#define I2C_MCR_STOP           BIT(14)         /* Stop condition */
+#define I2C_MCR_LENGTH         GENMASK(25, 15) /* Transaction length */
 
 /* Status register (SR) */
-#define I2C_SR_OP              (0x3 << 0)      /* Operation */
-#define I2C_SR_STATUS          (0x3 << 2)      /* controller status */
-#define I2C_SR_CAUSE           (0x7 << 4)      /* Abort cause */
-#define I2C_SR_TYPE            (0x3 << 7)      /* Receive type */
-#define I2C_SR_LENGTH          (0x7ff << 9)    /* Transfer length */
+#define I2C_SR_OP              GENMASK(1, 0)   /* Operation */
+#define I2C_SR_STATUS          GENMASK(3, 2)   /* controller status */
+#define I2C_SR_CAUSE           GENMASK(6, 4)   /* Abort cause */
+#define I2C_SR_TYPE            GENMASK(8, 7)   /* Receive type */
+#define I2C_SR_LENGTH          GENMASK(19, 9)  /* Transfer length */
+
+/* Baud-rate counter register (BRCR) */
+#define I2C_BRCR_BRCNT1                GENMASK(31, 16) /* Baud-rate counter 1 */
+#define I2C_BRCR_BRCNT2                GENMASK(15, 0)  /* Baud-rate counter 2 */
 
 /* Interrupt mask set/clear (IMSCR) bits */
-#define I2C_IT_TXFE            (0x1 << 0)
-#define I2C_IT_TXFNE           (0x1 << 1)
-#define I2C_IT_TXFF            (0x1 << 2)
-#define I2C_IT_TXFOVR          (0x1 << 3)
-#define I2C_IT_RXFE            (0x1 << 4)
-#define I2C_IT_RXFNF           (0x1 << 5)
-#define I2C_IT_RXFF            (0x1 << 6)
-#define I2C_IT_RFSR            (0x1 << 16)
-#define I2C_IT_RFSE            (0x1 << 17)
-#define I2C_IT_WTSR            (0x1 << 18)
-#define I2C_IT_MTD             (0x1 << 19)
-#define I2C_IT_STD             (0x1 << 20)
-#define I2C_IT_MAL             (0x1 << 24)
-#define I2C_IT_BERR            (0x1 << 25)
-#define I2C_IT_MTDWS           (0x1 << 28)
-
-#define GEN_MASK(val, mask, sb)  (((val) << (sb)) & (mask))
+#define I2C_IT_TXFE            BIT(0)
+#define I2C_IT_TXFNE           BIT(1)
+#define I2C_IT_TXFF            BIT(2)
+#define I2C_IT_TXFOVR          BIT(3)
+#define I2C_IT_RXFE            BIT(4)
+#define I2C_IT_RXFNF           BIT(5)
+#define I2C_IT_RXFF            BIT(6)
+#define I2C_IT_RFSR            BIT(16)
+#define I2C_IT_RFSE            BIT(17)
+#define I2C_IT_WTSR            BIT(18)
+#define I2C_IT_MTD             BIT(19)
+#define I2C_IT_STD             BIT(20)
+#define I2C_IT_MAL             BIT(24)
+#define I2C_IT_BERR            BIT(25)
+#define I2C_IT_MTDWS           BIT(28)
 
 /* some bits in ICR are reserved */
 #define I2C_CLEAR_ALL_INTS     0x131f007f
 
-/* first three msb bits are reserved */
-#define IRQ_MASK(mask)         (mask & 0x1fffffff)
-
 /* maximum threshold value */
 #define MAX_I2C_FIFO_THRESHOLD 15
 
@@ -107,6 +118,15 @@ enum i2c_freq_mode {
        I2C_FREQ_MODE_FAST_PLUS,        /* up to 1 Mb/s */
 };
 
+/* Mobileye EyeQ5 offset into a shared register region (called OLB) */
+#define NMK_I2C_EYEQ5_OLB_IOCR2                        0x0B8
+
+enum i2c_eyeq5_speed {
+       I2C_EYEQ5_SPEED_FAST,
+       I2C_EYEQ5_SPEED_FAST_PLUS,
+       I2C_EYEQ5_SPEED_HIGH_SPEED,
+};
+
 /**
  * struct i2c_vendor_data - per-vendor variations
  * @has_mtdws: variant has the MTDWS bit
@@ -131,6 +151,12 @@ enum i2c_operation {
        I2C_READ = 0x01
 };
 
+enum i2c_operating_mode {
+       I2C_OM_SLAVE,
+       I2C_OM_MASTER,
+       I2C_OM_MASTER_OR_SLAVE,
+};
+
 /**
  * struct i2c_nmk_client - client specific data
  * @slave_adr: 7-bit slave address
@@ -159,11 +185,13 @@ struct i2c_nmk_client {
  * @clk_freq: clock frequency for the operation mode
  * @tft: Tx FIFO Threshold in bytes
  * @rft: Rx FIFO Threshold in bytes
- * @timeout: Slave response timeout (ms)
+ * @timeout_usecs: Slave response timeout
  * @sm: speed mode
  * @stop: stop condition.
- * @xfer_complete: acknowledge completion for a I2C message.
+ * @xfer_wq: xfer done wait queue.
+ * @xfer_done: xfer done boolean.
  * @result: controller propogated result.
+ * @has_32b_bus: controller is on a bus that only supports 32-bit accesses.
  */
 struct nmk_i2c_dev {
        struct i2c_vendor_data          *vendor;
@@ -176,11 +204,13 @@ struct nmk_i2c_dev {
        u32                             clk_freq;
        unsigned char                   tft;
        unsigned char                   rft;
-       int                             timeout;
+       u32                             timeout_usecs;
        enum i2c_freq_mode              sm;
        int                             stop;
-       struct completion               xfer_complete;
+       struct wait_queue_head          xfer_wq;
+       bool                            xfer_done;
        int                             result;
+       bool                            has_32b_bus;
 };
 
 /* controller's abort causes */
@@ -204,18 +234,36 @@ static inline void i2c_clr_bit(void __iomem *reg, u32 mask)
        writel(readl(reg) & ~mask, reg);
 }
 
+static inline u8 nmk_i2c_readb(const struct nmk_i2c_dev *priv,
+                              unsigned long reg)
+{
+       if (priv->has_32b_bus)
+               return readl(priv->virtbase + reg);
+       else
+               return readb(priv->virtbase + reg);
+}
+
+static inline void nmk_i2c_writeb(const struct nmk_i2c_dev *priv, u32 val,
+                                 unsigned long reg)
+{
+       if (priv->has_32b_bus)
+               writel(val, priv->virtbase + reg);
+       else
+               writeb(val, priv->virtbase + reg);
+}
+
 /**
  * flush_i2c_fifo() - This function flushes the I2C FIFO
- * @dev: private data of I2C Driver
+ * @priv: private data of I2C Driver
  *
  * This function flushes the I2C Tx and Rx FIFOs. It returns
  * 0 on successful flushing of FIFO
  */
-static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
+static int flush_i2c_fifo(struct nmk_i2c_dev *priv)
 {
 #define LOOP_ATTEMPTS 10
+       ktime_t timeout;
        int i;
-       unsigned long timeout;
 
        /*
         * flush the transmit and receive FIFO. The flushing
@@ -224,19 +272,19 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
         * bits, until then no one must access Tx, Rx FIFO and
         * should poll on these bits waiting for the completion.
         */
-       writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
+       writel((I2C_CR_FTX | I2C_CR_FRX), priv->virtbase + I2C_CR);
 
        for (i = 0; i < LOOP_ATTEMPTS; i++) {
-               timeout = jiffies + dev->adap.timeout;
+               timeout = ktime_add_us(ktime_get(), priv->timeout_usecs);
 
-               while (!time_after(jiffies, timeout)) {
-                       if ((readl(dev->virtbase + I2C_CR) &
+               while (ktime_after(timeout, ktime_get())) {
+                       if ((readl(priv->virtbase + I2C_CR) &
                                (I2C_CR_FTX | I2C_CR_FRX)) == 0)
-                                       return 0;
+                               return 0;
                }
        }
 
-       dev_err(&dev->adev->dev,
+       dev_err(&priv->adev->dev,
                "flushing operation timed out giving up after %d attempts",
                LOOP_ATTEMPTS);
 
@@ -245,120 +293,121 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
 
 /**
  * disable_all_interrupts() - Disable all interrupts of this I2c Bus
- * @dev: private data of I2C Driver
+ * @priv: private data of I2C Driver
  */
-static void disable_all_interrupts(struct nmk_i2c_dev *dev)
+static void disable_all_interrupts(struct nmk_i2c_dev *priv)
 {
-       u32 mask = IRQ_MASK(0);
-       writel(mask, dev->virtbase + I2C_IMSCR);
+       writel(0, priv->virtbase + I2C_IMSCR);
 }
 
 /**
  * clear_all_interrupts() - Clear all interrupts of I2C Controller
- * @dev: private data of I2C Driver
+ * @priv: private data of I2C Driver
  */
-static void clear_all_interrupts(struct nmk_i2c_dev *dev)
+static void clear_all_interrupts(struct nmk_i2c_dev *priv)
 {
-       u32 mask;
-       mask = IRQ_MASK(I2C_CLEAR_ALL_INTS);
-       writel(mask, dev->virtbase + I2C_ICR);
+       writel(I2C_CLEAR_ALL_INTS, priv->virtbase + I2C_ICR);
 }
 
 /**
  * init_hw() - initialize the I2C hardware
- * @dev: private data of I2C Driver
+ * @priv: private data of I2C Driver
  */
-static int init_hw(struct nmk_i2c_dev *dev)
+static int init_hw(struct nmk_i2c_dev *priv)
 {
        int stat;
 
-       stat = flush_i2c_fifo(dev);
+       stat = flush_i2c_fifo(priv);
        if (stat)
                goto exit;
 
        /* disable the controller */
-       i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+       i2c_clr_bit(priv->virtbase + I2C_CR, I2C_CR_PE);
 
-       disable_all_interrupts(dev);
+       disable_all_interrupts(priv);
 
-       clear_all_interrupts(dev);
+       clear_all_interrupts(priv);
 
-       dev->cli.operation = I2C_NO_OPERATION;
+       priv->cli.operation = I2C_NO_OPERATION;
 
 exit:
        return stat;
 }
 
 /* enable peripheral, master mode operation */
-#define DEFAULT_I2C_REG_CR     ((1 << 1) | I2C_CR_PE)
+#define DEFAULT_I2C_REG_CR     (FIELD_PREP(I2C_CR_OM, I2C_OM_MASTER) | I2C_CR_PE)
+
+/* grab top three bits from extended I2C addresses */
+#define ADR_3MSB_BITS          GENMASK(9, 7)
 
 /**
  * load_i2c_mcr_reg() - load the MCR register
- * @dev: private data of controller
+ * @priv: private data of controller
  * @flags: message flags
  */
-static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags)
+static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *priv, u16 flags)
 {
        u32 mcr = 0;
        unsigned short slave_adr_3msb_bits;
 
-       mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
+       mcr |= FIELD_PREP(I2C_MCR_A7, priv->cli.slave_adr);
 
        if (unlikely(flags & I2C_M_TEN)) {
                /* 10-bit address transaction */
-               mcr |= GEN_MASK(2, I2C_MCR_AM, 12);
+               mcr |= FIELD_PREP(I2C_MCR_AM, 2);
                /*
                 * Get the top 3 bits.
                 * EA10 represents extended address in MCR. This includes
                 * the extension (MSB bits) of the 7 bit address loaded
                 * in A7
                 */
-               slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7;
+               slave_adr_3msb_bits = FIELD_GET(ADR_3MSB_BITS,
+                                               priv->cli.slave_adr);
 
-               mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8);
+               mcr |= FIELD_PREP(I2C_MCR_EA10, slave_adr_3msb_bits);
        } else {
                /* 7-bit address transaction */
-               mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
+               mcr |= FIELD_PREP(I2C_MCR_AM, 1);
        }
 
        /* start byte procedure not applied */
-       mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
+       mcr |= FIELD_PREP(I2C_MCR_SB, 0);
 
        /* check the operation, master read/write? */
-       if (dev->cli.operation == I2C_WRITE)
-               mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0);
+       if (priv->cli.operation == I2C_WRITE)
+               mcr |= FIELD_PREP(I2C_MCR_OP, I2C_WRITE);
        else
-               mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0);
+               mcr |= FIELD_PREP(I2C_MCR_OP, I2C_READ);
 
        /* stop or repeated start? */
-       if (dev->stop)
-               mcr |= GEN_MASK(1, I2C_MCR_STOP, 14);
+       if (priv->stop)
+               mcr |= FIELD_PREP(I2C_MCR_STOP, 1);
        else
-               mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14));
+               mcr &= ~FIELD_PREP(I2C_MCR_STOP, 1);
 
-       mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15);
+       mcr |= FIELD_PREP(I2C_MCR_LENGTH, priv->cli.count);
 
        return mcr;
 }
 
 /**
  * setup_i2c_controller() - setup the controller
- * @dev: private data of controller
+ * @priv: private data of controller
  */
-static void setup_i2c_controller(struct nmk_i2c_dev *dev)
+static void setup_i2c_controller(struct nmk_i2c_dev *priv)
 {
        u32 brcr1, brcr2;
        u32 i2c_clk, div;
        u32 ns;
        u16 slsu;
 
-       writel(0x0, dev->virtbase + I2C_CR);
-       writel(0x0, dev->virtbase + I2C_HSMCR);
-       writel(0x0, dev->virtbase + I2C_TFTR);
-       writel(0x0, dev->virtbase + I2C_RFTR);
-       writel(0x0, dev->virtbase + I2C_DMAR);
+       writel(0x0, priv->virtbase + I2C_CR);
+       writel(0x0, priv->virtbase + I2C_HSMCR);
+       writel(0x0, priv->virtbase + I2C_TFTR);
+       writel(0x0, priv->virtbase + I2C_RFTR);
+       writel(0x0, priv->virtbase + I2C_DMAR);
 
-       i2c_clk = clk_get_rate(dev->clk);
+       i2c_clk = clk_get_rate(priv->clk);
 
        /*
         * set the slsu:
@@ -373,7 +422,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * slsu = cycles / (1000000000 / f) + 1
         */
        ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk);
-       switch (dev->sm) {
+       switch (priv->sm) {
        case I2C_FREQ_MODE_FAST:
        case I2C_FREQ_MODE_FAST_PLUS:
                slsu = DIV_ROUND_UP(100, ns); /* Fast */
@@ -388,15 +437,15 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
        }
        slsu += 1;
 
-       dev_dbg(&dev->adev->dev, "calculated SLSU = %04x\n", slsu);
-       writel(slsu << 16, dev->virtbase + I2C_SCR);
+       dev_dbg(&priv->adev->dev, "calculated SLSU = %04x\n", slsu);
+       writel(FIELD_PREP(I2C_SCR_SLSU, slsu), priv->virtbase + I2C_SCR);
 
        /*
         * The spec says, in case of std. mode the divider is
         * 2 whereas it is 3 for fast and fastplus mode of
         * operation. TODO - high speed support.
         */
-       div = (dev->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2;
+       div = (priv->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2;
 
        /*
         * generate the mask for baud rate counters. The controller
@@ -405,11 +454,11 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * plus operation. Currently we do not supprt high speed mode
         * so set brcr1 to 0.
         */
-       brcr1 = 0 << 16;
-       brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff;
+       brcr1 = FIELD_PREP(I2C_BRCR_BRCNT1, 0);
+       brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, i2c_clk / (priv->clk_freq * div));
 
        /* set the baud rate counter register */
-       writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+       writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR);
 
        /*
         * set the speed mode. Currently we support
@@ -417,125 +466,142 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * TODO - support for fast mode plus (up to 1Mb/s)
         * and high speed (up to 3.4 Mb/s)
         */
-       if (dev->sm > I2C_FREQ_MODE_FAST) {
-               dev_err(&dev->adev->dev,
+       if (priv->sm > I2C_FREQ_MODE_FAST) {
+               dev_err(&priv->adev->dev,
                        "do not support this mode defaulting to std. mode\n");
-               brcr2 = i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2) & 0xffff;
-               writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
-               writel(I2C_FREQ_MODE_STANDARD << 4,
-                               dev->virtbase + I2C_CR);
+               brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2,
+                                  i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2));
+               writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR);
+               writel(FIELD_PREP(I2C_CR_SM, I2C_FREQ_MODE_STANDARD),
+                      priv->virtbase + I2C_CR);
        }
-       writel(dev->sm << 4, dev->virtbase + I2C_CR);
+       writel(FIELD_PREP(I2C_CR_SM, priv->sm), priv->virtbase + I2C_CR);
 
        /* set the Tx and Rx FIFO threshold */
-       writel(dev->tft, dev->virtbase + I2C_TFTR);
-       writel(dev->rft, dev->virtbase + I2C_RFTR);
+       writel(priv->tft, priv->virtbase + I2C_TFTR);
+       writel(priv->rft, priv->virtbase + I2C_RFTR);
+}
+
+static bool nmk_i2c_wait_xfer_done(struct nmk_i2c_dev *priv)
+{
+       if (priv->timeout_usecs < jiffies_to_usecs(1)) {
+               unsigned long timeout_usecs = priv->timeout_usecs;
+               ktime_t timeout = ktime_set(0, timeout_usecs * NSEC_PER_USEC);
+
+               wait_event_hrtimeout(priv->xfer_wq, priv->xfer_done, timeout);
+       } else {
+               unsigned long timeout = usecs_to_jiffies(priv->timeout_usecs);
+
+               wait_event_timeout(priv->xfer_wq, priv->xfer_done, timeout);
+       }
+
+       return priv->xfer_done;
 }
 
 /**
  * read_i2c() - Read from I2C client device
- * @dev: private data of I2C Driver
+ * @priv: private data of I2C Driver
  * @flags: message flags
  *
  * This function reads from i2c client device when controller is in
  * master mode. There is a completion timeout. If there is no transfer
  * before timeout error is returned.
  */
-static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
+static int read_i2c(struct nmk_i2c_dev *priv, u16 flags)
 {
-       int status = 0;
        u32 mcr, irq_mask;
-       unsigned long timeout;
+       int status = 0;
+       bool xfer_done;
 
-       mcr = load_i2c_mcr_reg(dev, flags);
-       writel(mcr, dev->virtbase + I2C_MCR);
+       mcr = load_i2c_mcr_reg(priv, flags);
+       writel(mcr, priv->virtbase + I2C_MCR);
 
        /* load the current CR value */
-       writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
-                       dev->virtbase + I2C_CR);
+       writel(readl(priv->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+              priv->virtbase + I2C_CR);
 
        /* enable the controller */
-       i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+       i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE);
 
-       init_completion(&dev->xfer_complete);
+       init_waitqueue_head(&priv->xfer_wq);
+       priv->xfer_done = false;
 
        /* enable interrupts by setting the mask */
        irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
                        I2C_IT_MAL | I2C_IT_BERR);
 
-       if (dev->stop || !dev->vendor->has_mtdws)
+       if (priv->stop || !priv->vendor->has_mtdws)
                irq_mask |= I2C_IT_MTD;
        else
                irq_mask |= I2C_IT_MTDWS;
 
-       irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+       irq_mask &= I2C_CLEAR_ALL_INTS;
 
-       writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
-                       dev->virtbase + I2C_IMSCR);
+       writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask,
+              priv->virtbase + I2C_IMSCR);
 
-       timeout = wait_for_completion_timeout(
-               &dev->xfer_complete, dev->adap.timeout);
+       xfer_done = nmk_i2c_wait_xfer_done(priv);
 
-       if (timeout == 0) {
+       if (!xfer_done) {
                /* Controller timed out */
-               dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n",
-                               dev->cli.slave_adr);
+               dev_err(&priv->adev->dev, "read from slave 0x%x timed out\n",
+                       priv->cli.slave_adr);
                status = -ETIMEDOUT;
        }
        return status;
 }
 
-static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+static void fill_tx_fifo(struct nmk_i2c_dev *priv, int no_bytes)
 {
        int count;
 
        for (count = (no_bytes - 2);
                        (count > 0) &&
-                       (dev->cli.count != 0);
+                       (priv->cli.count != 0);
                        count--) {
                /* write to the Tx FIFO */
-               writeb(*dev->cli.buffer,
-                       dev->virtbase + I2C_TFR);
-               dev->cli.buffer++;
-               dev->cli.count--;
-               dev->cli.xfer_bytes++;
+               nmk_i2c_writeb(priv, *priv->cli.buffer, I2C_TFR);
+               priv->cli.buffer++;
+               priv->cli.count--;
+               priv->cli.xfer_bytes++;
        }
 
 }
 
 /**
  * write_i2c() - Write data to I2C client.
- * @dev: private data of I2C Driver
+ * @priv: private data of I2C Driver
  * @flags: message flags
  *
  * This function writes data to I2C client
  */
-static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
+static int write_i2c(struct nmk_i2c_dev *priv, u16 flags)
 {
-       u32 status = 0;
        u32 mcr, irq_mask;
-       unsigned long timeout;
+       u32 status = 0;
+       bool xfer_done;
 
-       mcr = load_i2c_mcr_reg(dev, flags);
+       mcr = load_i2c_mcr_reg(priv, flags);
 
-       writel(mcr, dev->virtbase + I2C_MCR);
+       writel(mcr, priv->virtbase + I2C_MCR);
 
        /* load the current CR value */
-       writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
-                       dev->virtbase + I2C_CR);
+       writel(readl(priv->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+              priv->virtbase + I2C_CR);
 
        /* enable the controller */
-       i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+       i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE);
 
-       init_completion(&dev->xfer_complete);
+       init_waitqueue_head(&priv->xfer_wq);
+       priv->xfer_done = false;
 
        /* enable interrupts by settings the masks */
        irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
 
        /* Fill the TX FIFO with transmit data */
-       fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+       fill_tx_fifo(priv, MAX_I2C_FIFO_THRESHOLD);
 
-       if (dev->cli.count != 0)
+       if (priv->cli.count != 0)
                irq_mask |= I2C_IT_TXFNE;
 
        /*
@@ -543,23 +609,22 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
         * set the MTDWS bit (Master Transaction Done Without Stop)
         * to start repeated start operation
         */
-       if (dev->stop || !dev->vendor->has_mtdws)
+       if (priv->stop || !priv->vendor->has_mtdws)
                irq_mask |= I2C_IT_MTD;
        else
                irq_mask |= I2C_IT_MTDWS;
 
-       irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+       irq_mask &= I2C_CLEAR_ALL_INTS;
 
-       writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
-                       dev->virtbase + I2C_IMSCR);
+       writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask,
+              priv->virtbase + I2C_IMSCR);
 
-       timeout = wait_for_completion_timeout(
-               &dev->xfer_complete, dev->adap.timeout);
+       xfer_done = nmk_i2c_wait_xfer_done(priv);
 
-       if (timeout == 0) {
+       if (!xfer_done) {
                /* Controller timed out */
-               dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n",
-                               dev->cli.slave_adr);
+               dev_err(&priv->adev->dev, "write to slave 0x%x timed out\n",
+                       priv->cli.slave_adr);
                status = -ETIMEDOUT;
        }
 
@@ -568,44 +633,39 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
 
 /**
  * nmk_i2c_xfer_one() - transmit a single I2C message
- * @dev: device with a message encoded into it
+ * @priv: device with a message encoded into it
  * @flags: message flags
  */
-static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags)
 {
        int status;
 
        if (flags & I2C_M_RD) {
                /* read operation */
-               dev->cli.operation = I2C_READ;
-               status = read_i2c(dev, flags);
+               priv->cli.operation = I2C_READ;
+               status = read_i2c(priv, flags);
        } else {
                /* write operation */
-               dev->cli.operation = I2C_WRITE;
-               status = write_i2c(dev, flags);
+               priv->cli.operation = I2C_WRITE;
+               status = write_i2c(priv, flags);
        }
 
-       if (status || (dev->result)) {
+       if (status || priv->result) {
                u32 i2c_sr;
                u32 cause;
 
-               i2c_sr = readl(dev->virtbase + I2C_SR);
-               /*
-                * Check if the controller I2C operation status
-                * is set to ABORT(11b).
-                */
-               if (((i2c_sr >> 2) & 0x3) == 0x3) {
-                       /* get the abort cause */
-                       cause = (i2c_sr >> 4) & 0x7;
-                       dev_err(&dev->adev->dev, "%s\n",
+               i2c_sr = readl(priv->virtbase + I2C_SR);
+               if (FIELD_GET(I2C_SR_STATUS, i2c_sr) == I2C_ABORT) {
+                       cause = FIELD_GET(I2C_SR_CAUSE, i2c_sr);
+                       dev_err(&priv->adev->dev, "%s\n",
                                cause >= ARRAY_SIZE(abort_causes) ?
                                "unknown reason" :
                                abort_causes[cause]);
                }
 
-               (void) init_hw(dev);
+               init_hw(priv);
 
-               status = status ? status : dev->result;
+               status = status ? status : priv->result;
        }
 
        return status;
@@ -663,24 +723,24 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 {
        int status = 0;
        int i;
-       struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+       struct nmk_i2c_dev *priv = i2c_get_adapdata(i2c_adap);
        int j;
 
-       pm_runtime_get_sync(&dev->adev->dev);
+       pm_runtime_get_sync(&priv->adev->dev);
 
        /* Attempt three times to send the message queue */
        for (j = 0; j < 3; j++) {
                /* setup the i2c controller */
-               setup_i2c_controller(dev);
+               setup_i2c_controller(priv);
 
                for (i = 0; i < num_msgs; i++) {
-                       dev->cli.slave_adr      = msgs[i].addr;
-                       dev->cli.buffer         = msgs[i].buf;
-                       dev->cli.count          = msgs[i].len;
-                       dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
-                       dev->result = 0;
+                       priv->cli.slave_adr     = msgs[i].addr;
+                       priv->cli.buffer                = msgs[i].buf;
+                       priv->cli.count         = msgs[i].len;
+                       priv->stop = (i < (num_msgs - 1)) ? 0 : 1;
+                       priv->result = 0;
 
-                       status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+                       status = nmk_i2c_xfer_one(priv, msgs[i].flags);
                        if (status != 0)
                                break;
                }
@@ -688,7 +748,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
                        break;
        }
 
-       pm_runtime_put_sync(&dev->adev->dev);
+       pm_runtime_put_sync(&priv->adev->dev);
 
        /* return the no. messages processed */
        if (status)
@@ -699,14 +759,14 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 
 /**
  * disable_interrupts() - disable the interrupts
- * @dev: private data of controller
+ * @priv: private data of controller
  * @irq: interrupt number
  */
-static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
+static int disable_interrupts(struct nmk_i2c_dev *priv, u32 irq)
 {
-       irq = IRQ_MASK(irq);
-       writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq),
-                       dev->virtbase + I2C_IMSCR);
+       irq &= I2C_CLEAR_ALL_INTS;
+       writel(readl(priv->virtbase + I2C_IMSCR) & ~irq,
+              priv->virtbase + I2C_IMSCR);
        return 0;
 }
 
@@ -723,38 +783,39 @@ static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
  */
 static irqreturn_t i2c_irq_handler(int irq, void *arg)
 {
-       struct nmk_i2c_dev *dev = arg;
+       struct nmk_i2c_dev *priv = arg;
+       struct device *dev = &priv->adev->dev;
        u32 tft, rft;
        u32 count;
        u32 misr, src;
 
        /* load Tx FIFO and Rx FIFO threshold values */
-       tft = readl(dev->virtbase + I2C_TFTR);
-       rft = readl(dev->virtbase + I2C_RFTR);
+       tft = readl(priv->virtbase + I2C_TFTR);
+       rft = readl(priv->virtbase + I2C_RFTR);
 
        /* read interrupt status register */
-       misr = readl(dev->virtbase + I2C_MISR);
+       misr = readl(priv->virtbase + I2C_MISR);
 
        src = __ffs(misr);
-       switch ((1 << src)) {
+       switch (BIT(src)) {
 
        /* Transmit FIFO nearly empty interrupt */
        case I2C_IT_TXFNE:
        {
-               if (dev->cli.operation == I2C_READ) {
+               if (priv->cli.operation == I2C_READ) {
                        /*
                         * in read operation why do we care for writing?
                         * so disable the Transmit FIFO interrupt
                         */
-                       disable_interrupts(dev, I2C_IT_TXFNE);
+                       disable_interrupts(priv, I2C_IT_TXFNE);
                } else {
-                       fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
+                       fill_tx_fifo(priv, (MAX_I2C_FIFO_THRESHOLD - tft));
                        /*
                         * if done, close the transfer by disabling the
                         * corresponding TXFNE interrupt
                         */
-                       if (dev->cli.count == 0)
-                               disable_interrupts(dev, I2C_IT_TXFNE);
+                       if (priv->cli.count == 0)
+                               disable_interrupts(priv,        I2C_IT_TXFNE);
                }
        }
        break;
@@ -768,60 +829,63 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        case I2C_IT_RXFNF:
                for (count = rft; count > 0; count--) {
                        /* Read the Rx FIFO */
-                       *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
-                       dev->cli.buffer++;
+                       *priv->cli.buffer = nmk_i2c_readb(priv, I2C_RFR);
+                       priv->cli.buffer++;
                }
-               dev->cli.count -= rft;
-               dev->cli.xfer_bytes += rft;
+               priv->cli.count -= rft;
+               priv->cli.xfer_bytes += rft;
                break;
 
        /* Rx FIFO full */
        case I2C_IT_RXFF:
                for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) {
-                       *dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
-                       dev->cli.buffer++;
+                       *priv->cli.buffer = nmk_i2c_readb(priv, I2C_RFR);
+                       priv->cli.buffer++;
                }
-               dev->cli.count -= MAX_I2C_FIFO_THRESHOLD;
-               dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD;
+               priv->cli.count -= MAX_I2C_FIFO_THRESHOLD;
+               priv->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD;
                break;
 
        /* Master Transaction Done with/without stop */
        case I2C_IT_MTD:
        case I2C_IT_MTDWS:
-               if (dev->cli.operation == I2C_READ) {
-                       while (!(readl(dev->virtbase + I2C_RISR)
+               if (priv->cli.operation == I2C_READ) {
+                       while (!(readl(priv->virtbase + I2C_RISR)
                                 & I2C_IT_RXFE)) {
-                               if (dev->cli.count == 0)
+                               if (priv->cli.count == 0)
                                        break;
-                               *dev->cli.buffer =
-                                       readb(dev->virtbase + I2C_RFR);
-                               dev->cli.buffer++;
-                               dev->cli.count--;
-                               dev->cli.xfer_bytes++;
+                               *priv->cli.buffer =
+                                       nmk_i2c_readb(priv, I2C_RFR);
+                               priv->cli.buffer++;
+                               priv->cli.count--;
+                               priv->cli.xfer_bytes++;
                        }
                }
 
-               disable_all_interrupts(dev);
-               clear_all_interrupts(dev);
+               disable_all_interrupts(priv);
+               clear_all_interrupts(priv);
 
-               if (dev->cli.count) {
-                       dev->result = -EIO;
-                       dev_err(&dev->adev->dev,
-                               "%lu bytes still remain to be xfered\n",
-                               dev->cli.count);
-                       (void) init_hw(dev);
+               if (priv->cli.count) {
+                       priv->result = -EIO;
+                       dev_err(dev, "%lu bytes still remain to be xfered\n",
+                               priv->cli.count);
+                       init_hw(priv);
                }
-               complete(&dev->xfer_complete);
+               priv->xfer_done = true;
+               wake_up(&priv->xfer_wq);
+
 
                break;
 
        /* Master Arbitration lost interrupt */
        case I2C_IT_MAL:
-               dev->result = -EIO;
-               (void) init_hw(dev);
+               priv->result = -EIO;
+               init_hw(priv);
+
+               i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_MAL);
+               priv->xfer_done = true;
+               wake_up(&priv->xfer_wq);
 
-               i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
-               complete(&dev->xfer_complete);
 
                break;
 
@@ -831,15 +895,20 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * during the transaction.
         */
        case I2C_IT_BERR:
-               dev->result = -EIO;
-               /* get the status */
-               if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
-                       (void) init_hw(dev);
+       {
+               u32 sr;
 
-               i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR);
-               complete(&dev->xfer_complete);
+               sr = readl(priv->virtbase + I2C_SR);
+               priv->result = -EIO;
+               if (FIELD_GET(I2C_SR_STATUS, sr) == I2C_ABORT)
+                       init_hw(priv);
 
-               break;
+               i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_BERR);
+               priv->xfer_done = true;
+               wake_up(&priv->xfer_wq);
+
+       }
+       break;
 
        /*
         * Tx FIFO overrun interrupt.
@@ -847,11 +916,13 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * the Tx FIFO is full.
         */
        case I2C_IT_TXFOVR:
-               dev->result = -EIO;
-               (void) init_hw(dev);
+               priv->result = -EIO;
+               init_hw(priv);
+
+               dev_err(dev, "Tx Fifo Over run\n");
+               priv->xfer_done = true;
+               wake_up(&priv->xfer_wq);
 
-               dev_err(&dev->adev->dev, "Tx Fifo Over run\n");
-               complete(&dev->xfer_complete);
 
                break;
 
@@ -863,10 +934,10 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        case I2C_IT_RFSE:
        case I2C_IT_WTSR:
        case I2C_IT_STD:
-               dev_err(&dev->adev->dev, "unhandled Interrupt\n");
+               dev_err(dev, "unhandled Interrupt\n");
                break;
        default:
-               dev_err(&dev->adev->dev, "spurious Interrupt..\n");
+               dev_err(dev, "spurious Interrupt..\n");
                break;
        }
 
@@ -893,9 +964,9 @@ static int nmk_i2c_resume_early(struct device *dev)
 static int nmk_i2c_runtime_suspend(struct device *dev)
 {
        struct amba_device *adev = to_amba_device(dev);
-       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+       struct nmk_i2c_dev *priv = amba_get_drvdata(adev);
 
-       clk_disable_unprepare(nmk_i2c->clk);
+       clk_disable_unprepare(priv->clk);
        pinctrl_pm_select_idle_state(dev);
        return 0;
 }
@@ -903,10 +974,10 @@ static int nmk_i2c_runtime_suspend(struct device *dev)
 static int nmk_i2c_runtime_resume(struct device *dev)
 {
        struct amba_device *adev = to_amba_device(dev);
-       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+       struct nmk_i2c_dev *priv = amba_get_drvdata(adev);
        int ret;
 
-       ret = clk_prepare_enable(nmk_i2c->clk);
+       ret = clk_prepare_enable(priv->clk);
        if (ret) {
                dev_err(dev, "can't prepare_enable clock\n");
                return ret;
@@ -914,9 +985,9 @@ static int nmk_i2c_runtime_resume(struct device *dev)
 
        pinctrl_pm_select_default_state(dev);
 
-       ret = init_hw(nmk_i2c);
+       ret = init_hw(priv);
        if (ret) {
-               clk_disable_unprepare(nmk_i2c->clk);
+               clk_disable_unprepare(priv->clk);
                pinctrl_pm_select_idle_state(dev);
        }
 
@@ -939,107 +1010,160 @@ static const struct i2c_algorithm nmk_i2c_algo = {
 };
 
 static void nmk_i2c_of_probe(struct device_node *np,
-                            struct nmk_i2c_dev *nmk)
+                            struct nmk_i2c_dev *priv)
 {
+       u32 timeout_usecs;
+
        /* Default to 100 kHz if no frequency is given in the node */
-       if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq))
-               nmk->clk_freq = I2C_MAX_STANDARD_MODE_FREQ;
+       if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq))
+               priv->clk_freq = I2C_MAX_STANDARD_MODE_FREQ;
 
        /* This driver only supports 'standard' and 'fast' modes of operation. */
-       if (nmk->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ)
-               nmk->sm = I2C_FREQ_MODE_STANDARD;
+       if (priv->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ)
+               priv->sm = I2C_FREQ_MODE_STANDARD;
+       else
+               priv->sm = I2C_FREQ_MODE_FAST;
+       priv->tft = 1; /* Tx FIFO threshold */
+       priv->rft = 8; /* Rx FIFO threshold */
+
+       /* Slave response timeout */
+       if (!of_property_read_u32(np, "i2c-transfer-timeout-us", &timeout_usecs))
+               priv->timeout_usecs = timeout_usecs;
+       else
+               priv->timeout_usecs = 200 * USEC_PER_MSEC;
+}
+
+static const unsigned int nmk_i2c_eyeq5_masks[] = {
+       GENMASK(5, 4),
+       GENMASK(7, 6),
+       GENMASK(9, 8),
+       GENMASK(11, 10),
+       GENMASK(13, 12),
+};
+
+static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv)
+{
+       struct device *dev = &priv->adev->dev;
+       struct device_node *np = dev->of_node;
+       unsigned int mask, speed_mode;
+       struct regmap *olb;
+       unsigned int id;
+
+       priv->has_32b_bus = true;
+
+       olb = syscon_regmap_lookup_by_phandle_args(np, "mobileye,olb", 1, &id);
+       if (IS_ERR(olb))
+               return PTR_ERR(olb);
+       if (id >= ARRAY_SIZE(nmk_i2c_eyeq5_masks))
+               return -ENOENT;
+
+       if (priv->clk_freq <= 400000)
+               speed_mode = I2C_EYEQ5_SPEED_FAST;
+       else if (priv->clk_freq <= 1000000)
+               speed_mode = I2C_EYEQ5_SPEED_FAST_PLUS;
        else
-               nmk->sm = I2C_FREQ_MODE_FAST;
-       nmk->tft = 1; /* Tx FIFO threshold */
-       nmk->rft = 8; /* Rx FIFO threshold */
-       nmk->timeout = 200; /* Slave response timeout(ms) */
+               speed_mode = I2C_EYEQ5_SPEED_HIGH_SPEED;
+
+       mask = nmk_i2c_eyeq5_masks[id];
+       regmap_update_bits(olb, NMK_I2C_EYEQ5_OLB_IOCR2,
+                          mask, speed_mode << __fls(mask));
+
+       return 0;
 }
 
 static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
+       struct nmk_i2c_dev *priv;
        struct device_node *np = adev->dev.of_node;
-       struct nmk_i2c_dev      *dev;
+       struct device *dev = &adev->dev;
        struct i2c_adapter *adap;
        struct i2c_vendor_data *vendor = id->data;
        u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
 
-       dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev)
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
                return -ENOMEM;
 
-       dev->vendor = vendor;
-       dev->adev = adev;
-       nmk_i2c_of_probe(np, dev);
+       priv->vendor = vendor;
+       priv->adev = adev;
+       priv->has_32b_bus = false;
+       nmk_i2c_of_probe(np, priv);
+
+       if (of_device_is_compatible(np, "mobileye,eyeq5-i2c")) {
+               ret = nmk_i2c_eyeq5_probe(priv);
+               if (ret)
+                       return dev_err_probe(dev, ret, "failed OLB lookup\n");
+       }
 
-       if (dev->tft > max_fifo_threshold) {
-               dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
-                        dev->tft, max_fifo_threshold);
-               dev->tft = max_fifo_threshold;
+       if (priv->tft > max_fifo_threshold) {
+               dev_warn(dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
+                        priv->tft, max_fifo_threshold);
+               priv->tft = max_fifo_threshold;
        }
 
-       if (dev->rft > max_fifo_threshold) {
-               dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
-                       dev->rft, max_fifo_threshold);
-               dev->rft = max_fifo_threshold;
+       if (priv->rft > max_fifo_threshold) {
+               dev_warn(dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
+                        priv->rft, max_fifo_threshold);
+               priv->rft = max_fifo_threshold;
        }
 
-       amba_set_drvdata(adev, dev);
+       amba_set_drvdata(adev, priv);
 
-       dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
-                               resource_size(&adev->res));
-       if (!dev->virtbase)
+       priv->virtbase = devm_ioremap(dev, adev->res.start,
+                                     resource_size(&adev->res));
+       if (!priv->virtbase)
                return -ENOMEM;
 
-       dev->irq = adev->irq[0];
-       ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
-                               DRIVER_NAME, dev);
+       priv->irq = adev->irq[0];
+       ret = devm_request_irq(dev, priv->irq, i2c_irq_handler, 0,
+                              DRIVER_NAME, priv);
        if (ret)
-               return dev_err_probe(&adev->dev, ret,
-                                    "cannot claim the irq %d\n", dev->irq);
+               return dev_err_probe(dev, ret,
+                                    "cannot claim the irq %d\n", priv->irq);
 
-       dev->clk = devm_clk_get_enabled(&adev->dev, NULL);
-       if (IS_ERR(dev->clk))
-               return dev_err_probe(&adev->dev, PTR_ERR(dev->clk),
+       priv->clk = devm_clk_get_enabled(dev, NULL);
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(dev, PTR_ERR(priv->clk),
                                     "could enable i2c clock\n");
 
-       init_hw(dev);
+       init_hw(priv);
 
-       adap = &dev->adap;
+       adap = &priv->adap;
        adap->dev.of_node = np;
-       adap->dev.parent = &adev->dev;
+       adap->dev.parent = dev;
        adap->owner = THIS_MODULE;
        adap->class = I2C_CLASS_DEPRECATED;
        adap->algo = &nmk_i2c_algo;
-       adap->timeout = msecs_to_jiffies(dev->timeout);
+       adap->timeout = usecs_to_jiffies(priv->timeout_usecs);
        snprintf(adap->name, sizeof(adap->name),
                 "Nomadik I2C at %pR", &adev->res);
 
-       i2c_set_adapdata(adap, dev);
+       i2c_set_adapdata(adap, priv);
 
-       dev_info(&adev->dev,
+       dev_info(dev,
                 "initialize %s on virtual base %p\n",
-                adap->name, dev->virtbase);
+                adap->name, priv->virtbase);
 
        ret = i2c_add_adapter(adap);
        if (ret)
                return ret;
 
-       pm_runtime_put(&adev->dev);
+       pm_runtime_put(dev);
 
        return 0;
 }
 
 static void nmk_i2c_remove(struct amba_device *adev)
 {
-       struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
+       struct nmk_i2c_dev *priv = amba_get_drvdata(adev);
 
-       i2c_del_adapter(&dev->adap);
-       flush_i2c_fifo(dev);
-       disable_all_interrupts(dev);
-       clear_all_interrupts(dev);
+       i2c_del_adapter(&priv->adap);
+       flush_i2c_fifo(priv);
+       disable_all_interrupts(priv);
+       clear_all_interrupts(priv);
        /* disable the controller */
-       i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+       i2c_clr_bit(priv->virtbase + I2C_CR, I2C_CR_PE);
 }
 
 static struct i2c_vendor_data vendor_stn8815 = {
index f5dfc33b97c0ab94dfee90ae29d81c69395f180b..c3f4ff08ac3851a620d77e69caccdb95a2cc0ccb 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/pm.h>
 #include <linux/property.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <dt-bindings/mux/mux.h>
@@ -116,6 +117,9 @@ struct pca954x {
        unsigned int irq_mask;
        raw_spinlock_t lock;
        struct regulator *supply;
+
+       struct gpio_desc *reset_gpio;
+       struct reset_control *reset_cont;
 };
 
 /* Provide specs for the MAX735x, PCA954x and PCA984x types we know about */
@@ -518,6 +522,35 @@ static int pca954x_init(struct i2c_client *client, struct pca954x *data)
        return ret;
 }
 
+static int pca954x_get_reset(struct device *dev, struct pca954x *data)
+{
+       data->reset_cont = devm_reset_control_get_optional_shared(dev, NULL);
+       if (IS_ERR(data->reset_cont))
+               return dev_err_probe(dev, PTR_ERR(data->reset_cont),
+                                    "Failed to get reset\n");
+       else if (data->reset_cont)
+               return 0;
+
+       /*
+        * fallback to legacy reset-gpios
+        */
+       data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(data->reset_gpio)) {
+               return dev_err_probe(dev, PTR_ERR(data->reset_gpio),
+                                    "Failed to get reset gpio");
+       }
+
+       return 0;
+}
+
+static void pca954x_reset_deassert(struct pca954x *data)
+{
+       if (data->reset_cont)
+               reset_control_deassert(data->reset_cont);
+       else
+               gpiod_set_value_cansleep(data->reset_gpio, 0);
+}
+
 /*
  * I2C init/probing/exit functions
  */
@@ -526,7 +559,6 @@ static int pca954x_probe(struct i2c_client *client)
        const struct i2c_device_id *id = i2c_client_get_device_id(client);
        struct i2c_adapter *adap = client->adapter;
        struct device *dev = &client->dev;
-       struct gpio_desc *gpio;
        struct i2c_mux_core *muxc;
        struct pca954x *data;
        int num;
@@ -554,15 +586,13 @@ static int pca954x_probe(struct i2c_client *client)
                return dev_err_probe(dev, ret,
                                     "Failed to enable vdd supply\n");
 
-       /* Reset the mux if a reset GPIO is specified. */
-       gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
-       if (IS_ERR(gpio)) {
-               ret = PTR_ERR(gpio);
+       ret = pca954x_get_reset(dev, data);
+       if (ret)
                goto fail_cleanup;
-       }
-       if (gpio) {
+
+       if (data->reset_cont || data->reset_gpio) {
                udelay(1);
-               gpiod_set_value_cansleep(gpio, 0);
+               pca954x_reset_deassert(data);
                /* Give the chip some time to recover. */
                udelay(1);
        }
index 52eb46ef84c1b21958803dd0ac4401c58542f725..9c351ffc7bed6dd239352e0e85402ea11ef9feb3 100644 (file)
@@ -71,6 +71,15 @@ config IIO_TRIGGERED_EVENT
        help
          Provides helper functions for setting up triggered events.
 
+config IIO_BACKEND
+       tristate
+       help
+         Framework to handle complex IIO aggregate devices. The typical
+         architecture that can make use of this framework is to have one
+         device as the frontend device which can be "linked" against one or
+         multiple backend devices. The framework then makes it easy to get
+         and control such backend devices.
+
 source "drivers/iio/accel/Kconfig"
 source "drivers/iio/adc/Kconfig"
 source "drivers/iio/addac/Kconfig"
index 9622347a1c1befb78ce9fb92975760c8a31cfcea..0ba0e1521ba4f0cc30b7c48d59b077659f6ac9e7 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_IIO_GTS_HELPER) += industrialio-gts-helper.o
 obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o
 obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
 obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
+obj-$(CONFIG_IIO_BACKEND) += industrialio-backend.o
 
 obj-y += accel/
 obj-y += adc/
index c9d7afe489e832b4a9598ffe9266084dbebd9fd6..c2da5066e9a7bdd3bf43ff4ce36cc1fcc00dc1a8 100644 (file)
@@ -256,11 +256,11 @@ config BMC150_ACCEL_SPI
 
 config BMI088_ACCEL
        tristate "Bosch BMI088 Accelerometer Driver"
-       depends on SPI
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select REGMAP
-       select BMI088_ACCEL_SPI
+       select BMI088_ACCEL_SPI if SPI
+       select BMI088_ACCEL_I2C if I2C
        help
          Say yes here to build support for the following Bosch accelerometers:
          BMI088, BMI085, BMI090L. Note that all of these are combo module that
@@ -269,6 +269,10 @@ config BMI088_ACCEL
          This driver only implements the accelerometer part, which has its own
          address and register map. BMG160 provides the gyroscope driver.
 
+config BMI088_ACCEL_I2C
+       tristate
+       select REGMAP_I2C
+
 config BMI088_ACCEL_SPI
        tristate
        select REGMAP_SPI
index 311ead9c3ef18afa683cafc7214bae7e3475e57e..db90532ba24aab69ceac2434496c7cd26c875e83 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
 obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
 obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
 obj-$(CONFIG_BMI088_ACCEL) += bmi088-accel-core.o
+obj-$(CONFIG_BMI088_ACCEL_I2C) += bmi088-accel-i2c.o
 obj-$(CONFIG_BMI088_ACCEL_SPI) += bmi088-accel-spi.o
 obj-$(CONFIG_DA280)    += da280.o
 obj-$(CONFIG_DA311)    += da311.o
index 484fe2e9fb1742b9adbde28d737127a4fe1d6413..210228affb80d317d63f2c98bbd810c40da87f93 100644 (file)
@@ -339,22 +339,17 @@ static int adxl367_set_act_threshold(struct adxl367_state *st,
 {
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = adxl367_set_measure_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        ret = _adxl367_set_act_threshold(st, act, threshold);
        if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
-
-out:
-       mutex_unlock(&st->lock);
+               return ret;
 
-       return ret;
+       return adxl367_set_measure_en(st, true);
 }
 
 static int adxl367_set_act_proc_mode(struct adxl367_state *st,
@@ -482,51 +477,45 @@ static int adxl367_set_fifo_watermark(struct adxl367_state *st,
 static int adxl367_set_range(struct iio_dev *indio_dev,
                             enum adxl367_range range)
 {
-       struct adxl367_state *st = iio_priv(indio_dev);
-       int ret;
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               struct adxl367_state *st = iio_priv(indio_dev);
+               int ret;
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
-
-       mutex_lock(&st->lock);
-
-       ret = adxl367_set_measure_en(st, false);
-       if (ret)
-               goto out;
+               guard(mutex)(&st->lock);
 
-       ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
-                                ADXL367_FILTER_CTL_RANGE_MASK,
-                                FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
-                                           range));
-       if (ret)
-               goto out;
+               ret = adxl367_set_measure_en(st, false);
+               if (ret)
+                       return ret;
 
-       adxl367_scale_act_thresholds(st, st->range, range);
+               ret = regmap_update_bits(st->regmap, ADXL367_REG_FILTER_CTL,
+                                        ADXL367_FILTER_CTL_RANGE_MASK,
+                                        FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MASK,
+                                                   range));
+               if (ret)
+                       return ret;
 
-       /* Activity thresholds depend on range */
-       ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
-                                        st->act_threshold);
-       if (ret)
-               goto out;
+               adxl367_scale_act_thresholds(st, st->range, range);
 
-       ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
-                                        st->inact_threshold);
-       if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
-       if (ret)
-               goto out;
+               /* Activity thresholds depend on range */
+               ret = _adxl367_set_act_threshold(st, ADXL367_ACTIVITY,
+                                                st->act_threshold);
+               if (ret)
+                       return ret;
 
-       st->range = range;
+               ret = _adxl367_set_act_threshold(st, ADXL367_INACTIVITY,
+                                                st->inact_threshold);
+               if (ret)
+                       return ret;
 
-out:
-       mutex_unlock(&st->lock);
+               ret = adxl367_set_measure_en(st, true);
+               if (ret)
+                       return ret;
 
-       iio_device_release_direct_mode(indio_dev);
+               st->range = range;
 
-       return ret;
+               return 0;
+       }
+       unreachable();
 }
 
 static int adxl367_time_ms_to_samples(struct adxl367_state *st, unsigned int ms)
@@ -587,11 +576,11 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st,
 {
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = adxl367_set_measure_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        if (act == ADXL367_ACTIVITY)
                ret = _adxl367_set_act_time_ms(st, ms);
@@ -599,14 +588,9 @@ static int adxl367_set_act_time_ms(struct adxl367_state *st,
                ret = _adxl367_set_inact_time_ms(st, ms);
 
        if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
-
-out:
-       mutex_unlock(&st->lock);
+               return ret;
 
-       return ret;
+       return adxl367_set_measure_en(st, true);
 }
 
 static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
@@ -636,31 +620,23 @@ static int _adxl367_set_odr(struct adxl367_state *st, enum adxl367_odr odr)
 
 static int adxl367_set_odr(struct iio_dev *indio_dev, enum adxl367_odr odr)
 {
-       struct adxl367_state *st = iio_priv(indio_dev);
-       int ret;
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               struct adxl367_state *st = iio_priv(indio_dev);;
+               int ret;
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
+               guard(mutex)(&st->lock);
 
-       mutex_lock(&st->lock);
-
-       ret = adxl367_set_measure_en(st, false);
-       if (ret)
-               goto out;
-
-       ret = _adxl367_set_odr(st, odr);
-       if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
-
-out:
-       mutex_unlock(&st->lock);
+               ret = adxl367_set_measure_en(st, false);
+               if (ret)
+                       return ret;
 
-       iio_device_release_direct_mode(indio_dev);
+               ret = _adxl367_set_odr(st, odr);
+               if (ret)
+                       return ret;
 
-       return ret;
+               return adxl367_set_measure_en(st, true);
+       }
+       unreachable();
 }
 
 static int adxl367_set_temp_adc_en(struct adxl367_state *st, unsigned int reg,
@@ -749,36 +725,32 @@ static int adxl367_read_sample(struct iio_dev *indio_dev,
                               struct iio_chan_spec const *chan,
                               int *val)
 {
-       struct adxl367_state *st = iio_priv(indio_dev);
-       u16 sample;
-       int ret;
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               struct adxl367_state *st = iio_priv(indio_dev);
+               u16 sample;
+               int ret;
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
+               guard(mutex)(&st->lock);
 
-       mutex_lock(&st->lock);
-
-       ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
-       if (ret)
-               goto out;
-
-       ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
-                              sizeof(st->sample_buf));
-       if (ret)
-               goto out;
-
-       sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
-       *val = sign_extend32(sample, chan->scan_type.realbits - 1);
+               ret = adxl367_set_temp_adc_reg_en(st, chan->address, true);
+               if (ret)
+                       return ret;
 
-       ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
+               ret = regmap_bulk_read(st->regmap, chan->address, &st->sample_buf,
+                                      sizeof(st->sample_buf));
+               if (ret)
+                       return ret;
 
-out:
-       mutex_unlock(&st->lock);
+               sample = FIELD_GET(ADXL367_DATA_MASK, be16_to_cpu(st->sample_buf));
+               *val = sign_extend32(sample, chan->scan_type.realbits - 1);
 
-       iio_device_release_direct_mode(indio_dev);
+               ret = adxl367_set_temp_adc_reg_en(st, chan->address, false);
+               if (ret)
+                       return ret;
 
-       return ret ?: IIO_VAL_INT;
+               return IIO_VAL_INT;
+       }
+       unreachable();
 }
 
 static int adxl367_get_status(struct adxl367_state *st, u8 *status,
@@ -886,12 +858,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev,
                return adxl367_read_sample(indio_dev, chan, val);
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
-               case IIO_ACCEL:
-                       mutex_lock(&st->lock);
+               case IIO_ACCEL: {
+                       guard(mutex)(&st->lock);
                        *val = adxl367_range_scale_tbl[st->range][0];
                        *val2 = adxl367_range_scale_tbl[st->range][1];
-                       mutex_unlock(&st->lock);
                        return IIO_VAL_INT_PLUS_NANO;
+               }
                case IIO_TEMP:
                        *val = 1000;
                        *val2 = ADXL367_TEMP_PER_C;
@@ -914,12 +886,12 @@ static int adxl367_read_raw(struct iio_dev *indio_dev,
                default:
                        return -EINVAL;
                }
-       case IIO_CHAN_INFO_SAMP_FREQ:
-               mutex_lock(&st->lock);
+       case IIO_CHAN_INFO_SAMP_FREQ: {
+               guard(mutex)(&st->lock);
                *val = adxl367_samp_freq_tbl[st->odr][0];
                *val2 = adxl367_samp_freq_tbl[st->odr][1];
-               mutex_unlock(&st->lock);
                return IIO_VAL_INT_PLUS_MICRO;
+       }
        default:
                return -EINVAL;
        }
@@ -1004,18 +976,15 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev,
 {
        struct adxl367_state *st = iio_priv(indio_dev);
 
+       guard(mutex)(&st->lock);
        switch (info) {
        case IIO_EV_INFO_VALUE: {
                switch (dir) {
                case IIO_EV_DIR_RISING:
-                       mutex_lock(&st->lock);
                        *val = st->act_threshold;
-                       mutex_unlock(&st->lock);
                        return IIO_VAL_INT;
                case IIO_EV_DIR_FALLING:
-                       mutex_lock(&st->lock);
                        *val = st->inact_threshold;
-                       mutex_unlock(&st->lock);
                        return IIO_VAL_INT;
                default:
                        return -EINVAL;
@@ -1024,15 +993,11 @@ static int adxl367_read_event_value(struct iio_dev *indio_dev,
        case IIO_EV_INFO_PERIOD:
                switch (dir) {
                case IIO_EV_DIR_RISING:
-                       mutex_lock(&st->lock);
                        *val = st->act_time_ms;
-                       mutex_unlock(&st->lock);
                        *val2 = 1000;
                        return IIO_VAL_FRACTIONAL;
                case IIO_EV_DIR_FALLING:
-                       mutex_lock(&st->lock);
                        *val = st->inact_time_ms;
-                       mutex_unlock(&st->lock);
                        *val2 = 1000;
                        return IIO_VAL_FRACTIONAL;
                default:
@@ -1110,9 +1075,7 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev,
                                      enum iio_event_direction dir,
                                      int state)
 {
-       struct adxl367_state *st = iio_priv(indio_dev);
        enum adxl367_activity_type act;
-       int ret;
 
        switch (dir) {
        case IIO_EV_DIR_RISING:
@@ -1125,33 +1088,28 @@ static int adxl367_write_event_config(struct iio_dev *indio_dev,
                return -EINVAL;
        }
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
-
-       mutex_lock(&st->lock);
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               struct adxl367_state *st = iio_priv(indio_dev);
+               int ret;
 
-       ret = adxl367_set_measure_en(st, false);
-       if (ret)
-               goto out;
+               guard(mutex)(&st->lock);
 
-       ret = adxl367_set_act_interrupt_en(st, act, state);
-       if (ret)
-               goto out;
-
-       ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
-                                               : ADXL367_ACT_DISABLED);
-       if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
+               ret = adxl367_set_measure_en(st, false);
+               if (ret)
+                       return ret;
 
-out:
-       mutex_unlock(&st->lock);
+               ret = adxl367_set_act_interrupt_en(st, act, state);
+               if (ret)
+                       return ret;
 
-       iio_device_release_direct_mode(indio_dev);
+               ret = adxl367_set_act_en(st, act, state ? ADCL367_ACT_REF_ENABLED
+                                        : ADXL367_ACT_DISABLED);
+               if (ret)
+                       return ret;
 
-       return ret;
+               return adxl367_set_measure_en(st, true);
+       }
+       unreachable();
 }
 
 static ssize_t adxl367_get_fifo_enabled(struct device *dev,
@@ -1176,9 +1134,8 @@ static ssize_t adxl367_get_fifo_watermark(struct device *dev,
        struct adxl367_state *st = iio_priv(dev_to_iio_dev(dev));
        unsigned int fifo_watermark;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        fifo_watermark = st->fifo_watermark;
-       mutex_unlock(&st->lock);
 
        return sysfs_emit(buf, "%d\n", fifo_watermark);
 }
@@ -1207,22 +1164,17 @@ static int adxl367_set_watermark(struct iio_dev *indio_dev, unsigned int val)
        if (val > ADXL367_FIFO_MAX_WATERMARK)
                return -EINVAL;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = adxl367_set_measure_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_fifo_watermark(st, val);
        if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
-
-out:
-       mutex_unlock(&st->lock);
+               return ret;
 
-       return ret;
+       return adxl367_set_measure_en(st, true);
 }
 
 static bool adxl367_find_mask_fifo_format(const unsigned long *scan_mask,
@@ -1253,27 +1205,24 @@ static int adxl367_update_scan_mode(struct iio_dev *indio_dev,
        if (!adxl367_find_mask_fifo_format(active_scan_mask, &fifo_format))
                return -EINVAL;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = adxl367_set_measure_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_fifo_format(st, fifo_format);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_measure_en(st, true);
        if (ret)
-               goto out;
+               return ret;
 
        st->fifo_set_size = bitmap_weight(active_scan_mask,
                                          indio_dev->masklength);
 
-out:
-       mutex_unlock(&st->lock);
-
-       return ret;
+       return 0;
 }
 
 static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
@@ -1281,31 +1230,26 @@ static int adxl367_buffer_postenable(struct iio_dev *indio_dev)
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
                                           true);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_measure_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_fifo_watermark_interrupt_en(st, true);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_STREAM);
        if (ret)
-               goto out;
-
-       ret = adxl367_set_measure_en(st, true);
-
-out:
-       mutex_unlock(&st->lock);
+               return ret;
 
-       return ret;
+       return adxl367_set_measure_en(st, true);
 }
 
 static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
@@ -1313,31 +1257,26 @@ static int adxl367_buffer_predisable(struct iio_dev *indio_dev)
        struct adxl367_state *st = iio_priv(indio_dev);
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = adxl367_set_measure_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_fifo_mode(st, ADXL367_FIFO_MODE_DISABLED);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_fifo_watermark_interrupt_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        ret = adxl367_set_measure_en(st, true);
        if (ret)
-               goto out;
-
-       ret = adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
-                                          false);
-
-out:
-       mutex_unlock(&st->lock);
+               return ret;
 
-       return ret;
+       return adxl367_set_temp_adc_mask_en(st, indio_dev->active_scan_mask,
+                                           false);
 }
 
 static const struct iio_buffer_setup_ops adxl367_buffer_ops = {
index 75a88f16c6c905ef62f3d3b0c4ace74d1bf349ac..787699773f96f9ab1777ccba17e4be455cf388f8 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
-#include <linux/of.h>
 #include <linux/spi/spi.h>
 
 #include "adxl372.h"
index ab4fccb24b6c021a3d61c7105e5eaf077a7812bd..6581772cb0c463c557524f3be6f421076e8cd41b 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/of.h>
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
index ee1ba134ad4237269ea39411563580ca2d1163c5..1c2e40369839a3f4667cac5761ef7ed27b7d94d4 100644 (file)
@@ -224,6 +224,19 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
        {"BMA250E"},
        {"BMC150A"},
        {"BMI055A"},
+       /*
+        * The "BOSC0200" identifier used here is not unique to devices using
+        * bmc150. The same "BOSC0200" identifier is found in the ACPI tables
+        * of the ASUS ROG ALLY and Ayaneo AIR Plus which both use a Bosch
+        * BMI323 chip. This creates a conflict with duplicate ACPI identifiers
+        * which multiple drivers want to use. Fortunately, when the bmc150
+        * driver starts to load on the ASUS ROG ALLY, the chip ID check
+        * portion fails (correctly) because the chip IDs received (via i2c)
+        * are unique between bmc150 and bmi323 and a dmesg output similar to
+        * this: "bmc150_accel_i2c i2c-BOSC0200:00: Invalid chip 0" can be
+        * seen. This allows the bmi323 driver to take over for ASUS ROG ALLY,
+        * and other devices using the bmi323 chip.
+        */
        {"BOSC0200"},
        {"BSBA0150"},
        {"DUAL250E"},
@@ -266,7 +279,7 @@ static struct i2c_driver bmc150_accel_driver = {
        .driver = {
                .name   = "bmc150_accel_i2c",
                .of_match_table = bmc150_accel_of_match,
-               .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+               .acpi_match_table = bmc150_accel_acpi_match,
                .pm     = &bmc150_accel_pm_ops,
        },
        .probe          = bmc150_accel_probe,
index 921fb46be0b8f06bcdbf18f784fbe83033e81cf0..a6b9f599eb7bdcf8aaa7fb2e8933884c0329c716 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/acpi.h>
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
 
@@ -70,7 +69,7 @@ MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
 static struct spi_driver bmc150_accel_driver = {
        .driver = {
                .name   = "bmc150_accel_spi",
-               .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+               .acpi_match_table = bmc150_accel_acpi_match,
                .pm     = &bmc150_accel_pm_ops,
        },
        .probe          = bmc150_accel_probe,
diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c
new file mode 100644 (file)
index 0000000..17e9156
--- /dev/null
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
+ *  - BMI088
+ *  - BMI085
+ *  - BMI090L
+ *
+ * Copyright 2023 Jun Yan <jerrysteve1101@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "bmi088-accel.h"
+
+static int bmi088_accel_probe(struct i2c_client *i2c)
+{
+       struct regmap *regmap;
+       const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
+
+       regmap = devm_regmap_init_i2c(i2c, &bmi088_regmap_conf);
+       if (IS_ERR(regmap)) {
+               dev_err(&i2c->dev, "Failed to initialize i2c regmap\n");
+               return PTR_ERR(regmap);
+       }
+
+       return bmi088_accel_core_probe(&i2c->dev, regmap, i2c->irq,
+                                       id->driver_data);
+}
+
+static void bmi088_accel_remove(struct i2c_client *i2c)
+{
+       bmi088_accel_core_remove(&i2c->dev);
+}
+
+static const struct of_device_id bmi088_of_match[] = {
+       { .compatible = "bosch,bmi085-accel" },
+       { .compatible = "bosch,bmi088-accel" },
+       { .compatible = "bosch,bmi090l-accel" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, bmi088_of_match);
+
+static const struct i2c_device_id bmi088_accel_id[] = {
+       { "bmi085-accel",  BOSCH_BMI085 },
+       { "bmi088-accel",  BOSCH_BMI088 },
+       { "bmi090l-accel", BOSCH_BMI090L },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, bmi088_accel_id);
+
+static struct i2c_driver bmi088_accel_driver = {
+       .driver = {
+               .name   = "bmi088_accel_i2c",
+               .pm     = pm_ptr(&bmi088_accel_pm_ops),
+               .of_match_table = bmi088_of_match,
+       },
+       .probe          = bmi088_accel_probe,
+       .remove         = bmi088_accel_remove,
+       .id_table       = bmi088_accel_id,
+};
+module_i2c_driver(bmi088_accel_driver);
+
+MODULE_AUTHOR("Jun Yan <jerrysteve1101@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("BMI088 accelerometer driver (I2C)");
+MODULE_IMPORT_NS(IIO_BMI088);
index 572bfe9694b079ab1f894e69dc8aa09e262addaa..9922868288449cc9f85cf6cf53a351d84c5acc49 100644 (file)
@@ -23,8 +23,6 @@
 #define DA280_MODE_ENABLE              0x1e
 #define DA280_MODE_DISABLE             0x9e
 
-enum da280_chipset { da217, da226, da280 };
-
 /*
  * a value of + or -4096 corresponds to + or - 1G
  * scale = 9.81 / 4096 = 0.002395019
@@ -47,6 +45,11 @@ static const struct iio_chan_spec da280_channels[] = {
        DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z),
 };
 
+struct da280_match_data {
+       const char *name;
+       int num_channels;
+};
+
 struct da280_data {
        struct i2c_client *client;
 };
@@ -89,17 +92,6 @@ static const struct iio_info da280_info = {
        .read_raw       = da280_read_raw,
 };
 
-static enum da280_chipset da280_match_acpi_device(struct device *dev)
-{
-       const struct acpi_device_id *id;
-
-       id = acpi_match_device(dev->driver->acpi_match_table, dev);
-       if (!id)
-               return -EINVAL;
-
-       return (enum da280_chipset) id->driver_data;
-}
-
 static void da280_disable(void *client)
 {
        da280_enable(client, false);
@@ -107,16 +99,21 @@ static void da280_disable(void *client)
 
 static int da280_probe(struct i2c_client *client)
 {
-       const struct i2c_device_id *id = i2c_client_get_device_id(client);
-       int ret;
+       const struct da280_match_data *match_data;
        struct iio_dev *indio_dev;
        struct da280_data *data;
-       enum da280_chipset chip;
+       int ret;
 
        ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID);
        if (ret != DA280_CHIP_ID)
                return (ret < 0) ? ret : -ENODEV;
 
+       match_data = i2c_get_match_data(client);
+       if (!match_data) {
+               dev_err(&client->dev, "Error match-data not set\n");
+               return -EINVAL;
+       }
+
        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
        if (!indio_dev)
                return -ENOMEM;
@@ -127,23 +124,8 @@ static int da280_probe(struct i2c_client *client)
        indio_dev->info = &da280_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = da280_channels;
-
-       if (ACPI_HANDLE(&client->dev)) {
-               chip = da280_match_acpi_device(&client->dev);
-       } else {
-               chip = id->driver_data;
-       }
-
-       if (chip == da217) {
-               indio_dev->name = "da217";
-               indio_dev->num_channels = 3;
-       } else if (chip == da226) {
-               indio_dev->name = "da226";
-               indio_dev->num_channels = 2;
-       } else {
-               indio_dev->name = "da280";
-               indio_dev->num_channels = 3;
-       }
+       indio_dev->num_channels = match_data->num_channels;
+       indio_dev->name = match_data->name;
 
        ret = da280_enable(client, true);
        if (ret < 0)
@@ -168,17 +150,21 @@ static int da280_resume(struct device *dev)
 
 static DEFINE_SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
 
+static const struct da280_match_data da217_match_data = { "da217", 3 };
+static const struct da280_match_data da226_match_data = { "da226", 2 };
+static const struct da280_match_data da280_match_data = { "da280", 3 };
+
 static const struct acpi_device_id da280_acpi_match[] = {
-       {"NSA2513", da217},
-       {"MIRAACC", da280},
-       {},
+       { "NSA2513", (kernel_ulong_t)&da217_match_data },
+       { "MIRAACC", (kernel_ulong_t)&da280_match_data },
+       {}
 };
 MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
 
 static const struct i2c_device_id da280_i2c_id[] = {
-       { "da217", da217 },
-       { "da226", da226 },
-       { "da280", da280 },
+       { "da217", (kernel_ulong_t)&da217_match_data },
+       { "da226", (kernel_ulong_t)&da226_match_data },
+       { "da280", (kernel_ulong_t)&da280_match_data },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
@@ -186,7 +172,7 @@ MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
 static struct i2c_driver da280_driver = {
        .driver = {
                .name = "da280",
-               .acpi_match_table = ACPI_PTR(da280_acpi_match),
+               .acpi_match_table = da280_acpi_match,
                .pm = pm_sleep_ptr(&da280_pm_ops),
        },
        .probe          = da280_probe,
index 894709286b0ccb22ff45cc0ac71729f28e06f487..126e8bdd6d0ed34b61bc6bf000066d38dba3992c 100644 (file)
@@ -422,6 +422,23 @@ static int kiox010a_dsm(struct device *dev, int fn_index)
        ACPI_FREE(obj);
        return 0;
 }
+
+static const struct acpi_device_id kx_acpi_match[] = {
+       {"KXCJ1013", KXCJK1013},
+       {"KXCJ1008", KXCJ91008},
+       {"KXCJ9000", KXCJ91008},
+       {"KIOX0008", KXCJ91008},
+       {"KIOX0009", KXTJ21009},
+       {"KIOX000A", KXCJ91008},
+       {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */
+       {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */
+       {"KXTJ1009", KXTJ21009},
+       {"KXJ2109",  KXTJ21009},
+       {"SMO8500",  KXCJ91008},
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
+
 #endif
 
 static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
@@ -619,6 +636,84 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
        return 0;
 }
 
+#ifdef CONFIG_ACPI
+static bool kxj_acpi_orientation(struct device *dev,
+                                struct iio_mount_matrix *orientation)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+       char *str;
+       union acpi_object *obj, *elements;
+       acpi_status status;
+       int i, j, val[3];
+       bool ret = false;
+
+       if (!acpi_has_method(adev->handle, "ROTM"))
+               return false;
+
+       status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer);
+       if (ACPI_FAILURE(status)) {
+               dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status);
+               return false;
+       }
+
+       obj = buffer.pointer;
+       if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
+               dev_err(dev, "Unknown ACPI mount matrix package format\n");
+               goto out_free_buffer;
+       }
+
+       elements = obj->package.elements;
+       for (i = 0; i < 3; i++) {
+               if (elements[i].type != ACPI_TYPE_STRING) {
+                       dev_err(dev, "Unknown ACPI mount matrix element format\n");
+                       goto out_free_buffer;
+               }
+
+               str = elements[i].string.pointer;
+               if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) {
+                       dev_err(dev, "Incorrect ACPI mount matrix string format\n");
+                       goto out_free_buffer;
+               }
+
+               for (j = 0; j < 3; j++) {
+                       switch (val[j]) {
+                       case -1: str = "-1"; break;
+                       case 0:  str = "0";  break;
+                       case 1:  str = "1";  break;
+                       default:
+                               dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]);
+                               goto out_free_buffer;
+                       }
+                       orientation->rotation[i * 3 + j] = str;
+               }
+       }
+
+       ret = true;
+
+out_free_buffer:
+       kfree(buffer.pointer);
+       return ret;
+}
+
+static bool kxj1009_apply_acpi_orientation(struct device *dev,
+                                         struct iio_mount_matrix *orientation)
+{
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL))
+               return kxj_acpi_orientation(dev, orientation);
+
+       return false;
+}
+#else
+static bool kxj1009_apply_acpi_orientation(struct device *dev,
+                                         struct iio_mount_matrix *orientation)
+{
+       return false;
+}
+#endif
+
 static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
 {
        int ret;
@@ -1449,9 +1544,12 @@ static int kxcjk1013_probe(struct i2c_client *client)
        } else {
                data->active_high_intr = true; /* default polarity */
 
-               ret = iio_read_mount_matrix(&client->dev, &data->orientation);
-               if (ret)
-                       return ret;
+               if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) {
+                       ret = iio_read_mount_matrix(&client->dev, &data->orientation);
+                       if (ret)
+                               return ret;
+               }
+
        }
 
        ret = devm_regulator_bulk_get_enable(&client->dev,
@@ -1687,22 +1785,6 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = {
                           kxcjk1013_runtime_resume, NULL)
 };
 
-static const struct acpi_device_id kx_acpi_match[] = {
-       {"KXCJ1013", KXCJK1013},
-       {"KXCJ1008", KXCJ91008},
-       {"KXCJ9000", KXCJ91008},
-       {"KIOX0008", KXCJ91008},
-       {"KIOX0009", KXTJ21009},
-       {"KIOX000A", KXCJ91008},
-       {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */
-       {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */
-       {"KXTJ1009", KXTJ21009},
-       {"KXJ2109",  KXTJ21009},
-       {"SMO8500",  KXCJ91008},
-       { },
-};
-MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
-
 static const struct i2c_device_id kxcjk1013_id[] = {
        {"kxcjk1013", KXCJK1013},
        {"kxcj91008", KXCJ91008},
index 1719a9f1d90ad04ed5f0d059dad0bb18e7ea3bcc..4414670dfb436be30a93364b1055a6b33868e727 100644 (file)
@@ -1,9 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <linux/device.h>
 #include <linux/kernel.h>
-#include <linux/of.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/slab.h>
 #include <linux/regmap.h>
 
index d823f2edc6d425b6b775ea1f05fc65a27cccd387..083c08f65bafe580cdac576b34b57e8449b85af7 100644 (file)
@@ -604,9 +604,9 @@ MODULE_DEVICE_TABLE(i2c, mma9551_id);
 static struct i2c_driver mma9551_driver = {
        .driver = {
                   .name = MMA9551_DRV_NAME,
-                  .acpi_match_table = ACPI_PTR(mma9551_acpi_match),
+                  .acpi_match_table = mma9551_acpi_match,
                   .pm = pm_ptr(&mma9551_pm_ops),
-                  },
+       },
        .probe = mma9551_probe,
        .remove = mma9551_remove,
        .id_table = mma9551_id,
index d01aba4aecba5204507562f8b84c6fb88f7afb41..3cbd0fd4e6240dae9fa4a1a52e60edabd334313f 100644 (file)
@@ -1243,9 +1243,9 @@ MODULE_DEVICE_TABLE(i2c, mma9553_id);
 static struct i2c_driver mma9553_driver = {
        .driver = {
                   .name = MMA9553_DRV_NAME,
-                  .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
+                  .acpi_match_table = mma9553_acpi_match,
                   .pm = pm_ptr(&mma9553_pm_ops),
-                  },
+       },
        .probe = mma9553_probe,
        .remove = mma9553_remove,
        .id_table = mma9553_id,
index 82e8d0b3904958c4e171cd5a7d7f208b7c7c1606..61839be501c21a023790c15c40f55a48cd8d3da3 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/trigger.h>
@@ -472,6 +472,7 @@ static int mxc4005_probe(struct i2c_client *client)
 static const struct acpi_device_id mxc4005_acpi_match[] = {
        {"MXC4005",     0},
        {"MXC6655",     0},
+       {"MDA6655",     0},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
@@ -493,7 +494,7 @@ MODULE_DEVICE_TABLE(i2c, mxc4005_id);
 static struct i2c_driver mxc4005_driver = {
        .driver = {
                .name = MXC4005_DRV_NAME,
-               .acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
+               .acpi_match_table = mxc4005_acpi_match,
                .of_match_table = mxc4005_of_match,
        },
        .probe          = mxc4005_probe,
index 33c2253561e6b2289465f87f517477b9121ca2dd..ac228128c4f9e48a545397e7e7db854dc696dc9a 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/iio/iio.h>
 #include <linux/delay.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
 #include <linux/iio/sysfs.h>
 
@@ -181,7 +181,7 @@ MODULE_DEVICE_TABLE(i2c, mxc6255_id);
 static struct i2c_driver mxc6255_driver = {
        .driver = {
                .name = MXC6255_DRV_NAME,
-               .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
+               .acpi_match_table = mxc6255_acpi_match,
        },
        .probe          = mxc6255_probe,
        .id_table       = mxc6255_id,
index 71ee861b29808e9a1768c5d5d48afc8245973bfb..fd374987112158cd51f6e08614e830cc426fb662 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
-#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
 
@@ -127,14 +126,12 @@ static const struct of_device_id st_accel_of_match[] = {
 };
 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)LIS2DH12_ACCEL_DEV_NAME},
        {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
-#endif
 
 static const struct i2c_device_id st_accel_id_table[] = {
        { LSM303DLH_ACCEL_DEV_NAME },
@@ -204,7 +201,7 @@ static struct i2c_driver st_accel_driver = {
        .driver = {
                .name = "st-accel-i2c",
                .of_match_table = st_accel_of_match,
-               .acpi_match_table = ACPI_PTR(st_accel_acpi_match),
+               .acpi_match_table = st_accel_acpi_match,
        },
        .probe = st_accel_i2c_probe,
        .id_table = st_accel_id_table,
index 3415ac1b449535fbf796f40463604f696ad1f2f0..668edc88c89dc80c14ea294e04d418176ce5538f 100644 (file)
@@ -7,11 +7,11 @@
  * STK8BA50 7-bit I2C address: 0x18.
  */
 
-#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -541,7 +541,7 @@ static struct i2c_driver stk8ba50_driver = {
        .driver = {
                .name = "stk8ba50",
                .pm = pm_sleep_ptr(&stk8ba50_pm_ops),
-               .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
+               .acpi_match_table = stk8ba50_acpi_id,
        },
        .probe =        stk8ba50_probe,
        .remove =           stk8ba50_remove,
index 3b73c509bd68ef55094e90284b14466b98e48c9e..0d9282fa67f59ca403c89f601233cc7bb30d6568 100644 (file)
@@ -291,7 +291,7 @@ config AD799X
 config AD9467
        tristate "Analog Devices AD9467 High Speed ADC driver"
        depends on SPI
-       depends on ADI_AXI_ADC
+       select IIO_BACKEND
        help
          Say yes here to build support for Analog Devices:
          * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter
@@ -309,7 +309,7 @@ config ADI_AXI_ADC
        select IIO_BUFFER_HW_CONSUMER
        select IIO_BUFFER_DMAENGINE
        select REGMAP_MMIO
-       depends on OF
+       select IIO_BACKEND
        help
          Say yes here to build support for Analog Devices Generic
          AXI ADC IP core. The IP core is used for interfacing with
@@ -930,6 +930,17 @@ config NPCM_ADC
          This driver can also be built as a module. If so, the module
          will be called npcm_adc.
 
+config PAC1934
+       tristate "Microchip Technology PAC1934 driver"
+       depends on I2C
+       help
+         Say yes here to build support for Microchip Technology's PAC1931,
+         PAC1932, PAC1933, PAC1934 Single/Multi-Channel Power Monitor with
+         Accumulator.
+
+         This driver can also be built as a module. If so, the module
+         will be called pac1934.
+
 config PALMAS_GPADC
        tristate "TI Palmas General Purpose ADC"
        depends on MFD_PALMAS
@@ -1312,6 +1323,17 @@ config TI_ADS1100
          This driver can also be built as a module. If so, the module will be
          called ti-ads1100.
 
+config TI_ADS1298
+       tristate "Texas Instruments ADS1298"
+       depends on SPI
+       select IIO_BUFFER
+       help
+         If you say yes here you get support for Texas Instruments ADS1298
+         medical ADC chips
+
+         This driver can also be built as a module. If so, the module will be
+         called ti-ads1298.
+
 config TI_ADS7950
        tristate "Texas Instruments ADS7950 ADC driver"
        depends on SPI && GPIOLIB
index d2fda54a3259c9766766d4bd80f1500d140260c2..b3c434722364a2b735025e914eed1b59b5d70125 100644 (file)
@@ -86,6 +86,7 @@ obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
 obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
+obj-$(CONFIG_PAC1934) += pac1934.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
 obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
 obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
@@ -116,6 +117,7 @@ obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
 obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
 obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
 obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
+obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
 obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
 obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
 obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
index 62490424b6aed44698c376560550af353073b72b..febb64e67955eec99761bfa1835de528e7f199c1 100644 (file)
@@ -887,9 +887,9 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
        unsigned int old_fs;
        int ret = 0;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        if (setup_info->filter_mode == val)
-               goto out;
+               return 0;
 
        old_fs = setup_info->fs;
        old_filter_mode = setup_info->filter_mode;
@@ -911,12 +911,10 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
        if (ret) {
                setup_info->fs = old_fs;
                setup_info->filter_mode = old_filter_mode;
+               return ret;
        }
 
- out:
-       mutex_unlock(&st->lock);
-
-       return ret;
+       return 0;
 }
 
 static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
@@ -927,9 +925,8 @@ static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
        struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
        enum ad4130_filter_mode filter_mode;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        filter_mode = setup_info->filter_mode;
-       mutex_unlock(&st->lock);
 
        return filter_mode;
 }
@@ -971,7 +968,7 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
        struct ad4130_chan_info *chan_info = &st->chans_info[channel];
        struct ad4130_setup_info *setup_info = &chan_info->setup;
        unsigned int pga, old_pga;
-       int ret = 0;
+       int ret;
 
        for (pga = 0; pga < AD4130_MAX_PGA; pga++)
                if (val == st->scale_tbls[setup_info->ref_sel][pga][0] &&
@@ -981,21 +978,20 @@ static int ad4130_set_channel_pga(struct ad4130_state *st, unsigned int channel,
        if (pga == AD4130_MAX_PGA)
                return -EINVAL;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        if (pga == setup_info->pga)
-               goto out;
+               return 0;
 
        old_pga = setup_info->pga;
        setup_info->pga = pga;
 
        ret = ad4130_write_channel_setup(st, channel, false);
-       if (ret)
+       if (ret) {
                setup_info->pga = old_pga;
+               return ret;
+       }
 
-out:
-       mutex_unlock(&st->lock);
-
-       return ret;
+       return 0;
 }
 
 static int ad4130_set_channel_freq(struct ad4130_state *st,
@@ -1004,26 +1000,25 @@ static int ad4130_set_channel_freq(struct ad4130_state *st,
        struct ad4130_chan_info *chan_info = &st->chans_info[channel];
        struct ad4130_setup_info *setup_info = &chan_info->setup;
        unsigned int fs, old_fs;
-       int ret = 0;
+       int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        old_fs = setup_info->fs;
 
        ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs);
 
        if (fs == setup_info->fs)
-               goto out;
+               return 0;
 
        setup_info->fs = fs;
 
        ret = ad4130_write_channel_setup(st, channel, false);
-       if (ret)
+       if (ret) {
                setup_info->fs = old_fs;
+               return ret;
+       }
 
-out:
-       mutex_unlock(&st->lock);
-
-       return ret;
+       return 0;
 }
 
 static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
@@ -1065,20 +1060,13 @@ static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
 static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
                              int *val)
 {
-       struct ad4130_state *st = iio_priv(indio_dev);
-       int ret;
-
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               struct ad4130_state *st = iio_priv(indio_dev);
 
-       mutex_lock(&st->lock);
-       ret = _ad4130_read_sample(indio_dev, channel, val);
-       mutex_unlock(&st->lock);
-
-       iio_device_release_direct_mode(indio_dev);
-
-       return ret;
+               guard(mutex)(&st->lock);
+               return _ad4130_read_sample(indio_dev, channel, val);
+       }
+       unreachable();
 }
 
 static int ad4130_read_raw(struct iio_dev *indio_dev,
@@ -1092,24 +1080,24 @@ static int ad4130_read_raw(struct iio_dev *indio_dev,
        switch (info) {
        case IIO_CHAN_INFO_RAW:
                return ad4130_read_sample(indio_dev, channel, val);
-       case IIO_CHAN_INFO_SCALE:
-               mutex_lock(&st->lock);
+       case IIO_CHAN_INFO_SCALE: {
+               guard(mutex)(&st->lock);
                *val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0];
                *val2 = st->scale_tbls[setup_info->ref_sel][setup_info->pga][1];
-               mutex_unlock(&st->lock);
 
                return IIO_VAL_INT_PLUS_NANO;
+       }
        case IIO_CHAN_INFO_OFFSET:
                *val = st->bipolar ? -BIT(chan->scan_type.realbits - 1) : 0;
 
                return IIO_VAL_INT;
-       case IIO_CHAN_INFO_SAMP_FREQ:
-               mutex_lock(&st->lock);
+       case IIO_CHAN_INFO_SAMP_FREQ: {
+               guard(mutex)(&st->lock);
                ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
                                  val, val2);
-               mutex_unlock(&st->lock);
 
                return IIO_VAL_INT_PLUS_NANO;
+       }
        default:
                return -EINVAL;
        }
@@ -1134,9 +1122,9 @@ static int ad4130_read_avail(struct iio_dev *indio_dev,
 
                return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_SAMP_FREQ:
-               mutex_lock(&st->lock);
-               filter_config = &ad4130_filter_configs[setup_info->filter_mode];
-               mutex_unlock(&st->lock);
+               scoped_guard(mutex, &st->lock) {
+                       filter_config = &ad4130_filter_configs[setup_info->filter_mode];
+               }
 
                *vals = (int *)filter_config->samp_freq_avail;
                *length = filter_config->samp_freq_avail_len * 2;
@@ -1197,21 +1185,18 @@ static int ad4130_update_scan_mode(struct iio_dev *indio_dev,
        unsigned int val = 0;
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        for_each_set_bit(channel, scan_mask, indio_dev->num_channels) {
                ret = ad4130_set_channel_enable(st, channel, true);
                if (ret)
-                       goto out;
+                       return ret;
 
                val++;
        }
 
        st->num_enabled_channels = val;
 
-out:
-       mutex_unlock(&st->lock);
-
        return 0;
 }
 
@@ -1232,22 +1217,19 @@ static int ad4130_set_fifo_watermark(struct iio_dev *indio_dev, unsigned int val
                 */
                eff = rounddown(AD4130_FIFO_SIZE, st->num_enabled_channels);
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = regmap_update_bits(st->regmap, AD4130_FIFO_CONTROL_REG,
                                 AD4130_FIFO_CONTROL_WM_MASK,
                                 FIELD_PREP(AD4130_FIFO_CONTROL_WM_MASK,
                                            ad4130_watermark_reg_val(eff)));
        if (ret)
-               goto out;
+               return ret;
 
        st->effective_watermark = eff;
        st->watermark = val;
 
-out:
-       mutex_unlock(&st->lock);
-
-       return ret;
+       return 0;
 }
 
 static const struct iio_info ad4130_info = {
@@ -1265,26 +1247,21 @@ static int ad4130_buffer_postenable(struct iio_dev *indio_dev)
        struct ad4130_state *st = iio_priv(indio_dev);
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = ad4130_set_watermark_interrupt_en(st, true);
        if (ret)
-               goto out;
+               return ret;
 
        ret = irq_set_irq_type(st->spi->irq, st->inv_irq_trigger);
        if (ret)
-               goto out;
+               return ret;
 
        ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_WM);
        if (ret)
-               goto out;
-
-       ret = ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
-
-out:
-       mutex_unlock(&st->lock);
+               return ret;
 
-       return ret;
+       return ad4130_set_mode(st, AD4130_MODE_CONTINUOUS);
 }
 
 static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
@@ -1293,23 +1270,23 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
        unsigned int i;
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        ret = ad4130_set_mode(st, AD4130_MODE_IDLE);
        if (ret)
-               goto out;
+               return ret;
 
        ret = irq_set_irq_type(st->spi->irq, st->irq_trigger);
        if (ret)
-               goto out;
+               return ret;
 
        ret = ad4130_set_fifo_mode(st, AD4130_FIFO_MODE_DISABLED);
        if (ret)
-               goto out;
+               return ret;
 
        ret = ad4130_set_watermark_interrupt_en(st, false);
        if (ret)
-               goto out;
+               return ret;
 
        /*
         * update_scan_mode() is not called in the disable path, disable all
@@ -1318,13 +1295,10 @@ static int ad4130_buffer_predisable(struct iio_dev *indio_dev)
        for (i = 0; i < indio_dev->num_channels; i++) {
                ret = ad4130_set_channel_enable(st, i, false);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
-out:
-       mutex_unlock(&st->lock);
-
-       return ret;
+       return 0;
 }
 
 static const struct iio_buffer_setup_ops ad4130_buffer_ops = {
@@ -1338,9 +1312,8 @@ static ssize_t hwfifo_watermark_show(struct device *dev,
        struct ad4130_state *st = iio_priv(dev_to_iio_dev(dev));
        unsigned int val;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        val = st->watermark;
-       mutex_unlock(&st->lock);
 
        return sysfs_emit(buf, "%d\n", val);
 }
index f4255b91acfc9849df2986f0c619d3f816f3b57c..d6876259ad14499df0983b4744834d66aa789f27 100644 (file)
@@ -86,28 +86,25 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
        unsigned int read_val;
        int ret;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
 
        switch (m) {
        case IIO_CHAN_INFO_RAW:
-               if (st->mode != AD7091R_MODE_COMMAND) {
-                       ret = -EBUSY;
-                       goto unlock;
-               }
+               if (st->mode != AD7091R_MODE_COMMAND)
+                       return -EBUSY;
 
                ret = ad7091r_read_one(iio_dev, chan->channel, &read_val);
                if (ret)
-                       goto unlock;
+                       return ret;
 
                *val = read_val;
-               ret = IIO_VAL_INT;
-               break;
+               return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
                if (st->vref) {
                        ret = regulator_get_voltage(st->vref);
                        if (ret < 0)
-                               goto unlock;
+                               return ret;
 
                        *val = ret / 1000;
                } else {
@@ -115,17 +112,11 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
                }
 
                *val2 = chan->scan_type.realbits;
-               ret = IIO_VAL_FRACTIONAL_LOG2;
-               break;
+               return IIO_VAL_FRACTIONAL_LOG2;
 
        default:
-               ret = -EINVAL;
-               break;
+               return -EINVAL;
        }
-
-unlock:
-       mutex_unlock(&st->lock);
-       return ret;
 }
 
 static int ad7091r_read_event_config(struct iio_dev *indio_dev,
index 6581fce4ba959af08df2ffd7e0fa67306755e2be..7475ec2a56c722e3449df9f84edd91ee5ed72079 100644 (file)
 #include <linux/of.h>
 
 
+#include <linux/iio/backend.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 
 #include <linux/clk.h>
 
-#include <linux/iio/adc/adi-axi-adc.h>
-
 /*
  * ADI High-Speed ADC common spi interface registers
  * See Application-Note AN-877:
 #define AD9467_REG_VREF_MASK           0x0F
 
 struct ad9467_chip_info {
-       struct adi_axi_adc_chip_info    axi_adc_info;
-       unsigned int                    default_output_mode;
-       unsigned int                    vref_mask;
+       const char              *name;
+       unsigned int            id;
+       const struct            iio_chan_spec *channels;
+       unsigned int            num_channels;
+       const unsigned int      (*scale_table)[2];
+       int                     num_scales;
+       unsigned long           max_rate;
+       unsigned int            default_output_mode;
+       unsigned int            vref_mask;
 };
 
-#define to_ad9467_chip_info(_info)     \
-       container_of(_info, struct ad9467_chip_info, axi_adc_info)
-
 struct ad9467_state {
+       const struct ad9467_chip_info   *info;
+       struct iio_backend              *back;
        struct spi_device               *spi;
        struct clk                      *clk;
        unsigned int                    output_mode;
@@ -151,10 +155,10 @@ static int ad9467_spi_write(struct spi_device *spi, unsigned int reg,
        return spi_write(spi, buf, ARRAY_SIZE(buf));
 }
 
-static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg,
+static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg,
                             unsigned int writeval, unsigned int *readval)
 {
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       struct ad9467_state *st = iio_priv(indio_dev);
        struct spi_device *spi = st->spi;
        int ret;
 
@@ -191,10 +195,10 @@ static const unsigned int ad9467_scale_table[][2] = {
        {2300, 8}, {2400, 9}, {2500, 10},
 };
 
-static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index,
+static void __ad9467_get_scale(struct ad9467_state *st, int index,
                               unsigned int *val, unsigned int *val2)
 {
-       const struct adi_axi_adc_chip_info *info = conv->chip_info;
+       const struct ad9467_chip_info *info = st->info;
        const struct iio_chan_spec *chan = &info->channels[0];
        unsigned int tmp;
 
@@ -229,52 +233,44 @@ static const struct iio_chan_spec ad9467_channels[] = {
 };
 
 static const struct ad9467_chip_info ad9467_chip_tbl = {
-       .axi_adc_info = {
-               .name = "ad9467",
-               .id = CHIPID_AD9467,
-               .max_rate = 250000000UL,
-               .scale_table = ad9467_scale_table,
-               .num_scales = ARRAY_SIZE(ad9467_scale_table),
-               .channels = ad9467_channels,
-               .num_channels = ARRAY_SIZE(ad9467_channels),
-       },
+       .name = "ad9467",
+       .id = CHIPID_AD9467,
+       .max_rate = 250000000UL,
+       .scale_table = ad9467_scale_table,
+       .num_scales = ARRAY_SIZE(ad9467_scale_table),
+       .channels = ad9467_channels,
+       .num_channels = ARRAY_SIZE(ad9467_channels),
        .default_output_mode = AD9467_DEF_OUTPUT_MODE,
        .vref_mask = AD9467_REG_VREF_MASK,
 };
 
 static const struct ad9467_chip_info ad9434_chip_tbl = {
-       .axi_adc_info = {
-               .name = "ad9434",
-               .id = CHIPID_AD9434,
-               .max_rate = 500000000UL,
-               .scale_table = ad9434_scale_table,
-               .num_scales = ARRAY_SIZE(ad9434_scale_table),
-               .channels = ad9434_channels,
-               .num_channels = ARRAY_SIZE(ad9434_channels),
-       },
+       .name = "ad9434",
+       .id = CHIPID_AD9434,
+       .max_rate = 500000000UL,
+       .scale_table = ad9434_scale_table,
+       .num_scales = ARRAY_SIZE(ad9434_scale_table),
+       .channels = ad9434_channels,
+       .num_channels = ARRAY_SIZE(ad9434_channels),
        .default_output_mode = AD9434_DEF_OUTPUT_MODE,
        .vref_mask = AD9434_REG_VREF_MASK,
 };
 
 static const struct ad9467_chip_info ad9265_chip_tbl = {
-       .axi_adc_info = {
-               .name = "ad9265",
-               .id = CHIPID_AD9265,
-               .max_rate = 125000000UL,
-               .scale_table = ad9265_scale_table,
-               .num_scales = ARRAY_SIZE(ad9265_scale_table),
-               .channels = ad9467_channels,
-               .num_channels = ARRAY_SIZE(ad9467_channels),
-       },
+       .name = "ad9265",
+       .id = CHIPID_AD9265,
+       .max_rate = 125000000UL,
+       .scale_table = ad9265_scale_table,
+       .num_scales = ARRAY_SIZE(ad9265_scale_table),
+       .channels = ad9467_channels,
+       .num_channels = ARRAY_SIZE(ad9467_channels),
        .default_output_mode = AD9265_DEF_OUTPUT_MODE,
        .vref_mask = AD9265_REG_VREF_MASK,
 };
 
-static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
+static int ad9467_get_scale(struct ad9467_state *st, int *val, int *val2)
 {
-       const struct adi_axi_adc_chip_info *info = conv->chip_info;
-       const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info);
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       const struct ad9467_chip_info *info = st->info;
        unsigned int i, vref_val;
        int ret;
 
@@ -282,7 +278,7 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
        if (ret < 0)
                return ret;
 
-       vref_val = ret & info1->vref_mask;
+       vref_val = ret & info->vref_mask;
 
        for (i = 0; i < info->num_scales; i++) {
                if (vref_val == info->scale_table[i][1])
@@ -292,15 +288,14 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
        if (i == info->num_scales)
                return -ERANGE;
 
-       __ad9467_get_scale(conv, i, val, val2);
+       __ad9467_get_scale(st, i, val, val2);
 
        return IIO_VAL_INT_PLUS_MICRO;
 }
 
-static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
+static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
 {
-       const struct adi_axi_adc_chip_info *info = conv->chip_info;
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       const struct ad9467_chip_info *info = st->info;
        unsigned int scale_val[2];
        unsigned int i;
        int ret;
@@ -309,7 +304,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
                return -EINVAL;
 
        for (i = 0; i < info->num_scales; i++) {
-               __ad9467_get_scale(conv, i, &scale_val[0], &scale_val[1]);
+               __ad9467_get_scale(st, i, &scale_val[0], &scale_val[1]);
                if (scale_val[0] != val || scale_val[1] != val2)
                        continue;
 
@@ -326,15 +321,15 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
        return -EINVAL;
 }
 
-static int ad9467_read_raw(struct adi_axi_adc_conv *conv,
+static int ad9467_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2, long m)
 {
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       struct ad9467_state *st = iio_priv(indio_dev);
 
        switch (m) {
        case IIO_CHAN_INFO_SCALE:
-               return ad9467_get_scale(conv, val, val2);
+               return ad9467_get_scale(st, val, val2);
        case IIO_CHAN_INFO_SAMP_FREQ:
                *val = clk_get_rate(st->clk);
 
@@ -344,17 +339,17 @@ static int ad9467_read_raw(struct adi_axi_adc_conv *conv,
        }
 }
 
-static int ad9467_write_raw(struct adi_axi_adc_conv *conv,
+static int ad9467_write_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int val, int val2, long mask)
 {
-       const struct adi_axi_adc_chip_info *info = conv->chip_info;
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       struct ad9467_state *st = iio_priv(indio_dev);
+       const struct ad9467_chip_info *info = st->info;
        long r_clk;
 
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
-               return ad9467_set_scale(conv, val, val2);
+               return ad9467_set_scale(st, val, val2);
        case IIO_CHAN_INFO_SAMP_FREQ:
                r_clk = clk_round_rate(st->clk, val);
                if (r_clk < 0 || r_clk > info->max_rate) {
@@ -369,13 +364,13 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv,
        }
 }
 
-static int ad9467_read_avail(struct adi_axi_adc_conv *conv,
+static int ad9467_read_avail(struct iio_dev *indio_dev,
                             struct iio_chan_spec const *chan,
                             const int **vals, int *type, int *length,
                             long mask)
 {
-       const struct adi_axi_adc_chip_info *info = conv->chip_info;
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       struct ad9467_state *st = iio_priv(indio_dev);
+       const struct ad9467_chip_info *info = st->info;
 
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
@@ -389,6 +384,33 @@ static int ad9467_read_avail(struct adi_axi_adc_conv *conv,
        }
 }
 
+static int ad9467_update_scan_mode(struct iio_dev *indio_dev,
+                                  const unsigned long *scan_mask)
+{
+       struct ad9467_state *st = iio_priv(indio_dev);
+       unsigned int c;
+       int ret;
+
+       for (c = 0; c < st->info->num_channels; c++) {
+               if (test_bit(c, scan_mask))
+                       ret = iio_backend_chan_enable(st->back, c);
+               else
+                       ret = iio_backend_chan_disable(st->back, c);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static const struct iio_info ad9467_info = {
+       .read_raw = ad9467_read_raw,
+       .write_raw = ad9467_write_raw,
+       .update_scan_mode = ad9467_update_scan_mode,
+       .debugfs_reg_access = ad9467_reg_access,
+       .read_avail = ad9467_read_avail,
+};
+
 static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
 {
        int ret;
@@ -401,10 +423,9 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
                                AN877_ADC_TRANSFER_SYNC);
 }
 
-static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
+static int ad9467_scale_fill(struct ad9467_state *st)
 {
-       const struct adi_axi_adc_chip_info *info = conv->chip_info;
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       const struct ad9467_chip_info *info = st->info;
        unsigned int i, val1, val2;
 
        st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales,
@@ -413,7 +434,7 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
                return -ENOMEM;
 
        for (i = 0; i < info->num_scales; i++) {
-               __ad9467_get_scale(conv, i, &val1, &val2);
+               __ad9467_get_scale(st, i, &val1, &val2);
                st->scales[i][0] = val1;
                st->scales[i][1] = val2;
        }
@@ -421,11 +442,27 @@ static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
        return 0;
 }
 
-static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
+static int ad9467_setup(struct ad9467_state *st)
 {
-       struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+       struct iio_backend_data_fmt data = {
+               .sign_extend = true,
+               .enable = true,
+       };
+       unsigned int c, mode;
+       int ret;
+
+       mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+       ret = ad9467_outputmode_set(st->spi, mode);
+       if (ret)
+               return ret;
 
-       return ad9467_outputmode_set(st->spi, st->output_mode);
+       for (c = 0; c < st->info->num_channels; c++) {
+               ret = iio_backend_data_format_set(st->back, c, &data);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int ad9467_reset(struct device *dev)
@@ -443,25 +480,65 @@ static int ad9467_reset(struct device *dev)
        return 0;
 }
 
+static int ad9467_iio_backend_get(struct ad9467_state *st)
+{
+       struct device *dev = &st->spi->dev;
+       struct device_node *__back;
+
+       st->back = devm_iio_backend_get(dev, NULL);
+       if (!IS_ERR(st->back))
+               return 0;
+       /* If not found, don't error out as we might have legacy DT property */
+       if (PTR_ERR(st->back) != -ENOENT)
+               return PTR_ERR(st->back);
+
+       /*
+        * if we don't get the backend using the normal API's, use the legacy
+        * 'adi,adc-dev' property. So we get all nodes with that property, and
+        * look for the one pointing at us. Then we directly lookup that fwnode
+        * on the backend list of registered devices. This is done so we don't
+        * make io-backends mandatory which would break DT ABI.
+        */
+       for_each_node_with_property(__back, "adi,adc-dev") {
+               struct device_node *__me;
+
+               __me = of_parse_phandle(__back, "adi,adc-dev", 0);
+               if (!__me)
+                       continue;
+
+               if (!device_match_of_node(dev, __me)) {
+                       of_node_put(__me);
+                       continue;
+               }
+
+               of_node_put(__me);
+               st->back = __devm_iio_backend_get_from_fwnode_lookup(dev,
+                                                                    of_fwnode_handle(__back));
+               of_node_put(__back);
+               return PTR_ERR_OR_ZERO(st->back);
+       }
+
+       return -ENODEV;
+}
+
 static int ad9467_probe(struct spi_device *spi)
 {
-       const struct ad9467_chip_info *info;
-       struct adi_axi_adc_conv *conv;
+       struct iio_dev *indio_dev;
        struct ad9467_state *st;
        unsigned int id;
        int ret;
 
-       info = spi_get_device_match_data(spi);
-       if (!info)
-               return -ENODEV;
-
-       conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st));
-       if (IS_ERR(conv))
-               return PTR_ERR(conv);
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
 
-       st = adi_axi_adc_conv_priv(conv);
+       st = iio_priv(indio_dev);
        st->spi = spi;
 
+       st->info = spi_get_device_match_data(spi);
+       if (!st->info)
+               return -ENODEV;
+
        st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
        if (IS_ERR(st->clk))
                return PTR_ERR(st->clk);
@@ -475,29 +552,39 @@ static int ad9467_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       conv->chip_info = &info->axi_adc_info;
-
-       ret = ad9467_scale_fill(conv);
+       ret = ad9467_scale_fill(st);
        if (ret)
                return ret;
 
        id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
-       if (id != conv->chip_info->id) {
+       if (id != st->info->id) {
                dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
-                       id, conv->chip_info->id);
+                       id, st->info->id);
                return -ENODEV;
        }
 
-       conv->reg_access = ad9467_reg_access;
-       conv->write_raw = ad9467_write_raw;
-       conv->read_raw = ad9467_read_raw;
-       conv->read_avail = ad9467_read_avail;
-       conv->preenable_setup = ad9467_preenable_setup;
+       indio_dev->name = st->info->name;
+       indio_dev->channels = st->info->channels;
+       indio_dev->num_channels = st->info->num_channels;
+       indio_dev->info = &ad9467_info;
 
-       st->output_mode = info->default_output_mode |
-                         AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+       ret = ad9467_iio_backend_get(st);
+       if (ret)
+               return ret;
 
-       return 0;
+       ret = devm_iio_backend_request_buffer(&spi->dev, st->back, indio_dev);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_backend_enable(&spi->dev, st->back);
+       if (ret)
+               return ret;
+
+       ret = ad9467_setup(st);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
 }
 
 static const struct of_device_id ad9467_of_match[] = {
@@ -529,4 +616,4 @@ module_spi_driver(ad9467_driver);
 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver");
 MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(IIO_ADI_AXI);
+MODULE_IMPORT_NS(IIO_BACKEND);
index 55442eddf57ce6ca5e628a320986fbedfea336b3..a602429cdde4ef7c09cfdd7a4b64ab3f8e10d5ae 100644 (file)
@@ -568,6 +568,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA);
 static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
 {
        struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
+       unsigned long irq_flags = irq_get_trigger_type(sigma_delta->spi->irq);
        int ret;
 
        if (dev != &sigma_delta->spi->dev) {
@@ -588,9 +589,13 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
        /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */
        irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY);
 
+       /* Allow overwriting the flags from firmware */
+       if (!irq_flags)
+               irq_flags = sigma_delta->info->irq_flags;
+
        ret = devm_request_irq(dev, sigma_delta->spi->irq,
                               ad_sd_data_rdy_trig_poll,
-                              sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
+                              irq_flags | IRQF_NO_AUTOEN,
                               indio_dev->name,
                               sigma_delta);
        if (ret)
index c247ff1541d2863923727b435af19dd48bb07bb4..4156639b3c8bdb5a4101dacc47dc665aa5db2166 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/buffer-dmaengine.h>
-
 #include <linux/fpga/adi-axi-common.h>
-#include <linux/iio/adc/adi-axi-adc.h>
+
+#include <linux/iio/backend.h>
+#include <linux/iio/buffer-dmaengine.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
 
 /*
  * Register definitions:
@@ -44,6 +44,7 @@
 #define   ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR     BIT(10)
 #define   ADI_AXI_REG_CHAN_CTRL_IQCOR_EN       BIT(9)
 #define   ADI_AXI_REG_CHAN_CTRL_DCFILT_EN      BIT(8)
+#define   ADI_AXI_REG_CHAN_CTRL_FMT_MASK       GENMASK(6, 4)
 #define   ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT    BIT(6)
 #define   ADI_AXI_REG_CHAN_CTRL_FMT_TYPE       BIT(5)
 #define   ADI_AXI_REG_CHAN_CTRL_FMT_EN         BIT(4)
         ADI_AXI_REG_CHAN_CTRL_FMT_EN |         \
         ADI_AXI_REG_CHAN_CTRL_ENABLE)
 
-struct adi_axi_adc_core_info {
-       unsigned int                            version;
-};
-
 struct adi_axi_adc_state {
-       struct mutex                            lock;
-
-       struct adi_axi_adc_client               *client;
        struct regmap                           *regmap;
-};
-
-struct adi_axi_adc_client {
-       struct list_head                        entry;
-       struct adi_axi_adc_conv                 conv;
-       struct adi_axi_adc_state                *state;
        struct device                           *dev;
-       const struct adi_axi_adc_core_info      *info;
 };
 
-static LIST_HEAD(registered_clients);
-static DEFINE_MUTEX(registered_clients_lock);
-
-static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv)
-{
-       return container_of(conv, struct adi_axi_adc_client, conv);
-}
-
-void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv)
-{
-       struct adi_axi_adc_client *cl = conv_to_client(conv);
-
-       return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client),
-                                 IIO_DMA_MINALIGN);
-}
-EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI);
-
-static int adi_axi_adc_config_dma_buffer(struct device *dev,
-                                        struct iio_dev *indio_dev)
-{
-       const char *dma_name;
-
-       if (!device_property_present(dev, "dmas"))
-               return 0;
-
-       if (device_property_read_string(dev, "dma-names", &dma_name))
-               dma_name = "rx";
-
-       return devm_iio_dmaengine_buffer_setup(indio_dev->dev.parent,
-                                              indio_dev, dma_name);
-}
-
-static int adi_axi_adc_read_raw(struct iio_dev *indio_dev,
-                               struct iio_chan_spec const *chan,
-                               int *val, int *val2, long mask)
-{
-       struct adi_axi_adc_state *st = iio_priv(indio_dev);
-       struct adi_axi_adc_conv *conv = &st->client->conv;
-
-       if (!conv->read_raw)
-               return -EOPNOTSUPP;
-
-       return conv->read_raw(conv, chan, val, val2, mask);
-}
-
-static int adi_axi_adc_write_raw(struct iio_dev *indio_dev,
-                                struct iio_chan_spec const *chan,
-                                int val, int val2, long mask)
-{
-       struct adi_axi_adc_state *st = iio_priv(indio_dev);
-       struct adi_axi_adc_conv *conv = &st->client->conv;
-
-       if (!conv->write_raw)
-               return -EOPNOTSUPP;
-
-       return conv->write_raw(conv, chan, val, val2, mask);
-}
-
-static int adi_axi_adc_read_avail(struct iio_dev *indio_dev,
-                                 struct iio_chan_spec const *chan,
-                                 const int **vals, int *type, int *length,
-                                 long mask)
-{
-       struct adi_axi_adc_state *st = iio_priv(indio_dev);
-       struct adi_axi_adc_conv *conv = &st->client->conv;
-
-       if (!conv->read_avail)
-               return -EOPNOTSUPP;
-
-       return conv->read_avail(conv, chan, vals, type, length, mask);
-}
-
-static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev,
-                                       const unsigned long *scan_mask)
+static int axi_adc_enable(struct iio_backend *back)
 {
-       struct adi_axi_adc_state *st = iio_priv(indio_dev);
-       struct adi_axi_adc_conv *conv = &st->client->conv;
-       unsigned int i;
+       struct adi_axi_adc_state *st = iio_backend_get_priv(back);
        int ret;
 
-       for (i = 0; i < conv->chip_info->num_channels; i++) {
-               if (test_bit(i, scan_mask))
-                       ret = regmap_set_bits(st->regmap,
-                                             ADI_AXI_REG_CHAN_CTRL(i),
-                                             ADI_AXI_REG_CHAN_CTRL_ENABLE);
-               else
-                       ret = regmap_clear_bits(st->regmap,
-                                               ADI_AXI_REG_CHAN_CTRL(i),
-                                               ADI_AXI_REG_CHAN_CTRL_ENABLE);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev,
-                                                         size_t sizeof_priv)
-{
-       struct adi_axi_adc_client *cl;
-       size_t alloc_size;
-
-       alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_DMA_MINALIGN);
-       if (sizeof_priv)
-               alloc_size += ALIGN(sizeof_priv, IIO_DMA_MINALIGN);
-
-       cl = kzalloc(alloc_size, GFP_KERNEL);
-       if (!cl)
-               return ERR_PTR(-ENOMEM);
-
-       mutex_lock(&registered_clients_lock);
-
-       cl->dev = get_device(dev);
-
-       list_add_tail(&cl->entry, &registered_clients);
-
-       mutex_unlock(&registered_clients_lock);
+       ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
+                             ADI_AXI_REG_RSTN_MMCM_RSTN);
+       if (ret)
+               return ret;
 
-       return &cl->conv;
+       fsleep(10000);
+       return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
+                              ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
 }
 
-static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv)
+static void axi_adc_disable(struct iio_backend *back)
 {
-       struct adi_axi_adc_client *cl = conv_to_client(conv);
-
-       mutex_lock(&registered_clients_lock);
-
-       list_del(&cl->entry);
-       put_device(cl->dev);
+       struct adi_axi_adc_state *st = iio_backend_get_priv(back);
 
-       mutex_unlock(&registered_clients_lock);
-
-       kfree(cl);
+       regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
 }
 
-static void devm_adi_axi_adc_conv_release(void *conv)
+static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan,
+                                  const struct iio_backend_data_fmt *data)
 {
-       adi_axi_adc_conv_unregister(conv);
+       struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+       u32 val;
+
+       if (!data->enable)
+               return regmap_clear_bits(st->regmap,
+                                        ADI_AXI_REG_CHAN_CTRL(chan),
+                                        ADI_AXI_REG_CHAN_CTRL_FMT_EN);
+
+       val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true);
+       if (data->sign_extend)
+               val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true);
+       if (data->type == IIO_BACKEND_OFFSET_BINARY)
+               val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true);
+
+       return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
+                                 ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val);
 }
 
-struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
-                                                       size_t sizeof_priv)
+static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan)
 {
-       struct adi_axi_adc_conv *conv;
-       int ret;
-
-       conv = adi_axi_adc_conv_register(dev, sizeof_priv);
-       if (IS_ERR(conv))
-               return conv;
+       struct adi_axi_adc_state *st = iio_backend_get_priv(back);
 
-       ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release,
-                                      conv);
-       if (ret)
-               return ERR_PTR(ret);
-
-       return conv;
+       return regmap_set_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
+                              ADI_AXI_REG_CHAN_CTRL_ENABLE);
 }
-EXPORT_SYMBOL_NS_GPL(devm_adi_axi_adc_conv_register, IIO_ADI_AXI);
-
-static const struct iio_info adi_axi_adc_info = {
-       .read_raw = &adi_axi_adc_read_raw,
-       .write_raw = &adi_axi_adc_write_raw,
-       .update_scan_mode = &adi_axi_adc_update_scan_mode,
-       .read_avail = &adi_axi_adc_read_avail,
-};
-
-static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = {
-       .version = ADI_AXI_PCORE_VER(10, 0, 'a'),
-};
 
-static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev)
+static int axi_adc_chan_disable(struct iio_backend *back, unsigned int chan)
 {
-       const struct adi_axi_adc_core_info *info;
-       struct adi_axi_adc_client *cl;
-       struct device_node *cln;
-
-       info = of_device_get_match_data(dev);
-       if (!info)
-               return ERR_PTR(-ENODEV);
-
-       cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0);
-       if (!cln) {
-               dev_err(dev, "No 'adi,adc-dev' node defined\n");
-               return ERR_PTR(-ENODEV);
-       }
-
-       mutex_lock(&registered_clients_lock);
-
-       list_for_each_entry(cl, &registered_clients, entry) {
-               if (!cl->dev)
-                       continue;
-
-               if (cl->dev->of_node != cln)
-                       continue;
-
-               if (!try_module_get(cl->dev->driver->owner)) {
-                       mutex_unlock(&registered_clients_lock);
-                       of_node_put(cln);
-                       return ERR_PTR(-ENODEV);
-               }
-
-               get_device(cl->dev);
-               cl->info = info;
-               mutex_unlock(&registered_clients_lock);
-               of_node_put(cln);
-               return cl;
-       }
+       struct adi_axi_adc_state *st = iio_backend_get_priv(back);
 
-       mutex_unlock(&registered_clients_lock);
-       of_node_put(cln);
-
-       return ERR_PTR(-EPROBE_DEFER);
+       return regmap_clear_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
+                                ADI_AXI_REG_CHAN_CTRL_ENABLE);
 }
 
-static int adi_axi_adc_setup_channels(struct device *dev,
-                                     struct adi_axi_adc_state *st)
+static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back,
+                                                struct iio_dev *indio_dev)
 {
-       struct adi_axi_adc_conv *conv = &st->client->conv;
-       int i, ret;
+       struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+       struct iio_buffer *buffer;
+       const char *dma_name;
+       int ret;
 
-       if (conv->preenable_setup) {
-               ret = conv->preenable_setup(conv);
-               if (ret)
-                       return ret;
-       }
+       if (device_property_read_string(st->dev, "dma-names", &dma_name))
+               dma_name = "rx";
 
-       for (i = 0; i < conv->chip_info->num_channels; i++) {
-               ret = regmap_write(st->regmap, ADI_AXI_REG_CHAN_CTRL(i),
-                                  ADI_AXI_REG_CHAN_CTRL_DEFAULTS);
-               if (ret)
-                       return ret;
+       buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name);
+       if (IS_ERR(buffer)) {
+               dev_err(st->dev, "Could not get DMA buffer, %ld\n",
+                       PTR_ERR(buffer));
+               return ERR_CAST(buffer);
        }
 
-       return 0;
-}
-
-static int axi_adc_reset(struct adi_axi_adc_state *st)
-{
-       int ret;
-
-       ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
-       if (ret)
-               return ret;
-
-       mdelay(10);
-       ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN,
-                          ADI_AXI_REG_RSTN_MMCM_RSTN);
+       indio_dev->modes |= INDIO_BUFFER_HARDWARE;
+       ret = iio_device_attach_buffer(indio_dev, buffer);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 
-       mdelay(10);
-       return regmap_write(st->regmap, ADI_AXI_REG_RSTN,
-                           ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
+       return buffer;
 }
 
-static void adi_axi_adc_cleanup(void *data)
+static void axi_adc_free_buffer(struct iio_backend *back,
+                               struct iio_buffer *buffer)
 {
-       struct adi_axi_adc_client *cl = data;
-
-       put_device(cl->dev);
-       module_put(cl->dev->driver->owner);
+       iio_dmaengine_buffer_free(buffer);
 }
 
 static const struct regmap_config axi_adc_regmap_config = {
@@ -344,45 +159,47 @@ static const struct regmap_config axi_adc_regmap_config = {
        .max_register = 0x0800,
 };
 
+static const struct iio_backend_ops adi_axi_adc_generic = {
+       .enable = axi_adc_enable,
+       .disable = axi_adc_disable,
+       .data_format_set = axi_adc_data_format_set,
+       .chan_enable = axi_adc_chan_enable,
+       .chan_disable = axi_adc_chan_disable,
+       .request_buffer = axi_adc_request_buffer,
+       .free_buffer = axi_adc_free_buffer,
+};
+
 static int adi_axi_adc_probe(struct platform_device *pdev)
 {
-       struct adi_axi_adc_conv *conv;
-       struct iio_dev *indio_dev;
-       struct adi_axi_adc_client *cl;
+       const unsigned int *expected_ver;
        struct adi_axi_adc_state *st;
        void __iomem *base;
        unsigned int ver;
        int ret;
 
-       cl = adi_axi_adc_attach_client(&pdev->dev);
-       if (IS_ERR(cl))
-               return PTR_ERR(cl);
-
-       ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl);
-       if (ret)
-               return ret;
-
-       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
-       if (indio_dev == NULL)
+       st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
+       if (!st)
                return -ENOMEM;
 
-       st = iio_priv(indio_dev);
-       st->client = cl;
-       cl->state = st;
-       mutex_init(&st->lock);
-
        base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
+       st->dev = &pdev->dev;
        st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
                                           &axi_adc_regmap_config);
        if (IS_ERR(st->regmap))
                return PTR_ERR(st->regmap);
 
-       conv = &st->client->conv;
+       expected_ver = device_get_match_data(&pdev->dev);
+       if (!expected_ver)
+               return -ENODEV;
 
-       ret = axi_adc_reset(st);
+       /*
+        * Force disable the core. Up to the frontend to enable us. And we can
+        * still read/write registers...
+        */
+       ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
        if (ret)
                return ret;
 
@@ -390,33 +207,19 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       if (cl->info->version > ver) {
+       if (*expected_ver > ver) {
                dev_err(&pdev->dev,
                        "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
-                       ADI_AXI_PCORE_VER_MAJOR(cl->info->version),
-                       ADI_AXI_PCORE_VER_MINOR(cl->info->version),
-                       ADI_AXI_PCORE_VER_PATCH(cl->info->version),
+                       ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
+                       ADI_AXI_PCORE_VER_MINOR(*expected_ver),
+                       ADI_AXI_PCORE_VER_PATCH(*expected_ver),
                        ADI_AXI_PCORE_VER_MAJOR(ver),
                        ADI_AXI_PCORE_VER_MINOR(ver),
                        ADI_AXI_PCORE_VER_PATCH(ver));
                return -ENODEV;
        }
 
-       indio_dev->info = &adi_axi_adc_info;
-       indio_dev->name = "adi-axi-adc";
-       indio_dev->modes = INDIO_DIRECT_MODE;
-       indio_dev->num_channels = conv->chip_info->num_channels;
-       indio_dev->channels = conv->chip_info->channels;
-
-       ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev);
-       if (ret)
-               return ret;
-
-       ret = adi_axi_adc_setup_channels(&pdev->dev, st);
-       if (ret)
-               return ret;
-
-       ret = devm_iio_device_register(&pdev->dev, indio_dev);
+       ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st);
        if (ret)
                return ret;
 
@@ -428,6 +231,8 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
        return 0;
 }
 
+static unsigned int adi_axi_adc_10_0_a_info = ADI_AXI_PCORE_VER(10, 0, 'a');
+
 /* Match table for of_platform binding */
 static const struct of_device_id adi_axi_adc_of_match[] = {
        { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info },
@@ -447,3 +252,5 @@ module_platform_driver(adi_axi_adc_driver);
 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver");
 MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);
+MODULE_IMPORT_NS(IIO_BACKEND);
index 7c2a98b8c3a961d1e10ec1068e889f84857c857b..8b5bc96cb9fbf129f91ac0103f30daa6cdf76944 100644 (file)
@@ -357,62 +357,55 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev,
                                    int *val,
                                    long m)
 {
-       int ret = 0;
-       s32 data;
-       u8 rxbuf[2];
-       struct max1363_state *st = iio_priv(indio_dev);
-       struct i2c_client *client = st->client;
-
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
-       mutex_lock(&st->lock);
-
-       /*
-        * If monitor mode is enabled, the method for reading a single
-        * channel will have to be rather different and has not yet
-        * been implemented.
-        *
-        * Also, cannot read directly if buffered capture enabled.
-        */
-       if (st->monitor_on) {
-               ret = -EBUSY;
-               goto error_ret;
-       }
-
-       /* Check to see if current scan mode is correct */
-       if (st->current_mode != &max1363_mode_table[chan->address]) {
-               /* Update scan mode if needed */
-               st->current_mode = &max1363_mode_table[chan->address];
-               ret = max1363_set_scan_mode(st);
-               if (ret < 0)
-                       goto error_ret;
-       }
-       if (st->chip_info->bits != 8) {
-               /* Get reading */
-               data = st->recv(client, rxbuf, 2);
-               if (data < 0) {
-                       ret = data;
-                       goto error_ret;
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               s32 data;
+               u8 rxbuf[2];
+               struct max1363_state *st = iio_priv(indio_dev);
+               struct i2c_client *client = st->client;
+
+               guard(mutex)(&st->lock);
+
+               /*
+                * If monitor mode is enabled, the method for reading a single
+                * channel will have to be rather different and has not yet
+                * been implemented.
+                *
+                * Also, cannot read directly if buffered capture enabled.
+                */
+               if (st->monitor_on)
+                       return -EBUSY;
+
+               /* Check to see if current scan mode is correct */
+               if (st->current_mode != &max1363_mode_table[chan->address]) {
+                       int ret;
+
+                       /* Update scan mode if needed */
+                       st->current_mode = &max1363_mode_table[chan->address];
+                       ret = max1363_set_scan_mode(st);
+                       if (ret < 0)
+                               return ret;
                }
-               data = (rxbuf[1] | rxbuf[0] << 8) &
-                 ((1 << st->chip_info->bits) - 1);
-       } else {
-               /* Get reading */
-               data = st->recv(client, rxbuf, 1);
-               if (data < 0) {
-                       ret = data;
-                       goto error_ret;
+               if (st->chip_info->bits != 8) {
+                       /* Get reading */
+                       data = st->recv(client, rxbuf, 2);
+                       if (data < 0)
+                               return data;
+
+                       data = (rxbuf[1] | rxbuf[0] << 8) &
+                               ((1 << st->chip_info->bits) - 1);
+               } else {
+                       /* Get reading */
+                       data = st->recv(client, rxbuf, 1);
+                       if (data < 0)
+                               return data;
+
+                       data = rxbuf[0];
                }
-               data = rxbuf[0];
-       }
-       *val = data;
-
-error_ret:
-       mutex_unlock(&st->lock);
-       iio_device_release_direct_mode(indio_dev);
-       return ret;
+               *val = data;
 
+               return 0;
+       }
+       unreachable();
 }
 
 static int max1363_read_raw(struct iio_dev *indio_dev,
@@ -710,9 +703,8 @@ static ssize_t max1363_monitor_store_freq(struct device *dev,
        if (!found)
                return -EINVAL;
 
-       mutex_lock(&st->lock);
-       st->monitor_speed = i;
-       mutex_unlock(&st->lock);
+       scoped_guard(mutex, &st->lock)
+               st->monitor_speed = i;
 
        return 0;
 }
@@ -815,12 +807,11 @@ static int max1363_read_event_config(struct iio_dev *indio_dev,
        int val;
        int number = chan->channel;
 
-       mutex_lock(&st->lock);
+       guard(mutex)(&st->lock);
        if (dir == IIO_EV_DIR_FALLING)
                val = (1 << number) & st->mask_low;
        else
                val = (1 << number) & st->mask_high;
-       mutex_unlock(&st->lock);
 
        return val;
 }
@@ -962,46 +953,42 @@ static int max1363_write_event_config(struct iio_dev *indio_dev,
        const struct iio_chan_spec *chan, enum iio_event_type type,
        enum iio_event_direction dir, int state)
 {
-       int ret = 0;
        struct max1363_state *st = iio_priv(indio_dev);
-       u16 unifiedmask;
-       int number = chan->channel;
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
-       mutex_lock(&st->lock);
-
-       unifiedmask = st->mask_low | st->mask_high;
-       if (dir == IIO_EV_DIR_FALLING) {
-
-               if (state == 0)
-                       st->mask_low &= ~(1 << number);
-               else {
-                       ret = __max1363_check_event_mask((1 << number),
-                                                        unifiedmask);
-                       if (ret)
-                               goto error_ret;
-                       st->mask_low |= (1 << number);
-               }
-       } else {
-               if (state == 0)
-                       st->mask_high &= ~(1 << number);
-               else {
-                       ret = __max1363_check_event_mask((1 << number),
-                                                        unifiedmask);
-                       if (ret)
-                               goto error_ret;
-                       st->mask_high |= (1 << number);
+       iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+               int number = chan->channel;
+               u16 unifiedmask;
+               int ret;
+
+               guard(mutex)(&st->lock);
+
+               unifiedmask = st->mask_low | st->mask_high;
+               if (dir == IIO_EV_DIR_FALLING) {
+
+                       if (state == 0)
+                               st->mask_low &= ~(1 << number);
+                       else {
+                               ret = __max1363_check_event_mask((1 << number),
+                                                                unifiedmask);
+                               if (ret)
+                                       return ret;
+                               st->mask_low |= (1 << number);
+                       }
+               } else {
+                       if (state == 0)
+                               st->mask_high &= ~(1 << number);
+                       else {
+                               ret = __max1363_check_event_mask((1 << number),
+                                                                unifiedmask);
+                               if (ret)
+                                       return ret;
+                               st->mask_high |= (1 << number);
+                       }
                }
        }
-
        max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low));
-error_ret:
-       mutex_unlock(&st->lock);
-       iio_device_release_direct_mode(indio_dev);
 
-       return ret;
+       return 0;
 }
 
 /*
index f3b81798b3c9351d90c7796866d39d1d053ad5b5..da1421bd7b62944a28a6ef8ab41ca9ed6ab94a28 100644 (file)
@@ -371,6 +371,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
        },
 };
 
+static void mcp320x_regulator_disable(void *reg)
+{
+       regulator_disable(reg);
+}
+
 static int mcp320x_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
@@ -388,7 +393,6 @@ static int mcp320x_probe(struct spi_device *spi)
        indio_dev->name = spi_get_device_id(spi)->name;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &mcp320x_info;
-       spi_set_drvdata(spi, indio_dev);
 
        device_index = spi_get_device_id(spi)->driver_data;
        chip_info = &mcp320x_chip_infos[device_index];
@@ -445,27 +449,13 @@ static int mcp320x_probe(struct spi_device *spi)
        if (ret < 0)
                return ret;
 
-       mutex_init(&adc->lock);
-
-       ret = iio_device_register(indio_dev);
+       ret = devm_add_action_or_reset(&spi->dev, mcp320x_regulator_disable, adc->reg);
        if (ret < 0)
-               goto reg_disable;
-
-       return 0;
-
-reg_disable:
-       regulator_disable(adc->reg);
-
-       return ret;
-}
+               return ret;
 
-static void mcp320x_remove(struct spi_device *spi)
-{
-       struct iio_dev *indio_dev = spi_get_drvdata(spi);
-       struct mcp320x *adc = iio_priv(indio_dev);
+       mutex_init(&adc->lock);
 
-       iio_device_unregister(indio_dev);
-       regulator_disable(adc->reg);
+       return devm_iio_device_register(&spi->dev, indio_dev);
 }
 
 static const struct of_device_id mcp320x_dt_ids[] = {
@@ -520,7 +510,6 @@ static struct spi_driver mcp320x_driver = {
                .of_match_table = mcp320x_dt_ids,
        },
        .probe = mcp320x_probe,
-       .remove = mcp320x_remove,
        .id_table = mcp320x_id,
 };
 module_spi_driver(mcp320x_driver);
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
new file mode 100644 (file)
index 0000000..e0c2742
--- /dev/null
@@ -0,0 +1,1636 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * IIO driver for PAC1934 Multi-Channel DC Power/Energy Monitor
+ *
+ * Copyright (C) 2017-2024 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Bogdan Bolocan <bogdan.bolocan@microchip.com>
+ * Author: Victor Tudose
+ * Author: Marius Cristea <marius.cristea@microchip.com>
+ *
+ * Datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <asm/unaligned.h>
+
+/*
+ * maximum accumulation time should be (17 * 60 * 1000) around 17 minutes@1024 sps
+ * till PAC1934 accumulation registers starts to saturate
+ */
+#define PAC1934_MAX_RFSH_LIMIT_MS              60000
+/* 50msec is the timeout for validity of the cached registers */
+#define PAC1934_MIN_POLLING_TIME_MS            50
+/*
+ * 1000usec is the minimum wait time for normal conversions when sample
+ * rate doesn't change
+ */
+#define PAC1934_MIN_UPDATE_WAIT_TIME_US                1000
+
+/* 32000mV */
+#define PAC1934_VOLTAGE_MILLIVOLTS_MAX         32000
+/* voltage bits resolution when set for unsigned values */
+#define PAC1934_VOLTAGE_U_RES                  16
+/* voltage bits resolution when set for signed values */
+#define PAC1934_VOLTAGE_S_RES                  15
+
+/*
+ * max signed value that can be stored on 32 bits and 8 digits fractional value
+ * (2^31 - 1) * 10^8 + 99999999
+ */
+#define PAC_193X_MAX_POWER_ACC                 214748364799999999LL
+/*
+ * min signed value that can be stored on 32 bits and 8 digits fractional value
+ * -(2^31) * 10^8 - 99999999
+ */
+#define PAC_193X_MIN_POWER_ACC                 -214748364899999999LL
+
+#define PAC1934_MAX_NUM_CHANNELS               4
+
+#define PAC1934_MEAS_REG_LEN                   76
+#define PAC1934_CTRL_REG_LEN                   12
+
+#define PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ     1024
+
+/* I2C address map */
+#define PAC1934_REFRESH_REG_ADDR               0x00
+#define PAC1934_CTRL_REG_ADDR                  0x01
+#define PAC1934_ACC_COUNT_REG_ADDR             0x02
+#define PAC1934_VPOWER_ACC_1_ADDR              0x03
+#define PAC1934_VPOWER_ACC_2_ADDR              0x04
+#define PAC1934_VPOWER_ACC_3_ADDR              0x05
+#define PAC1934_VPOWER_ACC_4_ADDR              0x06
+#define PAC1934_VBUS_1_ADDR                    0x07
+#define PAC1934_VBUS_2_ADDR                    0x08
+#define PAC1934_VBUS_3_ADDR                    0x09
+#define PAC1934_VBUS_4_ADDR                    0x0A
+#define PAC1934_VSENSE_1_ADDR                  0x0B
+#define PAC1934_VSENSE_2_ADDR                  0x0C
+#define PAC1934_VSENSE_3_ADDR                  0x0D
+#define PAC1934_VSENSE_4_ADDR                  0x0E
+#define PAC1934_VBUS_AVG_1_ADDR                        0x0F
+#define PAC1934_VBUS_AVG_2_ADDR                        0x10
+#define PAC1934_VBUS_AVG_3_ADDR                        0x11
+#define PAC1934_VBUS_AVG_4_ADDR                        0x12
+#define PAC1934_VSENSE_AVG_1_ADDR              0x13
+#define PAC1934_VSENSE_AVG_2_ADDR              0x14
+#define PAC1934_VSENSE_AVG_3_ADDR              0x15
+#define PAC1934_VSENSE_AVG_4_ADDR              0x16
+#define PAC1934_VPOWER_1_ADDR                  0x17
+#define PAC1934_VPOWER_2_ADDR                  0x18
+#define PAC1934_VPOWER_3_ADDR                  0x19
+#define PAC1934_VPOWER_4_ADDR                  0x1A
+#define PAC1934_REFRESH_V_REG_ADDR             0x1F
+#define PAC1934_CTRL_STAT_REGS_ADDR            0x1C
+#define PAC1934_PID_REG_ADDR                   0xFD
+#define PAC1934_MID_REG_ADDR                   0xFE
+#define PAC1934_RID_REG_ADDR                   0xFF
+
+/* PRODUCT ID REGISTER + MANUFACTURER ID REGISTER + REVISION ID REGISTER */
+#define PAC1934_ID_REG_LEN                     3
+#define PAC1934_PID_IDX                                0
+#define PAC1934_MID_IDX                                1
+#define PAC1934_RID_IDX                                2
+
+#define PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS  1
+#define PAC1934_ACPI_GET_UOHMS_VALS            2
+#define PAC1934_ACPI_GET_BIPOLAR_SETTINGS      4
+#define PAC1934_ACPI_GET_SAMP                  5
+
+#define PAC1934_SAMPLE_RATE_SHIFT              6
+
+#define PAC1934_VBUS_SENSE_REG_LEN             2
+#define PAC1934_ACC_REG_LEN                    3
+#define PAC1934_VPOWER_REG_LEN                 4
+#define PAC1934_VPOWER_ACC_REG_LEN             6
+#define PAC1934_MAX_REGISTER_LENGTH            6
+
+#define PAC1934_CUSTOM_ATTR_FOR_CHANNEL                1
+
+/*
+ * relative offsets when using multi-byte reads/writes even though these
+ * bytes are read one after the other, they are not at adjacent memory
+ * locations within the I2C memory map. The chip can skip some addresses
+ */
+#define PAC1934_CHANNEL_DIS_REG_OFF            0
+#define PAC1934_NEG_PWR_REG_OFF                        1
+
+/*
+ * when reading/writing multiple bytes from offset PAC1934_CHANNEL_DIS_REG_OFF,
+ * the chip jumps over the 0x1E (REFRESH_G) and 0x1F (REFRESH_V) offsets
+ */
+#define PAC1934_SLOW_REG_OFF                   2
+#define PAC1934_CTRL_ACT_REG_OFF               3
+#define PAC1934_CHANNEL_DIS_ACT_REG_OFF                4
+#define PAC1934_NEG_PWR_ACT_REG_OFF            5
+#define PAC1934_CTRL_LAT_REG_OFF               6
+#define PAC1934_CHANNEL_DIS_LAT_REG_OFF                7
+#define PAC1934_NEG_PWR_LAT_REG_OFF            8
+#define PAC1934_PID_REG_OFF                    9
+#define PAC1934_MID_REG_OFF                    10
+#define PAC1934_REV_REG_OFF                    11
+#define PAC1934_CTRL_STATUS_INFO_LEN           12
+
+#define PAC1934_MID                            0x5D
+#define PAC1931_PID                            0x58
+#define PAC1932_PID                            0x59
+#define PAC1933_PID                            0x5A
+#define PAC1934_PID                            0x5B
+
+/* Scale constant = (10^3 * 3.2 * 10^9 / 2^28) for mili Watt-second */
+#define PAC1934_SCALE_CONSTANT                 11921
+
+#define PAC1934_MAX_VPOWER_RSHIFTED_BY_28B     11921
+#define PAC1934_MAX_VSENSE_RSHIFTED_BY_16B     1525
+
+#define PAC1934_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
+
+#define PAC1934_CRTL_SAMPLE_RATE_MASK  GENMASK(7, 6)
+#define PAC1934_CHAN_SLEEP_MASK                BIT(5)
+#define PAC1934_CHAN_SLEEP_SET         BIT(5)
+#define PAC1934_CHAN_SINGLE_MASK       BIT(4)
+#define PAC1934_CHAN_SINGLE_SHOT_SET   BIT(4)
+#define PAC1934_CHAN_ALERT_MASK                BIT(3)
+#define PAC1934_CHAN_ALERT_EN          BIT(3)
+#define PAC1934_CHAN_ALERT_CC_MASK     BIT(2)
+#define PAC1934_CHAN_ALERT_CC_EN       BIT(2)
+#define PAC1934_CHAN_OVF_ALERT_MASK    BIT(1)
+#define PAC1934_CHAN_OVF_ALERT_EN      BIT(1)
+#define PAC1934_CHAN_OVF_MASK          BIT(0)
+
+#define PAC1934_CHAN_DIS_CH1_OFF_MASK  BIT(7)
+#define PAC1934_CHAN_DIS_CH2_OFF_MASK  BIT(6)
+#define PAC1934_CHAN_DIS_CH3_OFF_MASK  BIT(5)
+#define PAC1934_CHAN_DIS_CH4_OFF_MASK  BIT(4)
+#define PAC1934_SMBUS_TIMEOUT_MASK     BIT(3)
+#define PAC1934_SMBUS_BYTECOUNT_MASK   BIT(2)
+#define PAC1934_SMBUS_NO_SKIP_MASK     BIT(1)
+
+#define PAC1934_NEG_PWR_CH1_BIDI_MASK  BIT(7)
+#define PAC1934_NEG_PWR_CH2_BIDI_MASK  BIT(6)
+#define PAC1934_NEG_PWR_CH3_BIDI_MASK  BIT(5)
+#define PAC1934_NEG_PWR_CH4_BIDI_MASK  BIT(4)
+#define PAC1934_NEG_PWR_CH1_BIDV_MASK  BIT(3)
+#define PAC1934_NEG_PWR_CH2_BIDV_MASK  BIT(2)
+#define PAC1934_NEG_PWR_CH3_BIDV_MASK  BIT(1)
+#define PAC1934_NEG_PWR_CH4_BIDV_MASK  BIT(0)
+
+/*
+ * Universal Unique Identifier (UUID),
+ * 033771E0-1705-47B4-9535-D1BBE14D9A09,
+ * is reserved to Microchip for the PAC1934.
+ */
+#define PAC1934_DSM_UUID               "033771E0-1705-47B4-9535-D1BBE14D9A09"
+
+enum pac1934_ids {
+       PAC1931,
+       PAC1932,
+       PAC1933,
+       PAC1934
+};
+
+enum pac1934_samps {
+       PAC1934_SAMP_1024SPS,
+       PAC1934_SAMP_256SPS,
+       PAC1934_SAMP_64SPS,
+       PAC1934_SAMP_8SPS
+};
+
+/*
+ * these indexes are exactly describing the element order within a single
+ * PAC1934 phys channel IIO channel descriptor; see the static const struct
+ * iio_chan_spec pac1934_single_channel[] declaration
+ */
+enum pac1934_ch_idx {
+       PAC1934_CH_ENERGY,
+       PAC1934_CH_POWER,
+       PAC1934_CH_VOLTAGE,
+       PAC1934_CH_CURRENT,
+       PAC1934_CH_VOLTAGE_AVERAGE,
+       PAC1934_CH_CURRENT_AVERAGE
+};
+
+/**
+ * struct pac1934_features - features of a pac1934 instance
+ * @phys_channels:     number of physical channels supported by the chip
+ * @name:              chip's name
+ */
+struct pac1934_features {
+       u8              phys_channels;
+       const char      *name;
+};
+
+struct samp_rate_mapping {
+       u16 samp_rate;
+       u8 shift2value;
+};
+
+static const unsigned int samp_rate_map_tbl[] = {
+       [PAC1934_SAMP_1024SPS] = 1024,
+       [PAC1934_SAMP_256SPS] = 256,
+       [PAC1934_SAMP_64SPS] = 64,
+       [PAC1934_SAMP_8SPS] = 8,
+};
+
+static const struct pac1934_features pac1934_chip_config[] = {
+       [PAC1931] = {
+           .phys_channels = 1,
+           .name = "pac1931",
+       },
+       [PAC1932] = {
+           .phys_channels = 2,
+           .name = "pac1932",
+       },
+       [PAC1933] = {
+           .phys_channels = 3,
+           .name = "pac1933",
+       },
+       [PAC1934] = {
+           .phys_channels = 4,
+           .name = "pac1934",
+       },
+};
+
+/**
+ * struct reg_data - data from the registers
+ * @meas_regs:                 snapshot of raw measurements registers
+ * @ctrl_regs:                 snapshot of control registers
+ * @energy_sec_acc:            snapshot of energy values
+ * @vpower_acc:                        accumulated vpower values
+ * @vpower:                    snapshot of vpower registers
+ * @vbus:                      snapshot of vbus registers
+ * @vbus_avg:                  averages of vbus registers
+ * @vsense:                    snapshot of vsense registers
+ * @vsense_avg:                        averages of vsense registers
+ * @num_enabled_channels:      count of how many chip channels are currently enabled
+ */
+struct reg_data {
+       u8      meas_regs[PAC1934_MEAS_REG_LEN];
+       u8      ctrl_regs[PAC1934_CTRL_REG_LEN];
+       s64     energy_sec_acc[PAC1934_MAX_NUM_CHANNELS];
+       s64     vpower_acc[PAC1934_MAX_NUM_CHANNELS];
+       s32     vpower[PAC1934_MAX_NUM_CHANNELS];
+       s32     vbus[PAC1934_MAX_NUM_CHANNELS];
+       s32     vbus_avg[PAC1934_MAX_NUM_CHANNELS];
+       s32     vsense[PAC1934_MAX_NUM_CHANNELS];
+       s32     vsense_avg[PAC1934_MAX_NUM_CHANNELS];
+       u8      num_enabled_channels;
+};
+
+/**
+ * struct pac1934_chip_info - information about the chip
+ * @client:                    the i2c-client attached to the device
+ * @lock:                      synchronize access to driver's state members
+ * @work_chip_rfsh:            work queue used for refresh commands
+ * @phys_channels:             phys channels count
+ * @active_channels:           array of values, true means that channel is active
+ * @enable_energy:             array of values, true means that channel energy is measured
+ * @bi_dir:                    array of bools, true means that channel is bidirectional
+ * @chip_variant:              chip variant
+ * @chip_revision:             chip revision
+ * @shunts:                    shunts
+ * @chip_reg_data:             chip reg data
+ * @sample_rate_value:         sampling frequency
+ * @labels:                    table with channels labels
+ * @iio_info:                  iio_info
+ * @tstamp:                    chip's uptime
+ */
+struct pac1934_chip_info {
+       struct i2c_client       *client;
+       struct mutex            lock; /* synchronize access to driver's state members */
+       struct delayed_work     work_chip_rfsh;
+       u8                      phys_channels;
+       bool                    active_channels[PAC1934_MAX_NUM_CHANNELS];
+       bool                    enable_energy[PAC1934_MAX_NUM_CHANNELS];
+       bool                    bi_dir[PAC1934_MAX_NUM_CHANNELS];
+       u8                      chip_variant;
+       u8                      chip_revision;
+       u32                     shunts[PAC1934_MAX_NUM_CHANNELS];
+       struct reg_data         chip_reg_data;
+       s32                     sample_rate_value;
+       char                    *labels[PAC1934_MAX_NUM_CHANNELS];
+       struct iio_info         iio_info;
+       unsigned long           tstamp;
+};
+
+#define TO_PAC1934_CHIP_INFO(d) container_of(d, struct pac1934_chip_info, work_chip_rfsh)
+
+#define PAC1934_VPOWER_ACC_CHANNEL(_index, _si, _address) {                    \
+       .type = IIO_ENERGY,                                                     \
+       .address = (_address),                                                  \
+       .indexed = 1,                                                           \
+       .channel = (_index),                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)    |                       \
+                             BIT(IIO_CHAN_INFO_SCALE)  |                       \
+                             BIT(IIO_CHAN_INFO_ENABLE),                        \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),                \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),      \
+       .scan_index = (_si),                                                    \
+       .scan_type = {                                                          \
+               .sign = 'u',                                                    \
+               .realbits = 48,                                                 \
+               .storagebits = 64,                                              \
+               .endianness = IIO_CPU,                                          \
+       }                                                                       \
+}
+
+#define PAC1934_VBUS_CHANNEL(_index, _si, _address) {                          \
+       .type = IIO_VOLTAGE,                                                    \
+       .address = (_address),                                                  \
+       .indexed = 1,                                                           \
+       .channel = (_index),                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)    |                       \
+                             BIT(IIO_CHAN_INFO_SCALE),                         \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),                \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),      \
+       .scan_index = (_si),                                                    \
+       .scan_type = {                                                          \
+               .sign = 'u',                                                    \
+               .realbits = 16,                                                 \
+               .storagebits = 16,                                              \
+               .endianness = IIO_CPU,                                          \
+       }                                                                       \
+}
+
+#define PAC1934_VBUS_AVG_CHANNEL(_index, _si, _address) {                      \
+       .type = IIO_VOLTAGE,                                                    \
+       .address = (_address),                                                  \
+       .indexed = 1,                                                           \
+       .channel = (_index),                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW)    |               \
+                             BIT(IIO_CHAN_INFO_SCALE),                         \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),                \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),      \
+       .scan_index = (_si),                                                    \
+       .scan_type = {                                                          \
+               .sign = 'u',                                                    \
+               .realbits = 16,                                                 \
+               .storagebits = 16,                                              \
+               .endianness = IIO_CPU,                                          \
+       }                                                                       \
+}
+
+#define PAC1934_VSENSE_CHANNEL(_index, _si, _address) {                                \
+       .type = IIO_CURRENT,                                                    \
+       .address = (_address),                                                  \
+       .indexed = 1,                                                           \
+       .channel = (_index),                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)    |                       \
+                             BIT(IIO_CHAN_INFO_SCALE),                         \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),                \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),      \
+       .scan_index = (_si),                                                    \
+       .scan_type = {                                                          \
+               .sign = 'u',                                                    \
+               .realbits = 16,                                                 \
+               .storagebits = 16,                                              \
+               .endianness = IIO_CPU,                                          \
+       }                                                                       \
+}
+
+#define PAC1934_VSENSE_AVG_CHANNEL(_index, _si, _address) {                    \
+       .type = IIO_CURRENT,                                                    \
+       .address = (_address),                                                  \
+       .indexed = 1,                                                           \
+       .channel = (_index),                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW)    |               \
+                             BIT(IIO_CHAN_INFO_SCALE),                         \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),                \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),      \
+       .scan_index = (_si),                                                    \
+       .scan_type = {                                                          \
+               .sign = 'u',                                                    \
+               .realbits = 16,                                                 \
+               .storagebits = 16,                                              \
+               .endianness = IIO_CPU,                                          \
+       }                                                                       \
+}
+
+#define PAC1934_VPOWER_CHANNEL(_index, _si, _address) {                                \
+       .type = IIO_POWER,                                                      \
+       .address = (_address),                                                  \
+       .indexed = 1,                                                           \
+       .channel = (_index),                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)    |                       \
+                             BIT(IIO_CHAN_INFO_SCALE),                         \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),                \
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),      \
+       .scan_index = (_si),                                                    \
+       .scan_type = {                                                          \
+               .sign = 'u',                                                    \
+               .realbits = 28,                                                 \
+               .storagebits = 32,                                              \
+               .shift = 4,                                                     \
+               .endianness = IIO_CPU,                                          \
+       }                                                                       \
+}
+
+static const struct iio_chan_spec pac1934_single_channel[] = {
+       PAC1934_VPOWER_ACC_CHANNEL(0, 0, PAC1934_VPOWER_ACC_1_ADDR),
+       PAC1934_VPOWER_CHANNEL(0, 0, PAC1934_VPOWER_1_ADDR),
+       PAC1934_VBUS_CHANNEL(0, 0, PAC1934_VBUS_1_ADDR),
+       PAC1934_VSENSE_CHANNEL(0, 0, PAC1934_VSENSE_1_ADDR),
+       PAC1934_VBUS_AVG_CHANNEL(0, 0, PAC1934_VBUS_AVG_1_ADDR),
+       PAC1934_VSENSE_AVG_CHANNEL(0, 0, PAC1934_VSENSE_AVG_1_ADDR),
+};
+
+/* Low-level I2c functions used to transfer up to 76 bytes at once */
+static int pac1934_i2c_read(struct i2c_client *client, u8 reg_addr,
+                           void *databuf, u8 len)
+{
+       int ret;
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = client->addr,
+                       .len = 1,
+                       .buf = (u8 *)&reg_addr,
+               },
+               {
+                       .addr = client->addr,
+                       .len = len,
+                       .buf = databuf,
+                       .flags = I2C_M_RD
+               }
+       };
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int pac1934_get_samp_rate_idx(struct pac1934_chip_info *info,
+                                    u32 new_samp_rate)
+{
+       int cnt;
+
+       for (cnt = 0; cnt < ARRAY_SIZE(samp_rate_map_tbl); cnt++)
+               if (new_samp_rate == samp_rate_map_tbl[cnt])
+                       return cnt;
+
+       /* not a valid sample rate value */
+       return -EINVAL;
+}
+
+static ssize_t pac1934_shunt_value_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct pac1934_chip_info *info = iio_priv(indio_dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       return sysfs_emit(buf, "%u\n", info->shunts[this_attr->address]);
+}
+
+static ssize_t pac1934_shunt_value_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct pac1934_chip_info *info = iio_priv(indio_dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int sh_val;
+
+       if (kstrtouint(buf, 10, &sh_val)) {
+               dev_err(dev, "Shunt value is not valid\n");
+               return -EINVAL;
+       }
+
+       scoped_guard(mutex, &info->lock)
+               info->shunts[this_attr->address] = sh_val;
+
+       return count;
+}
+
+static int pac1934_read_avail(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *channel,
+                             const int **vals, int *type, int *length, long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *type = IIO_VAL_INT;
+               *vals = samp_rate_map_tbl;
+               *length = ARRAY_SIZE(samp_rate_map_tbl);
+               return IIO_AVAIL_LIST;
+       }
+
+       return -EINVAL;
+}
+
+static int pac1934_send_refresh(struct pac1934_chip_info *info,
+                               u8 refresh_cmd, u32 wait_time)
+{
+       /* this function only sends REFRESH or REFRESH_V */
+       struct i2c_client *client = info->client;
+       int ret;
+       u8 bidir_reg;
+       bool revision_bug = false;
+
+       if (info->chip_revision == 2 || info->chip_revision == 3) {
+               /*
+                * chip rev 2 and 3 bug workaround
+                * see: PAC1934 Family Data Sheet Errata DS80000836A.pdf
+                */
+               revision_bug = true;
+
+               bidir_reg =
+                       FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDI_MASK, info->bi_dir[0]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDI_MASK, info->bi_dir[1]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDI_MASK, info->bi_dir[2]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDI_MASK, info->bi_dir[3]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDV_MASK, info->bi_dir[0]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDV_MASK, info->bi_dir[1]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDV_MASK, info->bi_dir[2]) |
+                       FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDV_MASK, info->bi_dir[3]);
+
+               ret = i2c_smbus_write_byte_data(client,
+                                               PAC1934_CTRL_STAT_REGS_ADDR +
+                                               PAC1934_NEG_PWR_REG_OFF,
+                                               bidir_reg);
+               if (ret)
+                       return ret;
+       }
+
+       ret = i2c_smbus_write_byte(client, refresh_cmd);
+       if (ret) {
+               dev_err(&client->dev, "%s - cannot send 0x%02X\n",
+                       __func__, refresh_cmd);
+               return ret;
+       }
+
+       if (revision_bug) {
+               /*
+                * chip rev 2 and 3 bug workaround - write again the same
+                * register write the updated registers back
+                */
+               ret = i2c_smbus_write_byte_data(client,
+                                               PAC1934_CTRL_STAT_REGS_ADDR +
+                                               PAC1934_NEG_PWR_REG_OFF, bidir_reg);
+               if (ret)
+                       return ret;
+       }
+
+       /* register data retrieval timestamp */
+       info->tstamp = jiffies;
+
+       /* wait till the data is available */
+       usleep_range(wait_time, wait_time + 100);
+
+       return ret;
+}
+
+static int pac1934_reg_snapshot(struct pac1934_chip_info *info,
+                               bool do_refresh, u8 refresh_cmd, u32 wait_time)
+{
+       int ret;
+       struct i2c_client *client = info->client;
+       u8 samp_shift, ctrl_regs_tmp;
+       u8 *offset_reg_data_p;
+       u16 tmp_value;
+       u32 samp_rate, cnt, tmp;
+       s64 curr_energy, inc;
+       u64 tmp_energy;
+       struct reg_data *reg_data;
+
+       guard(mutex)(&info->lock);
+
+       if (do_refresh) {
+               ret = pac1934_send_refresh(info, refresh_cmd, wait_time);
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "%s - cannot send refresh\n",
+                               __func__);
+                       return ret;
+               }
+       }
+
+       ret = i2c_smbus_read_i2c_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+                                           PAC1934_CTRL_REG_LEN,
+                                           (u8 *)info->chip_reg_data.ctrl_regs);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "%s - cannot read ctrl/status registers\n",
+                       __func__);
+               return ret;
+       }
+
+       reg_data = &info->chip_reg_data;
+
+       /* read the data registers */
+       ret = pac1934_i2c_read(client, PAC1934_ACC_COUNT_REG_ADDR,
+                              (u8 *)reg_data->meas_regs, PAC1934_MEAS_REG_LEN);
+       if (ret) {
+               dev_err(&client->dev,
+                       "%s - cannot read ACC_COUNT register: %d:%d\n",
+                       __func__, ret, PAC1934_MEAS_REG_LEN);
+               return ret;
+       }
+
+       /* see how much shift is required by the sample rate */
+       samp_rate = samp_rate_map_tbl[((reg_data->ctrl_regs[PAC1934_CTRL_LAT_REG_OFF]) >> 6)];
+       samp_shift = get_count_order(samp_rate);
+
+       ctrl_regs_tmp = reg_data->ctrl_regs[PAC1934_CHANNEL_DIS_LAT_REG_OFF];
+       offset_reg_data_p = &reg_data->meas_regs[PAC1934_ACC_REG_LEN];
+
+       /* start with VPOWER_ACC */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               /* check if the channel is active, skip all fields if disabled */
+               if ((ctrl_regs_tmp << cnt) & 0x80)
+                       continue;
+
+               /* skip if the energy accumulation is disabled */
+               if (info->enable_energy[cnt]) {
+                       curr_energy = info->chip_reg_data.energy_sec_acc[cnt];
+
+                       tmp_energy = get_unaligned_be48(offset_reg_data_p);
+
+                       if (info->bi_dir[cnt])
+                               reg_data->vpower_acc[cnt] = sign_extend64(tmp_energy, 47);
+                       else
+                               reg_data->vpower_acc[cnt] = tmp_energy;
+
+                       /*
+                        * compute the scaled to 1 second accumulated energy value;
+                        * energy accumulator scaled to 1sec = VPOWER_ACC/2^samp_shift
+                        * the chip's sampling rate is 2^samp_shift samples/sec
+                        */
+                       inc = (reg_data->vpower_acc[cnt] >> samp_shift);
+
+                       /* add the power_acc field */
+                       curr_energy += inc;
+
+                       clamp(curr_energy, PAC_193X_MIN_POWER_ACC, PAC_193X_MAX_POWER_ACC);
+
+                       reg_data->energy_sec_acc[cnt] = curr_energy;
+               }
+
+               offset_reg_data_p += PAC1934_VPOWER_ACC_REG_LEN;
+       }
+
+       /* continue with VBUS */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if ((ctrl_regs_tmp << cnt) & 0x80)
+                       continue;
+
+               tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+               if (info->bi_dir[cnt])
+                       reg_data->vbus[cnt] = sign_extend32((u32)(tmp_value), 15);
+               else
+                       reg_data->vbus[cnt] = tmp_value;
+
+               offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+       }
+
+       /* VSENSE */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if ((ctrl_regs_tmp << cnt) & 0x80)
+                       continue;
+
+               tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+               if (info->bi_dir[cnt])
+                       reg_data->vsense[cnt] = sign_extend32((u32)(tmp_value), 15);
+               else
+                       reg_data->vsense[cnt] = tmp_value;
+
+               offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+       }
+
+       /* VBUS_AVG */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if ((ctrl_regs_tmp << cnt) & 0x80)
+                       continue;
+
+               tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+               if (info->bi_dir[cnt])
+                       reg_data->vbus_avg[cnt] = sign_extend32((u32)(tmp_value), 15);
+               else
+                       reg_data->vbus_avg[cnt] = tmp_value;
+
+               offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+       }
+
+       /* VSENSE_AVG */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if ((ctrl_regs_tmp << cnt) & 0x80)
+                       continue;
+
+               tmp_value = get_unaligned_be16(offset_reg_data_p);
+
+               if (info->bi_dir[cnt])
+                       reg_data->vsense_avg[cnt] = sign_extend32((u32)(tmp_value), 15);
+               else
+                       reg_data->vsense_avg[cnt] = tmp_value;
+
+               offset_reg_data_p += PAC1934_VBUS_SENSE_REG_LEN;
+       }
+
+       /* VPOWER */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if ((ctrl_regs_tmp << cnt) & 0x80)
+                       continue;
+
+               tmp = get_unaligned_be32(offset_reg_data_p) >> 4;
+
+               if (info->bi_dir[cnt])
+                       reg_data->vpower[cnt] = sign_extend32(tmp, 27);
+               else
+                       reg_data->vpower[cnt] = tmp;
+
+               offset_reg_data_p += PAC1934_VPOWER_REG_LEN;
+       }
+
+       return 0;
+}
+
+static int pac1934_retrieve_data(struct pac1934_chip_info *info,
+                                u32 wait_time)
+{
+       int ret = 0;
+
+       /*
+        * check if the minimal elapsed time has passed and if so,
+        * re-read the chip, otherwise the cached info is just fine
+        */
+       if (time_after(jiffies, info->tstamp + msecs_to_jiffies(PAC1934_MIN_POLLING_TIME_MS))) {
+               ret = pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR,
+                                          wait_time);
+
+               /*
+                * Re-schedule the work for the read registers on timeout
+                * (to prevent chip registers saturation)
+                */
+               mod_delayed_work(system_wq, &info->work_chip_rfsh,
+                                msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
+       }
+
+       return ret;
+}
+
+static int pac1934_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan, int *val,
+                           int *val2, long mask)
+{
+       struct pac1934_chip_info *info = iio_priv(indio_dev);
+       s64 curr_energy;
+       int ret, channel = chan->channel - 1;
+
+       ret = pac1934_retrieve_data(info, PAC1934_MIN_UPDATE_WAIT_TIME_US);
+       if (ret < 0)
+               return ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       *val = info->chip_reg_data.vbus[channel];
+                       return IIO_VAL_INT;
+               case IIO_CURRENT:
+                       *val = info->chip_reg_data.vsense[channel];
+                       return IIO_VAL_INT;
+               case IIO_POWER:
+                       *val = info->chip_reg_data.vpower[channel];
+                       return IIO_VAL_INT;
+               case IIO_ENERGY:
+                       curr_energy = info->chip_reg_data.energy_sec_acc[channel];
+                       *val = (u32)curr_energy;
+                       *val2 = (u32)(curr_energy >> 32);
+                       return IIO_VAL_INT_64;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_AVERAGE_RAW:
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       *val = info->chip_reg_data.vbus_avg[channel];
+                       return IIO_VAL_INT;
+               case IIO_CURRENT:
+                       *val = info->chip_reg_data.vsense_avg[channel];
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_SCALE:
+               switch (chan->address) {
+               /* Voltages - scale for millivolts */
+               case PAC1934_VBUS_1_ADDR:
+               case PAC1934_VBUS_2_ADDR:
+               case PAC1934_VBUS_3_ADDR:
+               case PAC1934_VBUS_4_ADDR:
+               case PAC1934_VBUS_AVG_1_ADDR:
+               case PAC1934_VBUS_AVG_2_ADDR:
+               case PAC1934_VBUS_AVG_3_ADDR:
+               case PAC1934_VBUS_AVG_4_ADDR:
+                       *val = PAC1934_VOLTAGE_MILLIVOLTS_MAX;
+                       if (chan->scan_type.sign == 'u')
+                               *val2 = PAC1934_VOLTAGE_U_RES;
+                       else
+                               *val2 = PAC1934_VOLTAGE_S_RES;
+                       return IIO_VAL_FRACTIONAL_LOG2;
+               /*
+                * Currents - scale for mA - depends on the
+                * channel's shunt value
+                * (100mV * 1000000) / (2^16 * shunt(uohm))
+                */
+               case PAC1934_VSENSE_1_ADDR:
+               case PAC1934_VSENSE_2_ADDR:
+               case PAC1934_VSENSE_3_ADDR:
+               case PAC1934_VSENSE_4_ADDR:
+               case PAC1934_VSENSE_AVG_1_ADDR:
+               case PAC1934_VSENSE_AVG_2_ADDR:
+               case PAC1934_VSENSE_AVG_3_ADDR:
+               case PAC1934_VSENSE_AVG_4_ADDR:
+                       *val = PAC1934_MAX_VSENSE_RSHIFTED_BY_16B;
+                       if (chan->scan_type.sign == 'u')
+                               *val2 = info->shunts[channel];
+                       else
+                               *val2 = info->shunts[channel] >> 1;
+                       return IIO_VAL_FRACTIONAL;
+               /*
+                * Power - uW - it will use the combined scale
+                * for current and voltage
+                * current(mA) * voltage(mV) = power (uW)
+                */
+               case PAC1934_VPOWER_1_ADDR:
+               case PAC1934_VPOWER_2_ADDR:
+               case PAC1934_VPOWER_3_ADDR:
+               case PAC1934_VPOWER_4_ADDR:
+                       *val = PAC1934_MAX_VPOWER_RSHIFTED_BY_28B;
+                       if (chan->scan_type.sign == 'u')
+                               *val2 = info->shunts[channel];
+                       else
+                               *val2 = info->shunts[channel] >> 1;
+                       return IIO_VAL_FRACTIONAL;
+               case PAC1934_VPOWER_ACC_1_ADDR:
+               case PAC1934_VPOWER_ACC_2_ADDR:
+               case PAC1934_VPOWER_ACC_3_ADDR:
+               case PAC1934_VPOWER_ACC_4_ADDR:
+                       /*
+                        * expresses the 32 bit scale value here compute
+                        * the scale for energy (miliWatt-second or miliJoule)
+                        */
+                       *val = PAC1934_SCALE_CONSTANT;
+
+                       if (chan->scan_type.sign == 'u')
+                               *val2 = info->shunts[channel];
+                       else
+                               *val2 = info->shunts[channel] >> 1;
+                       return IIO_VAL_FRACTIONAL;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *val = info->sample_rate_value;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_ENABLE:
+               *val = info->enable_energy[channel];
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int pac1934_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct pac1934_chip_info *info = iio_priv(indio_dev);
+       struct i2c_client *client = info->client;
+       int ret = -EINVAL;
+       s32 old_samp_rate;
+       u8 ctrl_reg;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = pac1934_get_samp_rate_idx(info, val);
+               if (ret < 0)
+                       return ret;
+
+               /* write the new sampling value and trigger a snapshot(incl refresh) */
+               scoped_guard(mutex, &info->lock) {
+                       ctrl_reg = FIELD_PREP(PAC1934_CRTL_SAMPLE_RATE_MASK, ret);
+                       ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_REG_ADDR, ctrl_reg);
+                       if (ret) {
+                               dev_err(&client->dev,
+                                       "%s - can't update sample rate\n",
+                                       __func__);
+                               return ret;
+                       }
+               }
+
+               old_samp_rate = info->sample_rate_value;
+               info->sample_rate_value = val;
+
+               /*
+                * now, force a snapshot with refresh - call retrieve
+                * data in order to update the refresh timer
+                * alter the timestamp in order to force trigger a
+                * register snapshot and a timestamp update
+                */
+               info->tstamp -= msecs_to_jiffies(PAC1934_MIN_POLLING_TIME_MS);
+               ret = pac1934_retrieve_data(info, (1024 / old_samp_rate) * 1000);
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "%s - cannot snapshot ctrl and measurement regs\n",
+                               __func__);
+                       return ret;
+               }
+
+               return 0;
+       case IIO_CHAN_INFO_ENABLE:
+               scoped_guard(mutex, &info->lock) {
+                       info->enable_energy[chan->channel - 1] = val ? true : false;
+                       if (!val)
+                               info->chip_reg_data.energy_sec_acc[chan->channel - 1] = 0;
+               }
+
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int pac1934_read_label(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan, char *label)
+{
+       struct pac1934_chip_info *info = iio_priv(indio_dev);
+
+       switch (chan->address) {
+       case PAC1934_VBUS_1_ADDR:
+       case PAC1934_VBUS_2_ADDR:
+       case PAC1934_VBUS_3_ADDR:
+       case PAC1934_VBUS_4_ADDR:
+               return sysfs_emit(label, "%s_VBUS_%d\n",
+                                 info->labels[chan->scan_index],
+                                 chan->scan_index + 1);
+       case PAC1934_VBUS_AVG_1_ADDR:
+       case PAC1934_VBUS_AVG_2_ADDR:
+       case PAC1934_VBUS_AVG_3_ADDR:
+       case PAC1934_VBUS_AVG_4_ADDR:
+               return sysfs_emit(label, "%s_VBUS_AVG_%d\n",
+                                 info->labels[chan->scan_index],
+                                 chan->scan_index + 1);
+       case PAC1934_VSENSE_1_ADDR:
+       case PAC1934_VSENSE_2_ADDR:
+       case PAC1934_VSENSE_3_ADDR:
+       case PAC1934_VSENSE_4_ADDR:
+               return sysfs_emit(label, "%s_IBUS_%d\n",
+                                 info->labels[chan->scan_index],
+                                 chan->scan_index + 1);
+       case PAC1934_VSENSE_AVG_1_ADDR:
+       case PAC1934_VSENSE_AVG_2_ADDR:
+       case PAC1934_VSENSE_AVG_3_ADDR:
+       case PAC1934_VSENSE_AVG_4_ADDR:
+               return sysfs_emit(label, "%s_IBUS_AVG_%d\n",
+                                 info->labels[chan->scan_index],
+                                 chan->scan_index + 1);
+       case PAC1934_VPOWER_1_ADDR:
+       case PAC1934_VPOWER_2_ADDR:
+       case PAC1934_VPOWER_3_ADDR:
+       case PAC1934_VPOWER_4_ADDR:
+               return sysfs_emit(label, "%s_POWER_%d\n",
+                                 info->labels[chan->scan_index],
+                                 chan->scan_index + 1);
+       case PAC1934_VPOWER_ACC_1_ADDR:
+       case PAC1934_VPOWER_ACC_2_ADDR:
+       case PAC1934_VPOWER_ACC_3_ADDR:
+       case PAC1934_VPOWER_ACC_4_ADDR:
+               return sysfs_emit(label, "%s_ENERGY_%d\n",
+                                 info->labels[chan->scan_index],
+                                 chan->scan_index + 1);
+       }
+
+       return 0;
+}
+
+static void pac1934_work_periodic_rfsh(struct work_struct *work)
+{
+       struct pac1934_chip_info *info = TO_PAC1934_CHIP_INFO((struct delayed_work *)work);
+       struct device *dev = &info->client->dev;
+
+       dev_dbg(dev, "%s - Periodic refresh\n", __func__);
+
+       /* do a REFRESH, then read */
+       pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR,
+                            PAC1934_MIN_UPDATE_WAIT_TIME_US);
+
+       schedule_delayed_work(&info->work_chip_rfsh,
+                             msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
+}
+
+static int pac1934_read_revision(struct pac1934_chip_info *info, u8 *buf)
+{
+       int ret;
+       struct i2c_client *client = info->client;
+
+       ret = i2c_smbus_read_i2c_block_data(client, PAC1934_PID_REG_ADDR,
+                                           PAC1934_ID_REG_LEN,
+                                           buf);
+       if (ret < 0) {
+               dev_err(&client->dev, "cannot read revision\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pac1934_chip_identify(struct pac1934_chip_info *info)
+{
+       u8 rev_info[PAC1934_ID_REG_LEN];
+       struct device *dev = &info->client->dev;
+       int ret = 0;
+
+       ret = pac1934_read_revision(info, (u8 *)rev_info);
+       if (ret)
+               return ret;
+
+       info->chip_variant = rev_info[PAC1934_PID_IDX];
+       info->chip_revision = rev_info[PAC1934_RID_IDX];
+
+       dev_dbg(dev, "Chip variant: 0x%02X\n", info->chip_variant);
+       dev_dbg(dev, "Chip revision: 0x%02X\n", info->chip_revision);
+
+       switch (info->chip_variant) {
+       case PAC1934_PID:
+               return PAC1934;
+       case PAC1933_PID:
+               return PAC1933;
+       case PAC1932_PID:
+               return PAC1932;
+       case PAC1931_PID:
+               return PAC1931;
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * documentation related to the ACPI device definition
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
+ */
+static bool pac1934_acpi_parse_channel_config(struct i2c_client *client,
+                                             struct pac1934_chip_info *info)
+{
+       acpi_handle handle;
+       union acpi_object *rez;
+       struct device *dev = &client->dev;
+       unsigned short bi_dir_mask;
+       int idx, i;
+       guid_t guid;
+
+       handle = ACPI_HANDLE(dev);
+
+       guid_parse(PAC1934_DSM_UUID, &guid);
+
+       rez = acpi_evaluate_dsm(handle, &guid, 0, PAC1934_ACPI_GET_NAMES_AND_MOHMS_VALS, NULL);
+       if (!rez)
+               return false;
+
+       for (i = 0; i < rez->package.count; i += 2) {
+               idx = i / 2;
+               info->labels[idx] =
+                       devm_kmemdup(dev, rez->package.elements[i].string.pointer,
+                                    (size_t)rez->package.elements[i].string.length + 1,
+                                    GFP_KERNEL);
+               info->labels[idx][rez->package.elements[i].string.length] = '\0';
+               info->shunts[idx] = rez->package.elements[i + 1].integer.value * 1000;
+               info->active_channels[idx] = (info->shunts[idx] != 0);
+       }
+
+       ACPI_FREE(rez);
+
+       rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_UOHMS_VALS, NULL);
+       if (!rez) {
+               /*
+                * initializing with default values
+                * we assume all channels are unidirectional(the mask is zero)
+                * and assign the default sampling rate
+                */
+               info->sample_rate_value = PAC1934_DEFAULT_CHIP_SAMP_SPEED_HZ;
+               return true;
+       }
+
+       for (i = 0; i < rez->package.count; i++) {
+               idx = i;
+               info->shunts[idx] = rez->package.elements[i].integer.value;
+               info->active_channels[idx] = (info->shunts[idx] != 0);
+       }
+
+       ACPI_FREE(rez);
+
+       rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_BIPOLAR_SETTINGS, NULL);
+       if (!rez)
+               return false;
+
+       bi_dir_mask = rez->package.elements[0].integer.value;
+       info->bi_dir[0] = ((bi_dir_mask & (1 << 3)) | (bi_dir_mask & (1 << 7))) != 0;
+       info->bi_dir[1] = ((bi_dir_mask & (1 << 2)) | (bi_dir_mask & (1 << 6))) != 0;
+       info->bi_dir[2] = ((bi_dir_mask & (1 << 1)) | (bi_dir_mask & (1 << 5))) != 0;
+       info->bi_dir[3] = ((bi_dir_mask & (1 << 0)) | (bi_dir_mask & (1 << 4))) != 0;
+
+       ACPI_FREE(rez);
+
+       rez = acpi_evaluate_dsm(handle, &guid, 1, PAC1934_ACPI_GET_SAMP, NULL);
+       if (!rez)
+               return false;
+
+       info->sample_rate_value = rez->package.elements[0].integer.value;
+
+       ACPI_FREE(rez);
+
+       return true;
+}
+
+static bool pac1934_of_parse_channel_config(struct i2c_client *client,
+                                           struct pac1934_chip_info *info)
+{
+       struct fwnode_handle *node, *fwnode;
+       struct device *dev = &client->dev;
+       unsigned int current_channel;
+       int idx, ret;
+
+       info->sample_rate_value = 1024;
+       current_channel = 1;
+
+       fwnode = dev_fwnode(dev);
+       fwnode_for_each_available_child_node(fwnode, node) {
+               ret = fwnode_property_read_u32(node, "reg", &idx);
+               if (ret) {
+                       dev_err_probe(dev, ret,
+                                     "reading invalid channel index\n");
+                       goto err_fwnode;
+               }
+               /* adjust idx to match channel index (1 to 4) from the datasheet */
+               idx--;
+
+               if (current_channel >= (info->phys_channels + 1) ||
+                   idx >= info->phys_channels || idx < 0) {
+                       dev_err_probe(dev, -EINVAL,
+                                     "%s: invalid channel_index %d value\n",
+                                     fwnode_get_name(node), idx);
+                       goto err_fwnode;
+               }
+
+               /* enable channel */
+               info->active_channels[idx] = true;
+
+               ret = fwnode_property_read_u32(node, "shunt-resistor-micro-ohms",
+                                              &info->shunts[idx]);
+               if (ret) {
+                       dev_err_probe(dev, ret,
+                                     "%s: invalid shunt-resistor value: %d\n",
+                                     fwnode_get_name(node), info->shunts[idx]);
+                       goto err_fwnode;
+               }
+
+               if (fwnode_property_present(node, "label")) {
+                       ret = fwnode_property_read_string(node, "label",
+                                                         (const char **)&info->labels[idx]);
+                       if (ret) {
+                               dev_err_probe(dev, ret,
+                                             "%s: invalid rail-name value\n",
+                                             fwnode_get_name(node));
+                               goto err_fwnode;
+                       }
+               }
+
+               info->bi_dir[idx] = fwnode_property_read_bool(node, "bipolar");
+
+               current_channel++;
+       }
+
+       return true;
+
+err_fwnode:
+       fwnode_handle_put(node);
+
+       return false;
+}
+
+static void pac1934_cancel_delayed_work(void *dwork)
+{
+       cancel_delayed_work_sync(dwork);
+}
+
+static int pac1934_chip_configure(struct pac1934_chip_info *info)
+{
+       int cnt, ret;
+       struct i2c_client *client = info->client;
+       u8 regs[PAC1934_CTRL_STATUS_INFO_LEN], idx, ctrl_reg;
+       u32 wait_time;
+
+       info->chip_reg_data.num_enabled_channels = 0;
+       for (cnt = 0;  cnt < info->phys_channels; cnt++) {
+               if (info->active_channels[cnt])
+                       info->chip_reg_data.num_enabled_channels++;
+       }
+
+       /*
+        * read whatever information was gathered before the driver was loaded
+        * establish which channels are enabled/disabled and then establish the
+        * information retrieval mode (using SKIP or no).
+        * Read the chip ID values
+        */
+       ret = i2c_smbus_read_i2c_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+                                           ARRAY_SIZE(regs),
+                                           (u8 *)regs);
+       if (ret < 0) {
+               dev_err_probe(&client->dev, ret,
+                             "%s - cannot read regs from 0x%02X\n",
+                             __func__, PAC1934_CTRL_STAT_REGS_ADDR);
+               return ret;
+       }
+
+       /* write the CHANNEL_DIS and the NEG_PWR registers */
+       regs[PAC1934_CHANNEL_DIS_REG_OFF] =
+               FIELD_PREP(PAC1934_CHAN_DIS_CH1_OFF_MASK, info->active_channels[0] ? 0 : 1) |
+               FIELD_PREP(PAC1934_CHAN_DIS_CH2_OFF_MASK, info->active_channels[1] ? 0 : 1) |
+               FIELD_PREP(PAC1934_CHAN_DIS_CH3_OFF_MASK, info->active_channels[2] ? 0 : 1) |
+               FIELD_PREP(PAC1934_CHAN_DIS_CH4_OFF_MASK, info->active_channels[3] ? 0 : 1) |
+               FIELD_PREP(PAC1934_SMBUS_TIMEOUT_MASK, 0) |
+               FIELD_PREP(PAC1934_SMBUS_BYTECOUNT_MASK, 0) |
+               FIELD_PREP(PAC1934_SMBUS_NO_SKIP_MASK, 0);
+
+       regs[PAC1934_NEG_PWR_REG_OFF] =
+               FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDI_MASK, info->bi_dir[0]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDI_MASK, info->bi_dir[1]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDI_MASK, info->bi_dir[2]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDI_MASK, info->bi_dir[3]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH1_BIDV_MASK, info->bi_dir[0]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH2_BIDV_MASK, info->bi_dir[1]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH3_BIDV_MASK, info->bi_dir[2]) |
+               FIELD_PREP(PAC1934_NEG_PWR_CH4_BIDV_MASK, info->bi_dir[3]);
+
+       /* no SLOW triggered REFRESH, clear POR */
+       regs[PAC1934_SLOW_REG_OFF] = 0;
+
+       ret =  i2c_smbus_write_block_data(client, PAC1934_CTRL_STAT_REGS_ADDR,
+                                         ARRAY_SIZE(regs), (u8 *)regs);
+       if (ret)
+               return ret;
+
+       /* Default sampling rate */
+       ctrl_reg = FIELD_PREP(PAC1934_CRTL_SAMPLE_RATE_MASK, PAC1934_SAMP_1024SPS);
+
+       ret = i2c_smbus_write_byte_data(client, PAC1934_CTRL_REG_ADDR, ctrl_reg);
+       if (ret)
+               return ret;
+
+       /*
+        * send a REFRESH to the chip, so the new settings take place
+        * as well as resetting the accumulators
+        */
+       ret = i2c_smbus_write_byte(client, PAC1934_REFRESH_REG_ADDR);
+       if (ret) {
+               dev_err(&client->dev,
+                       "%s - cannot send 0x%02X\n",
+                       __func__, PAC1934_REFRESH_REG_ADDR);
+               return ret;
+       }
+
+       /*
+        * get the current(in the chip) sampling speed and compute the
+        * required timeout based on its value
+        * the timeout is 1/sampling_speed
+        */
+       idx = regs[PAC1934_CTRL_ACT_REG_OFF] >> PAC1934_SAMPLE_RATE_SHIFT;
+       wait_time = (1024 / samp_rate_map_tbl[idx]) * 1000;
+
+       /*
+        * wait the maximum amount of time to be on the safe side
+        * the maximum wait time is for 8sps
+        */
+       usleep_range(wait_time, wait_time + 100);
+
+       INIT_DELAYED_WORK(&info->work_chip_rfsh, pac1934_work_periodic_rfsh);
+       /* Setup the latest moment for reading the regs before saturation */
+       schedule_delayed_work(&info->work_chip_rfsh,
+                             msecs_to_jiffies(PAC1934_MAX_RFSH_LIMIT_MS));
+
+       return devm_add_action_or_reset(&client->dev, pac1934_cancel_delayed_work,
+                                       &info->work_chip_rfsh);
+}
+
+static int pac1934_prep_iio_channels(struct pac1934_chip_info *info, struct iio_dev *indio_dev)
+{
+       struct iio_chan_spec *ch_sp;
+       int channel_size, attribute_count, cnt;
+       void *dyn_ch_struct, *tmp_data;
+       struct device *dev = &info->client->dev;
+
+       /* find out dynamically how many IIO channels we need */
+       attribute_count = 0;
+       channel_size = 0;
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if (!info->active_channels[cnt])
+                       continue;
+
+               /* add the size of the properties of one chip physical channel */
+               channel_size += sizeof(pac1934_single_channel);
+               /* count how many enabled channels we have */
+               attribute_count += ARRAY_SIZE(pac1934_single_channel);
+               dev_dbg(dev, ":%s: Channel %d active\n", __func__, cnt + 1);
+       }
+
+       dyn_ch_struct = devm_kzalloc(dev, channel_size, GFP_KERNEL);
+       if (!dyn_ch_struct)
+               return -EINVAL;
+
+       tmp_data = dyn_ch_struct;
+
+       /* populate the dynamic channels and make all the adjustments */
+       for (cnt = 0; cnt < info->phys_channels; cnt++) {
+               if (!info->active_channels[cnt])
+                       continue;
+
+               memcpy(tmp_data, pac1934_single_channel, sizeof(pac1934_single_channel));
+               ch_sp = (struct iio_chan_spec *)tmp_data;
+               ch_sp[PAC1934_CH_ENERGY].channel = cnt + 1;
+               ch_sp[PAC1934_CH_ENERGY].scan_index = cnt;
+               ch_sp[PAC1934_CH_ENERGY].address = cnt + PAC1934_VPOWER_ACC_1_ADDR;
+               ch_sp[PAC1934_CH_POWER].channel = cnt + 1;
+               ch_sp[PAC1934_CH_POWER].scan_index = cnt;
+               ch_sp[PAC1934_CH_POWER].address = cnt + PAC1934_VPOWER_1_ADDR;
+               ch_sp[PAC1934_CH_VOLTAGE].channel = cnt + 1;
+               ch_sp[PAC1934_CH_VOLTAGE].scan_index = cnt;
+               ch_sp[PAC1934_CH_VOLTAGE].address = cnt + PAC1934_VBUS_1_ADDR;
+               ch_sp[PAC1934_CH_CURRENT].channel = cnt + 1;
+               ch_sp[PAC1934_CH_CURRENT].scan_index = cnt;
+               ch_sp[PAC1934_CH_CURRENT].address = cnt + PAC1934_VSENSE_1_ADDR;
+
+               /*
+                * In order to be able to use labels for PAC1934_CH_VOLTAGE, and
+                * PAC1934_CH_VOLTAGE_AVERAGE,respectively PAC1934_CH_CURRENT
+                * and PAC1934_CH_CURRENT_AVERAGE we need to use different
+                * channel numbers. We will add +5 (+1 to maximum PAC channels).
+                */
+               ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].channel = cnt + 5;
+               ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_index = cnt;
+               ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].address = cnt + PAC1934_VBUS_AVG_1_ADDR;
+               ch_sp[PAC1934_CH_CURRENT_AVERAGE].channel = cnt + 5;
+               ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_index = cnt;
+               ch_sp[PAC1934_CH_CURRENT_AVERAGE].address = cnt + PAC1934_VSENSE_AVG_1_ADDR;
+
+               /*
+                * now modify the parameters in all channels if the
+                * whole chip rail(channel) is bi-directional
+                */
+               if (info->bi_dir[cnt]) {
+                       ch_sp[PAC1934_CH_ENERGY].scan_type.sign = 's';
+                       ch_sp[PAC1934_CH_ENERGY].scan_type.realbits = 47;
+                       ch_sp[PAC1934_CH_POWER].scan_type.sign = 's';
+                       ch_sp[PAC1934_CH_POWER].scan_type.realbits = 27;
+                       ch_sp[PAC1934_CH_VOLTAGE].scan_type.sign = 's';
+                       ch_sp[PAC1934_CH_VOLTAGE].scan_type.realbits = 15;
+                       ch_sp[PAC1934_CH_CURRENT].scan_type.sign = 's';
+                       ch_sp[PAC1934_CH_CURRENT].scan_type.realbits = 15;
+                       ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_type.sign = 's';
+                       ch_sp[PAC1934_CH_VOLTAGE_AVERAGE].scan_type.realbits = 15;
+                       ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_type.sign = 's';
+                       ch_sp[PAC1934_CH_CURRENT_AVERAGE].scan_type.realbits = 15;
+               }
+               tmp_data += sizeof(pac1934_single_channel);
+       }
+
+       /*
+        * send the updated dynamic channel structure information towards IIO
+        * prepare the required field for IIO class registration
+        */
+       indio_dev->num_channels = attribute_count;
+       indio_dev->channels = (const struct iio_chan_spec *)dyn_ch_struct;
+
+       return 0;
+}
+
+static IIO_DEVICE_ATTR(in_shunt_resistor1, 0644,
+                      pac1934_shunt_value_show, pac1934_shunt_value_store, 0);
+static IIO_DEVICE_ATTR(in_shunt_resistor2, 0644,
+                      pac1934_shunt_value_show, pac1934_shunt_value_store, 1);
+static IIO_DEVICE_ATTR(in_shunt_resistor3, 0644,
+                      pac1934_shunt_value_show, pac1934_shunt_value_store, 2);
+static IIO_DEVICE_ATTR(in_shunt_resistor4, 0644,
+                      pac1934_shunt_value_show, pac1934_shunt_value_store, 3);
+
+static int pac1934_prep_custom_attributes(struct pac1934_chip_info *info,
+                                         struct iio_dev *indio_dev)
+{
+       int i, active_channels_count = 0;
+       struct attribute **pac1934_custom_attr;
+       struct attribute_group *pac1934_group;
+       struct device *dev = &info->client->dev;
+
+       for (i = 0 ; i < info->phys_channels; i++)
+               if (info->active_channels[i])
+                       active_channels_count++;
+
+       pac1934_group = devm_kzalloc(dev, sizeof(*pac1934_group), GFP_KERNEL);
+       if (!pac1934_group)
+               return -ENOMEM;
+
+       pac1934_custom_attr = devm_kzalloc(dev,
+                                          (PAC1934_CUSTOM_ATTR_FOR_CHANNEL *
+                                          active_channels_count)
+                                          * sizeof(*pac1934_group) + 1,
+                                          GFP_KERNEL);
+       if (!pac1934_custom_attr)
+               return -ENOMEM;
+
+       i = 0;
+       if (info->active_channels[0])
+               pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor1);
+
+       if (info->active_channels[1])
+               pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor2);
+
+       if (info->active_channels[2])
+               pac1934_custom_attr[i++] = PAC1934_DEV_ATTR(in_shunt_resistor3);
+
+       if (info->active_channels[3])
+               pac1934_custom_attr[i] = PAC1934_DEV_ATTR(in_shunt_resistor4);
+
+       pac1934_group->attrs = pac1934_custom_attr;
+       info->iio_info.attrs = pac1934_group;
+
+       return 0;
+}
+
+static void pac1934_mutex_destroy(void *data)
+{
+       struct mutex *lock = data;
+
+       mutex_destroy(lock);
+}
+
+static const struct iio_info pac1934_info = {
+       .read_raw = pac1934_read_raw,
+       .write_raw = pac1934_write_raw,
+       .read_avail = pac1934_read_avail,
+       .read_label = pac1934_read_label,
+};
+
+static int pac1934_probe(struct i2c_client *client)
+{
+       struct pac1934_chip_info *info;
+       const struct pac1934_features *chip;
+       struct iio_dev *indio_dev;
+       int cnt, ret;
+       bool match = false;
+       struct device *dev = &client->dev;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       info = iio_priv(indio_dev);
+
+       info->client = client;
+
+       /* always start with energy accumulation enabled */
+       for (cnt = 0; cnt < PAC1934_MAX_NUM_CHANNELS; cnt++)
+               info->enable_energy[cnt] = true;
+
+       ret = pac1934_chip_identify(info);
+       if (ret < 0) {
+               /*
+                * If failed to identify the hardware based on internal
+                * registers, try using fallback compatible in device tree
+                * to deal with some newer part number.
+                */
+               chip = i2c_get_match_data(client);
+               if (!chip)
+                       return -EINVAL;
+
+               info->phys_channels = chip->phys_channels;
+               indio_dev->name = chip->name;
+       } else {
+               info->phys_channels = pac1934_chip_config[ret].phys_channels;
+               indio_dev->name = pac1934_chip_config[ret].name;
+       }
+
+       if (acpi_match_device(dev->driver->acpi_match_table, dev))
+               match = pac1934_acpi_parse_channel_config(client, info);
+       else
+               /*
+                * This makes it possible to use also ACPI PRP0001 for
+                * registering the device using device tree properties.
+                */
+               match = pac1934_of_parse_channel_config(client, info);
+
+       if (!match)
+               return dev_err_probe(dev, -EINVAL,
+                                    "parameter parsing returned an error\n");
+
+       mutex_init(&info->lock);
+       ret = devm_add_action_or_reset(dev, pac1934_mutex_destroy,
+                                      &info->lock);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * do now any chip specific initialization (e.g. read/write
+        * some registers), enable/disable certain channels, change the sampling
+        * rate to the requested value
+        */
+       ret = pac1934_chip_configure(info);
+       if (ret < 0)
+               return ret;
+
+       /* prepare the channel information */
+       ret = pac1934_prep_iio_channels(info, indio_dev);
+       if (ret < 0)
+               return ret;
+
+       info->iio_info = pac1934_info;
+       indio_dev->info = &info->iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = pac1934_prep_custom_attributes(info, indio_dev);
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "Can't configure custom attributes for PAC1934 device\n");
+
+       /*
+        * read whatever has been accumulated in the chip so far
+        * and reset the accumulators
+        */
+       ret = pac1934_reg_snapshot(info, true, PAC1934_REFRESH_REG_ADDR,
+                                  PAC1934_MIN_UPDATE_WAIT_TIME_US);
+       if (ret < 0)
+               return ret;
+
+       ret = devm_iio_device_register(dev, indio_dev);
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "Can't register IIO device\n");
+
+       return 0;
+}
+
+static const struct i2c_device_id pac1934_id[] = {
+       { .name = "pac1931", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1931] },
+       { .name = "pac1932", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1932] },
+       { .name = "pac1933", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1933] },
+       { .name = "pac1934", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, pac1934_id);
+
+static const struct of_device_id pac1934_of_match[] = {
+       {
+               .compatible = "microchip,pac1931",
+               .data = &pac1934_chip_config[PAC1931]
+       },
+       {
+               .compatible = "microchip,pac1932",
+               .data = &pac1934_chip_config[PAC1932]
+       },
+       {
+               .compatible = "microchip,pac1933",
+               .data = &pac1934_chip_config[PAC1933]
+       },
+       {
+               .compatible = "microchip,pac1934",
+               .data = &pac1934_chip_config[PAC1934]
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pac1934_of_match);
+
+/*
+ * using MCHP1930 to be compatible with BIOS ACPI. See example:
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
+ */
+static const struct acpi_device_id pac1934_acpi_match[] = {
+       { "MCHP1930", .driver_data = (kernel_ulong_t)&pac1934_chip_config[PAC1934] },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, pac1934_acpi_match);
+
+static struct i2c_driver pac1934_driver = {
+       .driver  = {
+               .name = "pac1934",
+               .of_match_table = pac1934_of_match,
+               .acpi_match_table = pac1934_acpi_match
+       },
+       .probe = pac1934_probe,
+       .id_table = pac1934_id,
+};
+
+module_i2c_driver(pac1934_driver);
+
+MODULE_AUTHOR("Bogdan Bolocan <bogdan.bolocan@microchip.com>");
+MODULE_AUTHOR("Victor Tudose");
+MODULE_AUTHOR("Marius Cristea <marius.cristea@microchip.com>");
+MODULE_DESCRIPTION("IIO driver for PAC1934 Multi-Channel DC Power/Energy Monitor");
+MODULE_LICENSE("GPL");
index 01c5586df56dc87744e6b15571cb71b6ca9a9e9b..c9d2c66434e4f4489ddf46ecf7330a0ae220a0a9 100644 (file)
@@ -372,7 +372,6 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = {
  * @name: name of this channel
  * @hwchan: pointer to hardware channel information (muxing & scaling settings)
  * @calibration: whether to use absolute or ratiometric calibration
- * @scale_fn_type: scaling function type
  * @decimation: 0,1,2,3
  * @amux_ip_rsv: ratiometric scale value if using ratiometric
  * calibration: 0, 1, 2, 4, 5.
index dd94667a623bd99833792dffacec3fcf4725f53e..bbe954a738c7db13a8bfe5a881f91775a66a4766 100644 (file)
@@ -52,7 +52,7 @@
 #define SARADC2_START                  BIT(4)
 #define SARADC2_SINGLE_MODE            BIT(5)
 
-#define SARADC2_CONV_CHANNELS GENMASK(15, 0)
+#define SARADC2_CONV_CHANNELS GENMASK(3, 0)
 
 struct rockchip_saradc;
 
@@ -102,12 +102,12 @@ static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn)
        writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC);
        writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC);
        val = FIELD_PREP(SARADC2_EN_END_INT, 1);
-       val |= val << 16;
+       val |= SARADC2_EN_END_INT << 16;
        writel_relaxed(val, info->regs + SARADC2_END_INT_EN);
        val = FIELD_PREP(SARADC2_START, 1) |
              FIELD_PREP(SARADC2_SINGLE_MODE, 1) |
              FIELD_PREP(SARADC2_CONV_CHANNELS, chn);
-       val |= val << 16;
+       val |= (SARADC2_START | SARADC2_SINGLE_MODE | SARADC2_CONV_CHANNELS) << 16;
        writel(val, info->regs + SARADC2_CONV_CON);
 }
 
@@ -450,16 +450,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
         * The reset should be an optional property, as it should work
         * with old devicetrees as well
         */
-       info->reset = devm_reset_control_get_exclusive(&pdev->dev,
-                                                      "saradc-apb");
+       info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
+                                                               "saradc-apb");
        if (IS_ERR(info->reset)) {
                ret = PTR_ERR(info->reset);
-               if (ret != -ENOENT)
-                       return dev_err_probe(&pdev->dev, ret,
-                                            "failed to get saradc-apb\n");
-
-               dev_dbg(&pdev->dev, "no reset control found\n");
-               info->reset = NULL;
+               return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
        }
 
        init_completion(&info->completion);
index ad4cea6839b271de330829e5bdfc1c3d86db7e6f..a5464737e527ca1d0fe13abb0e23e4c9fe072b03 100644 (file)
 #define RTQ6056_DEFAULT_CONFIG 0x4127
 #define RTQ6056_CONT_ALLON     7
 
+#define RTQ6059_DEFAULT_CONFIG 0x3C47
+#define RTQ6059_VBUS_LSB_OFFSET        3
+#define RTQ6059_AVG_BASE       8
+
 enum {
        RTQ6056_CH_VSHUNT = 0,
        RTQ6056_CH_VBUS,
@@ -47,19 +51,46 @@ enum {
        RTQ6056_MAX_CHANNEL
 };
 
+/*
+ * The enum is to present the 0x00 CONFIG RG bitfield for the 16bit RG value
+ * field value order from LSB to MSB
+ * RTQ6053/6 is OPMODE->VSHUNTCT->VBUSCT->AVG->RESET
+ * RTQ6059 is OPMODE->SADC->BADC->PGA->RESET
+ */
 enum {
        F_OPMODE = 0,
        F_VSHUNTCT,
+       F_RTQ6059_SADC = F_VSHUNTCT,
        F_VBUSCT,
+       F_RTQ6059_BADC = F_VBUSCT,
        F_AVG,
+       F_RTQ6059_PGA = F_AVG,
        F_RESET,
        F_MAX_FIELDS
 };
 
+struct rtq6056_priv;
+
+struct richtek_dev_data {
+       bool fixed_samp_freq;
+       u8 vbus_offset;
+       int default_conv_time_us;
+       unsigned int default_config;
+       unsigned int calib_coefficient;
+       const int *avg_sample_list;
+       int avg_sample_list_length;
+       const struct reg_field *reg_fields;
+       const struct iio_chan_spec *channels;
+       int num_channels;
+       int (*read_scale)(struct iio_chan_spec const *ch, int *val, int *val2);
+       int (*set_average)(struct rtq6056_priv *priv, int val);
+};
+
 struct rtq6056_priv {
        struct device *dev;
        struct regmap *regmap;
        struct regmap_field *rm_fields[F_MAX_FIELDS];
+       const struct richtek_dev_data *devdata;
        u32 shunt_resistor_uohm;
        int vshuntct_us;
        int vbusct_us;
@@ -74,6 +105,14 @@ static const struct reg_field rtq6056_reg_fields[F_MAX_FIELDS] = {
        [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15),
 };
 
+static const struct reg_field rtq6059_reg_fields[F_MAX_FIELDS] = {
+       [F_OPMODE] = REG_FIELD(RTQ6056_REG_CONFIG, 0, 2),
+       [F_RTQ6059_SADC] = REG_FIELD(RTQ6056_REG_CONFIG, 3, 6),
+       [F_RTQ6059_BADC] = REG_FIELD(RTQ6056_REG_CONFIG, 7, 10),
+       [F_RTQ6059_PGA] = REG_FIELD(RTQ6056_REG_CONFIG, 11, 12),
+       [F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15),
+};
+
 static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = {
        {
                .type = IIO_VOLTAGE,
@@ -151,10 +190,93 @@ static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = {
        IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL),
 };
 
+/*
+ * Difference between RTQ6056 and RTQ6059
+ * - Fixed sampling conversion time
+ * - Average sample numbers
+ * - Channel scale
+ * - calibration coefficient
+ */
+static const struct iio_chan_spec rtq6059_channels[RTQ6056_MAX_CHANNEL + 1] = {
+       {
+               .type = IIO_VOLTAGE,
+               .indexed = 1,
+               .channel = 0,
+               .address = RTQ6056_REG_SHUNTVOLT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .scan_index = 0,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_CPU,
+               },
+       },
+       {
+               .type = IIO_VOLTAGE,
+               .indexed = 1,
+               .channel = 1,
+               .address = RTQ6056_REG_BUSVOLT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .scan_index = 1,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_CPU,
+               },
+       },
+       {
+               .type = IIO_POWER,
+               .indexed = 1,
+               .channel = 2,
+               .address = RTQ6056_REG_POWER,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .scan_index = 2,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_CPU,
+               },
+       },
+       {
+               .type = IIO_CURRENT,
+               .indexed = 1,
+               .channel = 3,
+               .address = RTQ6056_REG_CURRENT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .scan_index = 3,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_CPU,
+               },
+       },
+       IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL),
+};
+
 static int rtq6056_adc_read_channel(struct rtq6056_priv *priv,
                                    struct iio_chan_spec const *ch,
                                    int *val)
 {
+       const struct richtek_dev_data *devdata = priv->devdata;
        struct device *dev = priv->dev;
        unsigned int addr = ch->address;
        unsigned int regval;
@@ -168,12 +290,21 @@ static int rtq6056_adc_read_channel(struct rtq6056_priv *priv,
                return ret;
 
        /* Power and VBUS is unsigned 16-bit, others are signed 16-bit */
-       if (addr == RTQ6056_REG_BUSVOLT || addr == RTQ6056_REG_POWER)
+       switch (addr) {
+       case RTQ6056_REG_BUSVOLT:
+               regval >>= devdata->vbus_offset;
                *val = regval;
-       else
+               return IIO_VAL_INT;
+       case RTQ6056_REG_POWER:
+               *val = regval;
+               return IIO_VAL_INT;
+       case RTQ6056_REG_SHUNTVOLT:
+       case RTQ6056_REG_CURRENT:
                *val = sign_extend32(regval, 16);
-
-       return IIO_VAL_INT;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
 }
 
 static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val,
@@ -199,6 +330,28 @@ static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val,
        }
 }
 
+static int rtq6059_adc_read_scale(struct iio_chan_spec const *ch, int *val,
+                                 int *val2)
+{
+       switch (ch->address) {
+       case RTQ6056_REG_SHUNTVOLT:
+               /* VSHUNT lsb  10uV */
+               *val = 10000;
+               *val2 = 1000000;
+               return IIO_VAL_FRACTIONAL;
+       case RTQ6056_REG_BUSVOLT:
+               /* VBUS lsb 4mV */
+               *val = 4;
+               return IIO_VAL_INT;
+       case RTQ6056_REG_POWER:
+               /* Power lsb 20mW */
+               *val = 20;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
 /*
  * Sample frequency for channel VSHUNT and VBUS. The indices correspond
  * with the bit value expected by the chip. And it can be found at
@@ -248,6 +401,10 @@ static const int rtq6056_avg_sample_list[] = {
        1, 4, 16, 64, 128, 256, 512, 1024,
 };
 
+static const int rtq6059_avg_sample_list[] = {
+       1, 2, 4, 8, 16, 32, 64, 128,
+};
+
 static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val)
 {
        unsigned int selector;
@@ -268,6 +425,30 @@ static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val)
        return 0;
 }
 
+static int rtq6059_adc_set_average(struct rtq6056_priv *priv, int val)
+{
+       unsigned int selector;
+       int ret;
+
+       if (val > 128 || val < 1)
+               return -EINVAL;
+
+       /* The supported average sample is 2^x (x from 0 to 7) */
+       selector = fls(val) - 1;
+
+       ret = regmap_field_write(priv->rm_fields[F_RTQ6059_BADC],
+                                RTQ6059_AVG_BASE + selector);
+       if (ret)
+               return ret;
+
+       ret = regmap_field_write(priv->rm_fields[F_RTQ6059_SADC],
+                                RTQ6059_AVG_BASE + selector);
+
+       priv->avg_sample = BIT(selector);
+
+       return 0;
+}
+
 static int rtq6056_adc_get_sample_freq(struct rtq6056_priv *priv,
                                       struct iio_chan_spec const *ch, int *val)
 {
@@ -292,12 +473,13 @@ static int rtq6056_adc_read_raw(struct iio_dev *indio_dev,
                                int *val2, long mask)
 {
        struct rtq6056_priv *priv = iio_priv(indio_dev);
+       const struct richtek_dev_data *devdata = priv->devdata;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
                return rtq6056_adc_read_channel(priv, chan, val);
        case IIO_CHAN_INFO_SCALE:
-               return rtq6056_adc_read_scale(chan, val, val2);
+               return devdata->read_scale(chan, val, val2);
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
                *val = priv->avg_sample;
                return IIO_VAL_INT;
@@ -313,6 +495,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev,
                                  const int **vals, int *type, int *length,
                                  long mask)
 {
+       struct rtq6056_priv *priv = iio_priv(indio_dev);
+       const struct richtek_dev_data *devdata = priv->devdata;
+
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
                *vals = rtq6056_samp_freq_list;
@@ -320,9 +505,9 @@ static int rtq6056_adc_read_avail(struct iio_dev *indio_dev,
                *length = ARRAY_SIZE(rtq6056_samp_freq_list);
                return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
-               *vals = rtq6056_avg_sample_list;
+               *vals = devdata->avg_sample_list;
+               *length = devdata->avg_sample_list_length;
                *type = IIO_VAL_INT;
-               *length = ARRAY_SIZE(rtq6056_avg_sample_list);
                return IIO_AVAIL_LIST;
        default:
                return -EINVAL;
@@ -334,6 +519,7 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev,
                                 int val2, long mask)
 {
        struct rtq6056_priv *priv = iio_priv(indio_dev);
+       const struct richtek_dev_data *devdata = priv->devdata;
        int ret;
 
        ret = iio_device_claim_direct_mode(indio_dev);
@@ -342,10 +528,15 @@ static int rtq6056_adc_write_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
+               if (devdata->fixed_samp_freq) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                ret = rtq6056_adc_set_samp_freq(priv, chan, val);
                break;
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
-               ret = rtq6056_adc_set_average(priv, val);
+               ret = devdata->set_average(priv, val);
                break;
        default:
                ret = -EINVAL;
@@ -374,6 +565,7 @@ static int rtq6056_adc_read_label(struct iio_dev *indio_dev,
 static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv,
                                      int resistor_uohm)
 {
+       const struct richtek_dev_data *devdata = priv->devdata;
        unsigned int calib_val;
        int ret;
 
@@ -382,8 +574,8 @@ static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv,
                return -EINVAL;
        }
 
-       /* calibration = 5120000 / (Rshunt (uOhm) * current lsb (1mA)) */
-       calib_val = 5120000 / resistor_uohm;
+       /* calibration = coefficient / (Rshunt (uOhm) * current lsb (1mA)) */
+       calib_val = devdata->calib_coefficient / resistor_uohm;
        ret = regmap_write(priv->regmap, RTQ6056_REG_CALIBRATION, calib_val);
        if (ret)
                return ret;
@@ -450,6 +642,7 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct rtq6056_priv *priv = iio_priv(indio_dev);
+       const struct richtek_dev_data *devdata = priv->devdata;
        struct device *dev = priv->dev;
        struct {
                u16 vals[RTQ6056_MAX_CHANNEL];
@@ -469,6 +662,9 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
                if (ret)
                        goto out;
 
+               if (addr == RTQ6056_REG_BUSVOLT)
+                       raw >>= devdata->vbus_offset;
+
                data.vals[i++] = raw;
        }
 
@@ -528,20 +724,26 @@ static int rtq6056_probe(struct i2c_client *i2c)
        struct rtq6056_priv *priv;
        struct device *dev = &i2c->dev;
        struct regmap *regmap;
+       const struct richtek_dev_data *devdata;
        unsigned int vendor_id, shunt_resistor_uohm;
        int ret;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA))
                return -EOPNOTSUPP;
 
+       devdata = device_get_match_data(dev);
+       if (!devdata)
+               return dev_err_probe(dev, -EINVAL, "Invalid dev data\n");
+
        indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
        if (!indio_dev)
                return -ENOMEM;
 
        priv = iio_priv(indio_dev);
        priv->dev = dev;
-       priv->vshuntct_us = priv->vbusct_us = 1037;
+       priv->vshuntct_us = priv->vbusct_us = devdata->default_conv_time_us;
        priv->avg_sample = 1;
+       priv->devdata = devdata;
        i2c_set_clientdata(i2c, priv);
 
        regmap = devm_regmap_init_i2c(i2c, &rtq6056_regmap_config);
@@ -561,15 +763,11 @@ static int rtq6056_probe(struct i2c_client *i2c)
                                     "Invalid vendor id 0x%04x\n", vendor_id);
 
        ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->rm_fields,
-                                          rtq6056_reg_fields, F_MAX_FIELDS);
+                                          devdata->reg_fields, F_MAX_FIELDS);
        if (ret)
                return dev_err_probe(dev, ret, "Failed to init regmap field\n");
 
-       /*
-        * By default, configure average sample as 1, bus and shunt conversion
-        * time as 1037 microsecond, and operating mode to all on.
-        */
-       ret = regmap_write(regmap, RTQ6056_REG_CONFIG, RTQ6056_DEFAULT_CONFIG);
+       ret = regmap_write(regmap, RTQ6056_REG_CONFIG, devdata->default_config);
        if (ret)
                return dev_err_probe(dev, ret,
                                     "Failed to enable continuous sensing\n");
@@ -598,8 +796,8 @@ static int rtq6056_probe(struct i2c_client *i2c)
 
        indio_dev->name = "rtq6056";
        indio_dev->modes = INDIO_DIRECT_MODE;
-       indio_dev->channels = rtq6056_channels;
-       indio_dev->num_channels = ARRAY_SIZE(rtq6056_channels);
+       indio_dev->channels = devdata->channels;
+       indio_dev->num_channels = devdata->num_channels;
        indio_dev->info = &rtq6056_info;
 
        ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
@@ -640,8 +838,45 @@ static int rtq6056_runtime_resume(struct device *dev)
 static DEFINE_RUNTIME_DEV_PM_OPS(rtq6056_pm_ops, rtq6056_runtime_suspend,
                                 rtq6056_runtime_resume, NULL);
 
+static const struct richtek_dev_data rtq6056_devdata = {
+       .default_conv_time_us = 1037,
+       .calib_coefficient = 5120000,
+       /*
+        * By default, configure average sample as 1, bus and shunt conversion
+        * time as 1037 microsecond, and operating mode to all on.
+        */
+       .default_config = RTQ6056_DEFAULT_CONFIG,
+       .avg_sample_list = rtq6056_avg_sample_list,
+       .avg_sample_list_length = ARRAY_SIZE(rtq6056_avg_sample_list),
+       .reg_fields = rtq6056_reg_fields,
+       .channels = rtq6056_channels,
+       .num_channels = ARRAY_SIZE(rtq6056_channels),
+       .read_scale = rtq6056_adc_read_scale,
+       .set_average = rtq6056_adc_set_average,
+};
+
+static const struct richtek_dev_data rtq6059_devdata = {
+       .fixed_samp_freq = true,
+       .vbus_offset = RTQ6059_VBUS_LSB_OFFSET,
+       .default_conv_time_us = 532,
+       .calib_coefficient = 40960000,
+       /*
+        * By default, configure average sample as 1, bus and shunt conversion
+        * time as 532 microsecond, and operating mode to all on.
+        */
+       .default_config = RTQ6059_DEFAULT_CONFIG,
+       .avg_sample_list = rtq6059_avg_sample_list,
+       .avg_sample_list_length = ARRAY_SIZE(rtq6059_avg_sample_list),
+       .reg_fields = rtq6059_reg_fields,
+       .channels = rtq6059_channels,
+       .num_channels = ARRAY_SIZE(rtq6059_channels),
+       .read_scale = rtq6059_adc_read_scale,
+       .set_average = rtq6059_adc_set_average,
+};
+
 static const struct of_device_id rtq6056_device_match[] = {
-       { .compatible = "richtek,rtq6056" },
+       { .compatible = "richtek,rtq6056", .data = &rtq6056_devdata },
+       { .compatible = "richtek,rtq6059", .data = &rtq6059_devdata },
        {}
 };
 MODULE_DEVICE_TABLE(of, rtq6056_device_match);
index c82a161630e1d97d5e9073e811d437215c325a43..69fcbbc7e418a8022da249595932e332d85a2b14 100644 (file)
@@ -293,13 +293,11 @@ static const struct of_device_id adc108s102_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, adc108s102_of_match);
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id adc108s102_acpi_ids[] = {
        { "INT3495", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids);
-#endif
 
 static const struct spi_device_id adc108s102_id[] = {
        { "adc108s102", 0 },
@@ -311,7 +309,7 @@ static struct spi_driver adc108s102_driver = {
        .driver = {
                .name   = "adc108s102",
                .of_match_table = adc108s102_of_match,
-               .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
+               .acpi_match_table = adc108s102_acpi_ids,
        },
        .probe          = adc108s102_probe,
        .id_table       = adc108s102_id,
index 6799ea49dbc73c9b5b1ffa7518df3004e66befb7..6ae967e4d8fa761451281110e073467c51486df9 100644 (file)
@@ -925,7 +925,7 @@ static int ads1015_client_get_channels_config(struct i2c_client *client)
 
                if (!fwnode_property_read_u32(node, "ti,gain", &pval)) {
                        pga = pval;
-                       if (pga > 6) {
+                       if (pga > 5) {
                                dev_err(dev, "invalid gain on %pfw\n", node);
                                fwnode_handle_put(node);
                                return -EINVAL;
diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c
new file mode 100644 (file)
index 0000000..1d1eaba
--- /dev/null
@@ -0,0 +1,771 @@
+// SPDX-License-Identifier: GPL-2.0
+/* TI ADS1298 chip family driver
+ * Copyright (C) 2023 - 2024 Topic Embedded Products
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/log2.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#include <asm/unaligned.h>
+
+/* Commands */
+#define ADS1298_CMD_WAKEUP     0x02
+#define ADS1298_CMD_STANDBY    0x04
+#define ADS1298_CMD_RESET      0x06
+#define ADS1298_CMD_START      0x08
+#define ADS1298_CMD_STOP       0x0a
+#define ADS1298_CMD_RDATAC     0x10
+#define ADS1298_CMD_SDATAC     0x11
+#define ADS1298_CMD_RDATA      0x12
+#define ADS1298_CMD_RREG       0x20
+#define ADS1298_CMD_WREG       0x40
+
+/* Registers */
+#define ADS1298_REG_ID         0x00
+#define ADS1298_MASK_ID_FAMILY                 GENMASK(7, 3)
+#define ADS1298_MASK_ID_CHANNELS               GENMASK(2, 0)
+#define ADS1298_ID_FAMILY_ADS129X              0x90
+#define ADS1298_ID_FAMILY_ADS129XR             0xd0
+
+#define ADS1298_REG_CONFIG1    0x01
+#define ADS1298_MASK_CONFIG1_HR                        BIT(7)
+#define ADS1298_MASK_CONFIG1_DR                        GENMASK(2, 0)
+#define ADS1298_SHIFT_DR_HR                    6
+#define ADS1298_SHIFT_DR_LP                    7
+#define ADS1298_LOWEST_DR                      0x06
+
+#define ADS1298_REG_CONFIG2    0x02
+#define ADS1298_MASK_CONFIG2_RESERVED          BIT(6)
+#define ADS1298_MASK_CONFIG2_WCT_CHOP          BIT(5)
+#define ADS1298_MASK_CONFIG2_INT_TEST          BIT(4)
+#define ADS1298_MASK_CONFIG2_TEST_AMP          BIT(2)
+#define ADS1298_MASK_CONFIG2_TEST_FREQ_DC      GENMASK(1, 0)
+#define ADS1298_MASK_CONFIG2_TEST_FREQ_SLOW    0
+#define ADS1298_MASK_CONFIG2_TEST_FREQ_FAST    BIT(0)
+
+#define ADS1298_REG_CONFIG3    0x03
+#define ADS1298_MASK_CONFIG3_PWR_REFBUF                BIT(7)
+#define ADS1298_MASK_CONFIG3_RESERVED          BIT(6)
+#define ADS1298_MASK_CONFIG3_VREF_4V           BIT(5)
+
+#define ADS1298_REG_LOFF       0x04
+#define ADS1298_REG_CHnSET(n)  (0x05 + n)
+#define ADS1298_MASK_CH_PD             BIT(7)
+#define ADS1298_MASK_CH_PGA            GENMASK(6, 4)
+#define ADS1298_MASK_CH_MUX            GENMASK(2, 0)
+
+#define ADS1298_REG_LOFF_STATP 0x12
+#define ADS1298_REG_LOFF_STATN 0x13
+#define ADS1298_REG_CONFIG4    0x17
+#define ADS1298_MASK_CONFIG4_SINGLE_SHOT       BIT(3)
+
+#define ADS1298_REG_WCT1       0x18
+#define ADS1298_REG_WCT2       0x19
+
+#define ADS1298_MAX_CHANNELS   8
+#define ADS1298_BITS_PER_SAMPLE        24
+#define ADS1298_CLK_RATE_HZ    2048000
+#define ADS1298_CLOCKS_TO_USECS(x) \
+               (DIV_ROUND_UP((x) * MICROHZ_PER_HZ, ADS1298_CLK_RATE_HZ))
+/*
+ * Read/write register commands require 4 clocks to decode, for speeds above
+ * 2x the clock rate, this would require extra time between the command byte and
+ * the data. Much simpler is to just limit the SPI transfer speed while doing
+ * register access.
+ */
+#define ADS1298_SPI_BUS_SPEED_SLOW     ADS1298_CLK_RATE_HZ
+/* For reading and writing registers, we need a 3-byte buffer */
+#define ADS1298_SPI_CMD_BUFFER_SIZE    3
+/* Outputs status word and 'n' 24-bit samples, plus the command byte */
+#define ADS1298_SPI_RDATA_BUFFER_SIZE(n)       (((n) + 1) * 3 + 1)
+#define ADS1298_SPI_RDATA_BUFFER_SIZE_MAX \
+               ADS1298_SPI_RDATA_BUFFER_SIZE(ADS1298_MAX_CHANNELS)
+
+struct ads1298_private {
+       const struct ads1298_chip_info *chip_info;
+       struct spi_device *spi;
+       struct regulator *reg_avdd;
+       struct regulator *reg_vref;
+       struct clk *clk;
+       struct regmap *regmap;
+       struct completion completion;
+       struct iio_trigger *trig;
+       struct spi_transfer rdata_xfer;
+       struct spi_message rdata_msg;
+       spinlock_t irq_busy_lock; /* Handshake between SPI and DRDY irqs */
+       /*
+        * rdata_xfer_busy increments when a DRDY occurs and decrements when SPI
+        * completion is reported. Hence its meaning is:
+        * 0 = Waiting for DRDY interrupt
+        * 1 = SPI transfer in progress
+        * 2 = DRDY during SPI transfer, start another transfer on completion
+        * >2 = Multiple DRDY during transfer, lost rdata_xfer_busy - 2 samples
+        */
+       unsigned int rdata_xfer_busy;
+
+       /* Temporary storage for demuxing data after SPI transfer */
+       u32 bounce_buffer[ADS1298_MAX_CHANNELS];
+
+       /* For synchronous SPI exchanges (read/write registers) */
+       u8 cmd_buffer[ADS1298_SPI_CMD_BUFFER_SIZE] __aligned(IIO_DMA_MINALIGN);
+
+       /* Buffer used for incoming SPI data */
+       u8 rx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX];
+       /* Contains the RDATA command and zeroes to clock out */
+       u8 tx_buffer[ADS1298_SPI_RDATA_BUFFER_SIZE_MAX];
+};
+
+/* Three bytes per sample in RX buffer, starting at offset 4 */
+#define ADS1298_OFFSET_IN_RX_BUFFER(index)     (3 * (index) + 4)
+
+#define ADS1298_CHAN(index)                            \
+{                                                      \
+       .type = IIO_VOLTAGE,                            \
+       .indexed = 1,                                   \
+       .channel = index,                               \
+       .address = ADS1298_OFFSET_IN_RX_BUFFER(index),  \
+       .info_mask_separate =                           \
+               BIT(IIO_CHAN_INFO_RAW) |                \
+               BIT(IIO_CHAN_INFO_SCALE),               \
+       .info_mask_shared_by_all =                      \
+               BIT(IIO_CHAN_INFO_SAMP_FREQ) |          \
+               BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),  \
+       .scan_index = index,                            \
+       .scan_type = {                                  \
+               .sign = 's',                            \
+               .realbits = ADS1298_BITS_PER_SAMPLE,    \
+               .storagebits = 32,                      \
+               .endianness = IIO_CPU,                  \
+       },                                              \
+}
+
+static const struct iio_chan_spec ads1298_channels[] = {
+       ADS1298_CHAN(0),
+       ADS1298_CHAN(1),
+       ADS1298_CHAN(2),
+       ADS1298_CHAN(3),
+       ADS1298_CHAN(4),
+       ADS1298_CHAN(5),
+       ADS1298_CHAN(6),
+       ADS1298_CHAN(7),
+};
+
+static int ads1298_write_cmd(struct ads1298_private *priv, u8 command)
+{
+       struct spi_transfer xfer = {
+               .tx_buf = priv->cmd_buffer,
+               .rx_buf = priv->cmd_buffer,
+               .len = 1,
+               .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW,
+               .delay = {
+                       .value = 2,
+                       .unit = SPI_DELAY_UNIT_USECS,
+               },
+       };
+
+       priv->cmd_buffer[0] = command;
+
+       return spi_sync_transfer(priv->spi, &xfer, 1);
+}
+
+static int ads1298_read_one(struct ads1298_private *priv, int chan_index)
+{
+       int ret;
+
+       /* Enable the channel */
+       ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(chan_index),
+                                ADS1298_MASK_CH_PD, 0);
+       if (ret)
+               return ret;
+
+       /* Enable single-shot mode, so we don't need to send a STOP */
+       ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4,
+                                ADS1298_MASK_CONFIG4_SINGLE_SHOT,
+                                ADS1298_MASK_CONFIG4_SINGLE_SHOT);
+       if (ret)
+               return ret;
+
+       reinit_completion(&priv->completion);
+
+       ret = ads1298_write_cmd(priv, ADS1298_CMD_START);
+       if (ret < 0) {
+               dev_err(&priv->spi->dev, "CMD_START error: %d\n", ret);
+               return ret;
+       }
+
+       /* Cannot take longer than 40ms (250Hz) */
+       ret = wait_for_completion_timeout(&priv->completion, msecs_to_jiffies(50));
+       if (!ret)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int ads1298_get_samp_freq(struct ads1298_private *priv, int *val)
+{
+       unsigned long rate;
+       unsigned int cfg;
+       int ret;
+
+       ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, &cfg);
+       if (ret)
+               return ret;
+
+       if (priv->clk)
+               rate = clk_get_rate(priv->clk);
+       else
+               rate = ADS1298_CLK_RATE_HZ;
+       if (!rate)
+               return -EINVAL;
+
+       /* Data rate shift depends on HR/LP mode */
+       if (cfg & ADS1298_MASK_CONFIG1_HR)
+               rate >>= ADS1298_SHIFT_DR_HR;
+       else
+               rate >>= ADS1298_SHIFT_DR_LP;
+
+       *val = rate >> (cfg & ADS1298_MASK_CONFIG1_DR);
+
+       return IIO_VAL_INT;
+}
+
+static int ads1298_set_samp_freq(struct ads1298_private *priv, int val)
+{
+       unsigned long rate;
+       unsigned int factor;
+       unsigned int cfg;
+
+       if (priv->clk)
+               rate = clk_get_rate(priv->clk);
+       else
+               rate = ADS1298_CLK_RATE_HZ;
+       if (!rate)
+               return -EINVAL;
+       if (val <= 0)
+               return -EINVAL;
+
+       factor = (rate >> ADS1298_SHIFT_DR_HR) / val;
+       if (factor >= BIT(ADS1298_SHIFT_DR_LP))
+               cfg = ADS1298_LOWEST_DR;
+       else if (factor)
+               cfg = ADS1298_MASK_CONFIG1_HR | ilog2(factor); /* Use HR mode */
+       else
+               cfg = ADS1298_MASK_CONFIG1_HR; /* Fastest possible */
+
+       return regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG1,
+                                 ADS1298_MASK_CONFIG1_HR | ADS1298_MASK_CONFIG1_DR,
+                                 cfg);
+}
+
+static const u8 ads1298_pga_settings[] = { 6, 1, 2, 3, 4, 8, 12 };
+
+static int ads1298_get_scale(struct ads1298_private *priv,
+                            int channel, int *val, int *val2)
+{
+       int ret;
+       unsigned int regval;
+       u8 gain;
+
+       if (priv->reg_vref) {
+               ret = regulator_get_voltage(priv->reg_vref);
+               if (ret < 0)
+                       return ret;
+
+               *val = ret / MILLI; /* Convert to millivolts */
+       } else {
+               ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG3, &regval);
+               if (ret)
+                       return ret;
+
+               /* Refererence in millivolts */
+               *val = regval & ADS1298_MASK_CONFIG3_VREF_4V ? 4000 : 2400;
+       }
+
+       ret = regmap_read(priv->regmap, ADS1298_REG_CHnSET(channel), &regval);
+       if (ret)
+               return ret;
+
+       gain = ads1298_pga_settings[FIELD_GET(ADS1298_MASK_CH_PGA, regval)];
+       *val /= gain; /* Full scale is VREF / gain */
+
+       *val2 = ADS1298_BITS_PER_SAMPLE - 1; /* Signed, hence the -1 */
+
+       return IIO_VAL_FRACTIONAL_LOG2;
+}
+
+static int ads1298_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = ads1298_read_one(priv, chan->scan_index);
+
+               iio_device_release_direct_mode(indio_dev);
+
+               if (ret)
+                       return ret;
+
+               *val = sign_extend32(get_unaligned_be24(priv->rx_buffer + chan->address),
+                                    ADS1298_BITS_PER_SAMPLE - 1);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               return ads1298_get_scale(priv, chan->channel, val, val2);
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return ads1298_get_samp_freq(priv, val);
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               ret = regmap_read(priv->regmap, ADS1298_REG_CONFIG1, val);
+               if (ret)
+                       return ret;
+
+               *val = 16 << (*val & ADS1298_MASK_CONFIG1_DR);
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ads1298_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan, int val,
+                            int val2, long mask)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return ads1298_set_samp_freq(priv, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ads1298_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct ads1298_private *priv = context;
+       struct spi_transfer reg_write_xfer = {
+               .tx_buf = priv->cmd_buffer,
+               .rx_buf = priv->cmd_buffer,
+               .len = 3,
+               .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW,
+               .delay = {
+                       .value = 2,
+                       .unit = SPI_DELAY_UNIT_USECS,
+               },
+       };
+
+       priv->cmd_buffer[0] = ADS1298_CMD_WREG | reg;
+       priv->cmd_buffer[1] = 0; /* Number of registers to be written - 1 */
+       priv->cmd_buffer[2] = val;
+
+       return spi_sync_transfer(priv->spi, &reg_write_xfer, 1);
+}
+
+static int ads1298_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct ads1298_private *priv = context;
+       struct spi_transfer reg_read_xfer = {
+               .tx_buf = priv->cmd_buffer,
+               .rx_buf = priv->cmd_buffer,
+               .len = 3,
+               .speed_hz = ADS1298_SPI_BUS_SPEED_SLOW,
+               .delay = {
+                       .value = 2,
+                       .unit = SPI_DELAY_UNIT_USECS,
+               },
+       };
+       int ret;
+
+       priv->cmd_buffer[0] = ADS1298_CMD_RREG | reg;
+       priv->cmd_buffer[1] = 0; /* Number of registers to be read - 1 */
+       priv->cmd_buffer[2] = 0;
+
+       ret = spi_sync_transfer(priv->spi, &reg_read_xfer, 1);
+       if (ret)
+               return ret;
+
+       *val = priv->cmd_buffer[2];
+
+       return 0;
+}
+
+static int ads1298_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+                             unsigned int writeval, unsigned int *readval)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(priv->regmap, reg, readval);
+
+       return regmap_write(priv->regmap, reg, writeval);
+}
+
+static void ads1298_rdata_unmark_busy(struct ads1298_private *priv)
+{
+       /* Notify we're no longer waiting for the SPI transfer to complete */
+       guard(spinlock_irqsave)(&priv->irq_busy_lock);
+       priv->rdata_xfer_busy = 0;
+}
+
+static int ads1298_update_scan_mode(struct iio_dev *indio_dev,
+                                   const unsigned long *scan_mask)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+       unsigned int val;
+       int ret;
+       int i;
+
+       /* Make the interrupt routines start with a clean slate */
+       ads1298_rdata_unmark_busy(priv);
+
+       /* Configure power-down bits to match scan mask */
+       for (i = 0; i < indio_dev->num_channels; i++) {
+               val = test_bit(i, scan_mask) ? 0 : ADS1298_MASK_CH_PD;
+               ret = regmap_update_bits(priv->regmap, ADS1298_REG_CHnSET(i),
+                                        ADS1298_MASK_CH_PD, val);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static const struct iio_info ads1298_info = {
+       .read_raw = &ads1298_read_raw,
+       .write_raw = &ads1298_write_raw,
+       .update_scan_mode = &ads1298_update_scan_mode,
+       .debugfs_reg_access = &ads1298_reg_access,
+};
+
+static void ads1298_rdata_release_busy_or_restart(struct ads1298_private *priv)
+{
+       guard(spinlock_irqsave)(&priv->irq_busy_lock);
+
+       if (priv->rdata_xfer_busy > 1) {
+               /*
+                * DRDY interrupt occurred before SPI completion. Start a new
+                * SPI transaction now to retrieve the data that wasn't latched
+                * into the ADS1298 chip's transfer buffer yet.
+                */
+               spi_async(priv->spi, &priv->rdata_msg);
+               /*
+                * If more than one DRDY took place, there was an overrun. Since
+                * the sample is already lost, reset the counter to 1 so that
+                * we will wait for a DRDY interrupt after this SPI transaction.
+                */
+               priv->rdata_xfer_busy = 1;
+       } else {
+               /* No pending data, wait for DRDY */
+               priv->rdata_xfer_busy = 0;
+       }
+}
+
+/* Called from SPI completion interrupt handler */
+static void ads1298_rdata_complete(void *context)
+{
+       struct iio_dev *indio_dev = context;
+       struct ads1298_private *priv = iio_priv(indio_dev);
+       int scan_index;
+       u32 *bounce = priv->bounce_buffer;
+
+       if (!iio_buffer_enabled(indio_dev)) {
+               /*
+                * for a single transfer mode we're kept in direct_mode until
+                * completion, avoiding a race with buffered IO.
+                */
+               ads1298_rdata_unmark_busy(priv);
+               complete(&priv->completion);
+               return;
+       }
+
+       /* Demux the channel data into our bounce buffer */
+       for_each_set_bit(scan_index, indio_dev->active_scan_mask,
+                        indio_dev->masklength) {
+               const struct iio_chan_spec *scan_chan =
+                                       &indio_dev->channels[scan_index];
+               const u8 *data = priv->rx_buffer + scan_chan->address;
+
+               *bounce++ = get_unaligned_be24(data);
+       }
+
+       /* rx_buffer can be overwritten from this point on */
+       ads1298_rdata_release_busy_or_restart(priv);
+
+       iio_push_to_buffers(indio_dev, priv->bounce_buffer);
+}
+
+static irqreturn_t ads1298_interrupt(int irq, void *dev_id)
+{
+       struct iio_dev *indio_dev = dev_id;
+       struct ads1298_private *priv = iio_priv(indio_dev);
+       unsigned int wasbusy;
+
+       guard(spinlock_irqsave)(&priv->irq_busy_lock);
+
+       wasbusy = priv->rdata_xfer_busy++;
+       /* When no SPI transfer in transit, start one now */
+       if (!wasbusy)
+               spi_async(priv->spi, &priv->rdata_msg);
+
+       return IRQ_HANDLED;
+};
+
+static int ads1298_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+       int ret;
+
+       /* Disable single-shot mode */
+       ret = regmap_update_bits(priv->regmap, ADS1298_REG_CONFIG4,
+                                ADS1298_MASK_CONFIG4_SINGLE_SHOT, 0);
+       if (ret)
+               return ret;
+
+       return ads1298_write_cmd(priv, ADS1298_CMD_START);
+}
+
+static int ads1298_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+
+       return ads1298_write_cmd(priv, ADS1298_CMD_STOP);
+}
+
+static const struct iio_buffer_setup_ops ads1298_setup_ops = {
+       .postenable = &ads1298_buffer_postenable,
+       .predisable = &ads1298_buffer_predisable,
+};
+
+static void ads1298_reg_disable(void *reg)
+{
+       regulator_disable(reg);
+}
+
+static const struct regmap_range ads1298_regmap_volatile_range[] = {
+       regmap_reg_range(ADS1298_REG_LOFF_STATP, ADS1298_REG_LOFF_STATN),
+};
+
+static const struct regmap_access_table ads1298_regmap_volatile = {
+       .yes_ranges = ads1298_regmap_volatile_range,
+       .n_yes_ranges = ARRAY_SIZE(ads1298_regmap_volatile_range),
+};
+
+static const struct regmap_config ads1298_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .reg_read = ads1298_reg_read,
+       .reg_write = ads1298_reg_write,
+       .max_register = ADS1298_REG_WCT2,
+       .volatile_table = &ads1298_regmap_volatile,
+       .cache_type = REGCACHE_MAPLE,
+};
+
+static int ads1298_init(struct iio_dev *indio_dev)
+{
+       struct ads1298_private *priv = iio_priv(indio_dev);
+       struct device *dev = &priv->spi->dev;
+       const char *suffix;
+       unsigned int val;
+       int ret;
+
+       /* Device initializes into RDATAC mode, which we don't want */
+       ret = ads1298_write_cmd(priv, ADS1298_CMD_SDATAC);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(priv->regmap, ADS1298_REG_ID, &val);
+       if (ret)
+               return ret;
+
+       /* Fill in name and channel count based on what the chip told us */
+       indio_dev->num_channels = 4 + 2 * (val & ADS1298_MASK_ID_CHANNELS);
+       switch (val & ADS1298_MASK_ID_FAMILY) {
+       case ADS1298_ID_FAMILY_ADS129X:
+               suffix = "";
+               break;
+       case ADS1298_ID_FAMILY_ADS129XR:
+               suffix = "r";
+               break;
+       default:
+               return dev_err_probe(dev, -ENODEV, "Unknown ID: 0x%x\n", val);
+       }
+       indio_dev->name = devm_kasprintf(dev, GFP_KERNEL, "ads129%u%s",
+                                        indio_dev->num_channels, suffix);
+
+       /* Enable internal test signal, double amplitude, double frequency */
+       ret = regmap_write(priv->regmap, ADS1298_REG_CONFIG2,
+                          ADS1298_MASK_CONFIG2_RESERVED |
+                          ADS1298_MASK_CONFIG2_INT_TEST |
+                          ADS1298_MASK_CONFIG2_TEST_AMP |
+                          ADS1298_MASK_CONFIG2_TEST_FREQ_FAST);
+       if (ret)
+               return ret;
+
+       val = ADS1298_MASK_CONFIG3_RESERVED; /* Must write 1 always */
+       if (!priv->reg_vref) {
+               /* Enable internal reference */
+               val |= ADS1298_MASK_CONFIG3_PWR_REFBUF;
+               /* Use 4V VREF when power supply is at least 4.4V */
+               if (regulator_get_voltage(priv->reg_avdd) >= 4400000)
+                       val |= ADS1298_MASK_CONFIG3_VREF_4V;
+       }
+       return regmap_write(priv->regmap, ADS1298_REG_CONFIG3, val);
+}
+
+static int ads1298_probe(struct spi_device *spi)
+{
+       struct ads1298_private *priv;
+       struct iio_dev *indio_dev;
+       struct device *dev = &spi->dev;
+       struct gpio_desc *reset_gpio;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       priv = iio_priv(indio_dev);
+
+       /* Reset to be asserted before enabling clock and power */
+       reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(reset_gpio))
+               return dev_err_probe(dev, PTR_ERR(reset_gpio),
+                                    "Cannot get reset GPIO\n");
+
+       /* VREF can be supplied externally, otherwise use internal reference */
+       priv->reg_vref = devm_regulator_get_optional(dev, "vref");
+       if (IS_ERR(priv->reg_vref)) {
+               if (PTR_ERR(priv->reg_vref) != -ENODEV)
+                       return dev_err_probe(dev, PTR_ERR(priv->reg_vref),
+                                            "Failed to get vref regulator\n");
+
+               priv->reg_vref = NULL;
+       } else {
+               ret = regulator_enable(priv->reg_vref);
+               if (ret)
+                       return ret;
+
+               ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_vref);
+               if (ret)
+                       return ret;
+       }
+
+       priv->clk = devm_clk_get_optional_enabled(dev, "clk");
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clk\n");
+
+       priv->reg_avdd = devm_regulator_get(dev, "avdd");
+       if (IS_ERR(priv->reg_avdd))
+               return dev_err_probe(dev, PTR_ERR(priv->reg_avdd),
+                                    "Failed to get avdd regulator\n");
+
+       ret = regulator_enable(priv->reg_avdd);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to enable avdd regulator\n");
+
+       ret = devm_add_action_or_reset(dev, ads1298_reg_disable, priv->reg_avdd);
+       if (ret)
+               return ret;
+
+       priv->spi = spi;
+       init_completion(&priv->completion);
+       spin_lock_init(&priv->irq_busy_lock);
+       priv->regmap = devm_regmap_init(dev, NULL, priv, &ads1298_regmap_config);
+       if (IS_ERR(priv->regmap))
+               return PTR_ERR(priv->regmap);
+
+       indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+       indio_dev->channels = ads1298_channels;
+       indio_dev->info = &ads1298_info;
+
+       if (reset_gpio) {
+               /*
+                * Deassert reset now that clock and power are active.
+                * Minimum reset pulsewidth is 2 clock cycles.
+                */
+               fsleep(ADS1298_CLOCKS_TO_USECS(2));
+               gpiod_set_value_cansleep(reset_gpio, 0);
+       } else {
+               ret = ads1298_write_cmd(priv, ADS1298_CMD_RESET);
+               if (ret)
+                       return dev_err_probe(dev, ret, "RESET failed\n");
+       }
+       /* Wait 18 clock cycles for reset command to complete */
+       fsleep(ADS1298_CLOCKS_TO_USECS(18));
+
+       ret = ads1298_init(indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "Init failed\n");
+
+       priv->tx_buffer[0] = ADS1298_CMD_RDATA;
+       priv->rdata_xfer.tx_buf = priv->tx_buffer;
+       priv->rdata_xfer.rx_buf = priv->rx_buffer;
+       priv->rdata_xfer.len = ADS1298_SPI_RDATA_BUFFER_SIZE(indio_dev->num_channels);
+       /* Must keep CS low for 4 clocks */
+       priv->rdata_xfer.delay.value = 2;
+       priv->rdata_xfer.delay.unit = SPI_DELAY_UNIT_USECS;
+       spi_message_init_with_transfers(&priv->rdata_msg, &priv->rdata_xfer, 1);
+       priv->rdata_msg.complete = &ads1298_rdata_complete;
+       priv->rdata_msg.context = indio_dev;
+
+       ret = devm_request_irq(dev, spi->irq, &ads1298_interrupt,
+                              IRQF_TRIGGER_FALLING, indio_dev->name,
+                              indio_dev);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &ads1298_setup_ops);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id ads1298_id[] = {
+       { "ads1298" },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ads1298_id);
+
+static const struct of_device_id ads1298_of_table[] = {
+       { .compatible = "ti,ads1298" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ads1298_of_table);
+
+static struct spi_driver ads1298_driver = {
+       .driver = {
+               .name   = "ads1298",
+               .of_match_table = ads1298_of_table,
+       },
+       .probe          = ads1298_probe,
+       .id_table       = ads1298_id,
+};
+module_spi_driver(ads1298_driver);
+
+MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
+MODULE_DESCRIPTION("TI ADS1298 ADC");
+MODULE_LICENSE("GPL");
index ef06a897421ac4fdac4e042ffde1a4f7a56b7d6f..9440a268a78c4316139b66f4479cc7d916073841 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
index ed4d72922696197b8a160a42fdc6c72db1b6d696..2ee4c0d70281e24c1c818249b86d89ebe06d4876 100644 (file)
@@ -2,9 +2,10 @@
 /*
  * HMC425A and similar Gain Amplifiers
  *
- * Copyright 2020 Analog Devices Inc.
+ * Copyright 2020, 2024 Analog Devices Inc.
  */
 
+#include <linux/bits.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -12,6 +13,7 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/kernel.h>
+#include <linux/math.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/sysfs.h>
 
+/*
+ * The LTC6373 amplifier supports configuring gain using GPIO's with the following
+ *  values (OUTPUT_V / INPUT_V): 0(shutdown), 0.25, 0.5, 1, 2, 4, 8, 16
+ *
+ * Except for the shutdown value, all can be converted to dB using 20 * log10(x)
+ * From here, it is observed that all values are multiples of the '2' gain setting,
+ *  with the correspondent of 6.020dB.
+ */
+#define LTC6373_CONVERSION_CONSTANT    6020
+#define LTC6373_MIN_GAIN_CODE          0x6
+#define LTC6373_CONVERSION_MASK                GENMASK(2, 0)
+#define LTC6373_SHUTDOWN               GENMASK(2, 0)
+
 enum hmc425a_type {
        ID_HMC425A,
        ID_HMC540S,
-       ID_ADRF5740
+       ID_ADRF5740,
+       ID_LTC6373,
 };
 
 struct hmc425a_chip_info {
@@ -34,16 +50,110 @@ struct hmc425a_chip_info {
        int                             gain_min;
        int                             gain_max;
        int                             default_gain;
+       int                             powerdown_val;
+       bool                            has_powerdown;
+
+       int                             (*gain_dB_to_code)(int gain, int *code);
+       int                             (*code_to_gain_dB)(int code, int *val, int *val2);
 };
 
 struct hmc425a_state {
        struct  mutex lock; /* protect sensor state */
-       struct  hmc425a_chip_info *chip_info;
+       const struct    hmc425a_chip_info *chip_info;
        struct  gpio_descs *gpios;
-       enum    hmc425a_type type;
        u32     gain;
+       bool    powerdown;
 };
 
+static int gain_dB_to_code(struct hmc425a_state *st, int val, int val2, int *code)
+{
+       const struct hmc425a_chip_info *inf = st->chip_info;
+       int gain;
+
+       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;
+       if (st->powerdown)
+               return -EPERM;
+
+       return st->chip_info->gain_dB_to_code(gain, code);
+}
+
+static int hmc425a_gain_dB_to_code(int gain, int *code)
+{
+       *code = ~((abs(gain) / 500) & 0x3F);
+       return 0;
+}
+
+static int hmc540s_gain_dB_to_code(int gain, int *code)
+{
+       *code = ~((abs(gain) / 1000) & 0xF);
+       return 0;
+}
+
+static int adrf5740_gain_dB_to_code(int gain, int *code)
+{
+       int temp = (abs(gain) / 2000) & 0xF;
+
+       /* Bit [0-3]: 2dB 4dB 8dB 8dB */
+       *code = temp & BIT(3) ? temp | BIT(2) : temp;
+       return 0;
+}
+
+static int ltc6373_gain_dB_to_code(int gain, int *code)
+{
+       *code = ~(DIV_ROUND_CLOSEST(gain, LTC6373_CONVERSION_CONSTANT) + 3)
+               & LTC6373_CONVERSION_MASK;
+       return 0;
+}
+
+static int code_to_gain_dB(struct hmc425a_state *st, int *val, int *val2)
+{
+       if (st->powerdown)
+               return -EPERM;
+       return st->chip_info->code_to_gain_dB(st->gain, val, val2);
+}
+
+static int hmc425a_code_to_gain_dB(int code, int *val, int *val2)
+{
+       *val = (~code * -500) / 1000;
+       *val2 = ((~code * -500) % 1000) * 1000;
+       return 0;
+}
+
+static int hmc540s_code_to_gain_dB(int code, int *val, int *val2)
+{
+       *val = (~code * -1000) / 1000;
+       *val2 = ((~code * -1000) % 1000) * 1000;
+       return 0;
+}
+
+static int adrf5740_code_to_gain_dB(int code, int *val, int *val2)
+{
+       /*
+        * Bit [0-3]: 2dB 4dB 8dB 8dB
+        * When BIT(3) is set, unset BIT(2) and use 3 as double the place value
+        */
+       code = code & BIT(3) ? code & ~BIT(2) : code;
+       *val = (code * -2000) / 1000;
+       *val2 = ((code * -2000) % 1000) * 1000;
+       return 0;
+}
+
+static int ltc6373_code_to_gain_dB(int code, int *val, int *val2)
+{
+       int gain = ((~code & LTC6373_CONVERSION_MASK) - 3) *
+                  LTC6373_CONVERSION_CONSTANT;
+
+       *val = gain / 1000;
+       *val2 = (gain % 1000) * 1000;
+       return 0;
+}
+
 static int hmc425a_write(struct iio_dev *indio_dev, u32 value)
 {
        struct hmc425a_state *st = iio_priv(indio_dev);
@@ -61,30 +171,14 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev,
                            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;
+               ret = code_to_gain_dB(st, val, val2);
+               if (ret)
                        break;
-               case ID_HMC540S:
-                       gain = ~code * -1000;
-                       break;
-               case ID_ADRF5740:
-                       code = code & BIT(3) ? code & ~BIT(2) : code;
-                       gain = code * -2000;
-                       break;
-               }
-
-               *val = gain / 1000;
-               *val2 = (gain % 1000) * 1000;
-
                ret = IIO_VAL_INT_PLUS_MICRO_DB;
                break;
        default:
@@ -100,34 +194,14 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev,
                             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;
-       case ID_HMC540S:
-               code = ~((abs(gain) / 1000) & 0xF);
-               break;
-       case ID_ADRF5740:
-               code = (abs(gain) / 2000) & 0xF;
-               code = code & BIT(3) ? code | BIT(2) : code;
-               break;
-       }
+       int code = 0, ret;
 
        mutex_lock(&st->lock);
        switch (mask) {
        case IIO_CHAN_INFO_HARDWAREGAIN:
+               ret = gain_dB_to_code(st, val, val2, &code);
+               if (ret)
+                       break;
                st->gain = code;
 
                ret = hmc425a_write(indio_dev, st->gain);
@@ -158,6 +232,48 @@ static const struct iio_info hmc425a_info = {
        .write_raw_get_fmt = &hmc425a_write_raw_get_fmt,
 };
 
+static ssize_t ltc6373_read_powerdown(struct iio_dev *indio_dev,
+                                     uintptr_t private,
+                                     const struct iio_chan_spec *chan,
+                                     char *buf)
+{
+       struct hmc425a_state *st = iio_priv(indio_dev);
+
+       return sysfs_emit(buf, "%d\n", st->powerdown);
+}
+
+static ssize_t ltc6373_write_powerdown(struct iio_dev *indio_dev,
+                                      uintptr_t private,
+                                      const struct iio_chan_spec *chan,
+                                      const char *buf,
+                                      size_t len)
+{
+       struct hmc425a_state *st = iio_priv(indio_dev);
+       bool powerdown;
+       int code, ret;
+
+       ret = kstrtobool(buf, &powerdown);
+       if (ret)
+               return ret;
+
+       mutex_lock(&st->lock);
+       st->powerdown = powerdown;
+       code = (powerdown) ? LTC6373_SHUTDOWN : st->gain;
+       hmc425a_write(indio_dev, code);
+       mutex_unlock(&st->lock);
+       return len;
+}
+
+static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = {
+       {
+               .name = "powerdown",
+               .read = ltc6373_read_powerdown,
+               .write = ltc6373_write_powerdown,
+               .shared = IIO_SEPARATE,
+       },
+       {}
+};
+
 #define HMC425A_CHAN(_channel)                                         \
 {                                                                      \
        .type = IIO_VOLTAGE,                                            \
@@ -167,20 +283,25 @@ static const struct iio_info hmc425a_info = {
        .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),          \
 }
 
+#define LTC6373_CHAN(_channel)                                         \
+{                                                                      \
+       .type = IIO_VOLTAGE,                                            \
+       .output = 1,                                                    \
+       .indexed = 1,                                                   \
+       .channel = _channel,                                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),          \
+       .ext_info = ltc6373_ext_info,                                   \
+}
+
 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 },
-       { .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S },
-       { .compatible = "adi,adrf5740", .data = (void *)ID_ADRF5740 },
-       {},
+static const struct iio_chan_spec ltc6373_channels[] = {
+       LTC6373_CHAN(0),
 };
-MODULE_DEVICE_TABLE(of, hmc425a_of_match);
 
-static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
+static const struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
        [ID_HMC425A] = {
                .name = "hmc425a",
                .channels = hmc425a_channels,
@@ -189,6 +310,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
                .gain_min = -31500,
                .gain_max = 0,
                .default_gain = -0x40, /* set default gain -31.5db*/
+               .gain_dB_to_code = hmc425a_gain_dB_to_code,
+               .code_to_gain_dB = hmc425a_code_to_gain_dB,
        },
        [ID_HMC540S] = {
                .name = "hmc540s",
@@ -198,6 +321,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
                .gain_min = -15000,
                .gain_max = 0,
                .default_gain = -0x10, /* set default gain -15.0db*/
+               .gain_dB_to_code = hmc540s_gain_dB_to_code,
+               .code_to_gain_dB = hmc540s_code_to_gain_dB,
        },
        [ID_ADRF5740] = {
                .name = "adrf5740",
@@ -207,6 +332,21 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
                .gain_min = -22000,
                .gain_max = 0,
                .default_gain = 0xF, /* set default gain -22.0db*/
+               .gain_dB_to_code = adrf5740_gain_dB_to_code,
+               .code_to_gain_dB = adrf5740_code_to_gain_dB,
+       },
+       [ID_LTC6373] = {
+               .name = "ltc6373",
+               .channels = ltc6373_channels,
+               .num_channels = ARRAY_SIZE(ltc6373_channels),
+               .num_gpios = 3,
+               .gain_min = -12041, /* gain setting x0.25*/
+               .gain_max = 24082,  /* gain setting x16  */
+               .default_gain = LTC6373_MIN_GAIN_CODE,
+               .powerdown_val = LTC6373_SHUTDOWN,
+               .has_powerdown = true,
+               .gain_dB_to_code = ltc6373_gain_dB_to_code,
+               .code_to_gain_dB = ltc6373_code_to_gain_dB,
        },
 };
 
@@ -221,9 +361,8 @@ static int hmc425a_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        st = iio_priv(indio_dev);
-       st->type = (uintptr_t)device_get_match_data(&pdev->dev);
 
-       st->chip_info = &hmc425a_chip_info_tbl[st->type];
+       st->chip_info = device_get_match_data(&pdev->dev);
        indio_dev->num_channels = st->chip_info->num_channels;
        indio_dev->channels = st->chip_info->channels;
        indio_dev->name = st->chip_info->name;
@@ -249,12 +388,31 @@ static int hmc425a_probe(struct platform_device *pdev)
        indio_dev->info = &hmc425a_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       /* Set default gain */
-       hmc425a_write(indio_dev, st->gain);
+       if (st->chip_info->has_powerdown) {
+               st->powerdown = true;
+               hmc425a_write(indio_dev, st->chip_info->powerdown_val);
+       } else {
+               /* Set default gain */
+               hmc425a_write(indio_dev, st->gain);
+       }
 
        return devm_iio_device_register(&pdev->dev, indio_dev);
 }
 
+/* Match table for of_platform binding */
+static const struct of_device_id hmc425a_of_match[] = {
+       { .compatible = "adi,hmc425a",
+         .data = &hmc425a_chip_info_tbl[ID_HMC425A]},
+       { .compatible = "adi,hmc540s",
+         .data = &hmc425a_chip_info_tbl[ID_HMC540S]},
+       { .compatible = "adi,adrf5740",
+         .data = &hmc425a_chip_info_tbl[ID_ADRF5740]},
+       { .compatible = "adi,ltc6373",
+         .data = &hmc425a_chip_info_tbl[ID_LTC6373]},
+       {}
+};
+MODULE_DEVICE_TABLE(of, hmc425a_of_match);
+
 static struct platform_driver hmc425a_driver = {
        .driver = {
                .name = KBUILD_MODNAME,
index 5f85ba38e6f6e7a052ebd59b2aa5a0aed14d6bf4..a18c1da292af22822adab6504c9d58929d598c73 100644 (file)
@@ -159,7 +159,7 @@ static const struct iio_dev_attr *iio_dmaengine_buffer_attrs[] = {
  * Once done using the buffer iio_dmaengine_buffer_free() should be used to
  * release it.
  */
-static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
        const char *channel)
 {
        struct dmaengine_buffer *dmaengine_buffer;
@@ -210,6 +210,7 @@ err_free:
        kfree(dmaengine_buffer);
        return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_alloc, IIO_DMAENGINE_BUFFER);
 
 /**
  * iio_dmaengine_buffer_free() - Free dmaengine buffer
@@ -217,7 +218,7 @@ err_free:
  *
  * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc().
  */
-static void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
 {
        struct dmaengine_buffer *dmaengine_buffer =
                iio_buffer_to_dmaengine_buffer(buffer);
@@ -227,6 +228,7 @@ static void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
 
        iio_buffer_put(buffer);
 }
+EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER);
 
 static void __devm_iio_dmaengine_buffer_free(void *buffer)
 {
@@ -279,8 +281,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev,
 {
        struct iio_buffer *buffer;
 
-       buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent,
-                                                channel);
+       buffer = devm_iio_dmaengine_buffer_alloc(dev, channel);
        if (IS_ERR(buffer))
                return PTR_ERR(buffer);
 
@@ -288,7 +289,7 @@ int devm_iio_dmaengine_buffer_setup(struct device *dev,
 
        return iio_device_attach_buffer(indio_dev, buffer);
 }
-EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_setup);
+EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup, IIO_DMAENGINE_BUFFER);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("DMA buffer for the IIO framework");
index b5cf15a515d251a3cb4d862cf7a11ba82596baa8..43025866d5b791c1418898272d2cb2fa53bd125a 100644 (file)
@@ -211,8 +211,8 @@ static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
        return checksum == pms7003_calc_checksum(frame);
 }
 
-static ssize_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf,
-                                  size_t size)
+static size_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf,
+                                 size_t size)
 {
        struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
        struct pms7003_state *state = iio_priv(indio_dev);
index a47654591e555fcf107e5c23180438b99921a15d..2adb76dbb0209edc24c5f20c3c2c01bf609afe41 100644 (file)
@@ -174,8 +174,8 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u
        return 0;
 }
 
-static ssize_t scd30_serdev_receive_buf(struct serdev_device *serdev,
-                                       const u8 *buf, size_t size)
+static size_t scd30_serdev_receive_buf(struct serdev_device *serdev,
+                                      const u8 *buf, size_t size)
 {
        struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
        struct scd30_serdev_priv *priv;
index 3afa89f8acc329c73cf39f22cec98251a32d6120..a6dfbe28c914c7f6e8a3adacf14019447272e21e 100644 (file)
@@ -210,8 +210,8 @@ static int sps30_serial_command(struct sps30_state *state, unsigned char cmd,
        return rsp_size;
 }
 
-static ssize_t sps30_serial_receive_buf(struct serdev_device *serdev,
-                                       const u8 *buf, size_t size)
+static size_t sps30_serial_receive_buf(struct serdev_device *serdev,
+                                      const u8 *buf, size_t size)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
        struct sps30_serial_priv *priv;
index 03823ee57f5980521f7afe86e5baf4ac02450586..3b0f9598a7c773dd1364a901c81bee32527cd78e 100644 (file)
@@ -126,7 +126,7 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
        struct inv_sensors_timestamp_interval *it;
        int64_t delta, interval;
        const uint32_t fifo_mult = fifo_period / ts->chip.clock_period;
-       uint32_t period = ts->period;
+       uint32_t period;
        bool valid = false;
 
        if (fifo_nb == 0)
index 8a0480d338450a8ccabd2be253b0877cee7bd4fa..782e8f6b77829bf8041bed92f32c1aafc0c47e0a 100644 (file)
@@ -17,7 +17,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
 #include <linux/spi/spi.h>
 
 #include <linux/iio/iio.h>
index 5a0072727ba4b1f3c57a858c6cb0042937c75763..16d3f144dda040cbb5fa2ff9a5b8d04ae6fd8978 100644 (file)
@@ -31,8 +31,6 @@
  * @regs: irq regs we are faking
  * @lock: protect the evgen state
  * @inuse: mask of which irqs are connected
- * @irq_sim: interrupt simulator
- * @base: base of irq range
  * @irq_sim_domain: irq simulator domain
  */
 struct iio_dummy_eventgen {
index c24f609c2ade6df37b48bb0bc6517eb2ea4d410a..09efacaf8f78de397583873295c88019b5983562 100644 (file)
@@ -283,65 +283,63 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
                              long mask)
 {
        struct iio_dummy_state *st = iio_priv(indio_dev);
-       int ret = -EINVAL;
 
-       mutex_lock(&st->lock);
        switch (mask) {
        case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       if (chan->output) {
-                               /* Set integer part to cached value */
-                               *val = st->dac_val;
-                               ret = IIO_VAL_INT;
-                       } else if (chan->differential) {
-                               if (chan->channel == 1)
-                                       *val = st->differential_adc_val[0];
-                               else
-                                       *val = st->differential_adc_val[1];
-                               ret = IIO_VAL_INT;
-                       } else {
-                               *val = st->single_ended_adc_val;
-                               ret = IIO_VAL_INT;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+                       guard(mutex)(&st->lock);
+                       switch (chan->type) {
+                       case IIO_VOLTAGE:
+                               if (chan->output) {
+                                       /* Set integer part to cached value */
+                                       *val = st->dac_val;
+                                       return IIO_VAL_INT;
+                               } else if (chan->differential) {
+                                       if (chan->channel == 1)
+                                               *val = st->differential_adc_val[0];
+                                       else
+                                               *val = st->differential_adc_val[1];
+                                       return IIO_VAL_INT;
+                               } else {
+                                       *val = st->single_ended_adc_val;
+                                       return IIO_VAL_INT;
+                               }
+
+                       case IIO_ACCEL:
+                               *val = st->accel_val;
+                               return IIO_VAL_INT;
+                       default:
+                               return -EINVAL;
                        }
-                       break;
-               case IIO_ACCEL:
-                       *val = st->accel_val;
-                       ret = IIO_VAL_INT;
-                       break;
-               default:
-                       break;
                }
-               break;
+               unreachable();
        case IIO_CHAN_INFO_PROCESSED:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       *val = st->steps;
-                       ret = IIO_VAL_INT;
-                       break;
-               case IIO_ACTIVITY:
-                       switch (chan->channel2) {
-                       case IIO_MOD_RUNNING:
-                               *val = st->activity_running;
-                               ret = IIO_VAL_INT;
-                               break;
-                       case IIO_MOD_WALKING:
-                               *val = st->activity_walking;
-                               ret = IIO_VAL_INT;
-                               break;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
+                       guard(mutex)(&st->lock);
+                       switch (chan->type) {
+                       case IIO_STEPS:
+                               *val = st->steps;
+                               return IIO_VAL_INT;
+                       case IIO_ACTIVITY:
+                               switch (chan->channel2) {
+                               case IIO_MOD_RUNNING:
+                                       *val = st->activity_running;
+                                       return IIO_VAL_INT;
+                               case IIO_MOD_WALKING:
+                                       *val = st->activity_walking;
+                                       return IIO_VAL_INT;
+                               default:
+                                       return -EINVAL;
+                               }
                        default:
-                               break;
+                               return -EINVAL;
                        }
-                       break;
-               default:
-                       break;
                }
-               break;
+               unreachable();
        case IIO_CHAN_INFO_OFFSET:
                /* only single ended adc -> 7 */
                *val = 7;
-               ret = IIO_VAL_INT;
-               break;
+               return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
                switch (chan->type) {
                case IIO_VOLTAGE:
@@ -350,60 +348,57 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
                                /* only single ended adc -> 0.001333 */
                                *val = 0;
                                *val2 = 1333;
-                               ret = IIO_VAL_INT_PLUS_MICRO;
-                               break;
+                               return IIO_VAL_INT_PLUS_MICRO;
                        case 1:
                                /* all differential adc -> 0.000001344 */
                                *val = 0;
                                *val2 = 1344;
-                               ret = IIO_VAL_INT_PLUS_NANO;
+                               return IIO_VAL_INT_PLUS_NANO;
+                       default:
+                               return -EINVAL;
                        }
-                       break;
                default:
-                       break;
+                       return -EINVAL;
                }
-               break;
-       case IIO_CHAN_INFO_CALIBBIAS:
+       case IIO_CHAN_INFO_CALIBBIAS: {
+               guard(mutex)(&st->lock);
                /* only the acceleration axis - read from cache */
                *val = st->accel_calibbias;
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_CALIBSCALE:
+               return IIO_VAL_INT;
+       }
+       case IIO_CHAN_INFO_CALIBSCALE: {
+               guard(mutex)(&st->lock);
                *val = st->accel_calibscale->val;
                *val2 = st->accel_calibscale->val2;
-               ret = IIO_VAL_INT_PLUS_MICRO;
-               break;
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
        case IIO_CHAN_INFO_SAMP_FREQ:
                *val = 3;
                *val2 = 33;
-               ret = IIO_VAL_INT_PLUS_NANO;
-               break;
-       case IIO_CHAN_INFO_ENABLE:
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_ENABLE: {
+               guard(mutex)(&st->lock);
                switch (chan->type) {
                case IIO_STEPS:
                        *val = st->steps_enabled;
-                       ret = IIO_VAL_INT;
-                       break;
+                       return IIO_VAL_INT;
                default:
-                       break;
+                       return -EINVAL;
                }
-               break;
-       case IIO_CHAN_INFO_CALIBHEIGHT:
+       }
+       case IIO_CHAN_INFO_CALIBHEIGHT: {
+               guard(mutex)(&st->lock);
                switch (chan->type) {
                case IIO_STEPS:
                        *val = st->height;
-                       ret = IIO_VAL_INT;
-                       break;
+                       return IIO_VAL_INT;
                default:
-                       break;
+                       return -EINVAL;
                }
-               break;
-
+       }
        default:
-               break;
+               return -EINVAL;
        }
-       mutex_unlock(&st->lock);
-       return ret;
 }
 
 /**
@@ -426,7 +421,6 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
                               long mask)
 {
        int i;
-       int ret = 0;
        struct iio_dummy_state *st = iio_priv(indio_dev);
 
        switch (mask) {
@@ -436,10 +430,10 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
                        if (chan->output == 0)
                                return -EINVAL;
 
-                       /* Locking not required as writing single value */
-                       mutex_lock(&st->lock);
-                       st->dac_val = val;
-                       mutex_unlock(&st->lock);
+                       scoped_guard(mutex, &st->lock) {
+                               /* Locking not required as writing single value */
+                               st->dac_val = val;
+                       }
                        return 0;
                default:
                        return -EINVAL;
@@ -447,9 +441,9 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_PROCESSED:
                switch (chan->type) {
                case IIO_STEPS:
-                       mutex_lock(&st->lock);
-                       st->steps = val;
-                       mutex_unlock(&st->lock);
+                       scoped_guard(mutex, &st->lock) {
+                               st->steps = val;
+                       }
                        return 0;
                case IIO_ACTIVITY:
                        if (val < 0)
@@ -470,30 +464,29 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
                default:
                        return -EINVAL;
                }
-       case IIO_CHAN_INFO_CALIBSCALE:
-               mutex_lock(&st->lock);
+       case IIO_CHAN_INFO_CALIBSCALE: {
+               guard(mutex)(&st->lock);
                /* Compare against table - hard matching here */
                for (i = 0; i < ARRAY_SIZE(dummy_scales); i++)
                        if (val == dummy_scales[i].val &&
                            val2 == dummy_scales[i].val2)
                                break;
                if (i == ARRAY_SIZE(dummy_scales))
-                       ret = -EINVAL;
-               else
-                       st->accel_calibscale = &dummy_scales[i];
-               mutex_unlock(&st->lock);
-               return ret;
+                       return -EINVAL;
+               st->accel_calibscale = &dummy_scales[i];
+               return 0;
+       }
        case IIO_CHAN_INFO_CALIBBIAS:
-               mutex_lock(&st->lock);
-               st->accel_calibbias = val;
-               mutex_unlock(&st->lock);
+               scoped_guard(mutex, &st->lock) {
+                       st->accel_calibbias = val;
+               }
                return 0;
        case IIO_CHAN_INFO_ENABLE:
                switch (chan->type) {
                case IIO_STEPS:
-                       mutex_lock(&st->lock);
-                       st->steps_enabled = val;
-                       mutex_unlock(&st->lock);
+                       scoped_guard(mutex, &st->lock) {
+                               st->steps_enabled = val;
+                       }
                        return 0;
                default:
                        return -EINVAL;
index 9e85dfa585081cc02167a410cf4f353ec4cdc4a9..c455be7d4a1c888ff1ec215c1e361830addc0639 100644 (file)
@@ -60,6 +60,16 @@ config ADF4377
          To compile this driver as a module, choose M here: the
          module will be called adf4377.
 
+config ADMFM2000
+       tristate "Analog Devices ADMFM2000 Dual Microwave Down Converter"
+       depends on GPIOLIB
+       help
+         Say yes here to build support for Analog Devices ADMFM2000 Dual
+         Microwave Down Converter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called admfm2000.
+
 config ADMV1013
        tristate "Analog Devices ADMV1013 Microwave Upconverter"
        depends on SPI && COMMON_CLK
index b616c29b4a08736515242558aa2d2c8645b55552..70d0e0b70e8021cf10cf0ed5a3ecbc70fb0b2ac8 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_AD9523) += ad9523.o
 obj-$(CONFIG_ADF4350) += adf4350.o
 obj-$(CONFIG_ADF4371) += adf4371.o
 obj-$(CONFIG_ADF4377) += adf4377.o
+obj-$(CONFIG_ADMFM2000) += admfm2000.o
 obj-$(CONFIG_ADMV1013) += admv1013.o
 obj-$(CONFIG_ADMV1014) += admv1014.o
 obj-$(CONFIG_ADMV4420) += admv4420.o
diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c
new file mode 100644 (file)
index 0000000..c34d79e
--- /dev/null
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ADMFM2000 Dual Microwave Down Converter
+ *
+ * Copyright 2024 Analog Devices Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define ADMFM2000_MIXER_MODE           0
+#define ADMFM2000_DIRECT_IF_MODE       1
+#define ADMFM2000_DSA_GPIOS            5
+#define ADMFM2000_MODE_GPIOS           2
+#define ADMFM2000_MAX_GAIN             0
+#define ADMFM2000_MIN_GAIN             -31000
+#define ADMFM2000_DEFAULT_GAIN         -0x20
+
+struct admfm2000_state {
+       struct mutex                    lock; /* protect sensor state */
+       struct gpio_desc                *sw1_ch[2];
+       struct gpio_desc                *sw2_ch[2];
+       struct gpio_desc                *dsa1_gpios[5];
+       struct gpio_desc                *dsa2_gpios[5];
+       u32                             gain[2];
+};
+
+static int admfm2000_mode(struct iio_dev *indio_dev, u32 chan, u32 mode)
+{
+       struct admfm2000_state *st = iio_priv(indio_dev);
+       int i;
+
+       switch (mode) {
+       case ADMFM2000_MIXER_MODE:
+               for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) {
+                       gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 1 : 0);
+                       gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 0 : 1);
+               }
+               return 0;
+       case ADMFM2000_DIRECT_IF_MODE:
+               for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) {
+                       gpiod_set_value_cansleep(st->sw1_ch[i], (chan == 0) ? 0 : 1);
+                       gpiod_set_value_cansleep(st->sw2_ch[i], (chan == 0) ? 1 : 0);
+               }
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int admfm2000_attenuation(struct iio_dev *indio_dev, u32 chan, u32 value)
+{
+       struct admfm2000_state *st = iio_priv(indio_dev);
+       int i;
+
+       switch (chan) {
+       case 0:
+               for (i = 0; i < ADMFM2000_DSA_GPIOS; i++)
+                       gpiod_set_value_cansleep(st->dsa1_gpios[i], value & (1 << i));
+               return 0;
+       case 1:
+               for (i = 0; i < ADMFM2000_DSA_GPIOS; i++)
+                       gpiod_set_value_cansleep(st->dsa2_gpios[i], value & (1 << i));
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int admfm2000_read_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan, int *val,
+                             int *val2, long mask)
+{
+       struct admfm2000_state *st = iio_priv(indio_dev);
+       int gain;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               mutex_lock(&st->lock);
+               gain = ~(st->gain[chan->channel]) * -1000;
+               *val = gain / 1000;
+               *val2 = (gain % 1000) * 1000;
+               mutex_unlock(&st->lock);
+
+               return IIO_VAL_INT_PLUS_MICRO_DB;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int admfm2000_write_raw(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan, int val,
+                              int val2, long mask)
+{
+       struct admfm2000_state *st = iio_priv(indio_dev);
+       int gain, ret;
+
+       if (val < 0)
+               gain = (val * 1000) - (val2 / 1000);
+       else
+               gain = (val * 1000) + (val2 / 1000);
+
+       if (gain > ADMFM2000_MAX_GAIN || gain < ADMFM2000_MIN_GAIN)
+               return -EINVAL;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               mutex_lock(&st->lock);
+               st->gain[chan->channel] = ~((abs(gain) / 1000) & 0x1F);
+
+               ret = admfm2000_attenuation(indio_dev, chan->channel,
+                                           st->gain[chan->channel]);
+               mutex_unlock(&st->lock);
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int admfm2000_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 admfm2000_info = {
+       .read_raw = &admfm2000_read_raw,
+       .write_raw = &admfm2000_write_raw,
+       .write_raw_get_fmt = &admfm2000_write_raw_get_fmt,
+};
+
+#define ADMFM2000_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 admfm2000_channels[] = {
+       ADMFM2000_CHAN(0),
+       ADMFM2000_CHAN(1),
+};
+
+static int admfm2000_channel_config(struct admfm2000_state *st,
+                                   struct iio_dev *indio_dev)
+{
+       struct platform_device *pdev = to_platform_device(indio_dev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct fwnode_handle *child;
+       struct gpio_desc **dsa;
+       struct gpio_desc **sw;
+       int ret, i;
+       bool mode;
+       u32 reg;
+
+       device_for_each_child_node(dev, child) {
+               ret = fwnode_property_read_u32(child, "reg", &reg);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(dev, ret,
+                                            "Failed to get reg property\n");
+               }
+
+               if (reg >= indio_dev->num_channels) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(dev, -EINVAL, "reg bigger than: %d\n",
+                                            indio_dev->num_channels);
+               }
+
+               if (fwnode_property_present(child, "adi,mixer-mode"))
+                       mode = ADMFM2000_MIXER_MODE;
+               else
+                       mode = ADMFM2000_DIRECT_IF_MODE;
+
+               switch (reg) {
+               case 0:
+                       sw = st->sw1_ch;
+                       dsa = st->dsa1_gpios;
+                       break;
+               case 1:
+                       sw = st->sw2_ch;
+                       dsa = st->dsa2_gpios;
+                       break;
+               default:
+                       fwnode_handle_put(child);
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < ADMFM2000_MODE_GPIOS; i++) {
+                       sw[i] = devm_fwnode_gpiod_get_index(dev, child, "switch",
+                                                           i, GPIOD_OUT_LOW, NULL);
+                       if (IS_ERR(sw[i])) {
+                               fwnode_handle_put(child);
+                               return dev_err_probe(dev, PTR_ERR(sw[i]),
+                                                    "Failed to get gpios\n");
+                       }
+               }
+
+               for (i = 0; i < ADMFM2000_DSA_GPIOS; i++) {
+                       dsa[i] = devm_fwnode_gpiod_get_index(dev, child,
+                                                            "attenuation", i,
+                                                            GPIOD_OUT_LOW, NULL);
+                       if (IS_ERR(dsa[i])) {
+                               fwnode_handle_put(child);
+                               return dev_err_probe(dev, PTR_ERR(dsa[i]),
+                                                    "Failed to get gpios\n");
+                       }
+               }
+
+               ret = admfm2000_mode(indio_dev, reg, mode);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int admfm2000_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct admfm2000_state *st;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+
+       indio_dev->name = "admfm2000";
+       indio_dev->num_channels = ARRAY_SIZE(admfm2000_channels);
+       indio_dev->channels = admfm2000_channels;
+       indio_dev->info = &admfm2000_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       st->gain[0] = ADMFM2000_DEFAULT_GAIN;
+       st->gain[1] = ADMFM2000_DEFAULT_GAIN;
+
+       mutex_init(&st->lock);
+
+       ret = admfm2000_channel_config(st, indio_dev);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id admfm2000_of_match[] = {
+       { .compatible = "adi,admfm2000" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, admfm2000_of_match);
+
+static struct platform_driver admfm2000_driver = {
+       .driver = {
+               .name = "admfm2000",
+               .of_match_table = admfm2000_of_match,
+       },
+       .probe = admfm2000_probe,
+};
+module_platform_driver(admfm2000_driver);
+
+MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>");
+MODULE_DESCRIPTION("ADMFM2000 Dual Microwave Down Converter");
+MODULE_LICENSE("GPL");
index 2f9675596138b2663fd00a8c844183ea4c4cd710..9c8e20c25e96bde54b29595c36dfc96ec25df07a 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/regmap.h>
 #include <linux/iio/iio.h>
 #include <linux/module.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
 
 #include "bmg160.h"
 
@@ -66,7 +66,7 @@ MODULE_DEVICE_TABLE(of, bmg160_of_match);
 static struct i2c_driver bmg160_i2c_driver = {
        .driver = {
                .name   = "bmg160_i2c",
-               .acpi_match_table = ACPI_PTR(bmg160_acpi_match),
+               .acpi_match_table = bmg160_acpi_match,
                .of_match_table = bmg160_of_match,
                .pm     = &bmg160_pm_ops,
        },
index df3bc5c3d3786d05c0e3ed4896e8d464a5ede396..1dbe48dae74eedbd7226f9e46b06240cafebdeb3 100644 (file)
@@ -346,6 +346,13 @@ err:
        return IRQ_HANDLED;
 }
 
+static void afe4403_regulator_disable(void *data)
+{
+       struct regulator *regulator = data;
+
+       regulator_disable(regulator);
+}
+
 #define AFE4403_TIMING_PAIRS                   \
        { AFE440X_LED2STC,      0x000050 },     \
        { AFE440X_LED2ENDC,     0x0003e7 },     \
@@ -495,19 +502,24 @@ static int afe4403_probe(struct spi_device *spi)
                dev_err(afe->dev, "Unable to enable regulator\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(afe->dev, afe4403_regulator_disable, afe->regulator);
+       if (ret) {
+               dev_err(afe->dev, "Unable to add regulator disable action\n");
+               return ret;
+       }
 
        ret = regmap_write(afe->regmap, AFE440X_CONTROL0,
                           AFE440X_CONTROL0_SW_RESET);
        if (ret) {
                dev_err(afe->dev, "Unable to reset device\n");
-               goto err_disable_reg;
+               return ret;
        }
 
        ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences,
                                     ARRAY_SIZE(afe4403_reg_sequences));
        if (ret) {
                dev_err(afe->dev, "Unable to set register defaults\n");
-               goto err_disable_reg;
+               return ret;
        }
 
        indio_dev->modes = INDIO_DIRECT_MODE;
@@ -523,16 +535,15 @@ static int afe4403_probe(struct spi_device *spi)
                                                   iio_device_id(indio_dev));
                if (!afe->trig) {
                        dev_err(afe->dev, "Unable to allocate IIO trigger\n");
-                       ret = -ENOMEM;
-                       goto err_disable_reg;
+                       return -ENOMEM;
                }
 
                iio_trigger_set_drvdata(afe->trig, indio_dev);
 
-               ret = iio_trigger_register(afe->trig);
+               ret = devm_iio_trigger_register(afe->dev, afe->trig);
                if (ret) {
                        dev_err(afe->dev, "Unable to register IIO trigger\n");
-                       goto err_disable_reg;
+                       return ret;
                }
 
                ret = devm_request_threaded_irq(afe->dev, afe->irq,
@@ -542,52 +553,25 @@ static int afe4403_probe(struct spi_device *spi)
                                                afe->trig);
                if (ret) {
                        dev_err(afe->dev, "Unable to request IRQ\n");
-                       goto err_trig;
+                       return ret;
                }
        }
 
-       ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
-                                        afe4403_trigger_handler, NULL);
+       ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev,
+                                             &iio_pollfunc_store_time,
+                                             afe4403_trigger_handler, NULL);
        if (ret) {
                dev_err(afe->dev, "Unable to setup buffer\n");
-               goto err_trig;
+               return ret;
        }
 
-       ret = iio_device_register(indio_dev);
+       ret = devm_iio_device_register(afe->dev, indio_dev);
        if (ret) {
                dev_err(afe->dev, "Unable to register IIO device\n");
-               goto err_buff;
+               return ret;
        }
 
        return 0;
-
-err_buff:
-       iio_triggered_buffer_cleanup(indio_dev);
-err_trig:
-       if (afe->irq > 0)
-               iio_trigger_unregister(afe->trig);
-err_disable_reg:
-       regulator_disable(afe->regulator);
-
-       return ret;
-}
-
-static void afe4403_remove(struct spi_device *spi)
-{
-       struct iio_dev *indio_dev = spi_get_drvdata(spi);
-       struct afe4403_data *afe = iio_priv(indio_dev);
-       int ret;
-
-       iio_device_unregister(indio_dev);
-
-       iio_triggered_buffer_cleanup(indio_dev);
-
-       if (afe->irq > 0)
-               iio_trigger_unregister(afe->trig);
-
-       ret = regulator_disable(afe->regulator);
-       if (ret)
-               dev_warn(afe->dev, "Unable to disable regulator\n");
 }
 
 static const struct spi_device_id afe4403_ids[] = {
@@ -603,7 +587,6 @@ static struct spi_driver afe4403_spi_driver = {
                .pm = pm_sleep_ptr(&afe4403_pm_ops),
        },
        .probe = afe4403_probe,
-       .remove = afe4403_remove,
        .id_table = afe4403_ids,
 };
 module_spi_driver(afe4403_spi_driver);
index ede1e82013118c24c005ec4fa7a33c88f373525d..7768b07ef7a6f887ed0d43af928836dfaf24653d 100644 (file)
@@ -349,6 +349,13 @@ err:
        return IRQ_HANDLED;
 }
 
+static void afe4404_regulator_disable(void *data)
+{
+       struct regulator *regulator = data;
+
+       regulator_disable(regulator);
+}
+
 /* Default timings from data-sheet */
 #define AFE4404_TIMING_PAIRS                   \
        { AFE440X_PRPCOUNT,     39999   },      \
@@ -502,19 +509,24 @@ static int afe4404_probe(struct i2c_client *client)
                dev_err(afe->dev, "Unable to enable regulator\n");
                return ret;
        }
+       ret = devm_add_action_or_reset(afe->dev, afe4404_regulator_disable, afe->regulator);
+       if (ret) {
+               dev_err(afe->dev, "Unable to enable regulator\n");
+               return ret;
+       }
 
        ret = regmap_write(afe->regmap, AFE440X_CONTROL0,
                           AFE440X_CONTROL0_SW_RESET);
        if (ret) {
                dev_err(afe->dev, "Unable to reset device\n");
-               goto disable_reg;
+               return ret;
        }
 
        ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences,
                                     ARRAY_SIZE(afe4404_reg_sequences));
        if (ret) {
                dev_err(afe->dev, "Unable to set register defaults\n");
-               goto disable_reg;
+               return ret;
        }
 
        indio_dev->modes = INDIO_DIRECT_MODE;
@@ -530,16 +542,15 @@ static int afe4404_probe(struct i2c_client *client)
                                                   iio_device_id(indio_dev));
                if (!afe->trig) {
                        dev_err(afe->dev, "Unable to allocate IIO trigger\n");
-                       ret = -ENOMEM;
-                       goto disable_reg;
+                       return -ENOMEM;
                }
 
                iio_trigger_set_drvdata(afe->trig, indio_dev);
 
-               ret = iio_trigger_register(afe->trig);
+               ret = devm_iio_trigger_register(afe->dev, afe->trig);
                if (ret) {
                        dev_err(afe->dev, "Unable to register IIO trigger\n");
-                       goto disable_reg;
+                       return ret;
                }
 
                ret = devm_request_threaded_irq(afe->dev, afe->irq,
@@ -549,52 +560,25 @@ static int afe4404_probe(struct i2c_client *client)
                                                afe->trig);
                if (ret) {
                        dev_err(afe->dev, "Unable to request IRQ\n");
-                       goto disable_reg;
+                       return ret;
                }
        }
 
-       ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
-                                        afe4404_trigger_handler, NULL);
+       ret = devm_iio_triggered_buffer_setup(afe->dev, indio_dev,
+                                             &iio_pollfunc_store_time,
+                                             afe4404_trigger_handler, NULL);
        if (ret) {
                dev_err(afe->dev, "Unable to setup buffer\n");
-               goto unregister_trigger;
+               return ret;
        }
 
-       ret = iio_device_register(indio_dev);
+       ret = devm_iio_device_register(afe->dev, indio_dev);
        if (ret) {
                dev_err(afe->dev, "Unable to register IIO device\n");
-               goto unregister_triggered_buffer;
+               return ret;
        }
 
        return 0;
-
-unregister_triggered_buffer:
-       iio_triggered_buffer_cleanup(indio_dev);
-unregister_trigger:
-       if (afe->irq > 0)
-               iio_trigger_unregister(afe->trig);
-disable_reg:
-       regulator_disable(afe->regulator);
-
-       return ret;
-}
-
-static void afe4404_remove(struct i2c_client *client)
-{
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
-       struct afe4404_data *afe = iio_priv(indio_dev);
-       int ret;
-
-       iio_device_unregister(indio_dev);
-
-       iio_triggered_buffer_cleanup(indio_dev);
-
-       if (afe->irq > 0)
-               iio_trigger_unregister(afe->trig);
-
-       ret = regulator_disable(afe->regulator);
-       if (ret)
-               dev_err(afe->dev, "Unable to disable regulator\n");
 }
 
 static const struct i2c_device_id afe4404_ids[] = {
@@ -610,7 +594,6 @@ static struct i2c_driver afe4404_i2c_driver = {
                .pm = pm_sleep_ptr(&afe4404_pm_ops),
        },
        .probe = afe4404_probe,
-       .remove = afe4404_remove,
        .id_table = afe4404_ids,
 };
 module_i2c_driver(afe4404_i2c_driver);
index ed70415512f687b6333078f9416b9a0fd6edbfdb..1e5d0d4797b16eeac76698c20160ad01271c19e8 100644 (file)
@@ -5,41 +5,66 @@
  *
  * Copyright (C) 2023
  *
+ * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
+ *
  * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf
  */
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/cleanup.h>
 #include <linux/crc8.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/units.h>
 
 #include <asm/unaligned.h>
 
+#include <linux/iio/events.h>
 #include <linux/iio/iio.h>
 
-#define HDC3020_HEATER_CMD_MSB         0x30 /* shared by all heater commands */
-#define HDC3020_HEATER_ENABLE          0x6D
-#define HDC3020_HEATER_DISABLE         0x66
-#define HDC3020_HEATER_CONFIG          0x6E
+#define HDC3020_S_AUTO_10HZ_MOD0       0x2737
+#define HDC3020_S_STATUS               0x3041
+#define HDC3020_HEATER_DISABLE         0x3066
+#define HDC3020_HEATER_ENABLE          0x306D
+#define HDC3020_HEATER_CONFIG          0x306E
+#define HDC3020_EXIT_AUTO              0x3093
+#define HDC3020_S_T_RH_THRESH_LOW      0x6100
+#define HDC3020_S_T_RH_THRESH_LOW_CLR  0x610B
+#define HDC3020_S_T_RH_THRESH_HIGH_CLR 0x6116
+#define HDC3020_S_T_RH_THRESH_HIGH     0x611D
+#define HDC3020_R_T_RH_AUTO            0xE000
+#define HDC3020_R_T_LOW_AUTO           0xE002
+#define HDC3020_R_T_HIGH_AUTO          0xE003
+#define HDC3020_R_RH_LOW_AUTO          0xE004
+#define HDC3020_R_RH_HIGH_AUTO         0xE005
+#define HDC3020_R_T_RH_THRESH_LOW      0xE102
+#define HDC3020_R_T_RH_THRESH_LOW_CLR  0xE109
+#define HDC3020_R_T_RH_THRESH_HIGH_CLR 0xE114
+#define HDC3020_R_T_RH_THRESH_HIGH     0xE11F
+#define HDC3020_R_STATUS               0xF32D
+
+#define HDC3020_THRESH_TEMP_MASK       GENMASK(8, 0)
+#define HDC3020_THRESH_TEMP_TRUNC_SHIFT        7
+#define HDC3020_THRESH_HUM_MASK                GENMASK(15, 9)
+#define HDC3020_THRESH_HUM_TRUNC_SHIFT 9
+
+#define HDC3020_STATUS_T_LOW_ALERT     BIT(6)
+#define HDC3020_STATUS_T_HIGH_ALERT    BIT(7)
+#define HDC3020_STATUS_RH_LOW_ALERT    BIT(8)
+#define HDC3020_STATUS_RH_HIGH_ALERT   BIT(9)
 
 #define HDC3020_READ_RETRY_TIMES       10
 #define HDC3020_BUSY_DELAY_MS          10
 
 #define HDC3020_CRC8_POLYNOMIAL                0x31
 
-static const u8 HDC3020_S_AUTO_10HZ_MOD0[2] = { 0x27, 0x37 };
-
-static const u8 HDC3020_EXIT_AUTO[2] = { 0x30, 0x93 };
-
-static const u8 HDC3020_R_T_RH_AUTO[2] = { 0xE0, 0x00 };
-static const u8 HDC3020_R_T_LOW_AUTO[2] = { 0xE0, 0x02 };
-static const u8 HDC3020_R_T_HIGH_AUTO[2] = { 0xE0, 0x03 };
-static const u8 HDC3020_R_RH_LOW_AUTO[2] = { 0xE0, 0x04 };
-static const u8 HDC3020_R_RH_HIGH_AUTO[2] = { 0xE0, 0x05 };
+#define HDC3020_MIN_TEMP               -40
+#define HDC3020_MAX_TEMP               125
 
 struct hdc3020_data {
        struct i2c_client *client;
@@ -54,18 +79,37 @@ struct hdc3020_data {
 
 static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF};
 
+static const struct iio_event_spec hdc3020_t_rh_event[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+               BIT(IIO_EV_INFO_HYSTERESIS),
+       },
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+               BIT(IIO_EV_INFO_HYSTERESIS),
+       },
+};
+
 static const struct iio_chan_spec hdc3020_channels[] = {
        {
                .type = IIO_TEMP,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
                BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET),
+               .event_spec = hdc3020_t_rh_event,
+               .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event),
        },
        {
                .type = IIO_HUMIDITYRELATIVE,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
                BIT(IIO_CHAN_INFO_TROUGH),
+               .event_spec = hdc3020_t_rh_event,
+               .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event),
        },
        {
                /*
@@ -82,7 +126,7 @@ static const struct iio_chan_spec hdc3020_channels[] = {
 
 DECLARE_CRC8_TABLE(hdc3020_crc8_table);
 
-static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
+static int hdc3020_write_bytes(struct hdc3020_data *data, u8 *buf, u8 len)
 {
        struct i2c_client *client = data->client;
        struct i2c_msg msg;
@@ -90,7 +134,7 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
 
        msg.addr = client->addr;
        msg.flags = 0;
-       msg.buf = (char *)buf;
+       msg.buf = buf;
        msg.len = len;
 
        /*
@@ -109,26 +153,28 @@ static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
        return -ETIMEDOUT;
 }
 
-static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf,
-                             void *val, int len)
+static
+int hdc3020_read_bytes(struct hdc3020_data *data, u16 reg, u8 *buf, int len)
 {
+       u8 reg_buf[2];
        int ret, cnt;
        struct i2c_client *client = data->client;
        struct i2c_msg msg[2] = {
                [0] = {
                        .addr = client->addr,
                        .flags = 0,
-                       .buf = (char *)buf,
+                       .buf = reg_buf,
                        .len = 2,
                },
                [1] = {
                        .addr = client->addr,
                        .flags = I2C_M_RD,
-                       .buf = val,
+                       .buf = buf,
                        .len = len,
                },
        };
 
+       put_unaligned_be16(reg, reg_buf);
        /*
         * During the measurement process, HDC3020 will not return data.
         * So wait for a while and try again
@@ -145,48 +191,12 @@ static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf,
        return -ETIMEDOUT;
 }
 
-static int hdc3020_read_measurement(struct hdc3020_data *data,
-                                   enum iio_chan_type type, int *val)
-{
-       u8 crc, buf[6];
-       int ret;
-
-       ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6);
-       if (ret < 0)
-               return ret;
-
-       /* CRC check of the temperature measurement */
-       crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
-       if (crc != buf[2])
-               return -EINVAL;
-
-       /* CRC check of the relative humidity measurement */
-       crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE);
-       if (crc != buf[5])
-               return -EINVAL;
-
-       if (type == IIO_TEMP)
-               *val = get_unaligned_be16(buf);
-       else if (type == IIO_HUMIDITYRELATIVE)
-               *val = get_unaligned_be16(&buf[3]);
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-/*
- * After exiting the automatic measurement mode or resetting, the peak
- * value will be reset to the default value
- * This method is used to get the highest temp measured during automatic
- * measurement
- */
-static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val)
+static int hdc3020_read_be16(struct hdc3020_data *data, u16 reg)
 {
        u8 crc, buf[3];
        int ret;
 
-       ret = hdc3020_read_bytes(data, HDC3020_R_T_HIGH_AUTO, buf, 3);
+       ret = hdc3020_read_bytes(data, reg, buf, 3);
        if (ret < 0)
                return ret;
 
@@ -194,73 +204,43 @@ static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val)
        if (crc != buf[2])
                return -EINVAL;
 
-       *val = get_unaligned_be16(buf);
-
-       return 0;
+       return get_unaligned_be16(buf);
 }
 
-/*
- * This method is used to get the lowest temp measured during automatic
- * measurement
- */
-static int hdc3020_read_low_peak_t(struct hdc3020_data *data, int *val)
+static int hdc3020_exec_cmd(struct hdc3020_data *data, u16 reg)
 {
-       u8 crc, buf[3];
-       int ret;
+       u8 reg_buf[2];
 
-       ret = hdc3020_read_bytes(data, HDC3020_R_T_LOW_AUTO, buf, 3);
-       if (ret < 0)
-               return ret;
-
-       crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
-       if (crc != buf[2])
-               return -EINVAL;
-
-       *val = get_unaligned_be16(buf);
-
-       return 0;
+       put_unaligned_be16(reg, reg_buf);
+       return hdc3020_write_bytes(data, reg_buf, 2);
 }
 
-/*
- * This method is used to get the highest humidity measured during automatic
- * measurement
- */
-static int hdc3020_read_high_peak_rh(struct hdc3020_data *data, int *val)
+static int hdc3020_read_measurement(struct hdc3020_data *data,
+                                   enum iio_chan_type type, int *val)
 {
-       u8 crc, buf[3];
+       u8 crc, buf[6];
        int ret;
 
-       ret = hdc3020_read_bytes(data, HDC3020_R_RH_HIGH_AUTO, buf, 3);
+       ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6);
        if (ret < 0)
                return ret;
 
+       /* CRC check of the temperature measurement */
        crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
        if (crc != buf[2])
                return -EINVAL;
 
-       *val = get_unaligned_be16(buf);
-
-       return 0;
-}
-
-/*
- * This method is used to get the lowest humidity measured during automatic
- * measurement
- */
-static int hdc3020_read_low_peak_rh(struct hdc3020_data *data, int *val)
-{
-       u8 crc, buf[3];
-       int ret;
-
-       ret = hdc3020_read_bytes(data, HDC3020_R_RH_LOW_AUTO, buf, 3);
-       if (ret < 0)
-               return ret;
-
-       crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
-       if (crc != buf[2])
+       /* CRC check of the relative humidity measurement */
+       crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE);
+       if (crc != buf[5])
                return -EINVAL;
 
-       *val = get_unaligned_be16(buf);
+       if (type == IIO_TEMP)
+               *val = get_unaligned_be16(buf);
+       else if (type == IIO_HUMIDITYRELATIVE)
+               *val = get_unaligned_be16(&buf[3]);
+       else
+               return -EINVAL;
 
        return 0;
 }
@@ -286,28 +266,28 @@ static int hdc3020_read_raw(struct iio_dev *indio_dev,
        }
        case IIO_CHAN_INFO_PEAK: {
                guard(mutex)(&data->lock);
-               if (chan->type == IIO_TEMP) {
-                       ret = hdc3020_read_high_peak_t(data, val);
-                       if (ret < 0)
-                               return ret;
-               } else {
-                       ret = hdc3020_read_high_peak_rh(data, val);
-                       if (ret < 0)
-                               return ret;
-               }
+               if (chan->type == IIO_TEMP)
+                       ret = hdc3020_read_be16(data, HDC3020_R_T_HIGH_AUTO);
+               else
+                       ret = hdc3020_read_be16(data, HDC3020_R_RH_HIGH_AUTO);
+
+               if (ret < 0)
+                       return ret;
+
+               *val = ret;
                return IIO_VAL_INT;
        }
        case IIO_CHAN_INFO_TROUGH: {
                guard(mutex)(&data->lock);
-               if (chan->type == IIO_TEMP) {
-                       ret = hdc3020_read_low_peak_t(data, val);
-                       if (ret < 0)
-                               return ret;
-               } else {
-                       ret = hdc3020_read_low_peak_rh(data, val);
-                       if (ret < 0)
-                               return ret;
-               }
+               if (chan->type == IIO_TEMP)
+                       ret = hdc3020_read_be16(data, HDC3020_R_T_LOW_AUTO);
+               else
+                       ret = hdc3020_read_be16(data, HDC3020_R_RH_LOW_AUTO);
+
+               if (ret < 0)
+                       return ret;
+
+               *val = ret;
                return IIO_VAL_INT;
        }
        case IIO_CHAN_INFO_SCALE:
@@ -352,23 +332,17 @@ static int hdc3020_update_heater(struct hdc3020_data *data, int val)
        if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2])
                return -EINVAL;
 
-       buf[0] = HDC3020_HEATER_CMD_MSB;
+       if (!val)
+               hdc3020_exec_cmd(data, HDC3020_HEATER_DISABLE);
 
-       if (!val) {
-               buf[1] = HDC3020_HEATER_DISABLE;
-               return hdc3020_write_bytes(data, buf, 2);
-       }
-
-       buf[1] = HDC3020_HEATER_CONFIG;
+       put_unaligned_be16(HDC3020_HEATER_CONFIG, buf);
        put_unaligned_be16(val & GENMASK(13, 0), &buf[2]);
        buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
        ret = hdc3020_write_bytes(data, buf, 5);
        if (ret < 0)
                return ret;
 
-       buf[1] = HDC3020_HEATER_ENABLE;
-
-       return hdc3020_write_bytes(data, buf, 2);
+       return hdc3020_exec_cmd(data, HDC3020_HEATER_ENABLE);
 }
 
 static int hdc3020_write_raw(struct iio_dev *indio_dev,
@@ -389,15 +363,197 @@ static int hdc3020_write_raw(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
+static int hdc3020_write_thresh(struct iio_dev *indio_dev,
+                               const struct iio_chan_spec *chan,
+                               enum iio_event_type type,
+                               enum iio_event_direction dir,
+                               enum iio_event_info info,
+                               int val, int val2)
+{
+       struct hdc3020_data *data = iio_priv(indio_dev);
+       u8 buf[5];
+       u64 tmp;
+       u16 reg;
+       int ret;
+
+       /* Supported temperature range is from –40 to 125 degree celsius */
+       if (val < HDC3020_MIN_TEMP || val > HDC3020_MAX_TEMP)
+               return -EINVAL;
+
+       /* Select threshold register */
+       if (info == IIO_EV_INFO_VALUE) {
+               if (dir == IIO_EV_DIR_RISING)
+                       reg = HDC3020_S_T_RH_THRESH_HIGH;
+               else
+                       reg = HDC3020_S_T_RH_THRESH_LOW;
+       } else {
+               if (dir == IIO_EV_DIR_RISING)
+                       reg = HDC3020_S_T_RH_THRESH_HIGH_CLR;
+               else
+                       reg = HDC3020_S_T_RH_THRESH_LOW_CLR;
+       }
+
+       guard(mutex)(&data->lock);
+       ret = hdc3020_read_be16(data, reg);
+       if (ret < 0)
+               return ret;
+
+       switch (chan->type) {
+       case IIO_TEMP:
+               /*
+                * Calculate temperature threshold, shift it down to get the
+                * truncated threshold representation in the 9LSBs while keeping
+                * the current humidity threshold in the 7 MSBs.
+                */
+               tmp = ((u64)(((val + 45) * MICRO) + val2)) * 65535ULL;
+               tmp = div_u64(tmp, MICRO * 175);
+               val = tmp >> HDC3020_THRESH_TEMP_TRUNC_SHIFT;
+               val = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, val);
+               val |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, ret) <<
+                       HDC3020_THRESH_HUM_TRUNC_SHIFT);
+               break;
+       case IIO_HUMIDITYRELATIVE:
+               /*
+                * Calculate humidity threshold, shift it down and up to get the
+                * truncated threshold representation in the 7MSBs while keeping
+                * the current temperature threshold in the 9 LSBs.
+                */
+               tmp = ((u64)((val * MICRO) + val2)) * 65535ULL;
+               tmp = div_u64(tmp, MICRO * 100);
+               val = tmp >> HDC3020_THRESH_HUM_TRUNC_SHIFT;
+               val = FIELD_PREP(HDC3020_THRESH_HUM_MASK, val);
+               val |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       put_unaligned_be16(reg, buf);
+       put_unaligned_be16(val, buf + 2);
+       buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
+       return hdc3020_write_bytes(data, buf, 5);
+}
+
+static int hdc3020_read_thresh(struct iio_dev *indio_dev,
+                              const struct iio_chan_spec *chan,
+                              enum iio_event_type type,
+                              enum iio_event_direction dir,
+                              enum iio_event_info info,
+                              int *val, int *val2)
+{
+       struct hdc3020_data *data = iio_priv(indio_dev);
+       u16 reg;
+       int ret;
+
+       /* Select threshold register */
+       if (info == IIO_EV_INFO_VALUE) {
+               if (dir == IIO_EV_DIR_RISING)
+                       reg = HDC3020_R_T_RH_THRESH_HIGH;
+               else
+                       reg = HDC3020_R_T_RH_THRESH_LOW;
+       } else {
+               if (dir == IIO_EV_DIR_RISING)
+                       reg = HDC3020_R_T_RH_THRESH_HIGH_CLR;
+               else
+                       reg = HDC3020_R_T_RH_THRESH_LOW_CLR;
+       }
+
+       guard(mutex)(&data->lock);
+       ret = hdc3020_read_be16(data, reg);
+       if (ret < 0)
+               return ret;
+
+       switch (chan->type) {
+       case IIO_TEMP:
+               /*
+                * Get the temperature threshold from 9 LSBs, shift them to get
+                * the truncated temperature threshold representation and
+                * calculate the threshold according to the formula in the
+                * datasheet.
+                */
+               *val = FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret);
+               *val = *val << HDC3020_THRESH_TEMP_TRUNC_SHIFT;
+               *val = -2949075 + (175 * (*val));
+               *val2 = 65535;
+               return IIO_VAL_FRACTIONAL;
+       case IIO_HUMIDITYRELATIVE:
+               /*
+                * Get the humidity threshold from 7 MSBs, shift them to get the
+                * truncated humidity threshold representation and calculate the
+                * threshold according to the formula in the datasheet.
+                */
+               *val = FIELD_GET(HDC3020_THRESH_HUM_MASK, ret);
+               *val = (*val << HDC3020_THRESH_HUM_TRUNC_SHIFT) * 100;
+               *val2 = 65535;
+               return IIO_VAL_FRACTIONAL;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static irqreturn_t hdc3020_interrupt_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct hdc3020_data *data;
+       s64 time;
+       int ret;
+
+       data = iio_priv(indio_dev);
+       ret = hdc3020_read_be16(data, HDC3020_R_STATUS);
+       if (ret < 0)
+               return IRQ_HANDLED;
+
+       if (!(ret & (HDC3020_STATUS_T_HIGH_ALERT | HDC3020_STATUS_T_LOW_ALERT |
+               HDC3020_STATUS_RH_HIGH_ALERT | HDC3020_STATUS_RH_LOW_ALERT)))
+               return IRQ_NONE;
+
+       time = iio_get_time_ns(indio_dev);
+       if (ret & HDC3020_STATUS_T_HIGH_ALERT)
+               iio_push_event(indio_dev,
+                              IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
+                                                 IIO_NO_MOD,
+                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_DIR_RISING),
+                                                 time);
+
+       if (ret & HDC3020_STATUS_T_LOW_ALERT)
+               iio_push_event(indio_dev,
+                              IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
+                                                 IIO_NO_MOD,
+                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_DIR_FALLING),
+                                                 time);
+
+       if (ret & HDC3020_STATUS_RH_HIGH_ALERT)
+               iio_push_event(indio_dev,
+                              IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0,
+                                                 IIO_NO_MOD,
+                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_DIR_RISING),
+                                                 time);
+
+       if (ret & HDC3020_STATUS_RH_LOW_ALERT)
+               iio_push_event(indio_dev,
+                              IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0,
+                                                 IIO_NO_MOD,
+                                                 IIO_EV_TYPE_THRESH,
+                                                 IIO_EV_DIR_FALLING),
+                                                 time);
+
+       return IRQ_HANDLED;
+}
+
 static const struct iio_info hdc3020_info = {
        .read_raw = hdc3020_read_raw,
        .write_raw = hdc3020_write_raw,
        .read_avail = hdc3020_read_available,
+       .read_event_value = hdc3020_read_thresh,
+       .write_event_value = hdc3020_write_thresh,
 };
 
 static void hdc3020_stop(void *data)
 {
-       hdc3020_write_bytes((struct hdc3020_data *)data, HDC3020_EXIT_AUTO, 2);
+       hdc3020_exec_cmd((struct hdc3020_data *)data, HDC3020_EXIT_AUTO);
 }
 
 static int hdc3020_probe(struct i2c_client *client)
@@ -424,8 +580,25 @@ static int hdc3020_probe(struct i2c_client *client)
        indio_dev->info = &hdc3020_info;
        indio_dev->channels = hdc3020_channels;
        indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels);
+       if (client->irq) {
+               ret = devm_request_threaded_irq(&client->dev, client->irq,
+                                               NULL, hdc3020_interrupt_handler,
+                                               IRQF_ONESHOT, "hdc3020",
+                                               indio_dev);
+               if (ret)
+                       return dev_err_probe(&client->dev, ret,
+                                            "Failed to request IRQ\n");
+
+               /*
+                * The alert output is activated by default upon power up,
+                * hardware reset, and soft reset. Clear the status register.
+                */
+               ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS);
+               if (ret)
+                       return ret;
+       }
 
-       ret = hdc3020_write_bytes(data, HDC3020_S_AUTO_10HZ_MOD0, 2);
+       ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0);
        if (ret)
                return dev_err_probe(&client->dev, ret,
                                     "Unable to set up measurement\n");
index 30f2068ea156675cac8e976cff982263bc2c623c..5cb263e0ef5ac8bfcd5de7fed9b0cef66fc52910 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/regmap.h>
@@ -63,7 +63,7 @@ static struct i2c_driver hts221_driver = {
                .name = "hts221_i2c",
                .pm = pm_sleep_ptr(&hts221_pm_ops),
                .of_match_table = hts221_i2c_of_match,
-               .acpi_match_table = ACPI_PTR(hts221_acpi_match),
+               .acpi_match_table = hts221_acpi_match,
        },
        .probe = hts221_i2c_probe,
        .id_table = hts221_i2c_id_table,
index 64be656f0b80529f649f6fb6f09d8ce721783f54..01f55cc902faad356acb1e3f52ea80ea500a4bdb 100644 (file)
@@ -1363,22 +1363,16 @@ static int adis16475_config_sync_mode(struct adis16475 *st)
 static int adis16475_config_irq_pin(struct adis16475 *st)
 {
        int ret;
-       struct irq_data *desc;
        u32 irq_type;
        u16 val = 0;
        u8 polarity;
        struct spi_device *spi = st->adis.spi;
 
-       desc = irq_get_irq_data(spi->irq);
-       if (!desc) {
-               dev_err(&spi->dev, "Could not find IRQ %d\n", spi->irq);
-               return -EINVAL;
-       }
        /*
         * It is possible to configure the data ready polarity. Furthermore, we
         * need to update the adis struct if we want data ready as active low.
         */
-       irq_type = irqd_get_trigger_type(desc);
+       irq_type = irq_get_trigger_type(spi->irq);
        if (irq_type == IRQ_TYPE_EDGE_RISING) {
                polarity = 1;
                st->adis.irq_flag = IRQF_TRIGGER_RISING;
index fe520194a837177b758a28ff5edbbd6a5852693b..b40a55bba30c191dd83fa1664a9b87eeba8c2731 100644 (file)
@@ -1246,18 +1246,11 @@ static int adis16480_config_irq_pin(struct adis16480 *st)
 {
        struct device *dev = &st->adis.spi->dev;
        struct fwnode_handle *fwnode = dev_fwnode(dev);
-       struct irq_data *desc;
        enum adis16480_int_pin pin;
        unsigned int irq_type;
        uint16_t val;
        int i, irq = 0;
 
-       desc = irq_get_irq_data(st->adis.spi->irq);
-       if (!desc) {
-               dev_err(dev, "Could not find IRQ %d\n", irq);
-               return -EINVAL;
-       }
-
        /* Disable data ready since the default after reset is on */
        val = ADIS16480_DRDY_EN(0);
 
@@ -1285,7 +1278,7 @@ static int adis16480_config_irq_pin(struct adis16480 *st)
         * configured as positive or negative, corresponding to
         * IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING respectively.
         */
-       irq_type = irqd_get_trigger_type(desc);
+       irq_type = irq_get_trigger_type(st->adis.spi->irq);
        if (irq_type == IRQ_TYPE_EDGE_RISING) { /* Default */
                val |= ADIS16480_DRDY_POL(1);
        } else if (irq_type == IRQ_TYPE_EDGE_FALLING) {
index 81652c08e6441c4472b847c40a4d42e64a5d668e..a081305254dbb5109d0700a9e6f3f3e9b338f048 100644 (file)
@@ -43,6 +43,15 @@ static const struct i2c_device_id bmi160_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
 
 static const struct acpi_device_id bmi160_acpi_match[] = {
+       /*
+        * FIRMWARE BUG WORKAROUND
+        * Some manufacturers like GPD, Lenovo or Aya used the incorrect
+        * ID "10EC5280" for bmi160 in their DSDT. A fixed firmware is not
+        * available as of Feb 2024 after trying to work with OEMs, and
+        * this is not expected to change anymore since at least some of
+        * the affected devices are from 2021/2022.
+        */
+       {"10EC5280", 0},
        {"BMI0160", 0},
        { },
 };
index 183af482828f8e37442428ca5cd846a6a1e9e2a3..5d42ab9b176a389be85102b6dc94a271ffcf1ec5 100644 (file)
@@ -1668,52 +1668,41 @@ static int bmi323_write_raw(struct iio_dev *indio_dev,
                            int val2, long mask)
 {
        struct bmi323_data *data = iio_priv(indio_dev);
-       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type),
-                                    val, val2);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return bmi323_set_odr(data,
+                                             bmi323_iio_to_sensor(chan->type),
+                                             val, val2);
+               unreachable();
        case IIO_CHAN_INFO_SCALE:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type),
-                                      val, val2);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return bmi323_set_scale(data,
+                                               bmi323_iio_to_sensor(chan->type),
+                                               val, val2);
+               unreachable();
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type),
-                                        val);
-
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return bmi323_set_average(data,
+                                                 bmi323_iio_to_sensor(chan->type),
+                                                 val);
+               unreachable();
        case IIO_CHAN_INFO_ENABLE:
                return bmi323_enable_steps(data, val);
-       case IIO_CHAN_INFO_PROCESSED:
-               scoped_guard(mutex, &data->mutex) {
-                       if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK,
-                                             data->feature_events))
-                               return -EINVAL;
+       case IIO_CHAN_INFO_PROCESSED: {
+               guard(mutex)(&data->mutex);
 
-                       /* Clear step counter value */
-                       ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
-                                                   BMI323_STEP_SC1_RST_CNT_MSK,
-                                                   FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK,
-                                                              1));
-               }
-               return ret;
+               if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK,
+                                     data->feature_events))
+                       return -EINVAL;
+
+               /* Clear step counter value */
+               return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
+                                            BMI323_STEP_SC1_RST_CNT_MSK,
+                                            FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK,
+                                                       1));
+       }
        default:
                return -EINVAL;
        }
@@ -1724,7 +1713,6 @@ static int bmi323_read_raw(struct iio_dev *indio_dev,
                           int *val2, long mask)
 {
        struct bmi323_data *data = iio_priv(indio_dev);
-       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_PROCESSED:
@@ -1733,14 +1721,10 @@ static int bmi323_read_raw(struct iio_dev *indio_dev,
                switch (chan->type) {
                case IIO_ACCEL:
                case IIO_ANGL_VEL:
-                       ret = iio_device_claim_direct_mode(indio_dev);
-                       if (ret)
-                               return ret;
-
-                       ret = bmi323_read_axis(data, chan, val);
-
-                       iio_device_release_direct_mode(indio_dev);
-                       return ret;
+                       iio_device_claim_direct_scoped(return -EBUSY,
+                                                      indio_dev)
+                               return bmi323_read_axis(data, chan, val);
+                       unreachable();
                case IIO_TEMP:
                        return bmi323_get_temp_data(data, val);
                default:
index 20a8001b9956a39dddd1775543acdceb10e5a931..52140bf057658edf0b23519b8cf8bc11691a9520 100644 (file)
@@ -93,6 +93,26 @@ static int bmi323_i2c_probe(struct i2c_client *i2c)
        return bmi323_core_probe(dev);
 }
 
+static const struct acpi_device_id bmi323_acpi_match[] = {
+       /*
+        * The "BOSC0200" identifier used here is not unique to bmi323 devices.
+        * The same "BOSC0200" identifier is found in the ACPI tables of devices
+        * using the bmc150 chip. This creates a conflict with duplicate ACPI
+        * identifiers which multiple drivers want to use. If a non-bmi323
+        * device starts to load with this "BOSC0200" ACPI match here, then the
+        * chip ID check portion should fail because the chip IDs received (via
+        * i2c) are unique between bmc150 and bmi323 and the driver should
+        * relinquish the device. If and when a different driver (such as
+        * bmc150) starts to load with the "BOSC0200" ACPI match, a short reset
+        * should ensure that the device is not in a bad state during that
+        * driver initialization. This device reset does occur in both the
+        * bmi323 and bmc150 init sequences.
+        */
+       { "BOSC0200" },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match);
+
 static const struct i2c_device_id bmi323_i2c_ids[] = {
        { "bmi323" },
        { }
@@ -109,6 +129,7 @@ static struct i2c_driver bmi323_i2c_driver = {
        .driver = {
                .name = "bmi323",
                .of_match_table = bmi323_of_i2c_match,
+               .acpi_match_table = bmi323_acpi_match,
        },
        .probe = bmi323_i2c_probe,
        .id_table = bmi323_i2c_ids,
index 5677bdf4f846ebd0405fbba43d1b9ad108033a3a..694ff14a3aa2795bdfbd8b42420d0f29dc6c4e40 100644 (file)
@@ -378,8 +378,8 @@ static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status)
  * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything
  * unless we require to AND we don't queue more than one request per time).
  */
-static ssize_t bno055_ser_receive_buf(struct serdev_device *serdev,
-                                     const u8 *buf, size_t size)
+static size_t bno055_ser_receive_buf(struct serdev_device *serdev,
+                                    const u8 *buf, size_t size)
 {
        int status;
        struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev);
index 2ace306d0f9ab81b5124d451b0f3f2257874f1a6..e99677ad96a2f9041b8399a83b28586357371122 100644 (file)
@@ -10,7 +10,6 @@
  *      1    |  0    |  0x1C
  *      1    |  1    |  0x1F
  */
-#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -57,7 +56,7 @@ MODULE_DEVICE_TABLE(of, fxos8700_of_match);
 static struct i2c_driver fxos8700_i2c_driver = {
        .driver = {
                .name                   = "fxos8700_i2c",
-               .acpi_match_table       = ACPI_PTR(fxos8700_acpi_match),
+               .acpi_match_table       = fxos8700_acpi_match,
                .of_match_table         = fxos8700_of_match,
        },
        .probe          = fxos8700_i2c_probe,
index 27e694cce173e05f2312c4b8b6ef6a0a1cc40d0a..6b0dc7a776b9eca3841066dae0e9ead6a0f68875 100644 (file)
@@ -2,7 +2,6 @@
 /*
  * FXOS8700 - NXP IMU, SPI bits
  */
-#include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
@@ -46,7 +45,7 @@ static struct spi_driver fxos8700_spi_driver = {
        .probe          = fxos8700_spi_probe,
        .id_table       = fxos8700_spi_id,
        .driver = {
-               .acpi_match_table       = ACPI_PTR(fxos8700_acpi_match),
+               .acpi_match_table       = fxos8700_acpi_match,
                .of_match_table         = fxos8700_of_match,
                .name                   = "fxos8700_spi",
        },
index 958167b31241e639002090941ed044580949bde2..7d3e061f30463dfdc6c9c21b653a1ee9189fecbe 100644 (file)
@@ -1514,7 +1514,7 @@ MODULE_DEVICE_TABLE(i2c, kmx61_id);
 static struct i2c_driver kmx61_driver = {
        .driver = {
                .name = KMX61_DRV_NAME,
-               .acpi_match_table = ACPI_PTR(kmx61_acpi_match),
+               .acpi_match_table = kmx61_acpi_match,
                .pm = pm_ptr(&kmx61_pm_ops),
        },
        .probe          = kmx61_probe,
index 5865a295a4df36ecbd4b3bf9d2f3c563ba29592a..89d687ec3099cc3ecb848e44f610c5cd64c80ad1 100644 (file)
@@ -11,11 +11,32 @@ config IIO_ST_LSM6DSX
        select IIO_ST_LSM6DSX_I3C if (I3C)
        help
          Say yes here to build support for STMicroelectronics LSM6DSx imu
-         sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
-         ism330dlc, lsm6dso, lsm6dsox, asm330lhh, asm330lhhx, lsm6dsr,
-         lsm6ds3tr-c, ism330dhcx, lsm6dsrx, lsm6ds0, lsm6dsop, lsm6dstx,
-         lsm6dsv, lsm6dsv16x, lsm6dso16is, ism330is, asm330lhb, lsm6dst
-         and the accelerometer/gyroscope of lsm9ds1.
+         sensor.
+         Supported devices:
+         - asm330lhb
+         - asm330lhh
+         - asm330lhhx
+         - asm330lhhxg1
+         - ism330dhcx
+         - ism330dlc
+         - ism330is
+         - lsm6ds0
+         - lsm6ds3
+         - lsm6ds3h
+         - lsm6ds3tr-c
+         - lsm6dsl
+         - lsm6dsm
+         - lsm6dso
+         - lsm6dso16is
+         - lsm6dsop
+         - lsm6dsox
+         - lsm6dsr
+         - lsm6dsrx
+         - lsm6dst
+         - lsm6dstx
+         - lsm6dsv
+         - lsm6dsv16x
+         - lsm9ds1
 
          To compile this driver as a module, choose M here: the module
          will be called st_lsm6dsx.
index c19237717e8122f97d0410c69cdce8532819c7ba..a3b93566533bc06106be437d416249cb5aa326b2 100644 (file)
@@ -38,6 +38,7 @@
 #define ST_LSM6DSO16IS_DEV_NAME        "lsm6dso16is"
 #define ST_ISM330IS_DEV_NAME   "ism330is"
 #define ST_ASM330LHB_DEV_NAME  "asm330lhb"
+#define ST_ASM330LHHXG1_DEV_NAME       "asm330lhhxg1"
 
 enum st_lsm6dsx_hw_id {
        ST_LSM6DS3_ID = 1,
@@ -63,6 +64,7 @@ enum st_lsm6dsx_hw_id {
        ST_LSM6DSO16IS_ID,
        ST_ISM330IS_ID,
        ST_ASM330LHB_ID,
+       ST_ASM330LHHXG1_ID,
        ST_LSM6DSX_MAX_ID,
 };
 
index 066fe561c5e88dcc435a4e4bbea0a66c8536394c..0a7cd8c1aa3313a113b9092d6a58d597ba68290c 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * STMicroelectronics st_lsm6dsx FIFO buffer library driver
  *
- * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
+ * Pattern FIFO:
  * The FIFO buffer can be configured to store data from gyroscope and
  * accelerometer. Samples are queued without any tag according to a
  * specific pattern based on 'FIFO data sets' (6 bytes each):
  * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
  * value of the decimation factor and ODR set for each FIFO data set.
  *
- * LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/LSM6DSRX/ISM330DHCX/
- * LSM6DST/LSM6DSOP/LSM6DSTX/LSM6DSV/ASM330LHB:
+ * Supported devices:
+ * - ISM330DLC
+ * - LSM6DS3
+ * - LSM6DS3H
+ * - LSM6DS3TR-C
+ * - LSM6DSL
+ * - LSM6DSM
+ *
+ * Tagged FIFO:
  * The FIFO buffer can be configured to store data from gyroscope and
  * accelerometer. Each sample is queued with a tag (1B) indicating data
  * source (gyroscope, accelerometer, hw timer).
  *
+ * Supported devices:
+ * - ASM330LHB
+ * - ASM330LHH
+ * - ASM330LHHX
+ * - ASM330LHHXG1
+ * - ISM330DHCX
+ * - LSM6DSO
+ * - LSM6DSOP
+ * - LSM6DSOX
+ * - LSM6DSR
+ * - LSM6DSRX
+ * - LSM6DST
+ * - LSM6DSTX
+ * - LSM6DSV
+ *
  * FIFO supported modes:
  *  - BYPASS: FIFO disabled
  *  - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
index b6e6b1df8a618995e23eeca4ad89f4776091bada..0716986f981299beca0ab9876ff5c241ce29221a 100644 (file)
  * by a different driver.
  *
  * Supported sensors:
- * - LSM6DS3:
+ *
+ * - LSM6DS3
  *   - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
  *   - FIFO size: 8KB
  *
- * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
+ * - ISM330DLC
+ * - LSM6DS3H
+ * - LSM6DS3TR-C
+ * - LSM6DSL
+ * - LSM6DSM
  *   - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
  *   - FIFO size: 4KB
  *
- * - LSM6DSO/LSM6DSOX/ASM330LHH/ASM330LHHX/LSM6DSR/ISM330DHCX/LSM6DST/LSM6DSOP/
- *   LSM6DSTX/LSM6DSO16IS/ISM330IS:
+ * - ASM330LHH
+ * - ASM330LHHX
+ * - ASM330LHHXG1
+ * - ISM330DHCX
+ * - ISM330IS
+ * - LSM6DSO
+ * - LSM6DSO16IS
+ * - LSM6DSOP
+ * - LSM6DSOX
+ * - LSM6DSR
+ * - LSM6DST
+ * - LSM6DSTX
  *   - Accelerometer/Gyroscope supported ODR [Hz]: 12.5, 26, 52, 104, 208, 416,
  *     833
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
  *   - FIFO size: 3KB
  *
- * - LSM6DSV/LSM6DSV16X:
+ * - LSM6DSV
+ * - LSM6DSV16X
  *   - Accelerometer/Gyroscope supported ODR [Hz]: 7.5, 15, 30, 60, 120, 240,
  *     480, 960
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
  *   - Gyroscope supported full-scale [dps]: +-125/+-250/+-500/+-1000/+-2000
  *   - FIFO size: 3KB
  *
- * - LSM9DS1/LSM6DS0:
+ * - LSM6DS0
+ * - LSM9DS1
  *   - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
  *   - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952
@@ -820,6 +837,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                                .hw_id = ST_ASM330LHHX_ID,
                                .name = ST_ASM330LHHX_DEV_NAME,
                                .wai = 0x6b,
+                       }, {
+                               .hw_id = ST_ASM330LHHXG1_ID,
+                               .name = ST_ASM330LHHXG1_DEV_NAME,
+                               .wai = 0x6b,
                        }, {
                                .hw_id = ST_LSM6DSTX_ID,
                                .name = ST_LSM6DSTX_DEV_NAME,
index 911444ec57c0166bda209709e11543f9c7b2980d..cddf41cc0ca97f59b9891d543b5807a3ab03811a 100644 (file)
@@ -134,6 +134,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
                .compatible = "st,asm330lhb",
                .data = (void *)ST_ASM330LHB_ID,
        },
+       {
+               .compatible = "st,asm330lhhxg1",
+               .data = (void *)ST_ASM330LHHXG1_ID,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -168,6 +172,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
        { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
        { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
        { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
+       { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
index f56c170c41a9ded6aa06568a0eca493c9d766f5d..c122c8831365a4ffa4544d347946d51ba96ee001 100644 (file)
@@ -129,6 +129,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
                .compatible = "st,asm330lhb",
                .data = (void *)ST_ASM330LHB_ID,
        },
+       {
+               .compatible = "st,asm330lhhxg1",
+               .data = (void *)ST_ASM330LHHXG1_ID,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -157,6 +161,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
        { ST_LSM6DSO16IS_DEV_NAME, ST_LSM6DSO16IS_ID },
        { ST_ISM330IS_DEV_NAME, ST_ISM330IS_ID },
        { ST_ASM330LHB_DEV_NAME, ST_ASM330LHB_ID },
+       { ST_ASM330LHHXG1_DEV_NAME, ST_ASM330LHHXG1_ID },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
index 76678cdefb0747953a1adbfe9b773c3848e6a673..e67d31b48441855e7dec46d7cf8612d4fda9e68a 100644 (file)
@@ -4,9 +4,12 @@
 #ifndef ST_LSM9DS0_H
 #define ST_LSM9DS0_H
 
-struct iio_dev;
+struct device;
+struct regmap;
 struct regulator;
 
+struct iio_dev;
+
 struct st_lsm9ds0 {
        struct device *dev;
        const char *name;
index e887b45cdbcd7f741bd3d823ce80a148ef1d6689..10c1b2ba7a3d93050b07bd6edd234a80e6e43132 100644 (file)
@@ -7,10 +7,10 @@
  * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  */
 
-#include <linux/device.h>
+#include <linux/array_size.h>
+#include <linux/dev_printk.h>
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 
 #include <linux/iio/common/st_sensors.h>
@@ -25,10 +25,9 @@ static int st_lsm9ds0_probe_accel(struct st_lsm9ds0 *lsm9ds0, struct regmap *reg
        struct st_sensor_data *data;
 
        settings = st_accel_get_settings(lsm9ds0->name);
-       if (!settings) {
-               dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name);
-               return -ENODEV;
-       }
+       if (!settings)
+               return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n",
+                                    lsm9ds0->name);
 
        lsm9ds0->accel = devm_iio_device_alloc(dev, sizeof(*data));
        if (!lsm9ds0->accel)
@@ -51,10 +50,9 @@ static int st_lsm9ds0_probe_magn(struct st_lsm9ds0 *lsm9ds0, struct regmap *regm
        struct st_sensor_data *data;
 
        settings = st_magn_get_settings(lsm9ds0->name);
-       if (!settings) {
-               dev_err(dev, "device name %s not recognized.\n", lsm9ds0->name);
-               return -ENODEV;
-       }
+       if (!settings)
+               return dev_err_probe(dev, -ENODEV, "device name %s not recognized.\n",
+                                    lsm9ds0->name);
 
        lsm9ds0->magn = devm_iio_device_alloc(dev, sizeof(*data));
        if (!lsm9ds0->magn)
@@ -80,8 +78,7 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap)
        ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
                                             regulator_names);
        if (ret)
-               return dev_err_probe(dev, ret,
-                                    "unable to enable Vdd supply\n");
+               return dev_err_probe(dev, ret, "unable to enable Vdd supply\n");
 
        /* Setup accelerometer device */
        ret = st_lsm9ds0_probe_accel(lsm9ds0, regmap);
index 61d855083aa012e770dbb8107f6f5e2d5130e593..d03cec3b24fed0ab0c132130d37b3d9598e39ebb 100644 (file)
@@ -7,8 +7,10 @@
  * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  */
 
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gfp_types.h>
 #include <linux/i2c.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
@@ -39,7 +41,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm9ds0_id_table);
 
 static const struct acpi_device_id st_lsm9ds0_acpi_match[] = {
        {"ACCL0001", (kernel_ulong_t)LSM303D_IMU_DEV_NAME},
-       { },
+       {}
 };
 MODULE_DEVICE_TABLE(acpi, st_lsm9ds0_acpi_match);
 
index 8cc041d56cf76257105c4c114cb2bbbdca7860d8..69e9135795a3796be8ad30176292740554fc5b63 100644 (file)
@@ -7,7 +7,9 @@
  * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  */
 
-#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gfp_types.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c
new file mode 100644 (file)
index 0000000..2fea2bb
--- /dev/null
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Framework to handle complex IIO aggregate devices.
+ *
+ * The typical architecture is to have one device as the frontend device which
+ * can be "linked" against one or multiple backend devices. All the IIO and
+ * userspace interface is expected to be registers/managed by the frontend
+ * device which will callback into the backends when needed (to get/set some
+ * configuration that it does not directly control).
+ *
+ *                                           -------------------------------------------------------
+ * ------------------                        | ------------         ------------      -------  FPGA|
+ * |     ADC        |------------------------| | ADC CORE |---------| DMA CORE |------| RAM |      |
+ * | (Frontend/IIO) | Serial Data (eg: LVDS) | |(backend) |---------|          |------|     |      |
+ * |                |------------------------| ------------         ------------      -------      |
+ * ------------------                        -------------------------------------------------------
+ *
+ * The framework interface is pretty simple:
+ *   - Backends should register themselves with devm_iio_backend_register()
+ *   - Frontend devices should get backends with devm_iio_backend_get()
+ *
+ * Also to note that the primary target for this framework are converters like
+ * ADC/DACs so iio_backend_ops will have some operations typical of converter
+ * devices. On top of that, this is "generic" for all IIO which means any kind
+ * of device can make use of the framework. That said, If the iio_backend_ops
+ * struct begins to grow out of control, we can always refactor things so that
+ * the industrialio-backend.c is only left with the really generic stuff. Then,
+ * we can build on top of it depending on the needs.
+ *
+ * Copyright (C) 2023-2024 Analog Devices Inc.
+ */
+#define dev_fmt(fmt) "iio-backend: " fmt
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/iio/backend.h>
+
+struct iio_backend {
+       struct list_head entry;
+       const struct iio_backend_ops *ops;
+       struct device *dev;
+       struct module *owner;
+       void *priv;
+};
+
+/*
+ * Helper struct for requesting buffers. This ensures that we have all data
+ * that we need to free the buffer in a device managed action.
+ */
+struct iio_backend_buffer_pair {
+       struct iio_backend *back;
+       struct iio_buffer *buffer;
+};
+
+static LIST_HEAD(iio_back_list);
+static DEFINE_MUTEX(iio_back_lock);
+
+/*
+ * Helper macros to call backend ops. Makes sure the option is supported.
+ */
+#define iio_backend_check_op(back, op) ({ \
+       struct iio_backend *____back = back;                            \
+       int ____ret = 0;                                                \
+                                                                       \
+       if (!____back->ops->op)                                         \
+               ____ret = -EOPNOTSUPP;                                  \
+                                                                       \
+       ____ret;                                                        \
+})
+
+#define iio_backend_op_call(back, op, args...) ({              \
+       struct iio_backend *__back = back;                      \
+       int __ret;                                              \
+                                                               \
+       __ret = iio_backend_check_op(__back, op);               \
+       if (!__ret)                                             \
+               __ret = __back->ops->op(__back, ##args);        \
+                                                               \
+       __ret;                                                  \
+})
+
+#define iio_backend_ptr_op_call(back, op, args...) ({          \
+       struct iio_backend *__back = back;                      \
+       void *ptr_err;                                          \
+       int __ret;                                              \
+                                                               \
+       __ret = iio_backend_check_op(__back, op);               \
+       if (__ret)                                              \
+               ptr_err = ERR_PTR(__ret);                       \
+       else                                                    \
+               ptr_err = __back->ops->op(__back, ##args);      \
+                                                               \
+       ptr_err;                                                \
+})
+
+#define iio_backend_void_op_call(back, op, args...) {          \
+       struct iio_backend *__back = back;                      \
+       int __ret;                                              \
+                                                               \
+       __ret = iio_backend_check_op(__back, op);               \
+       if (!__ret)                                             \
+               __back->ops->op(__back, ##args);                \
+}
+
+/**
+ * iio_backend_chan_enable - Enable a backend channel
+ * @back:      Backend device
+ * @chan:      Channel number
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan)
+{
+       return iio_backend_op_call(back, chan_enable, chan);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_chan_disable - Disable a backend channel
+ * @back:      Backend device
+ * @chan:      Channel number
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan)
+{
+       return iio_backend_op_call(back, chan_disable, chan);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND);
+
+static void __iio_backend_disable(void *back)
+{
+       iio_backend_void_op_call(back, disable);
+}
+
+/**
+ * devm_iio_backend_enable - Device managed backend enable
+ * @dev:       Consumer device for the backend
+ * @back:      Backend device
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_backend_enable(struct device *dev, struct iio_backend *back)
+{
+       int ret;
+
+       ret = iio_backend_op_call(back, enable);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, __iio_backend_disable, back);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND);
+
+/**
+ * iio_backend_data_format_set - Configure the channel data format
+ * @back:      Backend device
+ * @chan:      Channel number
+ * @data:      Data format
+ *
+ * Properly configure a channel with respect to the expected data format. A
+ * @struct iio_backend_data_fmt must be passed with the settings.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan,
+                               const struct iio_backend_data_fmt *data)
+{
+       if (!data || data->type >= IIO_BACKEND_DATA_TYPE_MAX)
+               return -EINVAL;
+
+       return iio_backend_op_call(back, data_format_set, chan, data);
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND);
+
+static void iio_backend_free_buffer(void *arg)
+{
+       struct iio_backend_buffer_pair *pair = arg;
+
+       iio_backend_void_op_call(pair->back, free_buffer, pair->buffer);
+}
+
+/**
+ * devm_iio_backend_request_buffer - Device managed buffer request
+ * @dev:       Consumer device for the backend
+ * @back:      Backend device
+ * @indio_dev: IIO device
+ *
+ * Request an IIO buffer from the backend. The type of the buffer (typically
+ * INDIO_BUFFER_HARDWARE) is up to the backend to decide. This is because,
+ * normally, the backend dictates what kind of buffering we can get.
+ *
+ * The backend .free_buffer() hooks is automatically called on @dev detach.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_backend_request_buffer(struct device *dev,
+                                   struct iio_backend *back,
+                                   struct iio_dev *indio_dev)
+{
+       struct iio_backend_buffer_pair *pair;
+       struct iio_buffer *buffer;
+
+       pair = devm_kzalloc(dev, sizeof(*pair), GFP_KERNEL);
+       if (!pair)
+               return -ENOMEM;
+
+       buffer = iio_backend_ptr_op_call(back, request_buffer, indio_dev);
+       if (IS_ERR(buffer))
+               return PTR_ERR(buffer);
+
+       /* weak reference should be all what we need */
+       pair->back = back;
+       pair->buffer = buffer;
+
+       return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND);
+
+static void iio_backend_release(void *arg)
+{
+       struct iio_backend *back = arg;
+
+       module_put(back->owner);
+}
+
+static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back)
+{
+       struct device_link *link;
+       int ret;
+
+       /*
+        * Make sure the provider cannot be unloaded before the consumer module.
+        * Note that device_links would still guarantee that nothing is
+        * accessible (and breaks) but this makes it explicit that the consumer
+        * module must be also unloaded.
+        */
+       if (!try_module_get(back->owner))
+               return dev_err_probe(dev, -ENODEV,
+                                    "Cannot get module reference\n");
+
+       ret = devm_add_action_or_reset(dev, iio_backend_release, back);
+       if (ret)
+               return ret;
+
+       link = device_link_add(dev, back->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+       if (!link)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Could not link to supplier(%s)\n",
+                                    dev_name(back->dev));
+
+       dev_dbg(dev, "Found backend(%s) device\n", dev_name(back->dev));
+
+       return 0;
+}
+
+/**
+ * devm_iio_backend_get - Device managed backend device get
+ * @dev:       Consumer device for the backend
+ * @name:      Backend name
+ *
+ * Get's the backend associated with @dev.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name)
+{
+       struct fwnode_handle *fwnode;
+       struct iio_backend *back;
+       unsigned int index;
+       int ret;
+
+       if (name) {
+               ret = device_property_match_string(dev, "io-backend-names",
+                                                  name);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+               index = ret;
+       } else {
+               index = 0;
+       }
+
+       fwnode = fwnode_find_reference(dev_fwnode(dev), "io-backends", index);
+       if (IS_ERR(fwnode)) {
+               dev_err_probe(dev, PTR_ERR(fwnode),
+                             "Cannot get Firmware reference\n");
+               return ERR_CAST(fwnode);
+       }
+
+       guard(mutex)(&iio_back_lock);
+       list_for_each_entry(back, &iio_back_list, entry) {
+               if (!device_match_fwnode(back->dev, fwnode))
+                       continue;
+
+               fwnode_handle_put(fwnode);
+               ret = __devm_iio_backend_get(dev, back);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               return back;
+       }
+
+       fwnode_handle_put(fwnode);
+       return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND);
+
+/**
+ * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get
+ * @dev:       Consumer device for the backend
+ * @fwnode:    Firmware node of the backend device
+ *
+ * Search the backend list for a device matching @fwnode.
+ * This API should not be used and it's only present for preventing the first
+ * user of this framework to break it's DT ABI.
+ *
+ * RETURNS:
+ * A backend pointer, negative error pointer otherwise.
+ */
+struct iio_backend *
+__devm_iio_backend_get_from_fwnode_lookup(struct device *dev,
+                                         struct fwnode_handle *fwnode)
+{
+       struct iio_backend *back;
+       int ret;
+
+       guard(mutex)(&iio_back_lock);
+       list_for_each_entry(back, &iio_back_list, entry) {
+               if (!device_match_fwnode(back->dev, fwnode))
+                       continue;
+
+               ret = __devm_iio_backend_get(dev, back);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               return back;
+       }
+
+       return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND);
+
+/**
+ * iio_backend_get_priv - Get driver private data
+ * @back:      Backend device
+ */
+void *iio_backend_get_priv(const struct iio_backend *back)
+{
+       return back->priv;
+}
+EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND);
+
+static void iio_backend_unregister(void *arg)
+{
+       struct iio_backend *back = arg;
+
+       guard(mutex)(&iio_back_lock);
+       list_del(&back->entry);
+}
+
+/**
+ * devm_iio_backend_register - Device managed backend device register
+ * @dev:       Backend device being registered
+ * @ops:       Backend ops
+ * @priv:      Device private data
+ *
+ * @ops is mandatory. Not providing it results in -EINVAL.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_iio_backend_register(struct device *dev,
+                             const struct iio_backend_ops *ops, void *priv)
+{
+       struct iio_backend *back;
+
+       if (!ops)
+               return dev_err_probe(dev, -EINVAL, "No backend ops given\n");
+
+       /*
+        * Through device_links, we guarantee that a frontend device cannot be
+        * bound/exist if the backend driver is not around. Hence, we can bind
+        * the backend object lifetime with the device being passed since
+        * removing it will tear the frontend/consumer down.
+        */
+       back = devm_kzalloc(dev, sizeof(*back), GFP_KERNEL);
+       if (!back)
+               return -ENOMEM;
+
+       back->ops = ops;
+       back->owner = dev->driver->owner;
+       back->dev = dev;
+       back->priv = priv;
+       scoped_guard(mutex, &iio_back_lock)
+               list_add(&back->entry, &iio_back_list);
+
+       return devm_add_action_or_reset(dev, iio_backend_unregister, back);
+}
+EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
+MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices");
+MODULE_LICENSE("GPL");
index 173dc00762a152e414feac8f1d8d626e01d4bde8..4302093b92c75a93e6373051d67b2e8ccbc88c6b 100644 (file)
@@ -42,7 +42,7 @@ static DEFINE_IDA(iio_ida);
 static dev_t iio_devt;
 
 #define IIO_DEV_MAX 256
-struct bus_type iio_bus_type = {
+const struct bus_type iio_bus_type = {
        .name = "iio",
 };
 EXPORT_SYMBOL(iio_bus_type);
@@ -213,9 +213,7 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
 
-       return iio_dev_opaque->currentmode &
-              (INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE |
-               INDIO_BUFFER_TRIGGERED);
+       return iio_dev_opaque->currentmode & INDIO_ALL_BUFFER_MODES;
 }
 EXPORT_SYMBOL_GPL(iio_buffer_enabled);
 
index 7653261d2dc2bf4cb916f9ca30b239261597a018..b51eb6cb766f3fab9e824a7de8afe488b8c43e1f 100644 (file)
 static int iio_gts_get_gain(const u64 max, const u64 scale)
 {
        u64 full = max;
-       int tmp = 1;
 
        if (scale > full || !scale)
                return -EINVAL;
 
-       if (U64_MAX - full < scale) {
-               /* Risk of overflow */
-               if (full - scale < scale)
-                       return 1;
-
-               full -= scale;
-               tmp++;
-       }
-
-       while (full > scale * (u64)tmp)
-               tmp++;
-
-       return tmp;
+       return div64_u64(full, scale);
 }
 
 /**
index 143003232d1c2ae1d0eeca6eb69610ff641ccc28..fd5a9879a582cf7a60ca86538cfd22ebcdf68acd 100644 (file)
@@ -87,13 +87,14 @@ config APDS9960
          module will be called apds9960
 
 config AS73211
-       tristate "AMS AS73211 XYZ color sensor"
+       tristate "AMS AS73211 XYZ color sensor and AMS AS7331 UV sensor"
        depends on I2C
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
         If you say yes here you get support for the AMS AS73211
-        JENCOLOR(R) Digital XYZ Sensor.
+        JENCOLOR(R) Digital XYZ and the AMS AS7331 UVA, UVB and UVC
+        ultraviolet sensors.
 
         For triggered measurements, you will need an additional trigger driver
         like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER.
index 8f0119f392b7051ce07abc746d7fdaf2e56c082f..53569587ccb7ba4a6bf0806d21b0fdeb43421d16 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/bitfield.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/mod_devicetable.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
index d5957d85c27866e1997c7372425f0f75e80b0951..105f379b9b414f33466583aad1b6834f501d3837 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/bitfield.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 
 #include <linux/iio/iio.h>
index ec97a3a468392d8b79207546d60114d2f85c98c1..be0068081ebbbb37fdfb252b67a77b302ff725f6 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
+ * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331
+ * UVA, UVB and UVC (DUV) Ultraviolet Sensor
  *
  * Author: Christian Eggers <ceggers@arri.de>
  *
@@ -9,7 +10,9 @@
  * Color light sensor with 16-bit channels for x, y, z and temperature);
  * 7-bit I2C slave address 0x74 .. 0x77.
  *
- * Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
+ * Datasheets:
+ * AS73211: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
+ * AS7331: https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf
  */
 
 #include <linux/bitfield.h>
@@ -84,6 +87,20 @@ static const int as73211_hardwaregain_avail[] = {
        1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
 };
 
+struct as73211_data;
+
+/**
+ * struct as73211_spec_dev_data - device-specific data
+ * @intensity_scale:  Function to retrieve intensity scale values.
+ * @channels:          Device channels.
+ * @num_channels:     Number of channels of the device.
+ */
+struct as73211_spec_dev_data {
+       int (*intensity_scale)(struct as73211_data *data, int chan, int *val, int *val2);
+       struct iio_chan_spec const *channels;
+       int num_channels;
+};
+
 /**
  * struct as73211_data - Instance data for one AS73211
  * @client: I2C client.
@@ -94,6 +111,7 @@ static const int as73211_hardwaregain_avail[] = {
  * @mutex:  Keeps cached registers in sync with the device.
  * @completion: Completion to wait for interrupt.
  * @int_time_avail: Available integration times (depend on sampling frequency).
+ * @spec_dev: device-specific configuration.
  */
 struct as73211_data {
        struct i2c_client *client;
@@ -104,6 +122,7 @@ struct as73211_data {
        struct mutex mutex;
        struct completion completion;
        int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2];
+       const struct as73211_spec_dev_data *spec_dev;
 };
 
 #define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \
@@ -138,6 +157,10 @@ struct as73211_data {
 #define AS73211_SCALE_Y 298384270  /* nW/m^2 */
 #define AS73211_SCALE_Z 160241927  /* nW/m^2 */
 
+#define AS7331_SCALE_UVA 340000  /* nW/cm^2 */
+#define AS7331_SCALE_UVB 378000  /* nW/cm^2 */
+#define AS7331_SCALE_UVC 166000  /* nW/cm^2 */
+
 /* Channel order MUST match devices result register order */
 #define AS73211_SCAN_INDEX_TEMP 0
 #define AS73211_SCAN_INDEX_X    1
@@ -176,6 +199,28 @@ static const struct iio_chan_spec as73211_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
 };
 
+static const struct iio_chan_spec as7331_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate =
+                       BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_OFFSET) |
+                       BIT(IIO_CHAN_INFO_SCALE),
+               .address = AS73211_OUT_TEMP,
+               .scan_index = AS73211_SCAN_INDEX_TEMP,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_LE,
+               }
+       },
+       AS73211_COLOR_CHANNEL(LIGHT_UVA, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1),
+       AS73211_COLOR_CHANNEL(LIGHT_UVB, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2),
+       AS73211_COLOR_CHANNEL(LIGHT_DUV, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3),
+       IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
+};
+
 static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data)
 {
        /*
@@ -316,6 +361,48 @@ static int as73211_req_data(struct as73211_data *data)
        return 0;
 }
 
+static int as73211_intensity_scale(struct as73211_data *data, int chan,
+                                  int *val, int *val2)
+{
+       switch (chan) {
+       case IIO_MOD_X:
+               *val = AS73211_SCALE_X;
+               break;
+       case IIO_MOD_Y:
+               *val = AS73211_SCALE_Y;
+               break;
+       case IIO_MOD_Z:
+               *val = AS73211_SCALE_Z;
+               break;
+       default:
+               return -EINVAL;
+       }
+       *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data);
+
+       return IIO_VAL_FRACTIONAL;
+}
+
+static int as7331_intensity_scale(struct as73211_data *data, int chan,
+                                 int *val, int *val2)
+{
+       switch (chan) {
+       case IIO_MOD_LIGHT_UVA:
+               *val = AS7331_SCALE_UVA;
+               break;
+       case IIO_MOD_LIGHT_UVB:
+               *val = AS7331_SCALE_UVB;
+               break;
+       case IIO_MOD_LIGHT_DUV:
+               *val = AS7331_SCALE_UVC;
+               break;
+       default:
+               return -EINVAL;
+       }
+       *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data);
+
+       return IIO_VAL_FRACTIONAL;
+}
+
 static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
                             int *val, int *val2, long mask)
 {
@@ -355,30 +442,13 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons
                        *val2 = AS73211_SCALE_TEMP_MICRO;
                        return IIO_VAL_INT_PLUS_MICRO;
 
-               case IIO_INTENSITY: {
-                       unsigned int scale;
-
-                       switch (chan->channel2) {
-                       case IIO_MOD_X:
-                               scale = AS73211_SCALE_X;
-                               break;
-                       case IIO_MOD_Y:
-                               scale = AS73211_SCALE_Y;
-                               break;
-                       case IIO_MOD_Z:
-                               scale = AS73211_SCALE_Z;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-                       scale /= as73211_gain(data);
-                       scale /= as73211_integration_time_1024cyc(data);
-                       *val = scale;
-                       return IIO_VAL_INT;
+               case IIO_INTENSITY:
+                       return data->spec_dev->intensity_scale(data, chan->channel2,
+                                                              val, val2);
 
                default:
                        return -EINVAL;
-               }}
+               }
 
        case IIO_CHAN_INFO_SAMP_FREQ:
                /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
@@ -676,13 +746,17 @@ static int as73211_probe(struct i2c_client *client)
        i2c_set_clientdata(client, indio_dev);
        data->client = client;
 
+       data->spec_dev = i2c_get_match_data(client);
+       if (!data->spec_dev)
+               return -EINVAL;
+
        mutex_init(&data->mutex);
        init_completion(&data->completion);
 
        indio_dev->info = &as73211_info;
        indio_dev->name = AS73211_DRV_NAME;
-       indio_dev->channels = as73211_channels;
-       indio_dev->num_channels = ARRAY_SIZE(as73211_channels);
+       indio_dev->channels = data->spec_dev->channels;
+       indio_dev->num_channels = data->spec_dev->num_channels;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
        ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
@@ -772,14 +846,28 @@ static int as73211_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend,
                                as73211_resume);
 
+static const struct as73211_spec_dev_data as73211_spec = {
+       .intensity_scale = as73211_intensity_scale,
+       .channels = as73211_channels,
+       .num_channels = ARRAY_SIZE(as73211_channels),
+};
+
+static const struct as73211_spec_dev_data as7331_spec = {
+       .intensity_scale = as7331_intensity_scale,
+       .channels = as7331_channels,
+       .num_channels = ARRAY_SIZE(as7331_channels),
+};
+
 static const struct of_device_id as73211_of_match[] = {
-       { .compatible = "ams,as73211" },
+       { .compatible = "ams,as73211", &as73211_spec },
+       { .compatible = "ams,as7331", &as7331_spec },
        { }
 };
 MODULE_DEVICE_TABLE(of, as73211_of_match);
 
 static const struct i2c_device_id as73211_id[] = {
-       { "as73211", 0 },
+       { "as73211", (kernel_ulong_t)&as73211_spec },
+       { "as7331", (kernel_ulong_t)&as7331_spec },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, as73211_id);
index b6c4bef2a7bb22bbe42463ffc7d72e934e0a2591..260281194f61324e6fa20a6cb96851db68de115a 100644 (file)
 #include "../common/hid-sensors/hid-sensor-trigger.h"
 
 enum {
-       CHANNEL_SCAN_INDEX_INTENSITY = 0,
-       CHANNEL_SCAN_INDEX_ILLUM = 1,
+       CHANNEL_SCAN_INDEX_INTENSITY,
+       CHANNEL_SCAN_INDEX_ILLUM,
+       CHANNEL_SCAN_INDEX_COLOR_TEMP,
+       CHANNEL_SCAN_INDEX_CHROMATICITY_X,
+       CHANNEL_SCAN_INDEX_CHROMATICITY_Y,
        CHANNEL_SCAN_INDEX_MAX
 };
 
@@ -25,6 +28,7 @@ struct als_state {
        struct hid_sensor_hub_callbacks callbacks;
        struct hid_sensor_common common_attributes;
        struct hid_sensor_hub_attribute_info als[CHANNEL_SCAN_INDEX_MAX];
+       struct iio_chan_spec channels[CHANNEL_SCAN_INDEX_MAX + 1];
        struct {
                u32 illum[CHANNEL_SCAN_INDEX_MAX];
                u64 timestamp __aligned(8);
@@ -33,7 +37,18 @@ struct als_state {
        int scale_post_decml;
        int scale_precision;
        int value_offset;
+       int num_channels;
        s64 timestamp;
+       unsigned long als_scan_mask[2];
+};
+
+/* The order of usage ids must match scan index starting from CHANNEL_SCAN_INDEX_INTENSITY */
+static const u32 als_usage_ids[] = {
+       HID_USAGE_SENSOR_LIGHT_ILLUM,
+       HID_USAGE_SENSOR_LIGHT_ILLUM,
+       HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE,
+       HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X,
+       HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y,
 };
 
 static const u32 als_sensitivity_addresses[] = {
@@ -65,6 +80,40 @@ static const struct iio_chan_spec als_channels[] = {
                BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
                .scan_index = CHANNEL_SCAN_INDEX_ILLUM,
        },
+       {
+               .type = IIO_COLORTEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+               BIT(IIO_CHAN_INFO_SCALE) |
+               BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+               BIT(IIO_CHAN_INFO_HYSTERESIS) |
+               BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
+               .scan_index = CHANNEL_SCAN_INDEX_COLOR_TEMP,
+       },
+       {
+               .type = IIO_CHROMATICITY,
+               .modified = 1,
+               .channel2 = IIO_MOD_X,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+               BIT(IIO_CHAN_INFO_SCALE) |
+               BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+               BIT(IIO_CHAN_INFO_HYSTERESIS) |
+               BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
+               .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_X,
+       },
+       {
+               .type = IIO_CHROMATICITY,
+               .modified = 1,
+               .channel2 = IIO_MOD_Y,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+               BIT(IIO_CHAN_INFO_SCALE) |
+               BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+               BIT(IIO_CHAN_INFO_HYSTERESIS) |
+               BIT(IIO_CHAN_INFO_HYSTERESIS_RELATIVE),
+               .scan_index = CHANNEL_SCAN_INDEX_CHROMATICITY_Y,
+       },
        IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
 };
 
@@ -103,6 +152,21 @@ static int als_read_raw(struct iio_dev *indio_dev,
                        min = als_state->als[chan->scan_index].logical_minimum;
                        address = HID_USAGE_SENSOR_LIGHT_ILLUM;
                        break;
+               case  CHANNEL_SCAN_INDEX_COLOR_TEMP:
+                       report_id = als_state->als[chan->scan_index].report_id;
+                       min = als_state->als[chan->scan_index].logical_minimum;
+                       address = HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE;
+                       break;
+               case  CHANNEL_SCAN_INDEX_CHROMATICITY_X:
+                       report_id = als_state->als[chan->scan_index].report_id;
+                       min = als_state->als[chan->scan_index].logical_minimum;
+                       address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X;
+                       break;
+               case  CHANNEL_SCAN_INDEX_CHROMATICITY_Y:
+                       report_id = als_state->als[chan->scan_index].report_id;
+                       min = als_state->als[chan->scan_index].logical_minimum;
+                       address = HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y;
+                       break;
                default:
                        report_id = -1;
                        break;
@@ -223,6 +287,18 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
                als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
                ret = 0;
                break;
+       case HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE:
+               als_state->scan.illum[CHANNEL_SCAN_INDEX_COLOR_TEMP] = sample_data;
+               ret = 0;
+               break;
+       case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X:
+               als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_X] = sample_data;
+               ret = 0;
+               break;
+       case HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y:
+               als_state->scan.illum[CHANNEL_SCAN_INDEX_CHROMATICITY_Y] = sample_data;
+               ret = 0;
+               break;
        case HID_USAGE_SENSOR_TIME_TIMESTAMP:
                als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
                                                                    *(s64 *)raw_data);
@@ -238,27 +314,38 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
 /* Parse report which is specific to an usage id*/
 static int als_parse_report(struct platform_device *pdev,
                                struct hid_sensor_hub_device *hsdev,
-                               struct iio_chan_spec *channels,
                                unsigned usage_id,
                                struct als_state *st)
 {
-       int ret;
+       struct iio_chan_spec *channels;
+       int ret, index = 0;
        int i;
 
-       for (i = 0; i <= CHANNEL_SCAN_INDEX_ILLUM; ++i) {
+       channels = st->channels;
+
+       for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; ++i) {
                ret = sensor_hub_input_get_attribute_info(hsdev,
                                                HID_INPUT_REPORT,
                                                usage_id,
-                                               HID_USAGE_SENSOR_LIGHT_ILLUM,
+                                               als_usage_ids[i],
                                                &st->als[i]);
                if (ret < 0)
-                       return ret;
-               als_adjust_channel_bit_mask(channels, i, st->als[i].size);
+                       continue;
+
+               channels[index] = als_channels[i];
+               st->als_scan_mask[0] |= BIT(i);
+               als_adjust_channel_bit_mask(channels, index, st->als[i].size);
+               ++index;
 
                dev_dbg(&pdev->dev, "als %x:%x\n", st->als[i].index,
                        st->als[i].report_id);
        }
 
+       st->num_channels = index;
+       /* Return success even if one usage id is present */
+       if (index)
+               ret = 0;
+
        st->scale_precision = hid_sensor_format_scale(usage_id,
                                &st->als[CHANNEL_SCAN_INDEX_INTENSITY],
                                &st->scale_pre_decml, &st->scale_post_decml);
@@ -294,15 +381,7 @@ static int hid_als_probe(struct platform_device *pdev)
                return ret;
        }
 
-       indio_dev->channels = devm_kmemdup(&pdev->dev, als_channels,
-                                          sizeof(als_channels), GFP_KERNEL);
-       if (!indio_dev->channels) {
-               dev_err(&pdev->dev, "failed to duplicate channels\n");
-               return -ENOMEM;
-       }
-
        ret = als_parse_report(pdev, hsdev,
-                              (struct iio_chan_spec *)indio_dev->channels,
                               hsdev->usage,
                               als_state);
        if (ret) {
@@ -310,8 +389,15 @@ static int hid_als_probe(struct platform_device *pdev)
                return ret;
        }
 
-       indio_dev->num_channels =
-                               ARRAY_SIZE(als_channels);
+       /* Add timestamp channel */
+       als_state->channels[als_state->num_channels] = als_channels[CHANNEL_SCAN_INDEX_TIMESTAMP];
+
+       /* +1 for adding timestamp channel */
+       indio_dev->num_channels = als_state->num_channels + 1;
+
+       indio_dev->channels = als_state->channels;
+       indio_dev->available_scan_masks = als_state->als_scan_mask;
+
        indio_dev->info = &als_info;
        indio_dev->name = name;
        indio_dev->modes = INDIO_DIRECT_MODE;
index 37e2807041a1dd3ca8fd90fb9daee73cbeb3b6a6..869196746045e339cbc8a2765b0fcca3d8dbd9a5 100644 (file)
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
-#include <linux/acpi.h>
 #include <linux/regmap.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -438,7 +438,7 @@ static struct i2c_driver jsa1212_driver = {
        .driver = {
                .name   = JSA1212_DRIVER_NAME,
                .pm     = pm_sleep_ptr(&jsa1212_pm_ops),
-               .acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
+               .acpi_match_table = jsa1212_acpi_match,
        },
        .probe          = jsa1212_probe,
        .remove         = jsa1212_remove,
index 061c122fdc5e70f5c0e2f3abef1386536202cedf..8c516ede911619bb4ee8f8a823f242b7aaa6af55 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/delay.h>
@@ -1639,7 +1640,7 @@ static struct i2c_driver ltr501_driver = {
                .name   = LTR501_DRV_NAME,
                .of_match_table = ltr501_of_match,
                .pm     = pm_sleep_ptr(&ltr501_pm_ops),
-               .acpi_match_table = ACPI_PTR(ltr_acpi_match),
+               .acpi_match_table = ltr_acpi_match,
        },
        .probe = ltr501_probe,
        .remove = ltr501_remove,
index db96c5b73100c6047f3a9a3f6f18240f6217e70f..26b464b1b650eceaaaa76906f661f40b2ff4bf6d 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
@@ -19,7 +20,6 @@
 #include <linux/iio/buffer.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
-#include <linux/acpi.h>
 
 #define MAX44000_DRV_NAME              "max44000"
 
@@ -603,18 +603,16 @@ static const struct i2c_device_id max44000_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max44000_id);
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id max44000_acpi_match[] = {
        {"MAX44000", 0},
        { }
 };
 MODULE_DEVICE_TABLE(acpi, max44000_acpi_match);
-#endif
 
 static struct i2c_driver max44000_driver = {
        .driver = {
                .name   = MAX44000_DRV_NAME,
-               .acpi_match_table = ACPI_PTR(max44000_acpi_match),
+               .acpi_match_table = max44000_acpi_match,
        },
        .probe          = max44000_probe,
        .id_table       = max44000_id,
index bbb8581622f29d358f3f04415725b802a0952793..40d5732b5e320e35993c5368e2a532e16423d34f 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/delay.h>
-#include <linux/acpi.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
@@ -1119,7 +1119,7 @@ static struct i2c_driver rpr0521_driver = {
        .driver = {
                .name   = RPR0521_DRV_NAME,
                .pm     = pm_ptr(&rpr0521_pm_ops),
-               .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
+               .acpi_match_table = rpr0521_acpi_match,
        },
        .probe          = rpr0521_probe,
        .remove         = rpr0521_remove,
index 72b08d870d337b9ca583e2449f0b8a02a8e5dc19..7b71ad71d78ded6cb5384214977774c60edc0576 100644 (file)
@@ -7,11 +7,11 @@
  * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48.
  */
 
-#include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/regmap.h>
 #include <linux/iio/events.h>
 #include <linux/iio/iio.h>
@@ -712,7 +712,7 @@ static struct i2c_driver stk3310_driver = {
                .name = "stk3310",
                .of_match_table = stk3310_of_match,
                .pm = pm_sleep_ptr(&stk3310_pm_ops),
-               .acpi_match_table = ACPI_PTR(stk3310_acpi_id),
+               .acpi_match_table = stk3310_acpi_id,
        },
        .probe =        stk3310_probe,
        .remove =           stk3310_remove,
index 61b3b2aea626fb2322a5ab87be28085447f8e443..9189a1d4d7e1ab55cd9d67280d1881b8584fbdc4 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/acpi.h>
+#include <linux/mod_devicetable.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/iio/events.h>
@@ -972,7 +972,7 @@ static struct i2c_driver us5182d_driver = {
                .name = US5182D_DRV_NAME,
                .pm = pm_ptr(&us5182d_pm_ops),
                .of_match_table = us5182d_of_match,
-               .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
+               .acpi_match_table = us5182d_acpi_match,
        },
        .probe = us5182d_probe,
        .remove = us5182d_remove,
index fdf763a04b0bfac2fef3eb50a1f1d85df995122e..4e3641ff2ed446262c12380e520d3d220865c00c 100644 (file)
@@ -90,6 +90,7 @@
 #define VCNL4040_PS_CONF1_PS_SHUTDOWN  BIT(0)
 #define VCNL4040_PS_CONF2_PS_IT        GENMASK(3, 1) /* Proximity integration time */
 #define VCNL4040_CONF1_PS_PERS GENMASK(5, 4) /* Proximity interrupt persistence setting */
+#define VCNL4040_PS_CONF2_PS_HD                BIT(11) /* Proximity high definition */
 #define VCNL4040_PS_CONF2_PS_INT       GENMASK(9, 8) /* Proximity interrupt mode */
 #define VCNL4040_PS_CONF3_MPS          GENMASK(6, 5) /* Proximity multi pulse number */
 #define VCNL4040_PS_MS_LED_I           GENMASK(10, 8) /* Proximity current */
 #define VCNL4010_INT_DRDY \
        (BIT(VCNL4010_INT_PROXIMITY) | BIT(VCNL4010_INT_ALS))
 
+#define VCNL4040_CONF3_PS_MPS_16BITS   3       /* 8 multi pulses */
+#define VCNL4040_CONF3_PS_LED_I_16BITS 3       /* 120 mA */
+
+#define VCNL4040_CONF3_PS_SAMPLE_16BITS \
+       (FIELD_PREP(VCNL4040_PS_CONF3_MPS, VCNL4040_CONF3_PS_MPS_16BITS) | \
+        FIELD_PREP(VCNL4040_PS_MS_LED_I, VCNL4040_CONF3_PS_LED_I_16BITS))
+
 static const int vcnl4010_prox_sampling_frequency[][2] = {
        {1, 950000},
        {3, 906250},
@@ -195,6 +203,7 @@ struct vcnl4000_data {
        enum vcnl4000_device_ids id;
        int rev;
        int al_scale;
+       int ps_scale;
        u8 ps_int;              /* proximity interrupt mode */
        u8 als_int;             /* ambient light interrupt mode*/
        const struct vcnl4000_chip_spec *chip_spec;
@@ -345,6 +354,7 @@ static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
 static int vcnl4200_init(struct vcnl4000_data *data)
 {
        int ret, id;
+       u16 regval;
 
        ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
        if (ret < 0)
@@ -386,9 +396,32 @@ static int vcnl4200_init(struct vcnl4000_data *data)
                break;
        }
        data->al_scale = data->chip_spec->ulux_step;
+       data->ps_scale = 16;
        mutex_init(&data->vcnl4200_al.lock);
        mutex_init(&data->vcnl4200_ps.lock);
 
+       /* Use 16 bits proximity sensor readings */
+       ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF1);
+       if (ret < 0)
+               return ret;
+
+       regval = ret | VCNL4040_PS_CONF2_PS_HD;
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1,
+                                       regval);
+       if (ret < 0)
+               return ret;
+
+       /* Align proximity sensor sample rate to 16 bits data width */
+       ret = i2c_smbus_read_word_data(data->client, VCNL4200_PS_CONF3);
+       if (ret < 0)
+               return ret;
+
+       regval = ret | VCNL4040_CONF3_PS_SAMPLE_16BITS;
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF3,
+                                       regval);
+       if (ret < 0)
+               return ret;
+
        ret = data->chip_spec->set_power_state(data, true);
        if (ret < 0)
                return ret;
@@ -901,8 +934,9 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
                        break;
                case IIO_PROXIMITY:
                        ret = data->chip_spec->measure_proximity(data, val);
+                       *val2 = data->ps_scale;
                        if (!ret)
-                               ret = IIO_VAL_INT;
+                               ret = IIO_VAL_FRACTIONAL;
                        break;
                default:
                        ret = -EINVAL;
index d4948dfc31ff14ab13bed360c7889dfd94cda762..dcadf6428a87d24316df3a767bac067b09051f41 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
-#include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/util_macros.h>
 
index 38532d840f2a369619711ddf035ae0ed93a600e2..cd2917d719047bf81384bc3048c052f8368a67f2 100644 (file)
@@ -6,6 +6,18 @@
 
 menu "Magnetometer sensors"
 
+config AF8133J
+       tristate "Voltafield AF8133J 3-Axis Magnetometer"
+       depends on I2C
+       depends on OF
+       select REGMAP_I2C
+       help
+         Say yes here to build support for Voltafield AF8133J I2C-based
+         3-axis magnetometer chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called af8133j.
+
 config AK8974
        tristate "Asahi Kasei AK8974 3-Axis Magnetometer"
        depends on I2C
index b1c784ea71c8e082c4c716ec80db6ab624cdca25..ec5c46fbf999b6403593de2c425079cf69a29cac 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AF8133J)  += af8133j.o
 obj-$(CONFIG_AK8974)   += ak8974.o
 obj-$(CONFIG_AK8975)   += ak8975.o
 obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c
new file mode 100644 (file)
index 0000000..742bbdf
--- /dev/null
@@ -0,0 +1,528 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * af8133j.c - Voltafield AF8133J magnetometer driver
+ *
+ * Copyright 2021 Icenowy Zheng <icenowy@aosc.io>
+ * Copyright 2024 Ondřej Jirman <megi@xff.cz>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define AF8133J_REG_OUT                0x03
+#define AF8133J_REG_PCODE      0x00
+#define AF8133J_REG_PCODE_VAL  0x5e
+#define AF8133J_REG_STATUS     0x02
+#define AF8133J_REG_STATUS_ACQ BIT(0)
+#define AF8133J_REG_STATE      0x0a
+#define AF8133J_REG_STATE_STBY 0x00
+#define AF8133J_REG_STATE_WORK 0x01
+#define AF8133J_REG_RANGE      0x0b
+#define AF8133J_REG_RANGE_22G  0x12
+#define AF8133J_REG_RANGE_12G  0x34
+#define AF8133J_REG_SWR                0x11
+#define AF8133J_REG_SWR_PERFORM        0x81
+
+static const char * const af8133j_supply_names[] = {
+       "avdd",
+       "dvdd",
+};
+
+struct af8133j_data {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       /*
+        * Protect device internal state between starting a measurement
+        * and reading the result.
+        */
+       struct mutex mutex;
+       struct iio_mount_matrix orientation;
+
+       struct gpio_desc *reset_gpiod;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(af8133j_supply_names)];
+
+       u8 range;
+};
+
+enum af8133j_axis {
+       AXIS_X = 0,
+       AXIS_Y,
+       AXIS_Z,
+};
+
+static struct iio_mount_matrix *
+af8133j_get_mount_matrix(struct iio_dev *indio_dev,
+                        const struct iio_chan_spec *chan)
+{
+       struct af8133j_data *data = iio_priv(indio_dev);
+
+       return &data->orientation;
+}
+
+static const struct iio_chan_spec_ext_info af8133j_ext_info[] = {
+       IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, af8133j_get_mount_matrix),
+       { }
+};
+
+#define AF8133J_CHANNEL(_si, _axis) { \
+       .type = IIO_MAGN, \
+       .modified = 1, \
+       .channel2 = IIO_MOD_ ## _axis, \
+       .address = AXIS_ ## _axis, \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+       .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+       .ext_info = af8133j_ext_info, \
+       .scan_index = _si, \
+       .scan_type = { \
+               .sign = 's', \
+               .realbits = 16, \
+               .storagebits = 16, \
+               .endianness = IIO_LE, \
+       }, \
+}
+
+static const struct iio_chan_spec af8133j_channels[] = {
+       AF8133J_CHANNEL(0, X),
+       AF8133J_CHANNEL(1, Y),
+       AF8133J_CHANNEL(2, Z),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static int af8133j_product_check(struct af8133j_data *data)
+{
+       struct device *dev = &data->client->dev;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(data->regmap, AF8133J_REG_PCODE, &val);
+       if (ret) {
+               dev_err(dev, "Error reading product code (%d)\n", ret);
+               return ret;
+       }
+
+       if (val != AF8133J_REG_PCODE_VAL) {
+               dev_warn(dev, "Invalid product code (0x%02x)\n", val);
+               return 0; /* Allow unknown ID so fallback compatibles work */
+       }
+
+       return 0;
+}
+
+static int af8133j_reset(struct af8133j_data *data)
+{
+       struct device *dev = &data->client->dev;
+       int ret;
+
+       if (data->reset_gpiod) {
+               /* If we have GPIO reset line, use it */
+               gpiod_set_value_cansleep(data->reset_gpiod, 1);
+               udelay(10);
+               gpiod_set_value_cansleep(data->reset_gpiod, 0);
+       } else {
+               /* Otherwise use software reset */
+               ret = regmap_write(data->regmap, AF8133J_REG_SWR,
+                                  AF8133J_REG_SWR_PERFORM);
+               if (ret) {
+                       dev_err(dev, "Failed to reset the chip\n");
+                       return ret;
+               }
+       }
+
+       /* Wait for reset to finish */
+       usleep_range(1000, 1100);
+
+       /* Restore range setting */
+       if (data->range == AF8133J_REG_RANGE_22G) {
+               ret = regmap_write(data->regmap, AF8133J_REG_RANGE, data->range);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void af8133j_power_down(struct af8133j_data *data)
+{
+       gpiod_set_value_cansleep(data->reset_gpiod, 1);
+       regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
+}
+
+static int af8133j_power_up(struct af8133j_data *data)
+{
+       struct device *dev = &data->client->dev;
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
+       if (ret) {
+               dev_err(dev, "Could not enable regulators\n");
+               return ret;
+       }
+
+       gpiod_set_value_cansleep(data->reset_gpiod, 0);
+
+       /* Wait for power on reset */
+       usleep_range(15000, 16000);
+
+       ret = af8133j_reset(data);
+       if (ret) {
+               af8133j_power_down(data);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int af8133j_take_measurement(struct af8133j_data *data)
+{
+       unsigned int val;
+       int ret;
+
+       ret = regmap_write(data->regmap,
+                          AF8133J_REG_STATE, AF8133J_REG_STATE_WORK);
+       if (ret)
+               return ret;
+
+       /* The datasheet says "Mesaure Time <1.5ms" */
+       ret = regmap_read_poll_timeout(data->regmap, AF8133J_REG_STATUS, val,
+                                      val & AF8133J_REG_STATUS_ACQ,
+                                      500, 1500);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(data->regmap,
+                          AF8133J_REG_STATE, AF8133J_REG_STATE_STBY);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int af8133j_read_measurement(struct af8133j_data *data, __le16 buf[3])
+{
+       struct device *dev = &data->client->dev;
+       int ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret) {
+               /*
+                * Ignore EACCES because that happens when RPM is disabled
+                * during system sleep, while userspace leave eg. hrtimer
+                * trigger attached and IIO core keeps trying to do measurements.
+                */
+               if (ret != -EACCES)
+                       dev_err(dev, "Failed to power on (%d)\n", ret);
+               return ret;
+       }
+
+       scoped_guard(mutex, &data->mutex) {
+               ret = af8133j_take_measurement(data);
+               if (ret)
+                       goto out_rpm_put;
+
+               ret = regmap_bulk_read(data->regmap, AF8133J_REG_OUT,
+                                      buf, sizeof(__le16) * 3);
+       }
+
+out_rpm_put:
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
+}
+
+static const int af8133j_scales[][2] = {
+       [0] = { 0, 366210 }, /* 12 gauss */
+       [1] = { 0, 671386 }, /* 22 gauss */
+};
+
+static int af8133j_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan, int *val,
+                           int *val2, long mask)
+{
+       struct af8133j_data *data = iio_priv(indio_dev);
+       __le16 buf[3];
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = af8133j_read_measurement(data, buf);
+               if (ret)
+                       return ret;
+
+               *val = sign_extend32(le16_to_cpu(buf[chan->address]),
+                                    chan->scan_type.realbits - 1);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+
+               if (data->range == AF8133J_REG_RANGE_12G)
+                       *val2 = af8133j_scales[0][1];
+               else
+                       *val2 = af8133j_scales[1][1];
+
+               return IIO_VAL_INT_PLUS_NANO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int af8133j_read_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_SCALE:
+               *vals = (const int *)af8133j_scales;
+               *length = ARRAY_SIZE(af8133j_scales) * 2;
+               *type = IIO_VAL_INT_PLUS_NANO;
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int af8133j_set_scale(struct af8133j_data *data,
+                            unsigned int val, unsigned int val2)
+{
+       struct device *dev = &data->client->dev;
+       u8 range;
+       int ret = 0;
+
+       if (af8133j_scales[0][0] == val && af8133j_scales[0][1] == val2)
+               range = AF8133J_REG_RANGE_12G;
+       else if (af8133j_scales[1][0] == val && af8133j_scales[1][1] == val2)
+               range = AF8133J_REG_RANGE_22G;
+       else
+               return -EINVAL;
+
+       pm_runtime_disable(dev);
+
+       /*
+        * When suspended, just store the new range to data->range to be
+        * applied later during power up.
+        */
+       if (!pm_runtime_status_suspended(dev))
+               scoped_guard(mutex, &data->mutex)
+                       ret = regmap_write(data->regmap,
+                                          AF8133J_REG_RANGE, range);
+
+       pm_runtime_enable(dev);
+
+       data->range = range;
+       return ret;
+}
+
+static int af8133j_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct af8133j_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               return af8133j_set_scale(data, val, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int af8133j_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                    struct iio_chan_spec const *chan,
+                                    long mask)
+{
+       return IIO_VAL_INT_PLUS_NANO;
+}
+
+static const struct iio_info af8133j_info = {
+       .read_raw = af8133j_read_raw,
+       .read_avail = af8133j_read_avail,
+       .write_raw = af8133j_write_raw,
+       .write_raw_get_fmt = af8133j_write_raw_get_fmt,
+};
+
+static irqreturn_t af8133j_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct af8133j_data *data = iio_priv(indio_dev);
+       s64 timestamp = iio_get_time_ns(indio_dev);
+       struct {
+               __le16 values[3];
+               s64 timestamp __aligned(8);
+       } sample;
+       int ret;
+
+       memset(&sample, 0, sizeof(sample));
+
+       ret = af8133j_read_measurement(data, sample.values);
+       if (ret)
+               goto out_done;
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &sample, timestamp);
+
+out_done:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static const struct regmap_config af8133j_regmap_config = {
+       .name = "af8133j_regmap",
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = AF8133J_REG_SWR,
+       .cache_type = REGCACHE_NONE,
+};
+
+static void af8133j_power_down_action(void *ptr)
+{
+       struct af8133j_data *data = ptr;
+
+       if (!pm_runtime_status_suspended(&data->client->dev))
+               af8133j_power_down(data);
+}
+
+static int af8133j_probe(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct af8133j_data *data;
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       int ret, i;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_i2c(client, &af8133j_regmap_config);
+       if (IS_ERR(regmap))
+               return dev_err_probe(dev, PTR_ERR(regmap),
+                                    "regmap initialization failed\n");
+
+       data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
+       data->client = client;
+       data->regmap = regmap;
+       data->range = AF8133J_REG_RANGE_12G;
+       mutex_init(&data->mutex);
+
+       data->reset_gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(data->reset_gpiod))
+               return dev_err_probe(dev, PTR_ERR(data->reset_gpiod),
+                                    "Failed to get reset gpio\n");
+
+       for (i = 0; i < ARRAY_SIZE(af8133j_supply_names); i++)
+               data->supplies[i].supply = af8133j_supply_names[i];
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
+                                     data->supplies);
+       if (ret)
+               return ret;
+
+       ret = iio_read_mount_matrix(dev, &data->orientation);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to read mount matrix\n");
+
+       ret = af8133j_power_up(data);
+       if (ret)
+               return ret;
+
+       pm_runtime_set_active(dev);
+
+       ret = devm_add_action_or_reset(dev, af8133j_power_down_action, data);
+       if (ret)
+               return ret;
+
+       ret = af8133j_product_check(data);
+       if (ret)
+               return ret;
+
+       pm_runtime_get_noresume(dev);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_autosuspend_delay(dev, 500);
+       ret = devm_pm_runtime_enable(dev);
+       if (ret)
+               return ret;
+
+       pm_runtime_put_autosuspend(dev);
+
+       indio_dev->info = &af8133j_info;
+       indio_dev->name = "af8133j";
+       indio_dev->channels = af8133j_channels;
+       indio_dev->num_channels = ARRAY_SIZE(af8133j_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             &af8133j_trigger_handler, NULL);
+       if (ret)
+               return dev_err_probe(&client->dev, ret,
+                                    "Failed to setup iio triggered buffer\n");
+
+       ret = devm_iio_device_register(dev, indio_dev);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to register iio device");
+
+       return 0;
+}
+
+static int af8133j_runtime_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct af8133j_data *data = iio_priv(indio_dev);
+
+       af8133j_power_down(data);
+
+       return 0;
+}
+
+static int af8133j_runtime_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct af8133j_data *data = iio_priv(indio_dev);
+
+       return af8133j_power_up(data);
+}
+
+static const struct dev_pm_ops af8133j_pm_ops = {
+       SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+       RUNTIME_PM_OPS(af8133j_runtime_suspend, af8133j_runtime_resume, NULL)
+};
+
+static const struct of_device_id af8133j_of_match[] = {
+       { .compatible = "voltafield,af8133j", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, af8133j_of_match);
+
+static const struct i2c_device_id af8133j_id[] = {
+       { "af8133j", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, af8133j_id);
+
+static struct i2c_driver af8133j_driver = {
+       .driver = {
+               .name = "af8133j",
+               .of_match_table = af8133j_of_match,
+               .pm = pm_ptr(&af8133j_pm_ops),
+       },
+       .probe = af8133j_probe,
+       .id_table = af8133j_id,
+};
+
+module_i2c_driver(af8133j_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_AUTHOR("Ondřej Jirman <megi@xff.cz>");
+MODULE_DESCRIPTION("Voltafield AF8133J magnetic sensor driver");
+MODULE_LICENSE("GPL");
index 281d1fa31c8e17dc71f6a92e9e33b02904bc7f2c..48d9c698f520eadadfbf691a8fa360578abc53ad 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/mod_devicetable.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <linux/acpi.h>
 #include <linux/regmap.h>
 
 #include "bmc150_magn.h"
@@ -68,7 +67,7 @@ static struct i2c_driver bmc150_magn_driver = {
        .driver = {
                .name   = "bmc150_magn_i2c",
                .of_match_table = bmc150_magn_of_match,
-               .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+               .acpi_match_table = bmc150_magn_acpi_match,
                .pm     = &bmc150_magn_pm_ops,
        },
        .probe          = bmc150_magn_i2c_probe,
index 882987721071bd4c4193490a26fc4d4e53f5dc7f..abc75a05c46afdf2d49ec1324aebbf37207f405a 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/spi/spi.h>
-#include <linux/acpi.h>
 #include <linux/regmap.h>
 
 #include "bmc150_magn.h"
@@ -55,7 +54,7 @@ static struct spi_driver bmc150_magn_spi_driver = {
        .remove         = bmc150_magn_spi_remove,
        .id_table       = bmc150_magn_spi_id,
        .driver = {
-               .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+               .acpi_match_table = bmc150_magn_acpi_match,
                .name   = "bmc150_magn_spi",
        },
 };
index b495b8a6392848e3eca7dc278eacdcc21803291a..6b9f4b05619122582b40b5d213386e9af5954e2e 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/regmap.h>
-#include <linux/acpi.h>
 #include <linux/pm.h>
 
 #include <linux/iio/iio.h>
@@ -573,7 +573,7 @@ static struct i2c_driver mmc35240_driver = {
                .name = MMC35240_DRV_NAME,
                .of_match_table = mmc35240_of_match,
                .pm = pm_sleep_ptr(&mmc35240_pm_ops),
-               .acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
+               .acpi_match_table = mmc35240_acpi_match,
        },
        .probe          = mmc35240_probe,
        .id_table       = mmc35240_id,
index 42723c996c9f4f7ef48fdc8800c72bbae829fc2e..4838d2e72f53def3b388cba135cf62835a6dc89d 100644 (file)
@@ -5,8 +5,8 @@
  * Copyright (C) 2016 Cristina-Gabriela Moraru <cristina.moraru09@gmail.com>
  */
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/spi/spi.h>
-#include <linux/acpi.h>
 
 #include <linux/iio/sysfs.h>
 #include <linux/iio/iio.h>
@@ -144,7 +144,7 @@ MODULE_DEVICE_TABLE(acpi, max5487_acpi_match);
 static struct spi_driver max5487_driver = {
        .driver = {
                .name = "max5487",
-               .acpi_match_table = ACPI_PTR(max5487_acpi_match),
+               .acpi_match_table = max5487_acpi_match,
        },
        .id_table = max5487_id,
        .probe = max5487_spi_probe,
index 79adfd059c3a7e15a95b129d4fc686f8756f0e64..3ad38506028ef055f9ff14eb077a3599fa10c458 100644 (file)
@@ -114,6 +114,8 @@ config HSC030PA
        depends on (I2C || SPI_MASTER)
        select HSC030PA_I2C if I2C
        select HSC030PA_SPI if SPI_MASTER
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        help
          Say Y here to build support for the Honeywell TruStability
          HSC and SSC pressure and temperature sensor series.
@@ -181,7 +183,9 @@ config MPL3115
 
 config MPRLS0025PA
        tristate "Honeywell MPRLS0025PA (MicroPressure sensors series)"
-       depends on I2C
+       depends on (I2C || SPI_MASTER)
+       select MPRLS0025PA_I2C if I2C
+       select MPRLS0025PA_SPI if SPI_MASTER
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
@@ -192,6 +196,16 @@ config MPRLS0025PA
          To compile this driver as a module, choose M here: the module will be
          called mprls0025pa.
 
+config MPRLS0025PA_I2C
+       tristate
+       depends on MPRLS0025PA
+       depends on I2C
+
+config MPRLS0025PA_SPI
+       tristate
+       depends on MPRLS0025PA
+       depends on SPI_MASTER
+
 config MS5611
        tristate "Measurement Specialties MS5611 pressure sensor driver"
        select IIO_BUFFER
index b0f8b94662f2094e1a9a503381ea401c1ea1460b..a93709e357607d3704744eda98269f2b60e955e9 100644 (file)
@@ -24,6 +24,8 @@ obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o
 obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o
 obj-$(CONFIG_MPL3115) += mpl3115.o
 obj-$(CONFIG_MPRLS0025PA) += mprls0025pa.o
+obj-$(CONFIG_MPRLS0025PA_I2C) += mprls0025pa_i2c.o
+obj-$(CONFIG_MPRLS0025PA_SPI) += mprls0025pa_spi.o
 obj-$(CONFIG_MS5611) += ms5611_core.o
 obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
 obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
index a072de6cb59c7f82240156e73cc2699fcc29c152..261af1562827c8ef7c0d86a29b8b180596dedb11 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/delay.h>
 #include <linux/util_macros.h>
-#include <linux/acpi.h>
 
 #include <asm/unaligned.h>
 
@@ -400,20 +400,18 @@ static const struct i2c_device_id hp206c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, hp206c_id);
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id hp206c_acpi_match[] = {
        {"HOP206C", 0},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
-#endif
 
 static struct i2c_driver hp206c_driver = {
        .probe = hp206c_probe,
        .id_table = hp206c_id,
        .driver = {
                .name = "hp206c",
-               .acpi_match_table = ACPI_PTR(hp206c_acpi_match),
+               .acpi_match_table = hp206c_acpi_match,
        },
 };
 
index d6a51f0c335fad476a07d97ca63e02b920ce441b..1682b90d4557c2b394544074d439d908ba882c4b 100644 (file)
 #include <linux/types.h>
 #include <linux/units.h>
 
+#include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #include <asm/unaligned.h>
 
@@ -297,6 +300,29 @@ static int hsc_get_measurement(struct hsc_data *data)
        return 0;
 }
 
+static irqreturn_t hsc_trigger_handler(int irq, void *private)
+{
+       struct iio_poll_func *pf = private;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct hsc_data *data = iio_priv(indio_dev);
+       int ret;
+
+       ret = hsc_get_measurement(data);
+       if (ret)
+               goto error;
+
+       memcpy(&data->scan.chan[0], &data->buffer[0], 2);
+       memcpy(&data->scan.chan[1], &data->buffer[2], 2);
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
+                                          iio_get_time_ns(indio_dev));
+
+error:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
 /*
  * IIO ABI expects
  * value = (conv + offset) * scale
@@ -382,13 +408,29 @@ static const struct iio_chan_spec hsc_channels[] = {
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                                      BIT(IIO_CHAN_INFO_SCALE) |
                                      BIT(IIO_CHAN_INFO_OFFSET),
+               .scan_index = 0,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 14,
+                       .storagebits = 16,
+                       .endianness = IIO_BE,
+               },
        },
        {
                .type = IIO_TEMP,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                                      BIT(IIO_CHAN_INFO_SCALE) |
                                      BIT(IIO_CHAN_INFO_OFFSET),
+               .scan_index = 1,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 11,
+                       .storagebits = 16,
+                       .shift = 5,
+                       .endianness = IIO_BE,
+               },
        },
+       IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
 static const struct iio_info hsc_info = {
@@ -406,7 +448,7 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv)
        struct hsc_data *hsc;
        struct iio_dev *indio_dev;
        const char *triplet;
-       u64 tmp;
+       s64 tmp;
        int ret;
 
        indio_dev = devm_iio_device_alloc(dev, sizeof(*hsc));
@@ -485,6 +527,11 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv)
        indio_dev->channels = hsc->chip->channels;
        indio_dev->num_channels = hsc->chip->num_channels;
 
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             hsc_trigger_handler, NULL);
+       if (ret)
+               return ret;
+
        return devm_iio_device_register(dev, indio_dev);
 }
 EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA);
index d20420dba4f6b97601d29a63affbdb6049bc950d..9b40f46f575fff8ba7e04c9f5fd696f79d94ba9a 100644 (file)
 
 #include <linux/types.h>
 
+#include <linux/iio/iio.h>
+
 #define HSC_REG_MEASUREMENT_RD_SIZE 4
+#define HSC_RESP_TIME_MS            2
 
 struct device;
 
@@ -53,6 +56,10 @@ struct hsc_data {
        s32 p_scale_dec;
        s64 p_offset;
        s32 p_offset_dec;
+       struct {
+               __be16 chan[2];
+               s64 timestamp __aligned(8);
+       } scan;
        u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
 };
 
index e2b524b364170949cd4f2d21eeb6a479a6221028..b3fd230e71da12a34c3b26e1d3b01267faa6c3bf 100644 (file)
@@ -4,14 +4,17 @@
  *
  * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro>
  *
- * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf [hsc]
- * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf [i2c related]
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf
  */
 
+#include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/types.h>
 
 #include <linux/iio/iio.h>
 
@@ -23,6 +26,8 @@ static int hsc_i2c_recv(struct hsc_data *data)
        struct i2c_msg msg;
        int ret;
 
+       msleep_interruptible(HSC_RESP_TIME_MS);
+
        msg.addr = client->addr;
        msg.flags = client->flags | I2C_M_RD;
        msg.len = HSC_REG_MEASUREMENT_RD_SIZE;
index a719bade83266b7fd8c0cdfb843372bca7c8e844..818fa630345450080d2111d5bfc7c36ecb58d81f 100644 (file)
@@ -4,13 +4,17 @@
  *
  * Copyright (c) 2023 Petre Rodan <petre.rodan@subdimension.ro>
  *
- * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-spi-comms-digital-ouptu-pressure-sensors-tn-008202-3-en-ciid-45843.pdf
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/common/documents/sps-siot-sleep-mode-technical-note-008286-1-en-ciid-155793.pdf
  */
 
+#include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/stddef.h>
+#include <linux/types.h>
 
 #include <linux/iio/iio.h>
 
@@ -25,6 +29,7 @@ static int hsc_spi_recv(struct hsc_data *data)
                .len = HSC_REG_MEASUREMENT_RD_SIZE,
        };
 
+       msleep_interruptible(HSC_RESP_TIME_MS);
        return spi_sync_transfer(spi, &xfer, 1);
 }
 
index 30fb2de368210f40705f7d9f251d735354a46936..33a15d4c642c0a6b3ee9c7238e3d1a90e09a2c2c 100644 (file)
@@ -5,17 +5,13 @@
  * Copyright (c) Andreas Klinger <ak@it-klinger.de>
  *
  * Data sheet:
- *  https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/
- *    products/sensors/pressure-sensors/board-mount-pressure-sensors/
- *    micropressure-mpr-series/documents/
- *    sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ *  https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
  *
- * 7-bit I2C default slave address: 0x18
  */
 
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
 #include <linux/math64.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
@@ -25,7 +21,6 @@
 #include <linux/gpio/consumer.h>
 
 #include <linux/iio/buffer.h>
-#include <linux/iio/iio.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
 
 
 #include <asm/unaligned.h>
 
-/* bits in i2c status byte */
-#define MPR_I2C_POWER  BIT(6)  /* device is powered */
-#define MPR_I2C_BUSY   BIT(5)  /* device is busy */
-#define MPR_I2C_MEMORY BIT(2)  /* integrity test passed */
-#define MPR_I2C_MATH   BIT(0)  /* internal math saturation */
+#include "mprls0025pa.h"
+
+/* bits in status byte */
+#define MPR_ST_POWER  BIT(6) /* device is powered */
+#define MPR_ST_BUSY   BIT(5) /* device is busy */
+#define MPR_ST_MEMORY BIT(2) /* integrity test passed */
+#define MPR_ST_MATH   BIT(0) /* internal math saturation */
+
+#define MPR_ST_ERR_FLAG  (MPR_ST_BUSY | MPR_ST_MEMORY | MPR_ST_MATH)
 
 /*
  * support _RAW sysfs interface:
  * transfer function B:  2.5% to 22.5% of 2^24
  * transfer function C: 20%   to 80%   of 2^24
  */
-enum mpr_func_id {
-       MPR_FUNCTION_A,
-       MPR_FUNCTION_B,
-       MPR_FUNCTION_C,
-};
-
 struct mpr_func_spec {
        u32                     output_min;
        u32                     output_max;
 };
 
 static const struct mpr_func_spec mpr_func_spec[] = {
-       [MPR_FUNCTION_A] = {.output_min = 1677722, .output_max = 15099494},
-       [MPR_FUNCTION_B] = {.output_min =  419430, .output_max =  3774874},
-       [MPR_FUNCTION_C] = {.output_min = 3355443, .output_max = 13421773},
+       [MPR_FUNCTION_A] = { .output_min = 1677722, .output_max = 15099494 },
+       [MPR_FUNCTION_B] = { .output_min =  419430, .output_max =  3774874 },
+       [MPR_FUNCTION_C] = { .output_min = 3355443, .output_max = 13421773 },
 };
 
-struct mpr_chan {
-       s32                     pres;           /* pressure value */
-       s64                     ts;             /* timestamp */
+enum mpr_variants {
+       MPR0001BA = 0x00, MPR01_6BA = 0x01, MPR02_5BA = 0x02, MPR0060MG = 0x03,
+       MPR0100MG = 0x04, MPR0160MG = 0x05, MPR0250MG = 0x06, MPR0400MG = 0x07,
+       MPR0600MG = 0x08, MPR0001BG = 0x09, MPR01_6BG = 0x0a, MPR02_5BG = 0x0b,
+       MPR0100KA = 0x0c, MPR0160KA = 0x0d, MPR0250KA = 0x0e, MPR0006KG = 0x0f,
+       MPR0010KG = 0x10, MPR0016KG = 0x11, MPR0025KG = 0x12, MPR0040KG = 0x13,
+       MPR0060KG = 0x14, MPR0100KG = 0x15, MPR0160KG = 0x16, MPR0250KG = 0x17,
+       MPR0015PA = 0x18, MPR0025PA = 0x19, MPR0030PA = 0x1a, MPR0001PG = 0x1b,
+       MPR0005PG = 0x1c, MPR0015PG = 0x1d, MPR0030PG = 0x1e, MPR0300YG = 0x1f,
+       MPR_VARIANTS_MAX
+};
+
+static const char * const mpr_triplet_variants[MPR_VARIANTS_MAX] = {
+       [MPR0001BA] = "0001BA", [MPR01_6BA] = "01.6BA", [MPR02_5BA] = "02.5BA",
+       [MPR0060MG] = "0060MG", [MPR0100MG] = "0100MG", [MPR0160MG] = "0160MG",
+       [MPR0250MG] = "0250MG", [MPR0400MG] = "0400MG", [MPR0600MG] = "0600MG",
+       [MPR0001BG] = "0001BG", [MPR01_6BG] = "01.6BG", [MPR02_5BG] = "02.5BG",
+       [MPR0100KA] = "0100KA", [MPR0160KA] = "0160KA", [MPR0250KA] = "0250KA",
+       [MPR0006KG] = "0006KG", [MPR0010KG] = "0010KG", [MPR0016KG] = "0016KG",
+       [MPR0025KG] = "0025KG", [MPR0040KG] = "0040KG", [MPR0060KG] = "0060KG",
+       [MPR0100KG] = "0100KG", [MPR0160KG] = "0160KG", [MPR0250KG] = "0250KG",
+       [MPR0015PA] = "0015PA", [MPR0025PA] = "0025PA", [MPR0030PA] = "0030PA",
+       [MPR0001PG] = "0001PG", [MPR0005PG] = "0005PG", [MPR0015PG] = "0015PG",
+       [MPR0030PG] = "0030PG", [MPR0300YG] = "0300YG"
+};
+
+/**
+ * struct mpr_range_config - list of pressure ranges based on nomenclature
+ * @pmin: lowest pressure that can be measured
+ * @pmax: highest pressure that can be measured
+ */
+struct mpr_range_config {
+       const s32 pmin;
+       const s32 pmax;
 };
 
-struct mpr_data {
-       struct i2c_client       *client;
-       struct mutex            lock;           /*
-                                                * access to device during read
-                                                */
-       u32                     pmin;           /* minimal pressure in pascal */
-       u32                     pmax;           /* maximal pressure in pascal */
-       enum mpr_func_id        function;       /* transfer function */
-       u32                     outmin;         /*
-                                                * minimal numerical range raw
-                                                * value from sensor
-                                                */
-       u32                     outmax;         /*
-                                                * maximal numerical range raw
-                                                * value from sensor
-                                                */
-       int                     scale;          /* int part of scale */
-       int                     scale2;         /* nano part of scale */
-       int                     offset;         /* int part of offset */
-       int                     offset2;        /* nano part of offset */
-       struct gpio_desc        *gpiod_reset;   /* reset */
-       int                     irq;            /*
-                                                * end of conversion irq;
-                                                * used to distinguish between
-                                                * irq mode and reading in a
-                                                * loop until data is ready
-                                                */
-       struct completion       completion;     /* handshake from irq to read */
-       struct mpr_chan         chan;           /*
-                                                * channel values for buffered
-                                                * mode
-                                                */
+/* All min max limits have been converted to pascals */
+static const struct mpr_range_config mpr_range_config[MPR_VARIANTS_MAX] = {
+       [MPR0001BA] = { .pmin = 0, .pmax = 100000 },
+       [MPR01_6BA] = { .pmin = 0, .pmax = 160000 },
+       [MPR02_5BA] = { .pmin = 0, .pmax = 250000 },
+       [MPR0060MG] = { .pmin = 0, .pmax =   6000 },
+       [MPR0100MG] = { .pmin = 0, .pmax =  10000 },
+       [MPR0160MG] = { .pmin = 0, .pmax =  16000 },
+       [MPR0250MG] = { .pmin = 0, .pmax =  25000 },
+       [MPR0400MG] = { .pmin = 0, .pmax =  40000 },
+       [MPR0600MG] = { .pmin = 0, .pmax =  60000 },
+       [MPR0001BG] = { .pmin = 0, .pmax = 100000 },
+       [MPR01_6BG] = { .pmin = 0, .pmax = 160000 },
+       [MPR02_5BG] = { .pmin = 0, .pmax = 250000 },
+       [MPR0100KA] = { .pmin = 0, .pmax = 100000 },
+       [MPR0160KA] = { .pmin = 0, .pmax = 160000 },
+       [MPR0250KA] = { .pmin = 0, .pmax = 250000 },
+       [MPR0006KG] = { .pmin = 0, .pmax =   6000 },
+       [MPR0010KG] = { .pmin = 0, .pmax =  10000 },
+       [MPR0016KG] = { .pmin = 0, .pmax =  16000 },
+       [MPR0025KG] = { .pmin = 0, .pmax =  25000 },
+       [MPR0040KG] = { .pmin = 0, .pmax =  40000 },
+       [MPR0060KG] = { .pmin = 0, .pmax =  60000 },
+       [MPR0100KG] = { .pmin = 0, .pmax = 100000 },
+       [MPR0160KG] = { .pmin = 0, .pmax = 160000 },
+       [MPR0250KG] = { .pmin = 0, .pmax = 250000 },
+       [MPR0015PA] = { .pmin = 0, .pmax = 103421 },
+       [MPR0025PA] = { .pmin = 0, .pmax = 172369 },
+       [MPR0030PA] = { .pmin = 0, .pmax = 206843 },
+       [MPR0001PG] = { .pmin = 0, .pmax =   6895 },
+       [MPR0005PG] = { .pmin = 0, .pmax =  34474 },
+       [MPR0015PG] = { .pmin = 0, .pmax = 103421 },
+       [MPR0030PG] = { .pmin = 0, .pmax = 206843 },
+       [MPR0300YG] = { .pmin = 0, .pmax =  39997 }
 };
 
 static const struct iio_chan_spec mpr_channels[] = {
@@ -153,11 +179,11 @@ static void mpr_reset(struct mpr_data *data)
 }
 
 /**
- * mpr_read_pressure() - Read pressure value from sensor via I2C
+ * mpr_read_pressure() - Read pressure value from sensor
  * @data: Pointer to private data struct.
  * @press: Output value read from sensor.
  *
- * Reading from the sensor by sending and receiving I2C telegrams.
+ * Reading from the sensor by sending and receiving telegrams.
  *
  * If there is an end of conversion (EOC) interrupt registered the function
  * waits for a maximum of one second for the interrupt.
@@ -170,25 +196,17 @@ static void mpr_reset(struct mpr_data *data)
  */
 static int mpr_read_pressure(struct mpr_data *data, s32 *press)
 {
-       struct device *dev = &data->client->dev;
+       struct device *dev = data->dev;
        int ret, i;
-       u8 wdata[] = {0xAA, 0x00, 0x00};
-       s32 status;
        int nloops = 10;
-       u8 buf[4];
 
        reinit_completion(&data->completion);
 
-       ret = i2c_master_send(data->client, wdata, sizeof(wdata));
+       ret = data->ops->write(data, MPR_CMD_SYNC, MPR_PKT_SYNC_LEN);
        if (ret < 0) {
                dev_err(dev, "error while writing ret: %d\n", ret);
                return ret;
        }
-       if (ret != sizeof(wdata)) {
-               dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
-                                                       (u32)sizeof(wdata));
-               return -EIO;
-       }
 
        if (data->irq > 0) {
                ret = wait_for_completion_timeout(&data->completion, HZ);
@@ -206,14 +224,14 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press)
                         *     quite long
                         */
                        usleep_range(5000, 10000);
-                       status = i2c_smbus_read_byte(data->client);
-                       if (status < 0) {
+                       ret = data->ops->read(data, MPR_CMD_NOP, 1);
+                       if (ret < 0) {
                                dev_err(dev,
                                        "error while reading, status: %d\n",
-                                       status);
-                               return status;
+                                       ret);
+                               return ret;
                        }
-                       if (!(status & MPR_I2C_BUSY))
+                       if (!(data->buffer[0] & MPR_ST_ERR_FLAG))
                                break;
                }
                if (i == nloops) {
@@ -222,29 +240,19 @@ static int mpr_read_pressure(struct mpr_data *data, s32 *press)
                }
        }
 
-       ret = i2c_master_recv(data->client, buf, sizeof(buf));
-       if (ret < 0) {
-               dev_err(dev, "error in i2c_master_recv ret: %d\n", ret);
+       ret = data->ops->read(data, MPR_CMD_NOP, MPR_PKT_NOP_LEN);
+       if (ret < 0)
                return ret;
-       }
-       if (ret != sizeof(buf)) {
-               dev_err(dev, "received size doesn't fit - ret: %d / %u\n", ret,
-                                                       (u32)sizeof(buf));
-               return -EIO;
-       }
 
-       if (buf[0] & MPR_I2C_BUSY) {
-               /*
-                * it should never be the case that status still indicates
-                * business
-                */
-               dev_err(dev, "data still not ready: %08x\n", buf[0]);
+       if (data->buffer[0] & MPR_ST_ERR_FLAG) {
+               dev_err(data->dev,
+                       "unexpected status byte %02x\n", data->buffer[0]);
                return -ETIMEDOUT;
        }
 
-       *press = get_unaligned_be24(&buf[1]);
+       *press = get_unaligned_be24(&data->buffer[1]);
 
-       dev_dbg(dev, "received: %*ph cnt: %d\n", ret, buf, *press);
+       dev_dbg(dev, "received: %*ph cnt: %d\n", ret, data->buffer, *press);
 
        return 0;
 }
@@ -271,7 +279,7 @@ static irqreturn_t mpr_trigger_handler(int irq, void *p)
                goto err;
 
        iio_push_to_buffers_with_timestamp(indio_dev, &data->chan,
-                                               iio_get_time_ns(indio_dev));
+                                          iio_get_time_ns(indio_dev));
 
 err:
        mutex_unlock(&data->lock);
@@ -316,25 +324,23 @@ static const struct iio_info mpr_info = {
        .read_raw = &mpr_read_raw,
 };
 
-static int mpr_probe(struct i2c_client *client)
+int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq)
 {
        int ret;
        struct mpr_data *data;
        struct iio_dev *indio_dev;
-       struct device *dev = &client->dev;
+       const char *triplet;
        s64 scale, offset;
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE))
-               return dev_err_probe(dev, -EOPNOTSUPP,
-                                       "I2C functionality not supported\n");
+       u32 func;
 
        indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
        if (!indio_dev)
-               return dev_err_probe(dev, -ENOMEM, "couldn't get iio_dev\n");
+               return -ENOMEM;
 
        data = iio_priv(indio_dev);
-       data->client = client;
-       data->irq = client->irq;
+       data->dev = dev;
+       data->ops = ops;
+       data->irq = irq;
 
        mutex_init(&data->lock);
        init_completion(&data->completion);
@@ -348,103 +354,102 @@ static int mpr_probe(struct i2c_client *client)
        ret = devm_regulator_get_enable(dev, "vdd");
        if (ret)
                return dev_err_probe(dev, ret,
-                               "can't get and enable vdd supply\n");
+                                    "can't get and enable vdd supply\n");
 
-       if (dev_fwnode(dev)) {
+       ret = data->ops->init(data->dev);
+       if (ret)
+               return ret;
+
+       ret = device_property_read_u32(dev,
+                                      "honeywell,transfer-function", &func);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                            "honeywell,transfer-function could not be read\n");
+       data->function = func - 1;
+       if (data->function > MPR_FUNCTION_C)
+               return dev_err_probe(dev, -EINVAL,
+                                    "honeywell,transfer-function %d invalid\n",
+                                    data->function);
+
+       ret = device_property_read_string(dev, "honeywell,pressure-triplet",
+                                         &triplet);
+       if (ret) {
                ret = device_property_read_u32(dev, "honeywell,pmin-pascal",
-                                                               &data->pmin);
+                                              &data->pmin);
                if (ret)
                        return dev_err_probe(dev, ret,
-                               "honeywell,pmin-pascal could not be read\n");
+                                  "honeywell,pmin-pascal could not be read\n");
+
                ret = device_property_read_u32(dev, "honeywell,pmax-pascal",
-                                                               &data->pmax);
+                                              &data->pmax);
                if (ret)
                        return dev_err_probe(dev, ret,
-                               "honeywell,pmax-pascal could not be read\n");
-               ret = device_property_read_u32(dev,
-                               "honeywell,transfer-function", &data->function);
-               if (ret)
-                       return dev_err_probe(dev, ret,
-                               "honeywell,transfer-function could not be read\n");
-               if (data->function > MPR_FUNCTION_C)
-                       return dev_err_probe(dev, -EINVAL,
-                               "honeywell,transfer-function %d invalid\n",
-                                                               data->function);
+                                  "honeywell,pmax-pascal could not be read\n");
        } else {
-               /* when loaded as i2c device we need to use default values */
-               dev_notice(dev, "firmware node not found; using defaults\n");
-               data->pmin = 0;
-               data->pmax = 172369; /* 25 psi */
-               data->function = MPR_FUNCTION_A;
+               ret = device_property_match_property_string(dev,
+                                                  "honeywell,pressure-triplet",
+                                                  mpr_triplet_variants,
+                                                  MPR_VARIANTS_MAX);
+               if (ret < 0)
+                       return dev_err_probe(dev, -EINVAL,
+                                    "honeywell,pressure-triplet is invalid\n");
+
+               data->pmin = mpr_range_config[ret].pmin;
+               data->pmax = mpr_range_config[ret].pmax;
        }
 
+       if (data->pmin >= data->pmax)
+               return dev_err_probe(dev, -EINVAL,
+                                    "pressure limits are invalid\n");
+
        data->outmin = mpr_func_spec[data->function].output_min;
        data->outmax = mpr_func_spec[data->function].output_max;
 
        /* use 64 bit calculation for preserving a reasonable precision */
        scale = div_s64(((s64)(data->pmax - data->pmin)) * NANO,
-                                               data->outmax - data->outmin);
+                       data->outmax - data->outmin);
        data->scale = div_s64_rem(scale, NANO, &data->scale2);
        /*
         * multiply with NANO before dividing by scale and later divide by NANO
         * again.
         */
        offset = ((-1LL) * (s64)data->outmin) * NANO -
-                       div_s64(div_s64((s64)data->pmin * NANO, scale), NANO);
+                 div_s64(div_s64((s64)data->pmin * NANO, scale), NANO);
        data->offset = div_s64_rem(offset, NANO, &data->offset2);
 
        if (data->irq > 0) {
                ret = devm_request_irq(dev, data->irq, mpr_eoc_handler,
-                               IRQF_TRIGGER_RISING, client->name, data);
+                                      IRQF_TRIGGER_RISING,
+                                      dev_name(dev),
+                                      data);
                if (ret)
                        return dev_err_probe(dev, ret,
-                               "request irq %d failed\n", data->irq);
+                                         "request irq %d failed\n", data->irq);
        }
 
        data->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
-                                                       GPIOD_OUT_HIGH);
+                                                   GPIOD_OUT_HIGH);
        if (IS_ERR(data->gpiod_reset))
                return dev_err_probe(dev, PTR_ERR(data->gpiod_reset),
-                                               "request reset-gpio failed\n");
+                                    "request reset-gpio failed\n");
 
        mpr_reset(data);
 
        ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
-                                               mpr_trigger_handler, NULL);
+                                             mpr_trigger_handler, NULL);
        if (ret)
                return dev_err_probe(dev, ret,
-                                       "iio triggered buffer setup failed\n");
+                                    "iio triggered buffer setup failed\n");
 
        ret = devm_iio_device_register(dev, indio_dev);
        if (ret)
                return dev_err_probe(dev, ret,
-                                       "unable to register iio device\n");
+                                    "unable to register iio device\n");
 
        return 0;
 }
-
-static const struct of_device_id mpr_matches[] = {
-       { .compatible = "honeywell,mprls0025pa" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, mpr_matches);
-
-static const struct i2c_device_id mpr_id[] = {
-       { "mprls0025pa" },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, mpr_id);
-
-static struct i2c_driver mpr_driver = {
-       .probe          = mpr_probe,
-       .id_table       = mpr_id,
-       .driver         = {
-               .name           = "mprls0025pa",
-               .of_match_table = mpr_matches,
-       },
-};
-module_i2c_driver(mpr_driver);
+EXPORT_SYMBOL_NS(mpr_common_probe, IIO_HONEYWELL_MPRLS0025PA);
 
 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
-MODULE_DESCRIPTION("Honeywell MPRLS0025PA I2C driver");
+MODULE_DESCRIPTION("Honeywell MPR pressure sensor core driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/mprls0025pa.h b/drivers/iio/pressure/mprls0025pa.h
new file mode 100644 (file)
index 0000000..9d5c30a
--- /dev/null
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver
+ *
+ * Copyright (c) Andreas Klinger <ak@it-klinger.de>
+ *
+ * Data sheet:
+ *  https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ */
+
+#ifndef _MPRLS0025PA_H
+#define _MPRLS0025PA_H
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#define MPR_MEASUREMENT_RD_SIZE 4
+#define MPR_CMD_NOP      0xf0
+#define MPR_CMD_SYNC     0xaa
+#define MPR_PKT_NOP_LEN  MPR_MEASUREMENT_RD_SIZE
+#define MPR_PKT_SYNC_LEN 3
+
+struct device;
+
+struct iio_chan_spec;
+struct iio_dev;
+
+struct mpr_data;
+struct mpr_ops;
+
+/**
+ * struct mpr_chan
+ * @pres: pressure value
+ * @ts: timestamp
+ */
+struct mpr_chan {
+       s32 pres;
+       s64 ts;
+};
+
+enum mpr_func_id {
+       MPR_FUNCTION_A,
+       MPR_FUNCTION_B,
+       MPR_FUNCTION_C,
+};
+
+/**
+ * struct mpr_data
+ * @dev: current device structure
+ * @ops: functions that implement the sensor reads/writes, bus init
+ * @lock: access to device during read
+ * @pmin: minimal pressure in pascal
+ * @pmax: maximal pressure in pascal
+ * @function: transfer function
+ * @outmin: minimum raw pressure in counts (based on transfer function)
+ * @outmax: maximum raw pressure in counts (based on transfer function)
+ * @scale: pressure scale
+ * @scale2: pressure scale, decimal number
+ * @offset: pressure offset
+ * @offset2: pressure offset, decimal number
+ * @gpiod_reset: reset
+ * @irq: end of conversion irq. used to distinguish between irq mode and
+ *       reading in a loop until data is ready
+ * @completion: handshake from irq to read
+ * @chan: channel values for buffered mode
+ * @buffer: raw conversion data
+ */
+struct mpr_data {
+       struct device           *dev;
+       const struct mpr_ops    *ops;
+       struct mutex            lock;
+       u32                     pmin;
+       u32                     pmax;
+       enum mpr_func_id        function;
+       u32                     outmin;
+       u32                     outmax;
+       int                     scale;
+       int                     scale2;
+       int                     offset;
+       int                     offset2;
+       struct gpio_desc        *gpiod_reset;
+       int                     irq;
+       struct completion       completion;
+       struct mpr_chan         chan;
+       u8          buffer[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
+};
+
+struct mpr_ops {
+       int (*init)(struct device *dev);
+       int (*read)(struct mpr_data *data, const u8 cmd, const u8 cnt);
+       int (*write)(struct mpr_data *data, const u8 cmd, const u8 cnt);
+};
+
+int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq);
+
+#endif
diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c
new file mode 100644 (file)
index 0000000..7a5c5aa
--- /dev/null
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MPRLS0025PA - Honeywell MicroPressure pressure sensor series driver
+ *
+ * Copyright (c) Andreas Klinger <ak@it-klinger.de>
+ *
+ * Data sheet:
+ *  https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "mprls0025pa.h"
+
+static int mpr_i2c_init(struct device *unused)
+{
+       return 0;
+}
+
+static int mpr_i2c_read(struct mpr_data *data, const u8 unused, const u8 cnt)
+{
+       int ret;
+       struct i2c_client *client = to_i2c_client(data->dev);
+
+       if (cnt > MPR_MEASUREMENT_RD_SIZE)
+               return -EOVERFLOW;
+
+       memset(data->buffer, 0, MPR_MEASUREMENT_RD_SIZE);
+       ret = i2c_master_recv(client, data->buffer, cnt);
+       if (ret < 0)
+               return ret;
+       else if (ret != cnt)
+               return -EIO;
+
+       return 0;
+}
+
+static int mpr_i2c_write(struct mpr_data *data, const u8 cmd, const u8 unused)
+{
+       int ret;
+       struct i2c_client *client = to_i2c_client(data->dev);
+       u8 wdata[MPR_PKT_SYNC_LEN];
+
+       memset(wdata, 0, sizeof(wdata));
+       wdata[0] = cmd;
+
+       ret = i2c_master_send(client, wdata, MPR_PKT_SYNC_LEN);
+       if (ret < 0)
+               return ret;
+       else if (ret != MPR_PKT_SYNC_LEN)
+               return -EIO;
+
+       return 0;
+}
+
+static const struct mpr_ops mpr_i2c_ops = {
+       .init = mpr_i2c_init,
+       .read = mpr_i2c_read,
+       .write = mpr_i2c_write,
+};
+
+static int mpr_i2c_probe(struct i2c_client *client)
+{
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE))
+               return -EOPNOTSUPP;
+
+       return mpr_common_probe(&client->dev, &mpr_i2c_ops, client->irq);
+}
+
+static const struct of_device_id mpr_i2c_match[] = {
+       { .compatible = "honeywell,mprls0025pa" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mpr_i2c_match);
+
+static const struct i2c_device_id mpr_i2c_id[] = {
+       { "mprls0025pa" },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, mpr_i2c_id);
+
+static struct i2c_driver mpr_i2c_driver = {
+       .probe = mpr_i2c_probe,
+       .id_table = mpr_i2c_id,
+       .driver = {
+               .name = "mprls0025pa",
+               .of_match_table = mpr_i2c_match,
+       },
+};
+module_i2c_driver(mpr_i2c_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("Honeywell MPR pressure sensor i2c driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA);
diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c
new file mode 100644 (file)
index 0000000..3aed14c
--- /dev/null
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MPRLS0025PA - Honeywell MicroPressure MPR series SPI sensor driver
+ *
+ * Copyright (c) 2024 Petre Rodan <petre.rodan@subdimension.ro>
+ *
+ * Data sheet:
+ *  https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/micropressure-mpr-series/documents/sps-siot-mpr-series-datasheet-32332628-ciid-172626.pdf
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+#include "mprls0025pa.h"
+
+struct mpr_spi_buf {
+       u8 tx[MPR_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
+};
+
+static int mpr_spi_init(struct device *dev)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       struct mpr_spi_buf *buf;
+
+       buf = devm_kzalloc(dev, sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, buf);
+
+       return 0;
+}
+
+static int mpr_spi_xfer(struct mpr_data *data, const u8 cmd, const u8 pkt_len)
+{
+       struct spi_device *spi = to_spi_device(data->dev);
+       struct mpr_spi_buf *buf = spi_get_drvdata(spi);
+       struct spi_transfer xfer;
+
+       if (pkt_len > MPR_MEASUREMENT_RD_SIZE)
+               return -EOVERFLOW;
+
+       buf->tx[0] = cmd;
+       xfer.tx_buf = buf->tx;
+       xfer.rx_buf = data->buffer;
+       xfer.len = pkt_len;
+
+       return spi_sync_transfer(spi, &xfer, 1);
+}
+
+static const struct mpr_ops mpr_spi_ops = {
+       .init = mpr_spi_init,
+       .read = mpr_spi_xfer,
+       .write = mpr_spi_xfer,
+};
+
+static int mpr_spi_probe(struct spi_device *spi)
+{
+       return mpr_common_probe(&spi->dev, &mpr_spi_ops, spi->irq);
+}
+
+static const struct of_device_id mpr_spi_match[] = {
+       { .compatible = "honeywell,mprls0025pa" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mpr_spi_match);
+
+static const struct spi_device_id mpr_spi_id[] = {
+       { "mprls0025pa" },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, mpr_spi_id);
+
+static struct spi_driver mpr_spi_driver = {
+       .driver = {
+               .name = "mprls0025pa",
+               .of_match_table = mpr_spi_match,
+       },
+       .probe = mpr_spi_probe,
+       .id_table = mpr_spi_id,
+};
+module_spi_driver(mpr_spi_driver);
+
+MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>");
+MODULE_DESCRIPTION("Honeywell MPR pressure sensor spi driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA);
index 5101552e3f3849dd9b9660438a50ad482b51f56f..389523d6ae32106fcf396e2ae0290de4b9d759a7 100644 (file)
@@ -7,7 +7,6 @@
  * Denis Ciocca <denis.ciocca@st.com>
  */
 
-#include <linux/acpi.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -55,13 +54,11 @@ static const struct of_device_id st_press_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, st_press_of_match);
 
-#ifdef CONFIG_ACPI
 static const struct acpi_device_id st_press_acpi_match[] = {
        {"SNO9210", LPS22HB},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
-#endif
 
 static const struct i2c_device_id st_press_id_table[] = {
        { LPS001WP_PRESS_DEV_NAME, LPS001WP },
@@ -114,7 +111,7 @@ static struct i2c_driver st_press_driver = {
        .driver = {
                .name = "st-press-i2c",
                .of_match_table = st_press_of_match,
-               .acpi_match_table = ACPI_PTR(st_press_acpi_match),
+               .acpi_match_table = st_press_acpi_match,
        },
        .probe = st_press_i2c_probe,
        .id_table = st_press_id_table,
index bcebacaf3dab0d444dc683ec13ae3e888cf17053..4982686fb4c3091486f7851ed045292d4aad8f6b 100644 (file)
@@ -995,17 +995,16 @@ static const struct i2c_device_id isl29501_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, isl29501_id);
 
-#if defined(CONFIG_OF)
 static const struct of_device_id isl29501_i2c_matches[] = {
        { .compatible = "renesas,isl29501" },
        { }
 };
 MODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
-#endif
 
 static struct i2c_driver isl29501_driver = {
        .driver = {
                .name   = "isl29501",
+               .of_match_table = isl29501_i2c_matches,
        },
        .id_table       = isl29501_id,
        .probe          = isl29501_probe,
index 0d230a0dff56787230bee5368ede7c0e5411210f..427c9343d6d163a20c2a19a3800254c5be5eb34f 100644 (file)
@@ -337,28 +337,19 @@ static int sx9310_read_raw(struct iio_dev *indio_dev,
                           int *val2, long mask)
 {
        struct sx_common_data *data = iio_priv(indio_dev);
-       int ret;
 
        if (chan->type != IIO_PROXIMITY)
                return -EINVAL;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = sx_common_read_proximity(data, chan, val);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return sx_common_read_proximity(data, chan, val);
+               unreachable();
        case IIO_CHAN_INFO_HARDWAREGAIN:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = sx9310_read_gain(data, chan, val);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return sx9310_read_gain(data, chan, val);
+               unreachable();
        case IIO_CHAN_INFO_SAMP_FREQ:
                return sx9310_read_samp_freq(data, val, val2);
        default:
@@ -546,12 +537,10 @@ static int sx9310_write_thresh(struct sx_common_data *data,
                return -EINVAL;
 
        regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, reg,
-                                SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
-       mutex_unlock(&data->mutex);
 
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, reg,
+                                 SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
 }
 
 static int sx9310_write_hysteresis(struct sx_common_data *data,
@@ -576,17 +565,14 @@ static int sx9310_write_hysteresis(struct sx_common_data *data,
                return -EINVAL;
 
        hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
-                                SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
-       mutex_unlock(&data->mutex);
 
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+                                 SX9310_REG_PROX_CTRL10_HYST_MASK, hyst);
 }
 
 static int sx9310_write_far_debounce(struct sx_common_data *data, int val)
 {
-       int ret;
        unsigned int regval;
 
        if (val > 0)
@@ -596,18 +582,14 @@ static int sx9310_write_far_debounce(struct sx_common_data *data, int val)
 
        regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
-                                SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,
-                                regval);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+                                 SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK,
+                                 regval);
 }
 
 static int sx9310_write_close_debounce(struct sx_common_data *data, int val)
 {
-       int ret;
        unsigned int regval;
 
        if (val > 0)
@@ -617,13 +599,10 @@ static int sx9310_write_close_debounce(struct sx_common_data *data, int val)
 
        regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
-                                SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,
-                                regval);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10,
+                                 SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK,
+                                 regval);
 }
 
 static int sx9310_write_event_val(struct iio_dev *indio_dev,
@@ -658,7 +637,7 @@ static int sx9310_write_event_val(struct iio_dev *indio_dev,
 
 static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2)
 {
-       int i, ret;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++)
                if (val == sx9310_samp_freq_table[i].val &&
@@ -668,23 +647,17 @@ static int sx9310_set_samp_freq(struct sx_common_data *data, int val, int val2)
        if (i == ARRAY_SIZE(sx9310_samp_freq_table))
                return -EINVAL;
 
-       mutex_lock(&data->mutex);
-
-       ret = regmap_update_bits(
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(
                data->regmap, SX9310_REG_PROX_CTRL0,
                SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK,
                FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i));
-
-       mutex_unlock(&data->mutex);
-
-       return ret;
 }
 
 static int sx9310_write_gain(struct sx_common_data *data,
                             const struct iio_chan_spec *chan, int val)
 {
        unsigned int gain, mask;
-       int ret;
 
        gain = ilog2(val);
 
@@ -703,12 +676,9 @@ static int sx9310_write_gain(struct sx_common_data *data,
                return -EINVAL;
        }
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,
-                                gain);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask,
+                                 gain);
 }
 
 static int sx9310_write_raw(struct iio_dev *indio_dev,
@@ -969,22 +939,18 @@ static int sx9310_suspend(struct device *dev)
 
        disable_irq_nosync(data->client->irq);
 
-       mutex_lock(&data->mutex);
+       guard(mutex)(&data->mutex);
        ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,
                          &data->suspend_ctrl);
        if (ret)
-               goto out;
+               return ret;
 
        ctrl0 = data->suspend_ctrl & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
        ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
        if (ret)
-               goto out;
-
-       ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 0);
+               return ret;
 
-out:
-       mutex_unlock(&data->mutex);
-       return ret;
+       return regmap_write(data->regmap, SX9310_REG_PAUSE, 0);
 }
 
 static int sx9310_resume(struct device *dev)
@@ -992,18 +958,16 @@ static int sx9310_resume(struct device *dev)
        struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
        int ret;
 
-       mutex_lock(&data->mutex);
-       ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1);
-       if (ret)
-               goto out;
-
-       ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
-                          data->suspend_ctrl);
+       scoped_guard(mutex, &data->mutex) {
+               ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1);
+               if (ret)
+                       return ret;
 
-out:
-       mutex_unlock(&data->mutex);
-       if (ret)
-               return ret;
+               ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
+                                  data->suspend_ctrl);
+               if (ret)
+                       return ret;
+       }
 
        enable_irq(data->client->irq);
        return 0;
index ac2ed2da21ccc99f8f830458e7b83becef504eda..aa0d14a49d5e03bd95472e4b79c8314e2b534a53 100644 (file)
@@ -429,25 +429,16 @@ static int sx9324_read_raw(struct iio_dev *indio_dev,
                           int *val, int *val2, long mask)
 {
        struct sx_common_data *data = iio_priv(indio_dev);
-       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = sx_common_read_proximity(data, chan, val);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return sx_common_read_proximity(data, chan, val);
+               unreachable();
        case IIO_CHAN_INFO_HARDWAREGAIN:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = sx9324_read_gain(data, chan, val);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return sx9324_read_gain(data, chan, val);
+               unreachable();
        case IIO_CHAN_INFO_SAMP_FREQ:
                return sx9324_read_samp_freq(data, val, val2);
        default:
@@ -484,7 +475,7 @@ static int sx9324_read_avail(struct iio_dev *indio_dev,
 static int sx9324_set_samp_freq(struct sx_common_data *data,
                                int val, int val2)
 {
-       int i, ret;
+       int i;
 
        for (i = 0; i < ARRAY_SIZE(sx9324_samp_freq_table); i++)
                if (val == sx9324_samp_freq_table[i].val &&
@@ -494,15 +485,11 @@ static int sx9324_set_samp_freq(struct sx_common_data *data,
        if (i == ARRAY_SIZE(sx9324_samp_freq_table))
                return -EINVAL;
 
-       mutex_lock(&data->mutex);
-
-       ret = regmap_update_bits(data->regmap,
-                                SX9324_REG_GNRL_CTRL0,
-                                SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i);
-
-       mutex_unlock(&data->mutex);
+       guard(mutex)(&data->mutex);
 
-       return ret;
+       return regmap_update_bits(data->regmap,
+                                 SX9324_REG_GNRL_CTRL0,
+                                 SX9324_REG_GNRL_CTRL0_SCANPERIOD_MASK, i);
 }
 
 static int sx9324_read_thresh(struct sx_common_data *data,
@@ -623,7 +610,6 @@ static int sx9324_write_thresh(struct sx_common_data *data,
                               const struct iio_chan_spec *chan, int _val)
 {
        unsigned int reg, val = _val;
-       int ret;
 
        reg = SX9324_REG_PROX_CTRL6 + chan->channel / 2;
 
@@ -633,11 +619,9 @@ static int sx9324_write_thresh(struct sx_common_data *data,
        if (val > 0xff)
                return -EINVAL;
 
-       mutex_lock(&data->mutex);
-       ret = regmap_write(data->regmap, reg, val);
-       mutex_unlock(&data->mutex);
+       guard(mutex)(&data->mutex);
 
-       return ret;
+       return regmap_write(data->regmap, reg, val);
 }
 
 static int sx9324_write_hysteresis(struct sx_common_data *data,
@@ -662,18 +646,15 @@ static int sx9324_write_hysteresis(struct sx_common_data *data,
                return -EINVAL;
 
        hyst = FIELD_PREP(SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
-                                SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
-       mutex_unlock(&data->mutex);
+       guard(mutex)(&data->mutex);
 
-       return ret;
+       return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+                                 SX9324_REG_PROX_CTRL5_HYST_MASK, hyst);
 }
 
 static int sx9324_write_far_debounce(struct sx_common_data *data, int _val)
 {
        unsigned int regval, val = _val;
-       int ret;
 
        if (val > 0)
                val = ilog2(val);
@@ -682,19 +663,16 @@ static int sx9324_write_far_debounce(struct sx_common_data *data, int _val)
 
        regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK, val);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
-                                SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK,
-                                regval);
-       mutex_unlock(&data->mutex);
+       guard(mutex)(&data->mutex);
 
-       return ret;
+       return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+                                 SX9324_REG_PROX_CTRL5_FAR_DEBOUNCE_MASK,
+                                 regval);
 }
 
 static int sx9324_write_close_debounce(struct sx_common_data *data, int _val)
 {
        unsigned int regval, val = _val;
-       int ret;
 
        if (val > 0)
                val = ilog2(val);
@@ -703,13 +681,11 @@ static int sx9324_write_close_debounce(struct sx_common_data *data, int _val)
 
        regval = FIELD_PREP(SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK, val);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
-                                SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK,
-                                regval);
-       mutex_unlock(&data->mutex);
+       guard(mutex)(&data->mutex);
 
-       return ret;
+       return regmap_update_bits(data->regmap, SX9324_REG_PROX_CTRL5,
+                                 SX9324_REG_PROX_CTRL5_CLOSE_DEBOUNCE_MASK,
+                                 regval);
 }
 
 static int sx9324_write_event_val(struct iio_dev *indio_dev,
@@ -746,7 +722,6 @@ static int sx9324_write_gain(struct sx_common_data *data,
                             const struct iio_chan_spec *chan, int val)
 {
        unsigned int gain, reg;
-       int ret;
 
        reg = SX9324_REG_PROX_CTRL0 + chan->channel / 2;
 
@@ -756,13 +731,11 @@ static int sx9324_write_gain(struct sx_common_data *data,
 
        gain = FIELD_PREP(SX9324_REG_PROX_CTRL0_GAIN_MASK, gain);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, reg,
-                                SX9324_REG_PROX_CTRL0_GAIN_MASK,
-                                gain);
-       mutex_unlock(&data->mutex);
+       guard(mutex)(&data->mutex);
 
-       return ret;
+       return regmap_update_bits(data->regmap, reg,
+                                 SX9324_REG_PROX_CTRL0_GAIN_MASK,
+                                 gain);
 }
 
 static int sx9324_write_raw(struct iio_dev *indio_dev,
@@ -873,6 +846,29 @@ static int sx9324_init_compensation(struct iio_dev *indio_dev)
                                        20000, 2000000);
 }
 
+static u8 sx9324_parse_phase_prop(struct device *dev,
+                                 struct sx_common_reg_default *reg_def,
+                                 const char *prop)
+{
+       unsigned int pin_defs[SX9324_NUM_PINS];
+       int count, ret, pin;
+       u32 raw = 0;
+
+       count = device_property_count_u32(dev, prop);
+       if (count != ARRAY_SIZE(pin_defs))
+               return reg_def->def;
+       ret = device_property_read_u32_array(dev, prop, pin_defs,
+                                            ARRAY_SIZE(pin_defs));
+       if (ret)
+               return reg_def->def;
+
+       for (pin = 0; pin < SX9324_NUM_PINS; pin++)
+               raw |= (pin_defs[pin] << (2 * pin)) &
+                      SX9324_REG_AFE_PH0_PIN_MASK(pin);
+
+       return raw;
+}
+
 static const struct sx_common_reg_default *
 sx9324_get_default_reg(struct device *dev, int idx,
                       struct sx_common_reg_default *reg_def)
@@ -881,37 +877,29 @@ sx9324_get_default_reg(struct device *dev, int idx,
                "highest" };
        static const char * const sx9324_csidle[] = { "hi-z", "hi-z", "gnd",
                "vdd" };
-#define SX9324_PIN_DEF "semtech,ph0-pin"
-#define SX9324_RESOLUTION_DEF "semtech,ph01-resolution"
-#define SX9324_PROXRAW_DEF "semtech,ph01-proxraw-strength"
-       unsigned int pin_defs[SX9324_NUM_PINS];
-       char prop[] = SX9324_PROXRAW_DEF;
        u32 start = 0, raw = 0, pos = 0;
-       int ret, count, ph, pin;
+       const char *prop;
+       int ret;
 
        memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def));
 
        sx_common_get_raw_register_config(dev, reg_def);
        switch (reg_def->reg) {
        case SX9324_REG_AFE_PH0:
+               reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+                                                      "semtech,ph0-pin");
+               break;
        case SX9324_REG_AFE_PH1:
+               reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+                                                      "semtech,ph1-pin");
+               break;
        case SX9324_REG_AFE_PH2:
+               reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+                                                      "semtech,ph2-pin");
+               break;
        case SX9324_REG_AFE_PH3:
-               ph = reg_def->reg - SX9324_REG_AFE_PH0;
-               snprintf(prop, ARRAY_SIZE(prop), "semtech,ph%d-pin", ph);
-
-               count = device_property_count_u32(dev, prop);
-               if (count != ARRAY_SIZE(pin_defs))
-                       break;
-               ret = device_property_read_u32_array(dev, prop, pin_defs,
-                                                    ARRAY_SIZE(pin_defs));
-               if (ret)
-                       break;
-
-               for (pin = 0; pin < SX9324_NUM_PINS; pin++)
-                       raw |= (pin_defs[pin] << (2 * pin)) &
-                              SX9324_REG_AFE_PH0_PIN_MASK(pin);
-               reg_def->def = raw;
+               reg_def->def = sx9324_parse_phase_prop(dev, reg_def,
+                                                      "semtech,ph3-pin");
                break;
        case SX9324_REG_AFE_CTRL0:
                ret = device_property_match_property_string(dev, "semtech,cs-idle-sleep",
@@ -933,11 +921,9 @@ sx9324_get_default_reg(struct device *dev, int idx,
        case SX9324_REG_AFE_CTRL4:
        case SX9324_REG_AFE_CTRL7:
                if (reg_def->reg == SX9324_REG_AFE_CTRL4)
-                       strncpy(prop, "semtech,ph01-resolution",
-                               ARRAY_SIZE(prop));
+                       prop = "semtech,ph01-resolution";
                else
-                       strncpy(prop, "semtech,ph23-resolution",
-                               ARRAY_SIZE(prop));
+                       prop = "semtech,ph23-resolution";
 
                ret = device_property_read_u32(dev, prop, &raw);
                if (ret)
@@ -1008,11 +994,9 @@ sx9324_get_default_reg(struct device *dev, int idx,
        case SX9324_REG_PROX_CTRL0:
        case SX9324_REG_PROX_CTRL1:
                if (reg_def->reg == SX9324_REG_PROX_CTRL0)
-                       strncpy(prop, "semtech,ph01-proxraw-strength",
-                               ARRAY_SIZE(prop));
+                       prop = "semtech,ph01-proxraw-strength";
                else
-                       strncpy(prop, "semtech,ph23-proxraw-strength",
-                               ARRAY_SIZE(prop));
+                       prop = "semtech,ph23-proxraw-strength";
                ret = device_property_read_u32(dev, prop, &raw);
                if (ret)
                        break;
@@ -1081,34 +1065,30 @@ static int sx9324_suspend(struct device *dev)
 
        disable_irq_nosync(data->client->irq);
 
-       mutex_lock(&data->mutex);
+       guard(mutex)(&data->mutex);
        ret = regmap_read(data->regmap, SX9324_REG_GNRL_CTRL1, &regval);
+       if (ret < 0)
+               return ret;
 
        data->suspend_ctrl =
                FIELD_GET(SX9324_REG_GNRL_CTRL1_PHEN_MASK, regval);
 
-       if (ret < 0)
-               goto out;
 
        /* Disable all phases, send the device to sleep. */
-       ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0);
-
-out:
-       mutex_unlock(&data->mutex);
-       return ret;
+       return regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1, 0);
 }
 
 static int sx9324_resume(struct device *dev)
 {
        struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
-       int ret;
 
-       mutex_lock(&data->mutex);
-       ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1,
-                          data->suspend_ctrl | SX9324_REG_GNRL_CTRL1_PAUSECTRL);
-       mutex_unlock(&data->mutex);
-       if (ret)
-               return ret;
+       scoped_guard(mutex, &data->mutex) {
+               int ret = regmap_write(data->regmap, SX9324_REG_GNRL_CTRL1,
+                                      data->suspend_ctrl |
+                                      SX9324_REG_GNRL_CTRL1_PAUSECTRL);
+               if (ret)
+                       return ret;
+       }
 
        enable_irq(data->client->irq);
        return 0;
index 2c4e14a4fe9fbde8005bbdc1807e20f3c5b218f3..75a1c29f14ebedef7df797f6de551fa9d18b3963 100644 (file)
@@ -322,25 +322,16 @@ static int sx9360_read_raw(struct iio_dev *indio_dev,
                           int *val, int *val2, long mask)
 {
        struct sx_common_data *data = iio_priv(indio_dev);
-       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = sx_common_read_proximity(data, chan, val);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return sx_common_read_proximity(data, chan, val);
+               unreachable();
        case IIO_CHAN_INFO_HARDWAREGAIN:
-               ret = iio_device_claim_direct_mode(indio_dev);
-               if (ret)
-                       return ret;
-
-               ret = sx9360_read_gain(data, chan, val);
-               iio_device_release_direct_mode(indio_dev);
-               return ret;
+               iio_device_claim_direct_scoped(return -EBUSY, indio_dev)
+                       return sx9360_read_gain(data, chan, val);
+               unreachable();
        case IIO_CHAN_INFO_SAMP_FREQ:
                return sx9360_read_samp_freq(data, val, val2);
        default:
@@ -387,19 +378,15 @@ static int sx9360_read_avail(struct iio_dev *indio_dev,
 static int sx9360_set_samp_freq(struct sx_common_data *data,
                                int val, int val2)
 {
-       int ret, reg;
+       int reg;
        __be16 buf;
 
        reg = val * 8192 / SX9360_FOSC_HZ + val2 * 8192 / (SX9360_FOSC_MHZ);
        buf = cpu_to_be16(reg);
-       mutex_lock(&data->mutex);
-
-       ret = regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf,
-                               sizeof(buf));
+       guard(mutex)(&data->mutex);
 
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       return regmap_bulk_write(data->regmap, SX9360_REG_GNRL_CTRL1, &buf,
+                                sizeof(buf));
 }
 
 static int sx9360_read_thresh(struct sx_common_data *data, int *val)
@@ -510,7 +497,6 @@ static int sx9360_read_event_val(struct iio_dev *indio_dev,
 static int sx9360_write_thresh(struct sx_common_data *data, int _val)
 {
        unsigned int val = _val;
-       int ret;
 
        if (val >= 1)
                val = int_sqrt(2 * val);
@@ -518,11 +504,8 @@ static int sx9360_write_thresh(struct sx_common_data *data, int _val)
        if (val > 0xff)
                return -EINVAL;
 
-       mutex_lock(&data->mutex);
-       ret = regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_write(data->regmap, SX9360_REG_PROX_CTRL5, val);
 }
 
 static int sx9360_write_hysteresis(struct sx_common_data *data, int _val)
@@ -546,18 +529,14 @@ static int sx9360_write_hysteresis(struct sx_common_data *data, int _val)
                return -EINVAL;
 
        hyst = FIELD_PREP(SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
-                                SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+                                 SX9360_REG_PROX_CTRL4_HYST_MASK, hyst);
 }
 
 static int sx9360_write_far_debounce(struct sx_common_data *data, int _val)
 {
        unsigned int regval, val = _val;
-       int ret;
 
        if (val > 0)
                val = ilog2(val);
@@ -566,19 +545,15 @@ static int sx9360_write_far_debounce(struct sx_common_data *data, int _val)
 
        regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK, val);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
-                                SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK,
-                                regval);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+                                 SX9360_REG_PROX_CTRL4_FAR_DEBOUNCE_MASK,
+                                 regval);
 }
 
 static int sx9360_write_close_debounce(struct sx_common_data *data, int _val)
 {
        unsigned int regval, val = _val;
-       int ret;
 
        if (val > 0)
                val = ilog2(val);
@@ -587,13 +562,10 @@ static int sx9360_write_close_debounce(struct sx_common_data *data, int _val)
 
        regval = FIELD_PREP(SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK, val);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
-                                SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK,
-                                regval);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, SX9360_REG_PROX_CTRL4,
+                                 SX9360_REG_PROX_CTRL4_CLOSE_DEBOUNCE_MASK,
+                                 regval);
 }
 
 static int sx9360_write_event_val(struct iio_dev *indio_dev,
@@ -630,19 +602,15 @@ static int sx9360_write_gain(struct sx_common_data *data,
                             const struct iio_chan_spec *chan, int val)
 {
        unsigned int gain, reg;
-       int ret;
 
        gain = ilog2(val);
        reg = SX9360_REG_PROX_CTRL0_PHR + chan->channel;
        gain = FIELD_PREP(SX9360_REG_PROX_CTRL0_GAIN_MASK, gain);
 
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, reg,
-                                SX9360_REG_PROX_CTRL0_GAIN_MASK,
-                                gain);
-       mutex_unlock(&data->mutex);
-
-       return ret;
+       guard(mutex)(&data->mutex);
+       return regmap_update_bits(data->regmap, reg,
+                                 SX9360_REG_PROX_CTRL0_GAIN_MASK,
+                                 gain);
 }
 
 static int sx9360_write_raw(struct iio_dev *indio_dev,
@@ -827,36 +795,31 @@ static int sx9360_suspend(struct device *dev)
 
        disable_irq_nosync(data->client->irq);
 
-       mutex_lock(&data->mutex);
+       guard(mutex)(&data->mutex);
        ret = regmap_read(data->regmap, SX9360_REG_GNRL_CTRL0, &regval);
+       if (ret < 0)
+               return ret;
 
        data->suspend_ctrl =
                FIELD_GET(SX9360_REG_GNRL_CTRL0_PHEN_MASK, regval);
 
-       if (ret < 0)
-               goto out;
 
        /* Disable all phases, send the device to sleep. */
-       ret = regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0);
-
-out:
-       mutex_unlock(&data->mutex);
-       return ret;
+       return regmap_write(data->regmap, SX9360_REG_GNRL_CTRL0, 0);
 }
 
 static int sx9360_resume(struct device *dev)
 {
        struct sx_common_data *data = iio_priv(dev_get_drvdata(dev));
-       int ret;
-
-       mutex_lock(&data->mutex);
-       ret = regmap_update_bits(data->regmap, SX9360_REG_GNRL_CTRL0,
-                                SX9360_REG_GNRL_CTRL0_PHEN_MASK,
-                                data->suspend_ctrl);
-       mutex_unlock(&data->mutex);
-       if (ret)
-               return ret;
 
+       scoped_guard(mutex, &data->mutex) {
+               int ret = regmap_update_bits(data->regmap,
+                                            SX9360_REG_GNRL_CTRL0,
+                                            SX9360_REG_GNRL_CTRL0_PHEN_MASK,
+                                            data->suspend_ctrl);
+               if (ret)
+                       return ret;
+       }
        enable_irq(data->client->irq);
        return 0;
 }
index fcb96c44d9540793d20084579ab597155f3a3764..39447c786af342123e07c385adc474ee1de765af 100644 (file)
@@ -207,6 +207,7 @@ enum {
                container_of(_sensor, struct ltc2983_temp, sensor)
 
 struct ltc2983_chip_info {
+       const char *name;
        unsigned int max_channels_nr;
        bool has_temp;
        bool has_eeprom;
@@ -1346,7 +1347,7 @@ static irqreturn_t ltc2983_irq_handler(int irq, void *data)
        __chan; \
 })
 
-static int ltc2983_parse_dt(struct ltc2983_data *st)
+static int ltc2983_parse_fw(struct ltc2983_data *st)
 {
        struct device *dev = &st->spi->dev;
        struct fwnode_handle *child;
@@ -1605,7 +1606,6 @@ static int ltc2983_probe(struct spi_device *spi)
        struct ltc2983_data *st;
        struct iio_dev *indio_dev;
        struct gpio_desc *gpio;
-       const char *name = spi_get_device_id(spi)->name;
        int ret;
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@@ -1614,9 +1614,7 @@ static int ltc2983_probe(struct spi_device *spi)
 
        st = iio_priv(indio_dev);
 
-       st->info = device_get_match_data(&spi->dev);
-       if (!st->info)
-               st->info = (void *)spi_get_device_id(spi)->driver_data;
+       st->info = spi_get_device_match_data(spi);
        if (!st->info)
                return -ENODEV;
 
@@ -1632,7 +1630,7 @@ static int ltc2983_probe(struct spi_device *spi)
        st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY);
        spi_set_drvdata(spi, st);
 
-       ret = ltc2983_parse_dt(st);
+       ret = ltc2983_parse_fw(st);
        if (ret)
                return ret;
 
@@ -1657,7 +1655,7 @@ static int ltc2983_probe(struct spi_device *spi)
                return ret;
 
        ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
-                              IRQF_TRIGGER_RISING, name, st);
+                              IRQF_TRIGGER_RISING, st->info->name, st);
        if (ret) {
                dev_err(&spi->dev, "failed to request an irq, %d", ret);
                return ret;
@@ -1672,7 +1670,7 @@ static int ltc2983_probe(struct spi_device *spi)
                        return ret;
        }
 
-       indio_dev->name = name;
+       indio_dev->name = st->info->name;
        indio_dev->num_channels = st->iio_channels;
        indio_dev->channels = st->iio_chan;
        indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1703,15 +1701,25 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend,
                                ltc2983_resume);
 
 static const struct ltc2983_chip_info ltc2983_chip_info_data = {
+       .name = "ltc2983",
        .max_channels_nr = 20,
 };
 
 static const struct ltc2983_chip_info ltc2984_chip_info_data = {
+       .name = "ltc2984",
        .max_channels_nr = 20,
        .has_eeprom = true,
 };
 
 static const struct ltc2983_chip_info ltc2986_chip_info_data = {
+       .name = "ltc2986",
+       .max_channels_nr = 10,
+       .has_temp = true,
+       .has_eeprom = true,
+};
+
+static const struct ltc2983_chip_info ltm2985_chip_info_data = {
+       .name = "ltm2985",
        .max_channels_nr = 10,
        .has_temp = true,
        .has_eeprom = true,
@@ -1721,7 +1729,7 @@ static const struct spi_device_id ltc2983_id_table[] = {
        { "ltc2983", (kernel_ulong_t)&ltc2983_chip_info_data },
        { "ltc2984", (kernel_ulong_t)&ltc2984_chip_info_data },
        { "ltc2986", (kernel_ulong_t)&ltc2986_chip_info_data },
-       { "ltm2985", (kernel_ulong_t)&ltc2986_chip_info_data },
+       { "ltm2985", (kernel_ulong_t)&ltm2985_chip_info_data },
        {},
 };
 MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
@@ -1730,7 +1738,7 @@ static const struct of_device_id ltc2983_of_match[] = {
        { .compatible = "adi,ltc2983", .data = &ltc2983_chip_info_data },
        { .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
        { .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
-       { .compatible = "adi,ltm2985", .data = &ltc2986_chip_info_data },
+       { .compatible = "adi,ltm2985", .data = &ltm2985_chip_info_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, ltc2983_of_match);
index 059953015ae7241f7debdc1f13170eb522836384..8972083d903a2597b8ba2539d3f5d233c5b0371e 100644 (file)
@@ -9,6 +9,7 @@
  * Note: This driver assumes that the sensor has been calibrated beforehand.
  */
 
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
@@ -17,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/limits.h>
 #include <linux/property.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/iio/iio.h>
 
@@ -148,10 +150,17 @@ static int tmp117_probe(struct i2c_client *client)
        struct tmp117_data *data;
        struct iio_dev *indio_dev;
        int dev_id;
+       int ret;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
                return -EOPNOTSUPP;
 
+       ret = devm_regulator_get_enable(&client->dev, "vcc");
+       if (ret)
+               return ret;
+
+       fsleep(1500);
+
        dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
        if (dev_id < 0)
                return dev_id;
index 0b6e4e278a2f6179917c4cdb607b8cdd56b0a579..33cca49c8058ae211ad543d70596688ae5023068 100644 (file)
@@ -4,6 +4,20 @@
 #
 
 # Keep in alphabetical order
+config IIO_GTS_KUNIT_TEST
+       tristate "Test IIO formatting functions" if !KUNIT_ALL_TESTS
+       depends on KUNIT
+       select IIO_GTS_HELPER
+       select TEST_KUNIT_DEVICE_HELPERS
+       default KUNIT_ALL_TESTS
+       help
+         build unit tests for the IIO light sensor gain-time-scale helpers.
+
+         For more information on KUnit and unit tests in general, please refer
+         to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+         If unsure, say N. Keep in alphabetical order
+
 config IIO_RESCALE_KUNIT_TEST
        tristate "Test IIO rescale conversion functions" if !KUNIT_ALL_TESTS
        depends on KUNIT && IIO_RESCALE
index d76eaf36da820605e126b02b0f55d2a5454d979e..e9a4cf1ff57f01ea0b26f7f3dfd7a0161dabfb8e 100644 (file)
@@ -6,4 +6,5 @@
 # Keep in alphabetical order
 obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) += iio-test-rescale.o
 obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) += iio-test-format.o
+obj-$(CONFIG_IIO_GTS_KUNIT_TEST) += iio-test-gts.o
 CFLAGS_iio-test-format.o += $(DISABLE_STRUCTLEAK_PLUGIN)
diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c
new file mode 100644 (file)
index 0000000..cf7ab77
--- /dev/null
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Unit tests for IIO light sensor gain-time-scale helpers
+ *
+ * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com>
+ */
+
+#include <kunit/device.h>
+#include <kunit/test.h>
+#include <linux/device.h>
+#include <linux/iio/iio-gts-helper.h>
+#include <linux/iio/types.h>
+
+/*
+ * Please, read the "rant" from the top of the lib/test_linear_ranges.c if
+ * you see a line of helper code which is not being tested.
+ *
+ * Then, please look at the line which is not being tested. Is this line
+ * somehow unusually complex? If answer is "no", then chances are that the
+ * "development inertia" caused by adding a test exceeds the benefits.
+ *
+ * If yes, then adding a test is probably a good idea but please stop for a
+ * moment and consider the effort of changing all the tests when code gets
+ * refactored. Eventually it neeeds to be.
+ */
+
+#define TEST_TSEL_50           1
+#define TEST_TSEL_X_MIN                TEST_TSEL_50
+#define TEST_TSEL_100          0
+#define TEST_TSEL_200          2
+#define TEST_TSEL_400          4
+#define TEST_TSEL_X_MAX                TEST_TSEL_400
+
+#define TEST_GSEL_1            0x00
+#define TEST_GSEL_X_MIN                TEST_GSEL_1
+#define TEST_GSEL_4            0x08
+#define TEST_GSEL_16           0x0a
+#define TEST_GSEL_32           0x0b
+#define TEST_GSEL_64           0x0c
+#define TEST_GSEL_256          0x18
+#define TEST_GSEL_512          0x19
+#define TEST_GSEL_1024         0x1a
+#define TEST_GSEL_2048         0x1b
+#define TEST_GSEL_4096         0x1c
+#define TEST_GSEL_X_MAX                TEST_GSEL_4096
+
+#define TEST_SCALE_1X          64
+#define TEST_SCALE_MIN_X       TEST_SCALE_1X
+#define TEST_SCALE_2X          32
+#define TEST_SCALE_4X          16
+#define TEST_SCALE_8X          8
+#define TEST_SCALE_16X         4
+#define TEST_SCALE_32X         2
+#define TEST_SCALE_64X         1
+
+#define TEST_SCALE_NANO_128X   500000000
+#define TEST_SCALE_NANO_256X   250000000
+#define TEST_SCALE_NANO_512X   125000000
+#define TEST_SCALE_NANO_1024X  62500000
+#define TEST_SCALE_NANO_2048X  31250000
+#define TEST_SCALE_NANO_4096X  15625000
+#define TEST_SCALE_NANO_4096X2 7812500
+#define TEST_SCALE_NANO_4096X4 3906250
+#define TEST_SCALE_NANO_4096X8 1953125
+
+#define TEST_SCALE_NANO_MAX_X TEST_SCALE_NANO_4096X8
+
+/*
+ * Can't have this allocated from stack because the kunit clean-up will
+ * happen only after the test function has already gone
+ */
+static struct iio_gts gts;
+
+static const struct iio_gain_sel_pair gts_test_gains[] = {
+       GAIN_SCALE_GAIN(1, TEST_GSEL_1),
+       GAIN_SCALE_GAIN(4, TEST_GSEL_4),
+       GAIN_SCALE_GAIN(16, TEST_GSEL_16),
+       GAIN_SCALE_GAIN(32, TEST_GSEL_32),
+       GAIN_SCALE_GAIN(64, TEST_GSEL_64),
+       GAIN_SCALE_GAIN(256, TEST_GSEL_256),
+       GAIN_SCALE_GAIN(512, TEST_GSEL_512),
+       GAIN_SCALE_GAIN(1024, TEST_GSEL_1024),
+       GAIN_SCALE_GAIN(2048, TEST_GSEL_2048),
+       GAIN_SCALE_GAIN(4096, TEST_GSEL_4096),
+#define HWGAIN_MAX 4096
+};
+
+static const struct iio_itime_sel_mul gts_test_itimes[] = {
+       GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8),
+       GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
+       GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2),
+       GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1),
+#define TIMEGAIN_MAX 8
+};
+#define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX)
+#define IIO_GTS_TEST_DEV "iio-gts-test-dev"
+
+static struct device *__test_init_iio_gain_scale(struct kunit *test,
+               struct iio_gts *gts, const struct iio_gain_sel_pair *g_table,
+               int num_g, const struct iio_itime_sel_mul *i_table, int num_i)
+{
+       struct device *dev;
+       int ret;
+
+       dev = kunit_device_register(test, IIO_GTS_TEST_DEV);
+
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
+       if (IS_ERR_OR_NULL(dev))
+               return NULL;
+
+       ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, g_table, num_g,
+                                   i_table, num_i, gts);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       if (ret)
+               return NULL;
+
+       return dev;
+}
+
+#define test_init_iio_gain_scale(test, gts)    \
+       __test_init_iio_gain_scale(test, gts, gts_test_gains, \
+                                  ARRAY_SIZE(gts_test_gains), gts_test_itimes, \
+                                  ARRAY_SIZE(gts_test_itimes))
+
+static void test_init_iio_gts_invalid(struct kunit *test)
+{
+       struct device *dev;
+       int ret;
+       const struct iio_itime_sel_mul itimes_neg[] = {
+               GAIN_SCALE_ITIME_US(-10, TEST_TSEL_400, 8),
+               GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
+       };
+       const struct iio_gain_sel_pair gains_neg[] = {
+               GAIN_SCALE_GAIN(1, TEST_GSEL_1),
+               GAIN_SCALE_GAIN(2, TEST_GSEL_4),
+               GAIN_SCALE_GAIN(-2, TEST_GSEL_16),
+       };
+       /* 55555 * 38656 = 2147534080 => overflows 32bit int */
+       const struct iio_itime_sel_mul itimes_overflow[] = {
+               GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 55555),
+               GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
+       };
+       const struct iio_gain_sel_pair gains_overflow[] = {
+               GAIN_SCALE_GAIN(1, TEST_GSEL_1),
+               GAIN_SCALE_GAIN(2, TEST_GSEL_4),
+               GAIN_SCALE_GAIN(38656, TEST_GSEL_16),
+       };
+
+       dev = kunit_device_register(test, IIO_GTS_TEST_DEV);
+       KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
+       if (!dev)
+               return;
+
+       /* Ok gains, negative time */
+       ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gts_test_gains,
+                                   ARRAY_SIZE(gts_test_gains), itimes_neg,
+                                   ARRAY_SIZE(itimes_neg), &gts);
+       KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+
+       /* Ok times, negative gain */
+       ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_neg,
+                                   ARRAY_SIZE(gains_neg), gts_test_itimes,
+                                   ARRAY_SIZE(gts_test_itimes), &gts);
+       KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+
+       /* gain * time overflow int */
+       ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_overflow,
+                                   ARRAY_SIZE(gains_overflow), itimes_overflow,
+                                   ARRAY_SIZE(itimes_overflow), &gts);
+       KUNIT_EXPECT_EQ(test, -EOVERFLOW, ret);
+}
+
+static void test_iio_gts_find_gain_for_scale_using_time(struct kunit *test)
+{
+       struct device *dev;
+       int ret, gain_sel;
+
+       dev = test_init_iio_gain_scale(test, &gts);
+       if (!dev)
+               return;
+
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_100,
+                                               TEST_SCALE_8X, 0, &gain_sel);
+       /*
+        * Meas time 100 => gain by time 2x
+        * TEST_SCALE_8X matches total gain 8x
+        * => required HWGAIN 4x
+        */
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, TEST_GSEL_4, gain_sel);
+
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_200, 0,
+                                               TEST_SCALE_NANO_256X, &gain_sel);
+       /*
+        * Meas time 200 => gain by time 4x
+        * TEST_SCALE_256X matches total gain 256x
+        * => required HWGAIN 256/4 => 64x
+        */
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, TEST_GSEL_64, gain_sel);
+
+       /* Min time, Min gain */
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_X_MIN,
+                                               TEST_SCALE_MIN_X, 0, &gain_sel);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, TEST_GSEL_1, gain_sel);
+
+       /* Max time, Max gain */
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_X_MAX,
+                                       0, TEST_SCALE_NANO_MAX_X, &gain_sel);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, TEST_GSEL_4096, gain_sel);
+
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_100, 0,
+                                               TEST_SCALE_NANO_256X, &gain_sel);
+       /*
+        * Meas time 100 => gain by time 2x
+        * TEST_SCALE_256X matches total gain 256x
+        * => required HWGAIN 256/2 => 128x (not in gain-table - unsupported)
+        */
+       KUNIT_EXPECT_NE(test, 0, ret);
+
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_200, 0,
+                                               TEST_SCALE_NANO_MAX_X, &gain_sel);
+       /* We can't reach the max gain with integration time smaller than MAX */
+       KUNIT_EXPECT_NE(test, 0, ret);
+
+       ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_50, 0,
+                                               TEST_SCALE_NANO_MAX_X, &gain_sel);
+       /* We can't reach the max gain with integration time smaller than MAX */
+       KUNIT_EXPECT_NE(test, 0, ret);
+}
+
+static void test_iio_gts_find_new_gain_sel_by_old_gain_time(struct kunit *test)
+{
+       struct device *dev;
+       int ret, old_gain, new_gain, old_time_sel, new_time_sel;
+
+       dev = test_init_iio_gain_scale(test, &gts);
+       if (!dev)
+               return;
+
+       old_gain = 32;
+       old_time_sel = TEST_TSEL_200;
+       new_time_sel = TEST_TSEL_400;
+
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+                                       old_time_sel, new_time_sel, &new_gain);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       /*
+        * Doubling the integration time doubles the total gain - so old
+        * (hw)gain must be divided by two to compensate. => 32 / 2 => 16
+        */
+       KUNIT_EXPECT_EQ(test, 16, new_gain);
+
+       old_gain = 4;
+       old_time_sel = TEST_TSEL_50;
+       new_time_sel = TEST_TSEL_200;
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+                                       old_time_sel, new_time_sel, &new_gain);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       /*
+        * gain by time 1x => 4x - (hw)gain 4x => 1x
+        */
+       KUNIT_EXPECT_EQ(test, 1, new_gain);
+
+       old_gain = 512;
+       old_time_sel = TEST_TSEL_400;
+       new_time_sel = TEST_TSEL_50;
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+                                       old_time_sel, new_time_sel, &new_gain);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       /*
+        * gain by time 8x => 1x - (hw)gain 512x => 4096x)
+        */
+       KUNIT_EXPECT_EQ(test, 4096, new_gain);
+
+       /* Unsupported gain 2x */
+       old_gain = 4;
+       old_time_sel = TEST_TSEL_200;
+       new_time_sel = TEST_TSEL_400;
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+                                       old_time_sel, new_time_sel, &new_gain);
+       KUNIT_EXPECT_NE(test, 0, ret);
+
+       /* Too small gain */
+       old_gain = 4;
+       old_time_sel = TEST_TSEL_50;
+       new_time_sel = TEST_TSEL_400;
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+                                       old_time_sel, new_time_sel, &new_gain);
+       KUNIT_EXPECT_NE(test, 0, ret);
+
+       /* Too big gain */
+       old_gain = 1024;
+       old_time_sel = TEST_TSEL_400;
+       new_time_sel = TEST_TSEL_50;
+       ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
+                                       old_time_sel, new_time_sel, &new_gain);
+       KUNIT_EXPECT_NE(test, 0, ret);
+
+}
+
+static void test_iio_find_closest_gain_low(struct kunit *test)
+{
+       struct device *dev;
+       bool in_range;
+       int ret;
+
+       const struct iio_gain_sel_pair gts_test_gains_gain_low[] = {
+               GAIN_SCALE_GAIN(4, TEST_GSEL_4),
+               GAIN_SCALE_GAIN(16, TEST_GSEL_16),
+               GAIN_SCALE_GAIN(32, TEST_GSEL_32),
+       };
+
+       dev = test_init_iio_gain_scale(test, &gts);
+       if (!dev)
+               return;
+
+       ret = iio_find_closest_gain_low(&gts, 2, &in_range);
+       KUNIT_EXPECT_EQ(test, 1, ret);
+       KUNIT_EXPECT_EQ(test, true, in_range);
+
+       ret = iio_find_closest_gain_low(&gts, 1, &in_range);
+       KUNIT_EXPECT_EQ(test, 1, ret);
+       KUNIT_EXPECT_EQ(test, true, in_range);
+
+       ret = iio_find_closest_gain_low(&gts, 4095, &in_range);
+       KUNIT_EXPECT_EQ(test, 2048, ret);
+       KUNIT_EXPECT_EQ(test, true, in_range);
+
+       ret = iio_find_closest_gain_low(&gts, 4097, &in_range);
+       KUNIT_EXPECT_EQ(test, 4096, ret);
+       KUNIT_EXPECT_EQ(test, false, in_range);
+
+       kunit_device_unregister(test, dev);
+
+       dev = __test_init_iio_gain_scale(test, &gts, gts_test_gains_gain_low,
+                               ARRAY_SIZE(gts_test_gains_gain_low),
+                               gts_test_itimes, ARRAY_SIZE(gts_test_itimes));
+       if (!dev)
+               return;
+
+       ret = iio_find_closest_gain_low(&gts, 3, &in_range);
+       KUNIT_EXPECT_EQ(test, -EINVAL, ret);
+       KUNIT_EXPECT_EQ(test, false, in_range);
+}
+
+static void test_iio_gts_total_gain_to_scale(struct kunit *test)
+{
+       struct device *dev;
+       int ret, scale_int, scale_nano;
+
+       dev = test_init_iio_gain_scale(test, &gts);
+       if (!dev)
+               return;
+
+       ret = iio_gts_total_gain_to_scale(&gts, 1, &scale_int, &scale_nano);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int);
+       KUNIT_EXPECT_EQ(test, 0, scale_nano);
+
+       ret = iio_gts_total_gain_to_scale(&gts, 1, &scale_int, &scale_nano);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int);
+       KUNIT_EXPECT_EQ(test, 0, scale_nano);
+
+       ret = iio_gts_total_gain_to_scale(&gts, 4096 * 8, &scale_int,
+                                         &scale_nano);
+       KUNIT_EXPECT_EQ(test, 0, ret);
+       KUNIT_EXPECT_EQ(test, 0, scale_int);
+       KUNIT_EXPECT_EQ(test, TEST_SCALE_NANO_4096X8, scale_nano);
+}
+
+static void test_iio_gts_chk_times(struct kunit *test, const int *vals)
+{
+       static const int expected[] = {0, 50000, 0, 100000, 0, 200000, 0, 400000};
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(expected); i++)
+               KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
+}
+
+static void test_iio_gts_chk_scales_all(struct kunit *test, struct iio_gts *gts,
+                                       const int *vals, int len)
+{
+       static const int gains[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512,
+                                   1024, 2048, 4096, 4096 * 2, 4096 * 4,
+                                   4096 * 8};
+       int expected[ARRAY_SIZE(gains) * 2];
+       int i, ret;
+       int exp_len = ARRAY_SIZE(gains) * 2;
+
+       KUNIT_EXPECT_EQ(test, exp_len, len);
+       if (len != exp_len)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(gains); i++) {
+               ret = iio_gts_total_gain_to_scale(gts, gains[i],
+                                                 &expected[2 * i],
+                                                 &expected[2 * i + 1]);
+               KUNIT_EXPECT_EQ(test, 0, ret);
+               if (ret)
+                       return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(expected); i++)
+               KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
+}
+
+static void test_iio_gts_chk_scales_t200(struct kunit *test, struct iio_gts *gts,
+                                        const int *vals, int len)
+{
+       /* The gain caused by time 200 is 4x */
+       static const int gains[] = {
+               1 * 4,
+               4 * 4,
+               16 * 4,
+               32 * 4,
+               64 * 4,
+               256 * 4,
+               512 * 4,
+               1024 * 4,
+               2048 * 4,
+               4096 * 4
+       };
+       int expected[ARRAY_SIZE(gains) * 2];
+       int i, ret;
+
+       KUNIT_EXPECT_EQ(test, 2 * ARRAY_SIZE(gains), len);
+       if (len < 2 * ARRAY_SIZE(gains))
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(gains); i++) {
+               ret = iio_gts_total_gain_to_scale(gts, gains[i],
+                                                 &expected[2 * i],
+                                                 &expected[2 * i + 1]);
+               KUNIT_EXPECT_EQ(test, 0, ret);
+               if (ret)
+                       return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(expected); i++)
+               KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
+}
+
+static void test_iio_gts_avail_test(struct kunit *test)
+{
+       struct device *dev;
+       int ret;
+       int type, len;
+       const int *vals;
+
+       dev = test_init_iio_gain_scale(test, &gts);
+       if (!dev)
+               return;
+
+       /* test table building for times and iio_gts_avail_times() */
+       ret = iio_gts_avail_times(&gts, &vals, &type, &len);
+       KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
+       if (ret)
+               return;
+
+       KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_MICRO, type);
+       KUNIT_EXPECT_EQ(test, 8, len);
+       if (len < 8)
+               return;
+
+       test_iio_gts_chk_times(test, vals);
+
+       /* Test table building for all scales and iio_gts_all_avail_scales() */
+       ret = iio_gts_all_avail_scales(&gts, &vals, &type, &len);
+       KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
+       if (ret)
+               return;
+
+       KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type);
+
+       test_iio_gts_chk_scales_all(test, &gts, vals, len);
+
+       /*
+        * Test table building for scales/time and
+        * iio_gts_avail_scales_for_time()
+        */
+       ret = iio_gts_avail_scales_for_time(&gts, 200000, &vals, &type, &len);
+       KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
+       if (ret)
+               return;
+
+       KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type);
+       test_iio_gts_chk_scales_t200(test, &gts, vals, len);
+}
+
+static struct kunit_case iio_gts_test_cases[] = {
+       KUNIT_CASE(test_init_iio_gts_invalid),
+       KUNIT_CASE(test_iio_gts_find_gain_for_scale_using_time),
+       KUNIT_CASE(test_iio_gts_find_new_gain_sel_by_old_gain_time),
+       KUNIT_CASE(test_iio_find_closest_gain_low),
+       KUNIT_CASE(test_iio_gts_total_gain_to_scale),
+       KUNIT_CASE(test_iio_gts_avail_test),
+       {}
+};
+
+static struct kunit_suite iio_gts_test_suite = {
+       .name = "iio-gain-time-scale",
+       .test_cases = iio_gts_test_cases,
+};
+
+kunit_test_suite(iio_gts_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
+MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers");
+MODULE_IMPORT_NS(IIO_GTS_HELPER);
index ff58058aeadca7f61f018d3a5a09cf9833c95a67..bf0df6ee4f7857b4ac8d9ca1c9789b7ef3e4afa9 100644 (file)
@@ -34,6 +34,7 @@ MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("InfiniBand CM");
 MODULE_LICENSE("Dual BSD/GPL");
 
+#define CM_DESTROY_ID_WAIT_TIMEOUT 10000 /* msecs */
 static const char * const ibcm_rej_reason_strs[] = {
        [IB_CM_REJ_NO_QP]                       = "no QP",
        [IB_CM_REJ_NO_EEC]                      = "no EEC",
@@ -1025,10 +1026,20 @@ static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
        }
 }
 
+static noinline void cm_destroy_id_wait_timeout(struct ib_cm_id *cm_id)
+{
+       struct cm_id_private *cm_id_priv;
+
+       cm_id_priv = container_of(cm_id, struct cm_id_private, id);
+       pr_err("%s: cm_id=%p timed out. state=%d refcnt=%d\n", __func__,
+              cm_id, cm_id->state, refcount_read(&cm_id_priv->refcount));
+}
+
 static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
 {
        struct cm_id_private *cm_id_priv;
        struct cm_work *work;
+       int ret;
 
        cm_id_priv = container_of(cm_id, struct cm_id_private, id);
        spin_lock_irq(&cm_id_priv->lock);
@@ -1135,7 +1146,14 @@ retest:
 
        xa_erase(&cm.local_id_table, cm_local_id(cm_id->local_id));
        cm_deref_id(cm_id_priv);
-       wait_for_completion(&cm_id_priv->comp);
+       do {
+               ret = wait_for_completion_timeout(&cm_id_priv->comp,
+                                                 msecs_to_jiffies(
+                                                 CM_DESTROY_ID_WAIT_TIMEOUT));
+               if (!ret) /* timeout happened */
+                       cm_destroy_id_wait_timeout(cm_id);
+       } while (!ret);
+
        while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
                cm_free_work(work);
 
index 67bcea7a153c6a1c59054882ee3cd086417a833f..07cb6c5ffda0008fa035e7df7489b3aa097b7477 100644 (file)
@@ -1730,7 +1730,7 @@ static int assign_client_id(struct ib_client *client)
 {
        int ret;
 
-       down_write(&clients_rwsem);
+       lockdep_assert_held(&clients_rwsem);
        /*
         * The add/remove callbacks must be called in FIFO/LIFO order. To
         * achieve this we assign client_ids so they are sorted in
@@ -1739,14 +1739,11 @@ static int assign_client_id(struct ib_client *client)
        client->client_id = highest_client_id;
        ret = xa_insert(&clients, client->client_id, client, GFP_KERNEL);
        if (ret)
-               goto out;
+               return ret;
 
        highest_client_id++;
        xa_set_mark(&clients, client->client_id, CLIENT_REGISTERED);
-
-out:
-       up_write(&clients_rwsem);
-       return ret;
+       return 0;
 }
 
 static void remove_client_id(struct ib_client *client)
@@ -1776,25 +1773,35 @@ int ib_register_client(struct ib_client *client)
 {
        struct ib_device *device;
        unsigned long index;
+       bool need_unreg = false;
        int ret;
 
        refcount_set(&client->uses, 1);
        init_completion(&client->uses_zero);
+
+       /*
+        * The devices_rwsem is held in write mode to ensure that a racing
+        * ib_register_device() sees a consisent view of clients and devices.
+        */
+       down_write(&devices_rwsem);
+       down_write(&clients_rwsem);
        ret = assign_client_id(client);
        if (ret)
-               return ret;
+               goto out;
 
-       down_read(&devices_rwsem);
+       need_unreg = true;
        xa_for_each_marked (&devices, index, device, DEVICE_REGISTERED) {
                ret = add_client_context(device, client);
-               if (ret) {
-                       up_read(&devices_rwsem);
-                       ib_unregister_client(client);
-                       return ret;
-               }
+               if (ret)
+                       goto out;
        }
-       up_read(&devices_rwsem);
-       return 0;
+       ret = 0;
+out:
+       up_write(&clients_rwsem);
+       up_write(&devices_rwsem);
+       if (need_unreg && ret)
+               ib_unregister_client(client);
+       return ret;
 }
 EXPORT_SYMBOL(ib_register_client);
 
index 6de05ade2ba94c213fd906c1703889ba83615d75..3d3ee3eca98306184d891801b67bf01b24cf212c 100644 (file)
@@ -2737,7 +2737,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
 
        switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) {
        case IB_FLOW_SPEC_ETH:
-               ib_filter_sz = offsetof(struct ib_flow_eth_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_eth_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2748,7 +2748,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                memcpy(&ib_spec->eth.mask, kern_spec_mask, actual_filter_sz);
                break;
        case IB_FLOW_SPEC_IPV4:
-               ib_filter_sz = offsetof(struct ib_flow_ipv4_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_ipv4_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2759,7 +2759,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                memcpy(&ib_spec->ipv4.mask, kern_spec_mask, actual_filter_sz);
                break;
        case IB_FLOW_SPEC_IPV6:
-               ib_filter_sz = offsetof(struct ib_flow_ipv6_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_ipv6_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2775,7 +2775,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                break;
        case IB_FLOW_SPEC_TCP:
        case IB_FLOW_SPEC_UDP:
-               ib_filter_sz = offsetof(struct ib_flow_tcp_udp_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_tcp_udp_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2786,7 +2786,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                memcpy(&ib_spec->tcp_udp.mask, kern_spec_mask, actual_filter_sz);
                break;
        case IB_FLOW_SPEC_VXLAN_TUNNEL:
-               ib_filter_sz = offsetof(struct ib_flow_tunnel_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_tunnel_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2801,7 +2801,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                        return -EINVAL;
                break;
        case IB_FLOW_SPEC_ESP:
-               ib_filter_sz = offsetof(struct ib_flow_esp_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_esp_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2812,7 +2812,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                memcpy(&ib_spec->esp.mask, kern_spec_mask, actual_filter_sz);
                break;
        case IB_FLOW_SPEC_GRE:
-               ib_filter_sz = offsetof(struct ib_flow_gre_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_gre_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
@@ -2823,7 +2823,7 @@ int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
                memcpy(&ib_spec->gre.mask, kern_spec_mask, actual_filter_sz);
                break;
        case IB_FLOW_SPEC_MPLS:
-               ib_filter_sz = offsetof(struct ib_flow_mpls_filter, real_sz);
+               ib_filter_sz = sizeof(struct ib_flow_mpls_filter);
                actual_filter_sz = spec_filter_size(kern_spec_mask,
                                                    kern_filter_sz,
                                                    ib_filter_sz);
index d9799706c58e997c225b1e661307eb7e21afd420..f80da6a67e24e482a3aa8f068775e47c91eb7c3b 100644 (file)
 #include "uverbs.h"
 
 struct bundle_alloc_head {
-       struct bundle_alloc_head *next;
+       struct_group_tagged(bundle_alloc_head_hdr, hdr,
+               struct bundle_alloc_head *next;
+       );
        u8 data[];
 };
 
 struct bundle_priv {
        /* Must be first */
-       struct bundle_alloc_head alloc_head;
+       struct bundle_alloc_head_hdr alloc_head;
        struct bundle_alloc_head *allocated_mem;
        size_t internal_avail;
        size_t internal_used;
@@ -64,7 +66,7 @@ struct bundle_priv {
         * Must be last. bundle ends in a flex array which overlaps
         * internal_buffer.
         */
-       struct uverbs_attr_bundle bundle;
+       struct uverbs_attr_bundle_hdr bundle;
        u64 internal_buffer[32];
 };
 
@@ -77,9 +79,10 @@ void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
                              unsigned int num_attrs)
 {
        struct bundle_priv *pbundle;
+       struct uverbs_attr_bundle *bundle;
        size_t bundle_size =
                offsetof(struct bundle_priv, internal_buffer) +
-               sizeof(*pbundle->bundle.attrs) * method_elm->key_bitmap_len +
+               sizeof(*bundle->attrs) * method_elm->key_bitmap_len +
                sizeof(*pbundle->uattrs) * num_attrs;
 
        method_elm->use_stack = bundle_size <= sizeof(*pbundle);
@@ -107,7 +110,7 @@ __malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size,
                             gfp_t flags)
 {
        struct bundle_priv *pbundle =
-               container_of(bundle, struct bundle_priv, bundle);
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
        size_t new_used;
        void *res;
 
@@ -149,7 +152,7 @@ static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
                             const struct uverbs_attr *attr)
 {
        struct bundle_priv *pbundle =
-               container_of(bundle, struct bundle_priv, bundle);
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
        u16 flags;
 
        flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
@@ -166,6 +169,8 @@ static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
                                     struct ib_uverbs_attr *uattr,
                                     u32 attr_bkey)
 {
+       struct uverbs_attr_bundle *bundle =
+               container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
        const struct uverbs_attr_spec *spec = &attr_uapi->spec;
        size_t array_len;
        u32 *idr_vals;
@@ -184,7 +189,7 @@ static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
                return -EINVAL;
 
        attr->uobjects =
-               uverbs_alloc(&pbundle->bundle,
+               uverbs_alloc(bundle,
                             array_size(array_len, sizeof(*attr->uobjects)));
        if (IS_ERR(attr->uobjects))
                return PTR_ERR(attr->uobjects);
@@ -209,7 +214,7 @@ static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
        for (i = 0; i != array_len; i++) {
                attr->uobjects[i] = uverbs_get_uobject_from_file(
                        spec->u2.objs_arr.obj_type, spec->u2.objs_arr.access,
-                       idr_vals[i], &pbundle->bundle);
+                       idr_vals[i], bundle);
                if (IS_ERR(attr->uobjects[i])) {
                        ret = PTR_ERR(attr->uobjects[i]);
                        break;
@@ -240,7 +245,9 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
                               struct ib_uverbs_attr *uattr, u32 attr_bkey)
 {
        const struct uverbs_attr_spec *spec = &attr_uapi->spec;
-       struct uverbs_attr *e = &pbundle->bundle.attrs[attr_bkey];
+       struct uverbs_attr_bundle *bundle =
+               container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
+       struct uverbs_attr *e = &bundle->attrs[attr_bkey];
        const struct uverbs_attr_spec *val_spec = spec;
        struct uverbs_obj_attr *o_attr;
 
@@ -288,7 +295,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
                if (val_spec->alloc_and_copy && !uverbs_attr_ptr_is_inline(e)) {
                        void *p;
 
-                       p = uverbs_alloc(&pbundle->bundle, uattr->len);
+                       p = uverbs_alloc(bundle, uattr->len);
                        if (IS_ERR(p))
                                return PTR_ERR(p);
 
@@ -321,7 +328,7 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
                 */
                o_attr->uobject = uverbs_get_uobject_from_file(
                        spec->u.obj.obj_type, spec->u.obj.access,
-                       uattr->data_s64, &pbundle->bundle);
+                       uattr->data_s64, bundle);
                if (IS_ERR(o_attr->uobject))
                        return PTR_ERR(o_attr->uobject);
                __set_bit(attr_bkey, pbundle->uobj_finalize);
@@ -422,6 +429,8 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
                                unsigned int num_attrs)
 {
        int (*handler)(struct uverbs_attr_bundle *attrs);
+       struct uverbs_attr_bundle *bundle =
+               container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
        size_t uattrs_size = array_size(sizeof(*pbundle->uattrs), num_attrs);
        unsigned int destroy_bkey = pbundle->method_elm->destroy_bkey;
        unsigned int i;
@@ -434,7 +443,7 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
        if (!handler)
                return -EIO;
 
-       pbundle->uattrs = uverbs_alloc(&pbundle->bundle, uattrs_size);
+       pbundle->uattrs = uverbs_alloc(bundle, uattrs_size);
        if (IS_ERR(pbundle->uattrs))
                return PTR_ERR(pbundle->uattrs);
        if (copy_from_user(pbundle->uattrs, pbundle->user_attrs, uattrs_size))
@@ -453,25 +462,23 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
                return -EINVAL;
 
        if (pbundle->method_elm->has_udata)
-               uverbs_fill_udata(&pbundle->bundle,
-                                 &pbundle->bundle.driver_udata,
+               uverbs_fill_udata(bundle, &pbundle->bundle.driver_udata,
                                  UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
        else
                pbundle->bundle.driver_udata = (struct ib_udata){};
 
        if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) {
-               struct uverbs_obj_attr *destroy_attr =
-                       &pbundle->bundle.attrs[destroy_bkey].obj_attr;
+               struct uverbs_obj_attr *destroy_attr = &bundle->attrs[destroy_bkey].obj_attr;
 
-               ret = uobj_destroy(destroy_attr->uobject, &pbundle->bundle);
+               ret = uobj_destroy(destroy_attr->uobject, bundle);
                if (ret)
                        return ret;
                __clear_bit(destroy_bkey, pbundle->uobj_finalize);
 
-               ret = handler(&pbundle->bundle);
+               ret = handler(bundle);
                uobj_put_destroy(destroy_attr->uobject);
        } else {
-               ret = handler(&pbundle->bundle);
+               ret = handler(bundle);
        }
 
        /*
@@ -481,10 +488,10 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
         */
        if (!ret && pbundle->method_elm->has_udata) {
                const struct uverbs_attr *attr =
-                       uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT);
+                       uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT);
 
                if (!IS_ERR(attr))
-                       ret = uverbs_set_output(&pbundle->bundle, attr);
+                       ret = uverbs_set_output(bundle, attr);
        }
 
        /*
@@ -501,6 +508,8 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle,
 static void bundle_destroy(struct bundle_priv *pbundle, bool commit)
 {
        unsigned int key_bitmap_len = pbundle->method_elm->key_bitmap_len;
+       struct uverbs_attr_bundle *bundle =
+               container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
        struct bundle_alloc_head *memblock;
        unsigned int i;
 
@@ -508,20 +517,19 @@ static void bundle_destroy(struct bundle_priv *pbundle, bool commit)
        i = -1;
        while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len,
                                  i + 1)) < key_bitmap_len) {
-               struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
+               struct uverbs_attr *attr = &bundle->attrs[i];
 
                uverbs_finalize_object(
                        attr->obj_attr.uobject,
                        attr->obj_attr.attr_elm->spec.u.obj.access,
                        test_bit(i, pbundle->uobj_hw_obj_valid),
-                       commit,
-                       &pbundle->bundle);
+                       commit, bundle);
        }
 
        i = -1;
        while ((i = find_next_bit(pbundle->spec_finalize, key_bitmap_len,
                                  i + 1)) < key_bitmap_len) {
-               struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
+               struct uverbs_attr *attr = &bundle->attrs[i];
                const struct uverbs_api_attr *attr_uapi;
                void __rcu **slot;
 
@@ -535,7 +543,7 @@ static void bundle_destroy(struct bundle_priv *pbundle, bool commit)
 
                if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
                        uverbs_free_idrs_array(attr_uapi, &attr->objs_arr_attr,
-                                              commit, &pbundle->bundle);
+                                              commit, bundle);
                }
        }
 
@@ -578,7 +586,8 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
                        method_elm->bundle_size -
                        offsetof(struct bundle_priv, internal_buffer);
                pbundle->alloc_head.next = NULL;
-               pbundle->allocated_mem = &pbundle->alloc_head;
+               pbundle->allocated_mem = container_of(&pbundle->alloc_head,
+                                               struct bundle_alloc_head, hdr);
        } else {
                pbundle = &onstack;
                pbundle->internal_avail = sizeof(pbundle->internal_buffer);
@@ -596,8 +605,9 @@ static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
        pbundle->user_attrs = user_attrs;
 
        pbundle->internal_used = ALIGN(pbundle->method_elm->key_bitmap_len *
-                                              sizeof(*pbundle->bundle.attrs),
-                                      sizeof(*pbundle->internal_buffer));
+                                              sizeof(*container_of(&pbundle->bundle,
+                                                       struct uverbs_attr_bundle, hdr)->attrs),
+                                              sizeof(*pbundle->internal_buffer));
        memset(pbundle->bundle.attr_present, 0,
               sizeof(pbundle->bundle.attr_present));
        memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize));
@@ -700,11 +710,13 @@ void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
                       unsigned int attr_out)
 {
        struct bundle_priv *pbundle =
-               container_of(bundle, struct bundle_priv, bundle);
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
+       struct uverbs_attr_bundle *bundle_aux =
+               container_of(&pbundle->bundle, struct uverbs_attr_bundle, hdr);
        const struct uverbs_attr *in =
-               uverbs_attr_get(&pbundle->bundle, attr_in);
+               uverbs_attr_get(bundle_aux, attr_in);
        const struct uverbs_attr *out =
-               uverbs_attr_get(&pbundle->bundle, attr_out);
+               uverbs_attr_get(bundle_aux, attr_out);
 
        if (!IS_ERR(in)) {
                udata->inlen = in->ptr_attr.len;
@@ -829,7 +841,7 @@ void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
                                 u16 idx)
 {
        struct bundle_priv *pbundle =
-               container_of(bundle, struct bundle_priv, bundle);
+               container_of(&bundle->hdr, struct bundle_priv, bundle);
 
        __set_bit(uapi_bkey_attr(uapi_key_attr(idx)),
                  pbundle->uobj_hw_obj_valid);
index 50cb2259bf874396f1117233e9b30d99d67e6d3b..fb8a0c2488667ebc66a901a9df429e7213345c9a 100644 (file)
@@ -930,8 +930,6 @@ void c4iw_id_table_free(struct c4iw_id_table *alloc);
 
 typedef int (*c4iw_handler_func)(struct c4iw_dev *dev, struct sk_buff *skb);
 
-int c4iw_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new,
-                    struct l2t_entry *l2t);
 void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qpid,
                   struct c4iw_dev_ucontext *uctx);
 u32 c4iw_get_resource(struct c4iw_id_table *id_table);
index e2bdec32ae80539011a88c41b1f5db1ba595a131..926f9ff1f60fda6df21e58f948b5243be7960c16 100644 (file)
@@ -57,6 +57,7 @@ struct efa_dev {
        u64 db_bar_addr;
        u64 db_bar_len;
 
+       unsigned int num_irq_vectors;
        int admin_msix_vector_idx;
        struct efa_irq admin_irq;
 
index 7b1910a862164599ef95bdd07f11868672440885..5fa3603c80d82f83416f9cc8f514ee32f841b38b 100644 (file)
@@ -322,7 +322,9 @@ static int efa_create_eqs(struct efa_dev *dev)
        int err;
        int i;
 
-       neqs = min_t(unsigned int, neqs, num_online_cpus());
+       neqs = min_t(unsigned int, neqs,
+                    dev->num_irq_vectors - EFA_COMP_EQS_VEC_BASE);
+
        dev->neqs = neqs;
        dev->eqs = kcalloc(neqs, sizeof(*dev->eqs), GFP_KERNEL);
        if (!dev->eqs)
@@ -468,34 +470,30 @@ static void efa_disable_msix(struct efa_dev *dev)
 
 static int efa_enable_msix(struct efa_dev *dev)
 {
-       int msix_vecs, irq_num;
+       int max_vecs, num_vecs;
 
        /*
         * Reserve the max msix vectors we might need, one vector is reserved
         * for admin.
         */
-       msix_vecs = min_t(int, pci_msix_vec_count(dev->pdev),
-                         num_online_cpus() + 1);
+       max_vecs = min_t(int, pci_msix_vec_count(dev->pdev),
+                        num_online_cpus() + 1);
        dev_dbg(&dev->pdev->dev, "Trying to enable MSI-X, vectors %d\n",
-               msix_vecs);
+               max_vecs);
 
        dev->admin_msix_vector_idx = EFA_MGMNT_MSIX_VEC_IDX;
-       irq_num = pci_alloc_irq_vectors(dev->pdev, msix_vecs,
-                                       msix_vecs, PCI_IRQ_MSIX);
+       num_vecs = pci_alloc_irq_vectors(dev->pdev, 1,
+                                        max_vecs, PCI_IRQ_MSIX);
 
-       if (irq_num < 0) {
-               dev_err(&dev->pdev->dev, "Failed to enable MSI-X. irq_num %d\n",
-                       irq_num);
+       if (num_vecs < 0) {
+               dev_err(&dev->pdev->dev, "Failed to enable MSI-X. error %d\n",
+                       num_vecs);
                return -ENOSPC;
        }
 
-       if (irq_num != msix_vecs) {
-               efa_disable_msix(dev);
-               dev_err(&dev->pdev->dev,
-                       "Allocated %d MSI-X (out of %d requested)\n",
-                       irq_num, msix_vecs);
-               return -ENOSPC;
-       }
+       dev_dbg(&dev->pdev->dev, "Allocated %d MSI-X vectors\n", num_vecs);
+
+       dev->num_irq_vectors = num_vecs;
 
        return 0;
 }
index 18b05ffb415a3050586f08db1d6f020de60766ca..c465966a1d9c9d19d2daff9c9ded56feeb211a79 100644 (file)
@@ -315,7 +315,7 @@ int hfi1_kern_exp_rcv_init(struct hfi1_ctxtdata *rcd, int reinit)
  * This routine returns the receive context associated
  * with a a qp's qpn.
  *
- * Returns the context.
+ * Return: the context.
  */
 static struct hfi1_ctxtdata *qp_to_rcd(struct rvt_dev_info *rdi,
                                       struct rvt_qp *qp)
@@ -710,7 +710,7 @@ void hfi1_tid_rdma_flush_wait(struct rvt_qp *qp)
  * The exp_lock must be held.
  *
  * Return:
- * On success: a value postive value between 0 and RXE_NUM_TID_FLOWS - 1
+ * On success: a value positive value between 0 and RXE_NUM_TID_FLOWS - 1
  * On failure: -EAGAIN
  */
 static int kern_reserve_flow(struct hfi1_ctxtdata *rcd, int last)
@@ -1007,7 +1007,7 @@ static u32 tid_flush_pages(struct tid_rdma_pageset *list,
  * pages are tested two at a time, i, i + 1 for contiguous
  * pages and i - 1 and i contiguous pages.
  *
- * If any condition is false, any accumlated pages are flushed and
+ * If any condition is false, any accumulated pages are flushed and
  * v0,v1 are emitted as separate PAGE_SIZE pagesets
  *
  * Otherwise, the current 8k is totaled for a future flush.
@@ -1434,7 +1434,7 @@ static void kern_program_rcvarray(struct tid_rdma_flow *flow)
  * (5) computes a tidarray with formatted TID entries which can be sent
  *     to the sender
  * (6) Reserves and programs HW flows.
- * (7) It also manages queing the QP when TID/flow resources are not
+ * (7) It also manages queueing the QP when TID/flow resources are not
  *     available.
  *
  * @req points to struct tid_rdma_request of which the segments are a part. The
@@ -1604,7 +1604,7 @@ void hfi1_kern_exp_rcv_clear_all(struct tid_rdma_request *req)
 }
 
 /**
- * hfi1_kern_exp_rcv_free_flows - free priviously allocated flow information
+ * hfi1_kern_exp_rcv_free_flows - free previously allocated flow information
  * @req: the tid rdma request to be cleaned
  */
 static void hfi1_kern_exp_rcv_free_flows(struct tid_rdma_request *req)
@@ -2055,7 +2055,7 @@ static int tid_rdma_rcv_error(struct hfi1_packet *packet,
                 * req->clear_tail is advanced). However, when an earlier
                 * request is received, this request will not be complete any
                 * more (qp->s_tail_ack_queue is moved back, see below).
-                * Consequently, we need to update the TID flow info everytime
+                * Consequently, we need to update the TID flow info every time
                 * a duplicate request is received.
                 */
                bth0 = be32_to_cpu(ohdr->bth[0]);
@@ -2219,7 +2219,7 @@ void hfi1_rc_rcv_tid_rdma_read_req(struct hfi1_packet *packet)
        /*
         * 1. Verify TID RDMA READ REQ as per IB_OPCODE_RC_RDMA_READ
         *    (see hfi1_rc_rcv())
-        * 2. Put TID RDMA READ REQ into the response queueu (s_ack_queue)
+        * 2. Put TID RDMA READ REQ into the response queue (s_ack_queue)
         *     - Setup struct tid_rdma_req with request info
         *     - Initialize struct tid_rdma_flow info;
         *     - Copy TID entries;
@@ -2439,7 +2439,7 @@ find_tid_request(struct rvt_qp *qp, u32 psn, enum ib_wr_opcode opcode)
 
 void hfi1_rc_rcv_tid_rdma_read_resp(struct hfi1_packet *packet)
 {
-       /* HANDLER FOR TID RDMA READ RESPONSE packet (Requestor side */
+       /* HANDLER FOR TID RDMA READ RESPONSE packet (Requester side) */
 
        /*
         * 1. Find matching SWQE
@@ -3649,7 +3649,7 @@ void hfi1_rc_rcv_tid_rdma_write_req(struct hfi1_packet *packet)
         * 1. Verify TID RDMA WRITE REQ as per IB_OPCODE_RC_RDMA_WRITE_FIRST
         *    (see hfi1_rc_rcv())
         *     - Don't allow 0-length requests.
-        * 2. Put TID RDMA WRITE REQ into the response queueu (s_ack_queue)
+        * 2. Put TID RDMA WRITE REQ into the response queue (s_ack_queue)
         *     - Setup struct tid_rdma_req with request info
         *     - Prepare struct tid_rdma_flow array?
         * 3. Set the qp->s_ack_state as state diagram in design doc.
@@ -4026,7 +4026,7 @@ unlock_r_lock:
 
 void hfi1_rc_rcv_tid_rdma_write_resp(struct hfi1_packet *packet)
 {
-       /* HANDLER FOR TID RDMA WRITE RESPONSE packet (Requestor side */
+       /* HANDLER FOR TID RDMA WRITE RESPONSE packet (Requester side) */
 
        /*
         * 1. Find matching SWQE
@@ -5440,8 +5440,9 @@ static bool _hfi1_schedule_tid_send(struct rvt_qp *qp)
  * the two state machines can step on each other with respect to the
  * RVT_S_BUSY flag.
  * Therefore, a modified test is used.
- * @return true if the second leg is scheduled;
- *  false if the second leg is not scheduled.
+ *
+ * Return: %true if the second leg is scheduled;
+ *  %false if the second leg is not scheduled.
  */
 bool hfi1_schedule_tid_send(struct rvt_qp *qp)
 {
index 052a3d60905aa3063f00596c529d6facf52de74e..11dbbabebdc908db409e52e546cfa95ded0fef39 100644 (file)
@@ -108,6 +108,9 @@ enum {
        HNS_ROCE_CMD_QUERY_CEQC         = 0x92,
        HNS_ROCE_CMD_DESTROY_CEQC       = 0x93,
 
+       /* SCC CTX commands */
+       HNS_ROCE_CMD_QUERY_SCCC         = 0xa2,
+
        /* SCC CTX BT commands */
        HNS_ROCE_CMD_READ_SCCC_BT0      = 0xa4,
        HNS_ROCE_CMD_WRITE_SCCC_BT0     = 0xa5,
index 1b6d16af8c12beec30b77f779784f4bdd24f4f03..7250d0643b5c5dd9baaa6e95388dc447d36c7ad0 100644 (file)
@@ -133,14 +133,12 @@ static int alloc_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
        struct hns_roce_cq_table *cq_table = &hr_dev->cq_table;
        struct ib_device *ibdev = &hr_dev->ib_dev;
        u64 mtts[MTT_MIN_COUNT] = {};
-       dma_addr_t dma_handle;
        int ret;
 
-       ret = hns_roce_mtr_find(hr_dev, &hr_cq->mtr, 0, mtts, ARRAY_SIZE(mtts),
-                               &dma_handle);
-       if (!ret) {
+       ret = hns_roce_mtr_find(hr_dev, &hr_cq->mtr, 0, mtts, ARRAY_SIZE(mtts));
+       if (ret) {
                ibdev_err(ibdev, "failed to find CQ mtr, ret = %d.\n", ret);
-               return -EINVAL;
+               return ret;
        }
 
        /* Get CQC memory HEM(Hardware Entry Memory) table */
@@ -157,7 +155,8 @@ static int alloc_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
                goto err_put;
        }
 
-       ret = hns_roce_create_cqc(hr_dev, hr_cq, mtts, dma_handle);
+       ret = hns_roce_create_cqc(hr_dev, hr_cq, mtts,
+                                 hns_roce_get_mtr_ba(&hr_cq->mtr));
        if (ret)
                goto err_xa;
 
index b1fce5ddf6316c743f3cb634da79e1d83d3f2685..c3cbd0a494bfd8e573aa30595782801011839c72 100644 (file)
@@ -179,6 +179,7 @@ enum {
 
 #define HNS_ROCE_CMD_SUCCESS                   1
 
+#define HNS_ROCE_MAX_HOP_NUM                   3
 /* The minimum page size is 4K for hardware */
 #define HNS_HW_PAGE_SHIFT                      12
 #define HNS_HW_PAGE_SIZE                       (1 << HNS_HW_PAGE_SHIFT)
@@ -269,6 +270,11 @@ struct hns_roce_hem_list {
        dma_addr_t root_ba; /* pointer to the root ba table */
 };
 
+enum mtr_type {
+       MTR_DEFAULT = 0,
+       MTR_PBL,
+};
+
 struct hns_roce_buf_attr {
        struct {
                size_t  size;  /* region size */
@@ -277,7 +283,10 @@ struct hns_roce_buf_attr {
        unsigned int region_count; /* valid region count */
        unsigned int page_shift;  /* buffer page shift */
        unsigned int user_access; /* umem access flag */
+       u64 iova;
+       enum mtr_type type;
        bool mtt_only; /* only alloc buffer-required MTT memory */
+       bool adaptive; /* adaptive for page_shift and hopnum */
 };
 
 struct hns_roce_hem_cfg {
@@ -585,6 +594,13 @@ struct hns_roce_work {
        u32 queue_num;
 };
 
+enum hns_roce_cong_type {
+       CONG_TYPE_DCQCN,
+       CONG_TYPE_LDCP,
+       CONG_TYPE_HC3,
+       CONG_TYPE_DIP,
+};
+
 struct hns_roce_qp {
        struct ib_qp            ibqp;
        struct hns_roce_wq      rq;
@@ -628,6 +644,7 @@ struct hns_roce_qp {
        struct list_head        sq_node; /* all send qps are on a list */
        struct hns_user_mmap_entry *dwqe_mmap_entry;
        u32                     config;
+       enum hns_roce_cong_type cong_type;
 };
 
 struct hns_roce_ib_iboe {
@@ -699,13 +716,6 @@ struct hns_roce_eq_table {
        struct hns_roce_eq      *eq;
 };
 
-enum cong_type {
-       CONG_TYPE_DCQCN,
-       CONG_TYPE_LDCP,
-       CONG_TYPE_HC3,
-       CONG_TYPE_DIP,
-};
-
 struct hns_roce_caps {
        u64             fw_ver;
        u8              num_ports;
@@ -835,7 +845,8 @@ struct hns_roce_caps {
        u16             default_aeq_period;
        u16             default_aeq_arm_st;
        u16             default_ceq_arm_st;
-       enum cong_type  cong_type;
+       u8              cong_cap;
+       enum hns_roce_cong_type default_cong_type;
 };
 
 enum hns_roce_device_state {
@@ -936,6 +947,7 @@ struct hns_roce_hw {
        int (*query_qpc)(struct hns_roce_dev *hr_dev, u32 qpn, void *buffer);
        int (*query_mpt)(struct hns_roce_dev *hr_dev, u32 key, void *buffer);
        int (*query_srqc)(struct hns_roce_dev *hr_dev, u32 srqn, void *buffer);
+       int (*query_sccc)(struct hns_roce_dev *hr_dev, u32 qpn, void *buffer);
        int (*query_hw_counter)(struct hns_roce_dev *hr_dev,
                                u64 *stats, u32 port, int *hw_counters);
        const struct ib_device_ops *hns_roce_dev_ops;
@@ -1152,8 +1164,13 @@ void hns_roce_cmd_use_polling(struct hns_roce_dev *hr_dev);
 
 /* hns roce hw need current block and next block addr from mtt */
 #define MTT_MIN_COUNT   2
+static inline dma_addr_t hns_roce_get_mtr_ba(struct hns_roce_mtr *mtr)
+{
+       return mtr->hem_cfg.root_ba;
+}
+
 int hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
-                     u32 offset, u64 *mtt_buf, int mtt_max, u64 *base_addr);
+                     u32 offset, u64 *mtt_buf, int mtt_max);
 int hns_roce_mtr_create(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
                        struct hns_roce_buf_attr *buf_attr,
                        unsigned int page_shift, struct ib_udata *udata,
index c4ac06a338696910939656703a308342832f5ba0..a4b3f19161dc1309f919b345e4ad8c88f4bd1038 100644 (file)
@@ -249,61 +249,34 @@ int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
 }
 
 static struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev,
-                                              int npages,
                                               unsigned long hem_alloc_size,
                                               gfp_t gfp_mask)
 {
-       struct hns_roce_hem_chunk *chunk = NULL;
        struct hns_roce_hem *hem;
-       struct scatterlist *mem;
        int order;
        void *buf;
 
        WARN_ON(gfp_mask & __GFP_HIGHMEM);
 
+       order = get_order(hem_alloc_size);
+       if (PAGE_SIZE << order != hem_alloc_size) {
+               dev_err(hr_dev->dev, "invalid hem_alloc_size: %lu!\n",
+                       hem_alloc_size);
+               return NULL;
+       }
+
        hem = kmalloc(sizeof(*hem),
                      gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
        if (!hem)
                return NULL;
 
-       INIT_LIST_HEAD(&hem->chunk_list);
-
-       order = get_order(hem_alloc_size);
-
-       while (npages > 0) {
-               if (!chunk) {
-                       chunk = kmalloc(sizeof(*chunk),
-                               gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
-                       if (!chunk)
-                               goto fail;
-
-                       sg_init_table(chunk->mem, HNS_ROCE_HEM_CHUNK_LEN);
-                       chunk->npages = 0;
-                       chunk->nsg = 0;
-                       memset(chunk->buf, 0, sizeof(chunk->buf));
-                       list_add_tail(&chunk->list, &hem->chunk_list);
-               }
+       buf = dma_alloc_coherent(hr_dev->dev, hem_alloc_size,
+                                &hem->dma, gfp_mask);
+       if (!buf)
+               goto fail;
 
-               while (1 << order > npages)
-                       --order;
-
-               /*
-                * Alloc memory one time. If failed, don't alloc small block
-                * memory, directly return fail.
-                */
-               mem = &chunk->mem[chunk->npages];
-               buf = dma_alloc_coherent(hr_dev->dev, PAGE_SIZE << order,
-                               &sg_dma_address(mem), gfp_mask);
-               if (!buf)
-                       goto fail;
-
-               chunk->buf[chunk->npages] = buf;
-               sg_dma_len(mem) = PAGE_SIZE << order;
-
-               ++chunk->npages;
-               ++chunk->nsg;
-               npages -= 1 << order;
-       }
+       hem->buf = buf;
+       hem->size = hem_alloc_size;
 
        return hem;
 
@@ -314,20 +287,10 @@ fail:
 
 void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem)
 {
-       struct hns_roce_hem_chunk *chunk, *tmp;
-       int i;
-
        if (!hem)
                return;
 
-       list_for_each_entry_safe(chunk, tmp, &hem->chunk_list, list) {
-               for (i = 0; i < chunk->npages; ++i)
-                       dma_free_coherent(hr_dev->dev,
-                                  sg_dma_len(&chunk->mem[i]),
-                                  chunk->buf[i],
-                                  sg_dma_address(&chunk->mem[i]));
-               kfree(chunk);
-       }
+       dma_free_coherent(hr_dev->dev, hem->size, hem->buf, hem->dma);
 
        kfree(hem);
 }
@@ -415,7 +378,6 @@ static int alloc_mhop_hem(struct hns_roce_dev *hr_dev,
 {
        u32 bt_size = mhop->bt_chunk_size;
        struct device *dev = hr_dev->dev;
-       struct hns_roce_hem_iter iter;
        gfp_t flag;
        u64 bt_ba;
        u32 size;
@@ -456,16 +418,15 @@ static int alloc_mhop_hem(struct hns_roce_dev *hr_dev,
         */
        size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size : bt_size;
        flag = GFP_KERNEL | __GFP_NOWARN;
-       table->hem[index->buf] = hns_roce_alloc_hem(hr_dev, size >> PAGE_SHIFT,
-                                                   size, flag);
+       table->hem[index->buf] = hns_roce_alloc_hem(hr_dev, size, flag);
        if (!table->hem[index->buf]) {
                ret = -ENOMEM;
                goto err_alloc_hem;
        }
 
        index->inited |= HEM_INDEX_BUF;
-       hns_roce_hem_first(table->hem[index->buf], &iter);
-       bt_ba = hns_roce_hem_addr(&iter);
+       bt_ba = table->hem[index->buf]->dma;
+
        if (table->type < HEM_TYPE_MTT) {
                if (mhop->hop_num == 2)
                        *(table->bt_l1[index->l1] + mhop->l2_idx) = bt_ba;
@@ -586,7 +547,6 @@ int hns_roce_table_get(struct hns_roce_dev *hr_dev,
        }
 
        table->hem[i] = hns_roce_alloc_hem(hr_dev,
-                                      table->table_chunk_size >> PAGE_SHIFT,
                                       table->table_chunk_size,
                                       GFP_KERNEL | __GFP_NOWARN);
        if (!table->hem[i]) {
@@ -725,7 +685,6 @@ void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
                          struct hns_roce_hem_table *table,
                          unsigned long obj, dma_addr_t *dma_handle)
 {
-       struct hns_roce_hem_chunk *chunk;
        struct hns_roce_hem_mhop mhop;
        struct hns_roce_hem *hem;
        unsigned long mhop_obj = obj;
@@ -734,7 +693,6 @@ void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
        int offset, dma_offset;
        void *addr = NULL;
        u32 hem_idx = 0;
-       int length;
        int i, j;
 
        mutex_lock(&table->mutex);
@@ -767,23 +725,8 @@ void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
        if (!hem)
                goto out;
 
-       list_for_each_entry(chunk, &hem->chunk_list, list) {
-               for (i = 0; i < chunk->npages; ++i) {
-                       length = sg_dma_len(&chunk->mem[i]);
-                       if (dma_handle && dma_offset >= 0) {
-                               if (length > (u32)dma_offset)
-                                       *dma_handle = sg_dma_address(
-                                               &chunk->mem[i]) + dma_offset;
-                               dma_offset -= length;
-                       }
-
-                       if (length > (u32)offset) {
-                               addr = chunk->buf[i] + offset;
-                               goto out;
-                       }
-                       offset -= length;
-               }
-       }
+       *dma_handle = hem->dma + dma_offset;
+       addr = hem->buf + offset;
 
 out:
        mutex_unlock(&table->mutex);
index 7d23d3c51da46b177f44a9c9f06ee9dcb5282116..6fb51db9682b8f2647172749bb3c28cfd544dbb8 100644 (file)
@@ -56,10 +56,6 @@ enum {
        HEM_TYPE_TRRL,
 };
 
-#define HNS_ROCE_HEM_CHUNK_LEN \
-        ((256 - sizeof(struct list_head) - 2 * sizeof(int)) /   \
-        (sizeof(struct scatterlist) + sizeof(void *)))
-
 #define check_whether_bt_num_3(type, hop_num) \
        (type < HEM_TYPE_MTT && hop_num == 2)
 
@@ -72,25 +68,13 @@ enum {
        (type >= HEM_TYPE_MTT && hop_num == 1) || \
        (type >= HEM_TYPE_MTT && hop_num == HNS_ROCE_HOP_NUM_0))
 
-struct hns_roce_hem_chunk {
-       struct list_head         list;
-       int                      npages;
-       int                      nsg;
-       struct scatterlist       mem[HNS_ROCE_HEM_CHUNK_LEN];
-       void                     *buf[HNS_ROCE_HEM_CHUNK_LEN];
-};
-
 struct hns_roce_hem {
-       struct list_head chunk_list;
+       void *buf;
+       dma_addr_t dma;
+       unsigned long size;
        refcount_t refcount;
 };
 
-struct hns_roce_hem_iter {
-       struct hns_roce_hem              *hem;
-       struct hns_roce_hem_chunk        *chunk;
-       int                              page_idx;
-};
-
 struct hns_roce_hem_mhop {
        u32     hop_num;
        u32     buf_chunk_size;
@@ -133,38 +117,4 @@ void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev,
                                 struct hns_roce_hem_list *hem_list,
                                 int offset, int *mtt_cnt);
 
-static inline void hns_roce_hem_first(struct hns_roce_hem *hem,
-                                     struct hns_roce_hem_iter *iter)
-{
-       iter->hem = hem;
-       iter->chunk = list_empty(&hem->chunk_list) ? NULL :
-                                list_entry(hem->chunk_list.next,
-                                           struct hns_roce_hem_chunk, list);
-       iter->page_idx = 0;
-}
-
-static inline int hns_roce_hem_last(struct hns_roce_hem_iter *iter)
-{
-       return !iter->chunk;
-}
-
-static inline void hns_roce_hem_next(struct hns_roce_hem_iter *iter)
-{
-       if (++iter->page_idx >= iter->chunk->nsg) {
-               if (iter->chunk->list.next == &iter->hem->chunk_list) {
-                       iter->chunk = NULL;
-                       return;
-               }
-
-               iter->chunk = list_entry(iter->chunk->list.next,
-                                        struct hns_roce_hem_chunk, list);
-               iter->page_idx = 0;
-       }
-}
-
-static inline dma_addr_t hns_roce_hem_addr(struct hns_roce_hem_iter *iter)
-{
-       return sg_dma_address(&iter->chunk->mem[iter->page_idx]);
-}
-
 #endif /* _HNS_ROCE_HEM_H */
index 8206daea6767df60731feac8ed9f7b52256ed7af..ba7ae792d279d462e0b79b27e4f3bf92432f572e 100644 (file)
@@ -2209,11 +2209,12 @@ static int hns_roce_query_caps(struct hns_roce_dev *hr_dev)
        caps->max_wqes = 1 << le16_to_cpu(resp_c->sq_depth);
 
        caps->num_srqs = 1 << hr_reg_read(resp_d, PF_CAPS_D_NUM_SRQS);
-       caps->cong_type = hr_reg_read(resp_d, PF_CAPS_D_CONG_TYPE);
+       caps->cong_cap = hr_reg_read(resp_d, PF_CAPS_D_CONG_CAP);
        caps->max_srq_wrs = 1 << le16_to_cpu(resp_d->srq_depth);
        caps->ceqe_depth = 1 << hr_reg_read(resp_d, PF_CAPS_D_CEQ_DEPTH);
        caps->num_comp_vectors = hr_reg_read(resp_d, PF_CAPS_D_NUM_CEQS);
        caps->aeqe_depth = 1 << hr_reg_read(resp_d, PF_CAPS_D_AEQ_DEPTH);
+       caps->default_cong_type = hr_reg_read(resp_d, PF_CAPS_D_DEFAULT_ALG);
        caps->reserved_pds = hr_reg_read(resp_d, PF_CAPS_D_RSV_PDS);
        caps->num_uars = 1 << hr_reg_read(resp_d, PF_CAPS_D_NUM_UARS);
        caps->reserved_qps = hr_reg_read(resp_d, PF_CAPS_D_RSV_QPS);
@@ -3195,21 +3196,22 @@ static int set_mtpt_pbl(struct hns_roce_dev *hr_dev,
        u64 pages[HNS_ROCE_V2_MAX_INNER_MTPT_NUM] = { 0 };
        struct ib_device *ibdev = &hr_dev->ib_dev;
        dma_addr_t pbl_ba;
-       int i, count;
+       int ret;
+       int i;
 
-       count = hns_roce_mtr_find(hr_dev, &mr->pbl_mtr, 0, pages,
-                                 min_t(int, ARRAY_SIZE(pages), mr->npages),
-                                 &pbl_ba);
-       if (count < 1) {
-               ibdev_err(ibdev, "failed to find PBL mtr, count = %d.\n",
-                         count);
-               return -ENOBUFS;
+       ret = hns_roce_mtr_find(hr_dev, &mr->pbl_mtr, 0, pages,
+                               min_t(int, ARRAY_SIZE(pages), mr->npages));
+       if (ret) {
+               ibdev_err(ibdev, "failed to find PBL mtr, ret = %d.\n", ret);
+               return ret;
        }
 
        /* Aligned to the hardware address access unit */
-       for (i = 0; i < count; i++)
+       for (i = 0; i < ARRAY_SIZE(pages); i++)
                pages[i] >>= 6;
 
+       pbl_ba = hns_roce_get_mtr_ba(&mr->pbl_mtr);
+
        mpt_entry->pbl_size = cpu_to_le32(mr->npages);
        mpt_entry->pbl_ba_l = cpu_to_le32(pbl_ba >> 3);
        hr_reg_write(mpt_entry, MPT_PBL_BA_H, upper_32_bits(pbl_ba >> 3));
@@ -3308,18 +3310,12 @@ static int hns_roce_v2_rereg_write_mtpt(struct hns_roce_dev *hr_dev,
 static int hns_roce_v2_frmr_write_mtpt(struct hns_roce_dev *hr_dev,
                                       void *mb_buf, struct hns_roce_mr *mr)
 {
-       struct ib_device *ibdev = &hr_dev->ib_dev;
+       dma_addr_t pbl_ba = hns_roce_get_mtr_ba(&mr->pbl_mtr);
        struct hns_roce_v2_mpt_entry *mpt_entry;
-       dma_addr_t pbl_ba = 0;
 
        mpt_entry = mb_buf;
        memset(mpt_entry, 0, sizeof(*mpt_entry));
 
-       if (hns_roce_mtr_find(hr_dev, &mr->pbl_mtr, 0, NULL, 0, &pbl_ba) < 0) {
-               ibdev_err(ibdev, "failed to find frmr mtr.\n");
-               return -ENOBUFS;
-       }
-
        hr_reg_write(mpt_entry, MPT_ST, V2_MPT_ST_FREE);
        hr_reg_write(mpt_entry, MPT_PD, mr->pd);
 
@@ -4063,7 +4059,6 @@ static int hns_roce_v2_set_hem(struct hns_roce_dev *hr_dev,
                               struct hns_roce_hem_table *table, int obj,
                               u32 step_idx)
 {
-       struct hns_roce_hem_iter iter;
        struct hns_roce_hem_mhop mhop;
        struct hns_roce_hem *hem;
        unsigned long mhop_obj = obj;
@@ -4100,12 +4095,8 @@ static int hns_roce_v2_set_hem(struct hns_roce_dev *hr_dev,
 
        if (check_whether_last_step(hop_num, step_idx)) {
                hem = table->hem[hem_idx];
-               for (hns_roce_hem_first(hem, &iter);
-                    !hns_roce_hem_last(&iter); hns_roce_hem_next(&iter)) {
-                       bt_ba = hns_roce_hem_addr(&iter);
-                       ret = set_hem_to_hw(hr_dev, obj, bt_ba, table->type,
-                                           step_idx);
-               }
+
+               ret = set_hem_to_hw(hr_dev, obj, hem->dma, table->type, step_idx);
        } else {
                if (step_idx == 0)
                        bt_ba = table->bt_l0_dma_addr[i];
@@ -4346,17 +4337,20 @@ static int config_qp_rq_buf(struct hns_roce_dev *hr_dev,
 {
        u64 mtts[MTT_MIN_COUNT] = { 0 };
        u64 wqe_sge_ba;
-       int count;
+       int ret;
 
        /* Search qp buf's mtts */
-       count = hns_roce_mtr_find(hr_dev, &hr_qp->mtr, hr_qp->rq.offset, mtts,
-                                 MTT_MIN_COUNT, &wqe_sge_ba);
-       if (hr_qp->rq.wqe_cnt && count < 1) {
+       ret = hns_roce_mtr_find(hr_dev, &hr_qp->mtr, hr_qp->rq.offset, mtts,
+                               MTT_MIN_COUNT);
+       if (hr_qp->rq.wqe_cnt && ret) {
                ibdev_err(&hr_dev->ib_dev,
-                         "failed to find RQ WQE, QPN = 0x%lx.\n", hr_qp->qpn);
-               return -EINVAL;
+                         "failed to find QP(0x%lx) RQ WQE buf, ret = %d.\n",
+                         hr_qp->qpn, ret);
+               return ret;
        }
 
+       wqe_sge_ba = hns_roce_get_mtr_ba(&hr_qp->mtr);
+
        context->wqe_sge_ba = cpu_to_le32(wqe_sge_ba >> 3);
        qpc_mask->wqe_sge_ba = 0;
 
@@ -4418,23 +4412,23 @@ static int config_qp_sq_buf(struct hns_roce_dev *hr_dev,
        struct ib_device *ibdev = &hr_dev->ib_dev;
        u64 sge_cur_blk = 0;
        u64 sq_cur_blk = 0;
-       int count;
+       int ret;
 
        /* search qp buf's mtts */
-       count = hns_roce_mtr_find(hr_dev, &hr_qp->mtr, 0, &sq_cur_blk, 1, NULL);
-       if (count < 1) {
-               ibdev_err(ibdev, "failed to find QP(0x%lx) SQ buf.\n",
-                         hr_qp->qpn);
-               return -EINVAL;
+       ret = hns_roce_mtr_find(hr_dev, &hr_qp->mtr, hr_qp->sq.offset,
+                               &sq_cur_blk, 1);
+       if (ret) {
+               ibdev_err(ibdev, "failed to find QP(0x%lx) SQ WQE buf, ret = %d.\n",
+                         hr_qp->qpn, ret);
+               return ret;
        }
        if (hr_qp->sge.sge_cnt > 0) {
-               count = hns_roce_mtr_find(hr_dev, &hr_qp->mtr,
-                                         hr_qp->sge.offset,
-                                         &sge_cur_blk, 1, NULL);
-               if (count < 1) {
-                       ibdev_err(ibdev, "failed to find QP(0x%lx) SGE buf.\n",
-                                 hr_qp->qpn);
-                       return -EINVAL;
+               ret = hns_roce_mtr_find(hr_dev, &hr_qp->mtr,
+                                       hr_qp->sge.offset, &sge_cur_blk, 1);
+               if (ret) {
+                       ibdev_err(ibdev, "failed to find QP(0x%lx) SGE buf, ret = %d.\n",
+                                 hr_qp->qpn, ret);
+                       return ret;
                }
        }
 
@@ -4744,13 +4738,10 @@ enum {
 static int check_cong_type(struct ib_qp *ibqp,
                           struct hns_roce_congestion_algorithm *cong_alg)
 {
-       struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
-
-       if (ibqp->qp_type == IB_QPT_UD)
-               hr_dev->caps.cong_type = CONG_TYPE_DCQCN;
+       struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
 
        /* different congestion types match different configurations */
-       switch (hr_dev->caps.cong_type) {
+       switch (hr_qp->cong_type) {
        case CONG_TYPE_DCQCN:
                cong_alg->alg_sel = CONG_DCQCN;
                cong_alg->alg_sub_sel = UNSUPPORT_CONG_LEVEL;
@@ -4776,10 +4767,7 @@ static int check_cong_type(struct ib_qp *ibqp,
                cong_alg->wnd_mode_sel = WND_LIMIT;
                break;
        default:
-               ibdev_warn(&hr_dev->ib_dev,
-                          "invalid type(%u) for congestion selection.\n",
-                          hr_dev->caps.cong_type);
-               hr_dev->caps.cong_type = CONG_TYPE_DCQCN;
+               hr_qp->cong_type = CONG_TYPE_DCQCN;
                cong_alg->alg_sel = CONG_DCQCN;
                cong_alg->alg_sub_sel = UNSUPPORT_CONG_LEVEL;
                cong_alg->dip_vld = DIP_INVALID;
@@ -4798,6 +4786,7 @@ static int fill_cong_field(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
        struct hns_roce_congestion_algorithm cong_field;
        struct ib_device *ibdev = ibqp->device;
        struct hns_roce_dev *hr_dev = to_hr_dev(ibdev);
+       struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
        u32 dip_idx = 0;
        int ret;
 
@@ -4810,7 +4799,7 @@ static int fill_cong_field(struct ib_qp *ibqp, const struct ib_qp_attr *attr,
                return ret;
 
        hr_reg_write(context, QPC_CONG_ALGO_TMPL_ID, hr_dev->cong_algo_tmpl_id +
-                    hr_dev->caps.cong_type * HNS_ROCE_CONG_SIZE);
+                    hr_qp->cong_type * HNS_ROCE_CONG_SIZE);
        hr_reg_clear(qpc_mask, QPC_CONG_ALGO_TMPL_ID);
        hr_reg_write(&context->ext, QPCEX_CONG_ALG_SEL, cong_field.alg_sel);
        hr_reg_clear(&qpc_mask->ext, QPCEX_CONG_ALG_SEL);
@@ -5328,6 +5317,30 @@ out:
        return ret;
 }
 
+static int hns_roce_v2_query_sccc(struct hns_roce_dev *hr_dev, u32 qpn,
+                                 void *buffer)
+{
+       struct hns_roce_v2_scc_context *context;
+       struct hns_roce_cmd_mailbox *mailbox;
+       int ret;
+
+       mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, HNS_ROCE_CMD_QUERY_SCCC,
+                               qpn);
+       if (ret)
+               goto out;
+
+       context = mailbox->buf;
+       memcpy(buffer, context, sizeof(*context));
+
+out:
+       hns_roce_free_cmd_mailbox(hr_dev, mailbox);
+       return ret;
+}
+
 static u8 get_qp_timeout_attr(struct hns_roce_dev *hr_dev,
                              struct hns_roce_v2_qp_context *context)
 {
@@ -5581,18 +5594,20 @@ static int hns_roce_v2_write_srqc_index_queue(struct hns_roce_srq *srq,
        struct ib_device *ibdev = srq->ibsrq.device;
        struct hns_roce_dev *hr_dev = to_hr_dev(ibdev);
        u64 mtts_idx[MTT_MIN_COUNT] = {};
-       dma_addr_t dma_handle_idx = 0;
+       dma_addr_t dma_handle_idx;
        int ret;
 
        /* Get physical address of idx que buf */
        ret = hns_roce_mtr_find(hr_dev, &idx_que->mtr, 0, mtts_idx,
-                               ARRAY_SIZE(mtts_idx), &dma_handle_idx);
-       if (ret < 1) {
+                               ARRAY_SIZE(mtts_idx));
+       if (ret) {
                ibdev_err(ibdev, "failed to find mtr for SRQ idx, ret = %d.\n",
                          ret);
-               return -ENOBUFS;
+               return ret;
        }
 
+       dma_handle_idx = hns_roce_get_mtr_ba(&idx_que->mtr);
+
        hr_reg_write(ctx, SRQC_IDX_HOP_NUM,
                     to_hr_hem_hopnum(hr_dev->caps.idx_hop_num, srq->wqe_cnt));
 
@@ -5624,20 +5639,22 @@ static int hns_roce_v2_write_srqc(struct hns_roce_srq *srq, void *mb_buf)
        struct hns_roce_dev *hr_dev = to_hr_dev(ibdev);
        struct hns_roce_srq_context *ctx = mb_buf;
        u64 mtts_wqe[MTT_MIN_COUNT] = {};
-       dma_addr_t dma_handle_wqe = 0;
+       dma_addr_t dma_handle_wqe;
        int ret;
 
        memset(ctx, 0, sizeof(*ctx));
 
        /* Get the physical address of srq buf */
        ret = hns_roce_mtr_find(hr_dev, &srq->buf_mtr, 0, mtts_wqe,
-                               ARRAY_SIZE(mtts_wqe), &dma_handle_wqe);
-       if (ret < 1) {
+                               ARRAY_SIZE(mtts_wqe));
+       if (ret) {
                ibdev_err(ibdev, "failed to find mtr for SRQ WQE, ret = %d.\n",
                          ret);
-               return -ENOBUFS;
+               return ret;
        }
 
+       dma_handle_wqe = hns_roce_get_mtr_ba(&srq->buf_mtr);
+
        hr_reg_write(ctx, SRQC_SRQ_ST, 1);
        hr_reg_write_bool(ctx, SRQC_SRQ_TYPE,
                          srq->ibsrq.srq_type == IB_SRQT_XRC);
@@ -6353,7 +6370,7 @@ static int config_eqc(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq,
        u64 eqe_ba[MTT_MIN_COUNT] = { 0 };
        struct hns_roce_eq_context *eqc;
        u64 bt_ba = 0;
-       int count;
+       int ret;
 
        eqc = mb_buf;
        memset(eqc, 0, sizeof(struct hns_roce_eq_context));
@@ -6361,13 +6378,15 @@ static int config_eqc(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq,
        init_eq_config(hr_dev, eq);
 
        /* if not multi-hop, eqe buffer only use one trunk */
-       count = hns_roce_mtr_find(hr_dev, &eq->mtr, 0, eqe_ba, MTT_MIN_COUNT,
-                                 &bt_ba);
-       if (count < 1) {
-               dev_err(hr_dev->dev, "failed to find EQE mtr\n");
-               return -ENOBUFS;
+       ret = hns_roce_mtr_find(hr_dev, &eq->mtr, 0, eqe_ba,
+                               ARRAY_SIZE(eqe_ba));
+       if (ret) {
+               dev_err(hr_dev->dev, "failed to find EQE mtr, ret = %d\n", ret);
+               return ret;
        }
 
+       bt_ba = hns_roce_get_mtr_ba(&eq->mtr);
+
        hr_reg_write(eqc, EQC_EQ_ST, HNS_ROCE_V2_EQ_STATE_VALID);
        hr_reg_write(eqc, EQC_EQE_HOP_NUM, eq->hop_num);
        hr_reg_write(eqc, EQC_OVER_IGNORE, eq->over_ignore);
@@ -6714,6 +6733,7 @@ static const struct hns_roce_hw hns_roce_hw_v2 = {
        .query_qpc = hns_roce_v2_query_qpc,
        .query_mpt = hns_roce_v2_query_mpt,
        .query_srqc = hns_roce_v2_query_srqc,
+       .query_sccc = hns_roce_v2_query_sccc,
        .query_hw_counter = hns_roce_hw_v2_query_counter,
        .hns_roce_dev_ops = &hns_roce_v2_dev_ops,
        .hns_roce_dev_srq_ops = &hns_roce_v2_dev_srq_ops,
index cd97cbee682a6a51a4290720881a7a3b89d26a42..df04bc8ede57b65db434586ad22926314c7df4b8 100644 (file)
@@ -646,6 +646,12 @@ struct hns_roce_v2_qp_context {
 #define QPCEX_SQ_RQ_NOT_FORBID_EN QPCEX_FIELD_LOC(23, 23)
 #define QPCEX_STASH QPCEX_FIELD_LOC(82, 82)
 
+#define SCC_CONTEXT_SIZE 16
+
+struct hns_roce_v2_scc_context {
+       __le32 data[SCC_CONTEXT_SIZE];
+};
+
 #define        V2_QP_RWE_S 1 /* rdma write enable */
 #define        V2_QP_RRE_S 2 /* rdma read enable */
 #define        V2_QP_ATE_S 3 /* rdma atomic enable */
@@ -1214,12 +1220,13 @@ struct hns_roce_query_pf_caps_d {
 #define PF_CAPS_D_RQWQE_HOP_NUM PF_CAPS_D_FIELD_LOC(21, 20)
 #define PF_CAPS_D_EX_SGE_HOP_NUM PF_CAPS_D_FIELD_LOC(23, 22)
 #define PF_CAPS_D_SQWQE_HOP_NUM PF_CAPS_D_FIELD_LOC(25, 24)
-#define PF_CAPS_D_CONG_TYPE PF_CAPS_D_FIELD_LOC(29, 26)
+#define PF_CAPS_D_CONG_CAP PF_CAPS_D_FIELD_LOC(29, 26)
 #define PF_CAPS_D_CEQ_DEPTH PF_CAPS_D_FIELD_LOC(85, 64)
 #define PF_CAPS_D_NUM_CEQS PF_CAPS_D_FIELD_LOC(95, 86)
 #define PF_CAPS_D_AEQ_DEPTH PF_CAPS_D_FIELD_LOC(117, 96)
 #define PF_CAPS_D_AEQ_ARM_ST PF_CAPS_D_FIELD_LOC(119, 118)
 #define PF_CAPS_D_CEQ_ARM_ST PF_CAPS_D_FIELD_LOC(121, 120)
+#define PF_CAPS_D_DEFAULT_ALG PF_CAPS_D_FIELD_LOC(127, 122)
 #define PF_CAPS_D_RSV_PDS PF_CAPS_D_FIELD_LOC(147, 128)
 #define PF_CAPS_D_NUM_UARS PF_CAPS_D_FIELD_LOC(155, 148)
 #define PF_CAPS_D_RSV_QPS PF_CAPS_D_FIELD_LOC(179, 160)
index b55fe6911f9f1a8230ace74475f2b0d2cd8937e6..1dc60c2b2b7ab841266a4e25da2af3a4ce8218b9 100644 (file)
@@ -394,6 +394,9 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
                        resp.config |= HNS_ROCE_RSP_CQE_INLINE_FLAGS;
        }
 
+       if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09)
+               resp.congest_type = hr_dev->caps.cong_cap;
+
        ret = hns_roce_uar_alloc(hr_dev, &context->uar);
        if (ret)
                goto error_out;
index 91cd580480fe224c5a6e837ad9c0c5f9be511574..9e05b57a2d67d4bdf7d6c96c29f0cbcac4deb021 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <linux/vmalloc.h>
+#include <linux/count_zeros.h>
 #include <rdma/ib_umem.h>
 #include <linux/math.h>
 #include "hns_roce_device.h"
@@ -103,14 +104,21 @@ static int alloc_mr_pbl(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr,
        buf_attr.user_access = mr->access;
        /* fast MR's buffer is alloced before mapping, not at creation */
        buf_attr.mtt_only = is_fast;
+       buf_attr.iova = mr->iova;
+       /* pagesize and hopnum is fixed for fast MR */
+       buf_attr.adaptive = !is_fast;
+       buf_attr.type = MTR_PBL;
 
        err = hns_roce_mtr_create(hr_dev, &mr->pbl_mtr, &buf_attr,
                                  hr_dev->caps.pbl_ba_pg_sz + PAGE_SHIFT,
                                  udata, start);
-       if (err)
+       if (err) {
                ibdev_err(ibdev, "failed to alloc pbl mtr, ret = %d.\n", err);
-       else
-               mr->npages = mr->pbl_mtr.hem_cfg.buf_pg_count;
+               return err;
+       }
+
+       mr->npages = mr->pbl_mtr.hem_cfg.buf_pg_count;
+       mr->pbl_hop_num = buf_attr.region[0].hopnum;
 
        return err;
 }
@@ -695,7 +703,7 @@ static int mtr_alloc_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
                mtr->umem = NULL;
                mtr->kmem = hns_roce_buf_alloc(hr_dev, total_size,
                                               buf_attr->page_shift,
-                                              mtr->hem_cfg.is_direct ?
+                                              !mtr_has_mtt(buf_attr) ?
                                               HNS_ROCE_BUF_DIRECT : 0);
                if (IS_ERR(mtr->kmem)) {
                        ibdev_err(ibdev, "failed to alloc kmem, ret = %ld.\n",
@@ -707,14 +715,41 @@ static int mtr_alloc_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
        return 0;
 }
 
-static int mtr_map_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
-                       int page_count, unsigned int page_shift)
+static int cal_mtr_pg_cnt(struct hns_roce_mtr *mtr)
+{
+       struct hns_roce_buf_region *region;
+       int page_cnt = 0;
+       int i;
+
+       for (i = 0; i < mtr->hem_cfg.region_count; i++) {
+               region = &mtr->hem_cfg.region[i];
+               page_cnt += region->count;
+       }
+
+       return page_cnt;
+}
+
+static bool need_split_huge_page(struct hns_roce_mtr *mtr)
+{
+       /* When HEM buffer uses 0-level addressing, the page size is
+        * equal to the whole buffer size. If the current MTR has multiple
+        * regions, we split the buffer into small pages(4k, required by hns
+        * ROCEE). These pages will be used in multiple regions.
+        */
+       return mtr->hem_cfg.is_direct && mtr->hem_cfg.region_count > 1;
+}
+
+static int mtr_map_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr)
 {
        struct ib_device *ibdev = &hr_dev->ib_dev;
+       int page_count = cal_mtr_pg_cnt(mtr);
+       unsigned int page_shift;
        dma_addr_t *pages;
        int npage;
        int ret;
 
+       page_shift = need_split_huge_page(mtr) ? HNS_HW_PAGE_SHIFT :
+                                                mtr->hem_cfg.buf_pg_shift;
        /* alloc a tmp array to store buffer's dma address */
        pages = kvcalloc(page_count, sizeof(dma_addr_t), GFP_KERNEL);
        if (!pages)
@@ -734,7 +769,7 @@ static int mtr_map_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
                goto err_alloc_list;
        }
 
-       if (mtr->hem_cfg.is_direct && npage > 1) {
+       if (need_split_huge_page(mtr) && npage > 1) {
                ret = mtr_check_direct_pages(pages, npage, page_shift);
                if (ret) {
                        ibdev_err(ibdev, "failed to check %s page: %d / %d.\n",
@@ -809,47 +844,53 @@ int hns_roce_mtr_map(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
        return ret;
 }
 
-int hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
-                     u32 offset, u64 *mtt_buf, int mtt_max, u64 *base_addr)
+static int hns_roce_get_direct_addr_mtt(struct hns_roce_hem_cfg *cfg,
+                                       u32 start_index, u64 *mtt_buf,
+                                       int mtt_cnt)
 {
-       struct hns_roce_hem_cfg *cfg = &mtr->hem_cfg;
-       int mtt_count, left;
-       u32 start_index;
+       int mtt_count;
        int total = 0;
-       __le64 *mtts;
        u32 npage;
        u64 addr;
 
-       if (!mtt_buf || mtt_max < 1)
-               goto done;
-
-       /* no mtt memory in direct mode, so just return the buffer address */
-       if (cfg->is_direct) {
-               start_index = offset >> HNS_HW_PAGE_SHIFT;
-               for (mtt_count = 0; mtt_count < cfg->region_count &&
-                    total < mtt_max; mtt_count++) {
-                       npage = cfg->region[mtt_count].offset;
-                       if (npage < start_index)
-                               continue;
+       if (mtt_cnt > cfg->region_count)
+               return -EINVAL;
 
-                       addr = cfg->root_ba + (npage << HNS_HW_PAGE_SHIFT);
-                       mtt_buf[total] = addr;
+       for (mtt_count = 0; mtt_count < cfg->region_count && total < mtt_cnt;
+            mtt_count++) {
+               npage = cfg->region[mtt_count].offset;
+               if (npage < start_index)
+                       continue;
 
-                       total++;
-               }
+               addr = cfg->root_ba + (npage << HNS_HW_PAGE_SHIFT);
+               mtt_buf[total] = addr;
 
-               goto done;
+               total++;
        }
 
-       start_index = offset >> cfg->buf_pg_shift;
-       left = mtt_max;
+       if (!total)
+               return -ENOENT;
+
+       return 0;
+}
+
+static int hns_roce_get_mhop_mtt(struct hns_roce_dev *hr_dev,
+                                struct hns_roce_mtr *mtr, u32 start_index,
+                                u64 *mtt_buf, int mtt_cnt)
+{
+       int left = mtt_cnt;
+       int total = 0;
+       int mtt_count;
+       __le64 *mtts;
+       u32 npage;
+
        while (left > 0) {
                mtt_count = 0;
                mtts = hns_roce_hem_list_find_mtt(hr_dev, &mtr->hem_list,
                                                  start_index + total,
                                                  &mtt_count);
                if (!mtts || !mtt_count)
-                       goto done;
+                       break;
 
                npage = min(mtt_count, left);
                left -= npage;
@@ -857,69 +898,165 @@ int hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
                        mtt_buf[total++] = le64_to_cpu(mtts[mtt_count]);
        }
 
-done:
-       if (base_addr)
-               *base_addr = cfg->root_ba;
+       if (!total)
+               return -ENOENT;
+
+       return 0;
+}
+
+int hns_roce_mtr_find(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
+                     u32 offset, u64 *mtt_buf, int mtt_max)
+{
+       struct hns_roce_hem_cfg *cfg = &mtr->hem_cfg;
+       u32 start_index;
+       int ret;
+
+       if (!mtt_buf || mtt_max < 1)
+               return -EINVAL;
+
+       /* no mtt memory in direct mode, so just return the buffer address */
+       if (cfg->is_direct) {
+               start_index = offset >> HNS_HW_PAGE_SHIFT;
+               ret = hns_roce_get_direct_addr_mtt(cfg, start_index,
+                                                  mtt_buf, mtt_max);
+       } else {
+               start_index = offset >> cfg->buf_pg_shift;
+               ret = hns_roce_get_mhop_mtt(hr_dev, mtr, start_index,
+                                           mtt_buf, mtt_max);
+       }
+       return ret;
+}
+
+static int get_best_page_shift(struct hns_roce_dev *hr_dev,
+                              struct hns_roce_mtr *mtr,
+                              struct hns_roce_buf_attr *buf_attr)
+{
+       unsigned int page_sz;
+
+       if (!buf_attr->adaptive || buf_attr->type != MTR_PBL || !mtr->umem)
+               return 0;
+
+       page_sz = ib_umem_find_best_pgsz(mtr->umem,
+                                        hr_dev->caps.page_size_cap,
+                                        buf_attr->iova);
+       if (!page_sz)
+               return -EINVAL;
+
+       buf_attr->page_shift = order_base_2(page_sz);
+       return 0;
+}
+
+static int get_best_hop_num(struct hns_roce_dev *hr_dev,
+                           struct hns_roce_mtr *mtr,
+                           struct hns_roce_buf_attr *buf_attr,
+                           unsigned int ba_pg_shift)
+{
+#define INVALID_HOPNUM -1
+#define MIN_BA_CNT 1
+       size_t buf_pg_sz = 1 << buf_attr->page_shift;
+       struct ib_device *ibdev = &hr_dev->ib_dev;
+       size_t ba_pg_sz = 1 << ba_pg_shift;
+       int hop_num = INVALID_HOPNUM;
+       size_t unit = MIN_BA_CNT;
+       size_t ba_cnt;
+       int j;
+
+       if (!buf_attr->adaptive || buf_attr->type != MTR_PBL)
+               return 0;
+
+       /* Caculating the number of buf pages, each buf page need a BA */
+       if (mtr->umem)
+               ba_cnt = ib_umem_num_dma_blocks(mtr->umem, buf_pg_sz);
+       else
+               ba_cnt = DIV_ROUND_UP(buf_attr->region[0].size, buf_pg_sz);
+
+       for (j = 0; j <= HNS_ROCE_MAX_HOP_NUM; j++) {
+               if (ba_cnt <= unit) {
+                       hop_num = j;
+                       break;
+               }
+               /* Number of BAs can be represented at per hop */
+               unit *= ba_pg_sz / BA_BYTE_LEN;
+       }
+
+       if (hop_num < 0) {
+               ibdev_err(ibdev,
+                         "failed to calculate a valid hopnum.\n");
+               return -EINVAL;
+       }
 
-       return total;
+       buf_attr->region[0].hopnum = hop_num;
+
+       return 0;
+}
+
+static bool is_buf_attr_valid(struct hns_roce_dev *hr_dev,
+                             struct hns_roce_buf_attr *attr)
+{
+       struct ib_device *ibdev = &hr_dev->ib_dev;
+
+       if (attr->region_count > ARRAY_SIZE(attr->region) ||
+           attr->region_count < 1 || attr->page_shift < HNS_HW_PAGE_SHIFT) {
+               ibdev_err(ibdev,
+                         "invalid buf attr, region count %d, page shift %u.\n",
+                         attr->region_count, attr->page_shift);
+               return false;
+       }
+
+       return true;
 }
 
 static int mtr_init_buf_cfg(struct hns_roce_dev *hr_dev,
-                           struct hns_roce_buf_attr *attr,
-                           struct hns_roce_hem_cfg *cfg,
-                           unsigned int *buf_page_shift, u64 unalinged_size)
+                           struct hns_roce_mtr *mtr,
+                           struct hns_roce_buf_attr *attr)
 {
+       struct hns_roce_hem_cfg *cfg = &mtr->hem_cfg;
        struct hns_roce_buf_region *r;
-       u64 first_region_padding;
-       int page_cnt, region_cnt;
-       unsigned int page_shift;
+       size_t buf_pg_sz;
        size_t buf_size;
+       int page_cnt, i;
+       u64 pgoff = 0;
+
+       if (!is_buf_attr_valid(hr_dev, attr))
+               return -EINVAL;
 
        /* If mtt is disabled, all pages must be within a continuous range */
        cfg->is_direct = !mtr_has_mtt(attr);
+       cfg->region_count = attr->region_count;
        buf_size = mtr_bufs_size(attr);
-       if (cfg->is_direct) {
-               /* When HEM buffer uses 0-level addressing, the page size is
-                * equal to the whole buffer size, and we split the buffer into
-                * small pages which is used to check whether the adjacent
-                * units are in the continuous space and its size is fixed to
-                * 4K based on hns ROCEE's requirement.
-                */
-               page_shift = HNS_HW_PAGE_SHIFT;
-
-               /* The ROCEE requires the page size to be 4K * 2 ^ N. */
+       if (need_split_huge_page(mtr)) {
+               buf_pg_sz = HNS_HW_PAGE_SIZE;
                cfg->buf_pg_count = 1;
+               /* The ROCEE requires the page size to be 4K * 2 ^ N. */
                cfg->buf_pg_shift = HNS_HW_PAGE_SHIFT +
                        order_base_2(DIV_ROUND_UP(buf_size, HNS_HW_PAGE_SIZE));
-               first_region_padding = 0;
        } else {
-               page_shift = attr->page_shift;
-               cfg->buf_pg_count = DIV_ROUND_UP(buf_size + unalinged_size,
-                                                1 << page_shift);
-               cfg->buf_pg_shift = page_shift;
-               first_region_padding = unalinged_size;
+               buf_pg_sz = 1 << attr->page_shift;
+               cfg->buf_pg_count = mtr->umem ?
+                       ib_umem_num_dma_blocks(mtr->umem, buf_pg_sz) :
+                       DIV_ROUND_UP(buf_size, buf_pg_sz);
+               cfg->buf_pg_shift = attr->page_shift;
+               pgoff = mtr->umem ? mtr->umem->address & ~PAGE_MASK : 0;
        }
 
        /* Convert buffer size to page index and page count for each region and
         * the buffer's offset needs to be appended to the first region.
         */
-       for (page_cnt = 0, region_cnt = 0; region_cnt < attr->region_count &&
-            region_cnt < ARRAY_SIZE(cfg->region); region_cnt++) {
-               r = &cfg->region[region_cnt];
+       for (page_cnt = 0, i = 0; i < attr->region_count; i++) {
+               r = &cfg->region[i];
                r->offset = page_cnt;
-               buf_size = hr_hw_page_align(attr->region[region_cnt].size +
-                                           first_region_padding);
-               r->count = DIV_ROUND_UP(buf_size, 1 << page_shift);
-               first_region_padding = 0;
+               buf_size = hr_hw_page_align(attr->region[i].size + pgoff);
+               if (attr->type == MTR_PBL && mtr->umem)
+                       r->count = ib_umem_num_dma_blocks(mtr->umem, buf_pg_sz);
+               else
+                       r->count = DIV_ROUND_UP(buf_size, buf_pg_sz);
+
+               pgoff = 0;
                page_cnt += r->count;
-               r->hopnum = to_hr_hem_hopnum(attr->region[region_cnt].hopnum,
-                                            r->count);
+               r->hopnum = to_hr_hem_hopnum(attr->region[i].hopnum, r->count);
        }
 
-       cfg->region_count = region_cnt;
-       *buf_page_shift = page_shift;
-
-       return page_cnt;
+       return 0;
 }
 
 static u64 cal_pages_per_l1ba(unsigned int ba_per_bt, unsigned int hopnum)
@@ -1007,50 +1144,58 @@ int hns_roce_mtr_create(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
                        unsigned long user_addr)
 {
        struct ib_device *ibdev = &hr_dev->ib_dev;
-       unsigned int buf_page_shift = 0;
-       int buf_page_cnt;
        int ret;
 
-       buf_page_cnt = mtr_init_buf_cfg(hr_dev, buf_attr, &mtr->hem_cfg,
-                                       &buf_page_shift,
-                                       udata ? user_addr & ~PAGE_MASK : 0);
-       if (buf_page_cnt < 1 || buf_page_shift < HNS_HW_PAGE_SHIFT) {
-               ibdev_err(ibdev, "failed to init mtr cfg, count %d shift %u.\n",
-                         buf_page_cnt, buf_page_shift);
-               return -EINVAL;
-       }
-
-       ret = mtr_alloc_mtt(hr_dev, mtr, ba_page_shift);
-       if (ret) {
-               ibdev_err(ibdev, "failed to alloc mtr mtt, ret = %d.\n", ret);
-               return ret;
-       }
-
        /* The caller has its own buffer list and invokes the hns_roce_mtr_map()
         * to finish the MTT configuration.
         */
        if (buf_attr->mtt_only) {
                mtr->umem = NULL;
                mtr->kmem = NULL;
-               return 0;
+       } else {
+               ret = mtr_alloc_bufs(hr_dev, mtr, buf_attr, udata, user_addr);
+               if (ret) {
+                       ibdev_err(ibdev,
+                                 "failed to alloc mtr bufs, ret = %d.\n", ret);
+                       return ret;
+               }
+
+               ret = get_best_page_shift(hr_dev, mtr, buf_attr);
+               if (ret)
+                       goto err_init_buf;
+
+               ret = get_best_hop_num(hr_dev, mtr, buf_attr, ba_page_shift);
+               if (ret)
+                       goto err_init_buf;
        }
 
-       ret = mtr_alloc_bufs(hr_dev, mtr, buf_attr, udata, user_addr);
+       ret = mtr_init_buf_cfg(hr_dev, mtr, buf_attr);
+       if (ret)
+               goto err_init_buf;
+
+       ret = mtr_alloc_mtt(hr_dev, mtr, ba_page_shift);
        if (ret) {
-               ibdev_err(ibdev, "failed to alloc mtr bufs, ret = %d.\n", ret);
-               goto err_alloc_mtt;
+               ibdev_err(ibdev, "failed to alloc mtr mtt, ret = %d.\n", ret);
+               goto err_init_buf;
        }
 
+       if (buf_attr->mtt_only)
+               return 0;
+
        /* Write buffer's dma address to MTT */
-       ret = mtr_map_bufs(hr_dev, mtr, buf_page_cnt, buf_page_shift);
-       if (ret)
+       ret = mtr_map_bufs(hr_dev, mtr);
+       if (ret) {
                ibdev_err(ibdev, "failed to map mtr bufs, ret = %d.\n", ret);
-       else
-               return 0;
+               goto err_alloc_mtt;
+       }
+
+       return 0;
 
-       mtr_free_bufs(hr_dev, mtr);
 err_alloc_mtt:
        mtr_free_mtt(hr_dev, mtr);
+err_init_buf:
+       mtr_free_bufs(hr_dev, mtr);
+
        return ret;
 }
 
index 31b147210688ab6600d68124d063d78356b73fd0..f35a66325d9a6596b3425bac9676644fac675d4f 100644 (file)
@@ -1004,6 +1004,60 @@ static void free_kernel_wrid(struct hns_roce_qp *hr_qp)
        kfree(hr_qp->sq.wrid);
 }
 
+static void default_congest_type(struct hns_roce_dev *hr_dev,
+                                struct hns_roce_qp *hr_qp)
+{
+       if (hr_qp->ibqp.qp_type == IB_QPT_UD ||
+           hr_qp->ibqp.qp_type == IB_QPT_GSI)
+               hr_qp->cong_type = CONG_TYPE_DCQCN;
+       else
+               hr_qp->cong_type = hr_dev->caps.default_cong_type;
+}
+
+static int set_congest_type(struct hns_roce_qp *hr_qp,
+                           struct hns_roce_ib_create_qp *ucmd)
+{
+       struct hns_roce_dev *hr_dev = to_hr_dev(hr_qp->ibqp.device);
+
+       switch (ucmd->cong_type_flags) {
+       case HNS_ROCE_CREATE_QP_FLAGS_DCQCN:
+               hr_qp->cong_type = CONG_TYPE_DCQCN;
+               break;
+       case HNS_ROCE_CREATE_QP_FLAGS_LDCP:
+               hr_qp->cong_type = CONG_TYPE_LDCP;
+               break;
+       case HNS_ROCE_CREATE_QP_FLAGS_HC3:
+               hr_qp->cong_type = CONG_TYPE_HC3;
+               break;
+       case HNS_ROCE_CREATE_QP_FLAGS_DIP:
+               hr_qp->cong_type = CONG_TYPE_DIP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!test_bit(hr_qp->cong_type, (unsigned long *)&hr_dev->caps.cong_cap))
+               return -EOPNOTSUPP;
+
+       if (hr_qp->ibqp.qp_type == IB_QPT_UD &&
+           hr_qp->cong_type != CONG_TYPE_DCQCN)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
+static int set_congest_param(struct hns_roce_dev *hr_dev,
+                            struct hns_roce_qp *hr_qp,
+                            struct hns_roce_ib_create_qp *ucmd)
+{
+       if (ucmd->comp_mask & HNS_ROCE_CREATE_QP_MASK_CONGEST_TYPE)
+               return set_congest_type(hr_qp, ucmd);
+
+       default_congest_type(hr_dev, hr_qp);
+
+       return 0;
+}
+
 static int set_qp_param(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
                        struct ib_qp_init_attr *init_attr,
                        struct ib_udata *udata,
@@ -1043,6 +1097,10 @@ static int set_qp_param(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
                        ibdev_err(ibdev,
                                  "failed to set user SQ size, ret = %d.\n",
                                  ret);
+
+               ret = set_congest_param(hr_dev, hr_qp, ucmd);
+               if (ret)
+                       return ret;
        } else {
                if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09)
                        hr_qp->config = HNS_ROCE_EXSGE_FLAGS;
@@ -1051,6 +1109,8 @@ static int set_qp_param(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp,
                        ibdev_err(ibdev,
                                  "failed to set kernel SQ size, ret = %d.\n",
                                  ret);
+
+               default_congest_type(hr_dev, hr_qp);
        }
 
        return ret;
index f7f3c4cc7426d642de01b0f783607a24b44fc37e..356d988169497385fe433ea113bb7c87344f8777 100644 (file)
@@ -97,16 +97,33 @@ int hns_roce_fill_res_qp_entry_raw(struct sk_buff *msg, struct ib_qp *ib_qp)
 {
        struct hns_roce_dev *hr_dev = to_hr_dev(ib_qp->device);
        struct hns_roce_qp *hr_qp = to_hr_qp(ib_qp);
-       struct hns_roce_v2_qp_context context;
+       struct hns_roce_full_qp_ctx {
+               struct hns_roce_v2_qp_context qpc;
+               struct hns_roce_v2_scc_context sccc;
+       } context = {};
        int ret;
 
        if (!hr_dev->hw->query_qpc)
                return -EINVAL;
 
-       ret = hr_dev->hw->query_qpc(hr_dev, hr_qp->qpn, &context);
+       ret = hr_dev->hw->query_qpc(hr_dev, hr_qp->qpn, &context.qpc);
        if (ret)
-               return -EINVAL;
+               return ret;
+
+       /* If SCC is disabled or the query fails, the queried SCCC will
+        * be all 0.
+        */
+       if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL) ||
+           !hr_dev->hw->query_sccc)
+               goto out;
+
+       ret = hr_dev->hw->query_sccc(hr_dev, hr_qp->qpn, &context.sccc);
+       if (ret)
+               ibdev_warn_ratelimited(&hr_dev->ib_dev,
+                                      "failed to query SCCC, ret = %d.\n",
+                                      ret);
 
+out:
        ret = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, sizeof(context), &context);
 
        return ret;
index 0b046c061742be140251785f60ac25cff73aa2ba..12704efb7b19a8e7bd5422638617a6cd7f8436eb 100644 (file)
@@ -719,7 +719,6 @@ static int irdma_setup_kmode_qp(struct irdma_device *iwdev,
                info->rq_pa + (ukinfo->rq_depth * IRDMA_QP_WQE_MIN_SIZE);
        ukinfo->sq_size = ukinfo->sq_depth >> ukinfo->sq_shift;
        ukinfo->rq_size = ukinfo->rq_depth >> ukinfo->rq_shift;
-       ukinfo->qp_id = iwqp->ibqp.qp_num;
 
        iwqp->max_send_wr = (ukinfo->sq_depth - IRDMA_SQ_RSVD) >> ukinfo->sq_shift;
        iwqp->max_recv_wr = (ukinfo->rq_depth - IRDMA_RQ_RSVD) >> ukinfo->rq_shift;
@@ -944,7 +943,7 @@ static int irdma_create_qp(struct ib_qp *ibqp,
        iwqp->host_ctx.size = IRDMA_QP_CTX_SIZE;
 
        init_info.pd = &iwpd->sc_pd;
-       init_info.qp_uk_init_info.qp_id = iwqp->ibqp.qp_num;
+       init_info.qp_uk_init_info.qp_id = qp_num;
        if (!rdma_protocol_roce(&iwdev->ibdev, 1))
                init_info.qp_uk_init_info.first_sq_wq = 1;
        iwqp->ctx_info.qp_compl_ctx = (uintptr_t)qp;
index 83ebd070535aba1d49f3cb217672ce18be4304ec..4a71e678d09c19c50d6f7d1d5105dec8a8cc38f7 100644 (file)
@@ -16,7 +16,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
        int err;
 
        mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       gc = mdev->gdma_dev->gdma_context;
+       gc = mdev_to_gc(mdev);
 
        if (udata->inlen < sizeof(ucmd))
                return -EINVAL;
@@ -48,7 +48,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
                return err;
        }
 
-       err = mana_ib_gd_create_dma_region(mdev, cq->umem, &cq->gdma_region);
+       err = mana_ib_create_zero_offset_dma_region(mdev, cq->umem, &cq->gdma_region);
        if (err) {
                ibdev_dbg(ibdev,
                          "Failed to create dma region for create cq, %d\n",
@@ -57,7 +57,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
        }
 
        ibdev_dbg(ibdev,
-                 "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n",
+                 "create_dma_region ret %d gdma_region 0x%llx\n",
                  err, cq->gdma_region);
 
        /*
@@ -81,7 +81,7 @@ int mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
        int err;
 
        mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       gc = mdev->gdma_dev->gdma_context;
+       gc = mdev_to_gc(mdev);
 
        err = mana_ib_gd_destroy_dma_region(mdev, cq->gdma_region);
        if (err) {
@@ -100,10 +100,29 @@ int mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
        return 0;
 }
 
-void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq)
+static void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq)
 {
        struct mana_ib_cq *cq = ctx;
 
        if (cq->ibcq.comp_handler)
                cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
 }
+
+int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq)
+{
+       struct gdma_context *gc = mdev_to_gc(mdev);
+       struct gdma_queue *gdma_cq;
+
+       /* Create CQ table entry */
+       WARN_ON(gc->cq_table[cq->id]);
+       gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL);
+       if (!gdma_cq)
+               return -ENOMEM;
+
+       gdma_cq->cq.context = cq;
+       gdma_cq->type = GDMA_CQ;
+       gdma_cq->cq.callback = mana_ib_cq_handler;
+       gdma_cq->id = cq->id;
+       gc->cq_table[cq->id] = gdma_cq;
+       return 0;
+}
index faca092456fa3d692879979b40c75714ef2602fe..71e33feee61bb124ccabf510dda65eb0fb39fda9 100644 (file)
@@ -8,13 +8,10 @@
 void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd,
                         u32 port)
 {
-       struct gdma_dev *gd = &dev->gdma_dev->gdma_context->mana;
        struct mana_port_context *mpc;
        struct net_device *ndev;
-       struct mana_context *mc;
 
-       mc = gd->driver_data;
-       ndev = mc->ports[port];
+       ndev = mana_ib_get_netdev(&dev->ib_dev, port);
        mpc = netdev_priv(ndev);
 
        mutex_lock(&pd->vport_mutex);
@@ -31,14 +28,11 @@ void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd,
 int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd,
                      u32 doorbell_id)
 {
-       struct gdma_dev *mdev = &dev->gdma_dev->gdma_context->mana;
        struct mana_port_context *mpc;
-       struct mana_context *mc;
        struct net_device *ndev;
        int err;
 
-       mc = mdev->driver_data;
-       ndev = mc->ports[port];
+       ndev = mana_ib_get_netdev(&dev->ib_dev, port);
        mpc = netdev_priv(ndev);
 
        mutex_lock(&pd->vport_mutex);
@@ -79,17 +73,17 @@ int mana_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
        struct gdma_create_pd_req req = {};
        enum gdma_pd_flags flags = 0;
        struct mana_ib_dev *dev;
-       struct gdma_dev *mdev;
+       struct gdma_context *gc;
        int err;
 
        dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       mdev = dev->gdma_dev;
+       gc = mdev_to_gc(dev);
 
        mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_PD, sizeof(req),
                             sizeof(resp));
 
        req.flags = flags;
-       err = mana_gd_send_request(mdev->gdma_context, sizeof(req), &req,
+       err = mana_gd_send_request(gc, sizeof(req), &req,
                                   sizeof(resp), &resp);
 
        if (err || resp.hdr.status) {
@@ -119,17 +113,17 @@ int mana_ib_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
        struct gdma_destory_pd_resp resp = {};
        struct gdma_destroy_pd_req req = {};
        struct mana_ib_dev *dev;
-       struct gdma_dev *mdev;
+       struct gdma_context *gc;
        int err;
 
        dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       mdev = dev->gdma_dev;
+       gc = mdev_to_gc(dev);
 
        mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_PD, sizeof(req),
                             sizeof(resp));
 
        req.pd_handle = pd->pd_handle;
-       err = mana_gd_send_request(mdev->gdma_context, sizeof(req), &req,
+       err = mana_gd_send_request(gc, sizeof(req), &req,
                                   sizeof(resp), &resp);
 
        if (err || resp.hdr.status) {
@@ -206,13 +200,11 @@ int mana_ib_alloc_ucontext(struct ib_ucontext *ibcontext,
        struct ib_device *ibdev = ibcontext->device;
        struct mana_ib_dev *mdev;
        struct gdma_context *gc;
-       struct gdma_dev *dev;
        int doorbell_page;
        int ret;
 
        mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       dev = mdev->gdma_dev;
-       gc = dev->gdma_context;
+       gc = mdev_to_gc(mdev);
 
        /* Allocate a doorbell page index */
        ret = mana_gd_allocate_doorbell_page(gc, &doorbell_page);
@@ -238,7 +230,7 @@ void mana_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
        int ret;
 
        mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       gc = mdev->gdma_dev->gdma_context;
+       gc = mdev_to_gc(mdev);
 
        ret = mana_gd_destroy_doorbell_page(gc, mana_ucontext->doorbell);
        if (ret)
@@ -309,8 +301,8 @@ mana_ib_gd_add_dma_region(struct mana_ib_dev *dev, struct gdma_context *gc,
        return 0;
 }
 
-int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
-                                mana_handle_t *gdma_region)
+static int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
+                                       mana_handle_t *gdma_region, unsigned long page_sz)
 {
        struct gdma_dma_region_add_pages_req *add_req = NULL;
        size_t num_pages_processed = 0, num_pages_to_handle;
@@ -322,23 +314,14 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
        size_t max_pgs_create_cmd;
        struct gdma_context *gc;
        size_t num_pages_total;
-       struct gdma_dev *mdev;
-       unsigned long page_sz;
        unsigned int tail = 0;
        u64 *page_addr_list;
        void *request_buf;
        int err;
 
-       mdev = dev->gdma_dev;
-       gc = mdev->gdma_context;
+       gc = mdev_to_gc(dev);
        hwc = gc->hwc.driver_data;
 
-       /* Hardware requires dma region to align to chosen page size */
-       page_sz = ib_umem_find_best_pgsz(umem, PAGE_SZ_BM, 0);
-       if (!page_sz) {
-               ibdev_dbg(&dev->ib_dev, "failed to find page size.\n");
-               return -ENOMEM;
-       }
        num_pages_total = ib_umem_num_dma_blocks(umem, page_sz);
 
        max_pgs_create_cmd =
@@ -358,7 +341,7 @@ int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
                             sizeof(struct gdma_create_dma_region_resp));
 
        create_req->length = umem->length;
-       create_req->offset_in_page = umem->address & (page_sz - 1);
+       create_req->offset_in_page = ib_umem_dma_offset(umem, page_sz);
        create_req->gdma_page_type = order_base_2(page_sz) - PAGE_SHIFT;
        create_req->page_count = num_pages_total;
 
@@ -424,12 +407,39 @@ out:
        return err;
 }
 
+int mana_ib_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
+                             mana_handle_t *gdma_region, u64 virt)
+{
+       unsigned long page_sz;
+
+       page_sz = ib_umem_find_best_pgsz(umem, PAGE_SZ_BM, virt);
+       if (!page_sz) {
+               ibdev_dbg(&dev->ib_dev, "Failed to find page size.\n");
+               return -EINVAL;
+       }
+
+       return mana_ib_gd_create_dma_region(dev, umem, gdma_region, page_sz);
+}
+
+int mana_ib_create_zero_offset_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
+                                         mana_handle_t *gdma_region)
+{
+       unsigned long page_sz;
+
+       /* Hardware requires dma region to align to chosen page size */
+       page_sz = ib_umem_find_best_pgoff(umem, PAGE_SZ_BM, 0);
+       if (!page_sz) {
+               ibdev_dbg(&dev->ib_dev, "Failed to find page size.\n");
+               return -EINVAL;
+       }
+
+       return mana_ib_gd_create_dma_region(dev, umem, gdma_region, page_sz);
+}
+
 int mana_ib_gd_destroy_dma_region(struct mana_ib_dev *dev, u64 gdma_region)
 {
-       struct gdma_dev *mdev = dev->gdma_dev;
-       struct gdma_context *gc;
+       struct gdma_context *gc = mdev_to_gc(dev);
 
-       gc = mdev->gdma_context;
        ibdev_dbg(&dev->ib_dev, "destroy dma region 0x%llx\n", gdma_region);
 
        return mana_gd_destroy_dma_region(gc, gdma_region);
@@ -447,7 +457,7 @@ int mana_ib_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
        int ret;
 
        mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
-       gc = mdev->gdma_dev->gdma_context;
+       gc = mdev_to_gc(mdev);
 
        if (vma->vm_pgoff != 0) {
                ibdev_dbg(ibdev, "Unexpected vm_pgoff %lu\n", vma->vm_pgoff);
@@ -531,7 +541,7 @@ int mana_ib_gd_query_adapter_caps(struct mana_ib_dev *dev)
        req.hdr.resp.msg_version = GDMA_MESSAGE_V3;
        req.hdr.dev_id = dev->gdma_dev->dev_id;
 
-       err = mana_gd_send_request(dev->gdma_dev->gdma_context, sizeof(req),
+       err = mana_gd_send_request(mdev_to_gc(dev), sizeof(req),
                                   &req, sizeof(resp), &resp);
 
        if (err) {
index 6bdc0f5498d5bc148cd333a33bdb6192d8b53ee9..f83390eebb7d751d731c48f232dc03bfc6847baa 100644 (file)
@@ -142,8 +142,29 @@ struct mana_ib_query_adapter_caps_resp {
        u32 max_inline_data_size;
 }; /* HW Data */
 
-int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
-                                mana_handle_t *gdma_region);
+static inline struct gdma_context *mdev_to_gc(struct mana_ib_dev *mdev)
+{
+       return mdev->gdma_dev->gdma_context;
+}
+
+static inline struct net_device *mana_ib_get_netdev(struct ib_device *ibdev, u32 port)
+{
+       struct mana_ib_dev *mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
+       struct gdma_context *gc = mdev_to_gc(mdev);
+       struct mana_context *mc = gc->mana.driver_data;
+
+       if (port < 1 || port > mc->num_ports)
+               return NULL;
+       return mc->ports[port - 1];
+}
+
+int mana_ib_install_cq_cb(struct mana_ib_dev *mdev, struct mana_ib_cq *cq);
+
+int mana_ib_create_zero_offset_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
+                                         mana_handle_t *gdma_region);
+
+int mana_ib_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
+                             mana_handle_t *gdma_region, u64 virt);
 
 int mana_ib_gd_destroy_dma_region(struct mana_ib_dev *dev,
                                  mana_handle_t gdma_region);
@@ -210,6 +231,4 @@ int mana_ib_query_gid(struct ib_device *ibdev, u32 port, int index,
 void mana_ib_disassociate_ucontext(struct ib_ucontext *ibcontext);
 
 int mana_ib_gd_query_adapter_caps(struct mana_ib_dev *mdev);
-
-void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq);
 #endif
index 351207c60eb65da7505aeac271a310a79b346fc6..b70b13484f0974d19bf41ca4e0d1f6872e7756d1 100644 (file)
@@ -30,12 +30,9 @@ static int mana_ib_gd_create_mr(struct mana_ib_dev *dev, struct mana_ib_mr *mr,
 {
        struct gdma_create_mr_response resp = {};
        struct gdma_create_mr_request req = {};
-       struct gdma_dev *mdev = dev->gdma_dev;
-       struct gdma_context *gc;
+       struct gdma_context *gc = mdev_to_gc(dev);
        int err;
 
-       gc = mdev->gdma_context;
-
        mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_MR, sizeof(req),
                             sizeof(resp));
        req.pd_handle = mr_params->pd_handle;
@@ -77,12 +74,9 @@ static int mana_ib_gd_destroy_mr(struct mana_ib_dev *dev, u64 mr_handle)
 {
        struct gdma_destroy_mr_response resp = {};
        struct gdma_destroy_mr_request req = {};
-       struct gdma_dev *mdev = dev->gdma_dev;
-       struct gdma_context *gc;
+       struct gdma_context *gc = mdev_to_gc(dev);
        int err;
 
-       gc = mdev->gdma_context;
-
        mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_MR, sizeof(req),
                             sizeof(resp));
 
@@ -133,7 +127,7 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
                goto err_free;
        }
 
-       err = mana_ib_gd_create_dma_region(dev, mr->umem, &dma_region_handle);
+       err = mana_ib_create_dma_region(dev, mr->umem, &dma_region_handle, iova);
        if (err) {
                ibdev_dbg(ibdev, "Failed create dma region for user-mr, %d\n",
                          err);
@@ -141,7 +135,7 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
        }
 
        ibdev_dbg(ibdev,
-                 "mana_ib_gd_create_dma_region ret %d gdma_region %llx\n", err,
+                 "create_dma_region ret %d gdma_region %llx\n", err,
                  dma_region_handle);
 
        mr_params.pd_handle = pd->pd_handle;
@@ -164,8 +158,7 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
        return &mr->ibmr;
 
 err_dma_region:
-       mana_gd_destroy_dma_region(dev->gdma_dev->gdma_context,
-                                  dma_region_handle);
+       mana_gd_destroy_dma_region(mdev_to_gc(dev), dma_region_handle);
 
 err_umem:
        ib_umem_release(mr->umem);
index 21ac9fcadf3f239863cd5215a529215ea694653f..6e7627745c9578eada23d5db93e79b38cfd6307b 100644 (file)
@@ -17,12 +17,10 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev,
        struct mana_cfg_rx_steer_resp resp = {};
        mana_handle_t *req_indir_tab;
        struct gdma_context *gc;
-       struct gdma_dev *mdev;
        u32 req_buf_size;
        int i, err;
 
-       gc = dev->gdma_dev->gdma_context;
-       mdev = &gc->mana;
+       gc = mdev_to_gc(dev);
 
        req_buf_size =
                sizeof(*req) + sizeof(mana_handle_t) * MANA_INDIRECT_TABLE_SIZE;
@@ -39,7 +37,7 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev,
        req->rx_enable = 1;
        req->update_default_rxobj = 1;
        req->default_rxobj = default_rxobj;
-       req->hdr.dev_id = mdev->dev_id;
+       req->hdr.dev_id = gc->mana.dev_id;
 
        /* If there are more than 1 entries in indirection table, enable RSS */
        if (log_ind_tbl_size)
@@ -99,20 +97,17 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
        struct mana_ib_qp *qp = container_of(ibqp, struct mana_ib_qp, ibqp);
        struct mana_ib_dev *mdev =
                container_of(pd->device, struct mana_ib_dev, ib_dev);
+       struct gdma_context *gc = mdev_to_gc(mdev);
        struct ib_rwq_ind_table *ind_tbl = attr->rwq_ind_tbl;
        struct mana_ib_create_qp_rss_resp resp = {};
        struct mana_ib_create_qp_rss ucmd = {};
        struct gdma_queue **gdma_cq_allocated;
        mana_handle_t *mana_ind_table;
        struct mana_port_context *mpc;
-       struct gdma_queue *gdma_cq;
        unsigned int ind_tbl_size;
-       struct mana_context *mc;
        struct net_device *ndev;
-       struct gdma_context *gc;
        struct mana_ib_cq *cq;
        struct mana_ib_wq *wq;
-       struct gdma_dev *gd;
        struct mana_eq *eq;
        struct ib_cq *ibcq;
        struct ib_wq *ibwq;
@@ -120,10 +115,6 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
        u32 port;
        int ret;
 
-       gc = mdev->gdma_dev->gdma_context;
-       gd = &gc->mana;
-       mc = gd->driver_data;
-
        if (!udata || udata->inlen < sizeof(ucmd))
                return -EINVAL;
 
@@ -166,12 +157,12 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
 
        /* IB ports start with 1, MANA start with 0 */
        port = ucmd.port;
-       if (port < 1 || port > mc->num_ports) {
+       ndev = mana_ib_get_netdev(pd->device, port);
+       if (!ndev) {
                ibdev_dbg(&mdev->ib_dev, "Invalid port %u in creating qp\n",
                          port);
                return -EINVAL;
        }
-       ndev = mc->ports[port - 1];
        mpc = netdev_priv(ndev);
 
        ibdev_dbg(&mdev->ib_dev, "rx_hash_function %d port %d\n",
@@ -209,7 +200,7 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
                cq_spec.gdma_region = cq->gdma_region;
                cq_spec.queue_size = cq->cqe * COMP_ENTRY_SIZE;
                cq_spec.modr_ctx_id = 0;
-               eq = &mc->eqs[cq->comp_vector % gc->max_num_queues];
+               eq = &mpc->ac->eqs[cq->comp_vector % gc->max_num_queues];
                cq_spec.attached_eq = eq->eq->id;
 
                ret = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_RQ,
@@ -237,19 +228,11 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
                mana_ind_table[i] = wq->rx_object;
 
                /* Create CQ table entry */
-               WARN_ON(gc->cq_table[cq->id]);
-               gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL);
-               if (!gdma_cq) {
-                       ret = -ENOMEM;
+               ret = mana_ib_install_cq_cb(mdev, cq);
+               if (ret)
                        goto fail;
-               }
-               gdma_cq_allocated[i] = gdma_cq;
 
-               gdma_cq->cq.context = cq;
-               gdma_cq->type = GDMA_CQ;
-               gdma_cq->cq.callback = mana_ib_cq_handler;
-               gdma_cq->id = cq->id;
-               gc->cq_table[cq->id] = gdma_cq;
+               gdma_cq_allocated[i] = gc->cq_table[cq->id];
        }
        resp.num_entries = i;
 
@@ -306,14 +289,13 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
        struct mana_ib_ucontext *mana_ucontext =
                rdma_udata_to_drv_context(udata, struct mana_ib_ucontext,
                                          ibucontext);
-       struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana;
+       struct gdma_context *gc = mdev_to_gc(mdev);
        struct mana_ib_create_qp_resp resp = {};
        struct mana_ib_create_qp ucmd = {};
        struct gdma_queue *gdma_cq = NULL;
        struct mana_obj_spec wq_spec = {};
        struct mana_obj_spec cq_spec = {};
        struct mana_port_context *mpc;
-       struct mana_context *mc;
        struct net_device *ndev;
        struct ib_umem *umem;
        struct mana_eq *eq;
@@ -321,8 +303,6 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
        u32 port;
        int err;
 
-       mc = gd->driver_data;
-
        if (!mana_ucontext || udata->inlen < sizeof(ucmd))
                return -EINVAL;
 
@@ -333,11 +313,6 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
                return err;
        }
 
-       /* IB ports start with 1, MANA Ethernet ports start with 0 */
-       port = ucmd.port;
-       if (port < 1 || port > mc->num_ports)
-               return -EINVAL;
-
        if (attr->cap.max_send_wr > mdev->adapter_caps.max_qp_wr) {
                ibdev_dbg(&mdev->ib_dev,
                          "Requested max_send_wr %d exceeding limit\n",
@@ -352,11 +327,17 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
                return -EINVAL;
        }
 
-       ndev = mc->ports[port - 1];
+       port = ucmd.port;
+       ndev = mana_ib_get_netdev(ibpd->device, port);
+       if (!ndev) {
+               ibdev_dbg(&mdev->ib_dev, "Invalid port %u in creating qp\n",
+                         port);
+               return -EINVAL;
+       }
        mpc = netdev_priv(ndev);
        ibdev_dbg(&mdev->ib_dev, "port %u ndev %p mpc %p\n", port, ndev, mpc);
 
-       err = mana_ib_cfg_vport(mdev, port - 1, pd, mana_ucontext->doorbell);
+       err = mana_ib_cfg_vport(mdev, port, pd, mana_ucontext->doorbell);
        if (err)
                return -ENODEV;
 
@@ -376,8 +357,8 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
        }
        qp->sq_umem = umem;
 
-       err = mana_ib_gd_create_dma_region(mdev, qp->sq_umem,
-                                          &qp->sq_gdma_region);
+       err = mana_ib_create_zero_offset_dma_region(mdev, qp->sq_umem,
+                                                   &qp->sq_gdma_region);
        if (err) {
                ibdev_dbg(&mdev->ib_dev,
                          "Failed to create dma region for create qp-raw, %d\n",
@@ -386,7 +367,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
        }
 
        ibdev_dbg(&mdev->ib_dev,
-                 "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n",
+                 "create_dma_region ret %d gdma_region 0x%llx\n",
                  err, qp->sq_gdma_region);
 
        /* Create a WQ on the same port handle used by the Ethernet */
@@ -396,8 +377,8 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
        cq_spec.gdma_region = send_cq->gdma_region;
        cq_spec.queue_size = send_cq->cqe * COMP_ENTRY_SIZE;
        cq_spec.modr_ctx_id = 0;
-       eq_vec = send_cq->comp_vector % gd->gdma_context->max_num_queues;
-       eq = &mc->eqs[eq_vec];
+       eq_vec = send_cq->comp_vector % gc->max_num_queues;
+       eq = &mpc->ac->eqs[eq_vec];
        cq_spec.attached_eq = eq->eq->id;
 
        err = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_SQ, &wq_spec,
@@ -417,18 +398,9 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
        send_cq->id = cq_spec.queue_index;
 
        /* Create CQ table entry */
-       WARN_ON(gd->gdma_context->cq_table[send_cq->id]);
-       gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL);
-       if (!gdma_cq) {
-               err = -ENOMEM;
+       err = mana_ib_install_cq_cb(mdev, send_cq);
+       if (err)
                goto err_destroy_wq_obj;
-       }
-
-       gdma_cq->cq.context = send_cq;
-       gdma_cq->type = GDMA_CQ;
-       gdma_cq->cq.callback = mana_ib_cq_handler;
-       gdma_cq->id = send_cq->id;
-       gd->gdma_context->cq_table[send_cq->id] = gdma_cq;
 
        ibdev_dbg(&mdev->ib_dev,
                  "ret %d qp->tx_object 0x%llx sq id %llu cq id %llu\n", err,
@@ -450,7 +422,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
 
 err_release_gdma_cq:
        kfree(gdma_cq);
-       gd->gdma_context->cq_table[send_cq->id] = NULL;
+       gc->cq_table[send_cq->id] = NULL;
 
 err_destroy_wq_obj:
        mana_destroy_wq_obj(mpc, GDMA_SQ, qp->tx_object);
@@ -462,7 +434,7 @@ err_release_umem:
        ib_umem_release(umem);
 
 err_free_vport:
-       mana_ib_uncfg_vport(mdev, pd, port - 1);
+       mana_ib_uncfg_vport(mdev, pd, port);
 
        return err;
 }
@@ -500,16 +472,13 @@ static int mana_ib_destroy_qp_rss(struct mana_ib_qp *qp,
 {
        struct mana_ib_dev *mdev =
                container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
-       struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana;
        struct mana_port_context *mpc;
-       struct mana_context *mc;
        struct net_device *ndev;
        struct mana_ib_wq *wq;
        struct ib_wq *ibwq;
        int i;
 
-       mc = gd->driver_data;
-       ndev = mc->ports[qp->port - 1];
+       ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port);
        mpc = netdev_priv(ndev);
 
        for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) {
@@ -527,15 +496,12 @@ static int mana_ib_destroy_qp_raw(struct mana_ib_qp *qp, struct ib_udata *udata)
 {
        struct mana_ib_dev *mdev =
                container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
-       struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana;
        struct ib_pd *ibpd = qp->ibqp.pd;
        struct mana_port_context *mpc;
-       struct mana_context *mc;
        struct net_device *ndev;
        struct mana_ib_pd *pd;
 
-       mc = gd->driver_data;
-       ndev = mc->ports[qp->port - 1];
+       ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port);
        mpc = netdev_priv(ndev);
        pd = container_of(ibpd, struct mana_ib_pd, ibpd);
 
@@ -546,7 +512,7 @@ static int mana_ib_destroy_qp_raw(struct mana_ib_qp *qp, struct ib_udata *udata)
                ib_umem_release(qp->sq_umem);
        }
 
-       mana_ib_uncfg_vport(mdev, pd, qp->port - 1);
+       mana_ib_uncfg_vport(mdev, pd, qp->port);
 
        return 0;
 }
index 372d361510e0ca0ea9060f5b53d1a517a72cb178..7c9c6996257344e8bb2832900aafad4a3db1ed23 100644 (file)
@@ -46,7 +46,7 @@ struct ib_wq *mana_ib_create_wq(struct ib_pd *pd,
        wq->wq_buf_size = ucmd.wq_buf_size;
        wq->rx_object = INVALID_MANA_HANDLE;
 
-       err = mana_ib_gd_create_dma_region(mdev, wq->umem, &wq->gdma_region);
+       err = mana_ib_create_zero_offset_dma_region(mdev, wq->umem, &wq->gdma_region);
        if (err) {
                ibdev_dbg(&mdev->ib_dev,
                          "Failed to create dma region for create wq, %d\n",
@@ -55,7 +55,7 @@ struct ib_wq *mana_ib_create_wq(struct ib_pd *pd,
        }
 
        ibdev_dbg(&mdev->ib_dev,
-                 "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n",
+                 "create_dma_region ret %d gdma_region 0x%llx\n",
                  err, wq->gdma_region);
 
        /* WQ ID is returned at wq_create time, doesn't know the value yet */
index bbe79b86c71789c0e18647fc881e775e752d89e5..a8de35c07c9efb47985f39bea2629e10cdb7a306 100644 (file)
@@ -1377,7 +1377,6 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u32 port,
                       struct ib_port_attr *props);
 void mlx5_ib_populate_pas(struct ib_umem *umem, size_t page_size, __be64 *pas,
                          u64 access_flags);
-void mlx5_ib_copy_pas(u64 *old, u64 *new, int step, int num);
 int mlx5_ib_get_cqe_size(struct ib_cq *ibcq);
 int mlx5_mkey_cache_init(struct mlx5_ib_dev *dev);
 void mlx5_mkey_cache_cleanup(struct mlx5_ib_dev *dev);
index 54c723a6eddacef625cccbc47184a46cb93fe9a3..ae466e72fc43b3811908cff9f92f6f94c3fb443e 100644 (file)
@@ -160,8 +160,6 @@ void rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu)
 
        port->attr.active_mtu = mtu;
        port->mtu_cap = ib_mtu_enum_to_int(mtu);
-
-       rxe_info_dev(rxe, "Set mtu to %d", port->mtu_cap);
 }
 
 /* called by ifc layer to create new rxe device.
@@ -181,7 +179,7 @@ static int rxe_newlink(const char *ibdev_name, struct net_device *ndev)
        int err = 0;
 
        if (is_vlan_dev(ndev)) {
-               rxe_err("rxe creation allowed on top of a real device only");
+               rxe_err("rxe creation allowed on top of a real device only\n");
                err = -EPERM;
                goto err;
        }
@@ -189,7 +187,7 @@ static int rxe_newlink(const char *ibdev_name, struct net_device *ndev)
        rxe = rxe_get_dev_from_net(ndev);
        if (rxe) {
                ib_device_put(&rxe->ib_dev);
-               rxe_err_dev(rxe, "already configured on %s", ndev->name);
+               rxe_err_dev(rxe, "already configured on %s\n", ndev->name);
                err = -EEXIST;
                goto err;
        }
index d33dd6cf83d377eb43bc180d8495da68b258d7e6..d8fb2c7af30a7ed3a709f045ca2a7cfbc716e202 100644 (file)
@@ -38,7 +38,7 @@
 
 #define RXE_ROCE_V2_SPORT              (0xc000)
 
-#define rxe_dbg(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define rxe_dbg(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__)
 #define rxe_dbg_dev(rxe, fmt, ...) ibdev_dbg(&(rxe)->ib_dev,           \
                "%s: " fmt, __func__, ##__VA_ARGS__)
 #define rxe_dbg_uc(uc, fmt, ...) ibdev_dbg((uc)->ibuc.device,          \
@@ -58,7 +58,7 @@
 #define rxe_dbg_mw(mw, fmt, ...) ibdev_dbg((mw)->ibmw.device,          \
                "mw#%d %s:  " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__)
 
-#define rxe_err(fmt, ...) pr_err_ratelimited("%s: " fmt "\n", __func__, \
+#define rxe_err(fmt, ...) pr_err_ratelimited("%s: " fmt, __func__, \
                                        ##__VA_ARGS__)
 #define rxe_err_dev(rxe, fmt, ...) ibdev_err_ratelimited(&(rxe)->ib_dev, \
                "%s: " fmt, __func__, ##__VA_ARGS__)
@@ -79,7 +79,7 @@
 #define rxe_err_mw(mw, fmt, ...) ibdev_err_ratelimited((mw)->ibmw.device, \
                "mw#%d %s:  " fmt, (mw)->elem.index, __func__, ##__VA_ARGS__)
 
-#define rxe_info(fmt, ...) pr_info_ratelimited("%s: " fmt "\n", __func__, \
+#define rxe_info(fmt, ...) pr_info_ratelimited("%s: " fmt, __func__, \
                                        ##__VA_ARGS__)
 #define rxe_info_dev(rxe, fmt, ...) ibdev_info_ratelimited(&(rxe)->ib_dev, \
                "%s: " fmt, __func__, ##__VA_ARGS__)
index d0bdc2d8adc82430734a9335aa54dce553728ddd..b78b8c0856abdec8555678d72b919688ec4ddca4 100644 (file)
@@ -433,7 +433,7 @@ static void make_send_cqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
                }
        } else {
                if (wqe->status != IB_WC_WR_FLUSH_ERR)
-                       rxe_err_qp(qp, "non-flush error status = %d",
+                       rxe_err_qp(qp, "non-flush error status = %d\n",
                                wqe->status);
        }
 }
@@ -582,7 +582,7 @@ static int flush_send_wqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
 
        err = rxe_cq_post(qp->scq, &cqe, 0);
        if (err)
-               rxe_dbg_cq(qp->scq, "post cq failed, err = %d", err);
+               rxe_dbg_cq(qp->scq, "post cq failed, err = %d\n", err);
 
        return err;
 }
index d5486cbb3f100404808e1e1df5b68452239292cc..fec87c9030abdc9964598320e741c316eecae92d 100644 (file)
@@ -27,7 +27,7 @@ int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
        if (cq) {
                count = queue_count(cq->queue, QUEUE_TYPE_TO_CLIENT);
                if (cqe < count) {
-                       rxe_dbg_cq(cq, "cqe(%d) < current # elements in queue (%d)",
+                       rxe_dbg_cq(cq, "cqe(%d) < current # elements in queue (%d)\n",
                                        cqe, count);
                        goto err1;
                }
@@ -96,7 +96,7 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
 
        full = queue_full(cq->queue, QUEUE_TYPE_TO_CLIENT);
        if (unlikely(full)) {
-               rxe_err_cq(cq, "queue full");
+               rxe_err_cq(cq, "queue full\n");
                spin_unlock_irqrestore(&cq->cq_lock, flags);
                if (cq->ibcq.event_handler) {
                        ev.device = cq->ibcq.device;
index 4d2a8ef52c8503ad7225adb01ca001ad369373b4..746110898a0e6198c19509d977681f0af4c64678 100644 (file)
@@ -59,7 +59,7 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 /* rxe_mr.c */
 u8 rxe_get_next_key(u32 last_key);
 void rxe_mr_init_dma(int access, struct rxe_mr *mr);
-int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova,
+int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
                     int access, struct rxe_mr *mr);
 int rxe_mr_init_fast(int max_pages, struct rxe_mr *mr);
 int rxe_flush_pmem_iova(struct rxe_mr *mr, u64 iova, unsigned int length);
index f54042e9aeb2687c781aa142d621c44e687ccc4f..da3dee520876a3ab392637416524bf2c68450421 100644 (file)
@@ -34,7 +34,7 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
        case IB_MR_TYPE_MEM_REG:
                if (iova < mr->ibmr.iova ||
                    iova + length > mr->ibmr.iova + mr->ibmr.length) {
-                       rxe_dbg_mr(mr, "iova/length out of range");
+                       rxe_dbg_mr(mr, "iova/length out of range\n");
                        return -EINVAL;
                }
                return 0;
@@ -126,7 +126,7 @@ static int rxe_mr_fill_pages_from_sgt(struct rxe_mr *mr, struct sg_table *sgt)
        return xas_error(&xas);
 }
 
-int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, u64 iova,
+int rxe_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
                     int access, struct rxe_mr *mr)
 {
        struct ib_umem *umem;
@@ -319,7 +319,7 @@ int rxe_mr_copy(struct rxe_mr *mr, u64 iova, void *addr,
 
        err = mr_check_range(mr, iova, length);
        if (unlikely(err)) {
-               rxe_dbg_mr(mr, "iova out of range");
+               rxe_dbg_mr(mr, "iova out of range\n");
                return err;
        }
 
@@ -477,7 +477,7 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
        u64 *va;
 
        if (unlikely(mr->state != RXE_MR_STATE_VALID)) {
-               rxe_dbg_mr(mr, "mr not in valid state");
+               rxe_dbg_mr(mr, "mr not in valid state\n");
                return RESPST_ERR_RKEY_VIOLATION;
        }
 
@@ -490,7 +490,7 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
 
                err = mr_check_range(mr, iova, sizeof(value));
                if (err) {
-                       rxe_dbg_mr(mr, "iova out of range");
+                       rxe_dbg_mr(mr, "iova out of range\n");
                        return RESPST_ERR_RKEY_VIOLATION;
                }
                page_offset = rxe_mr_iova_to_page_offset(mr, iova);
@@ -501,7 +501,7 @@ int rxe_mr_do_atomic_op(struct rxe_mr *mr, u64 iova, int opcode,
        }
 
        if (unlikely(page_offset & 0x7)) {
-               rxe_dbg_mr(mr, "iova not aligned");
+               rxe_dbg_mr(mr, "iova not aligned\n");
                return RESPST_ERR_MISALIGNED_ATOMIC;
        }
 
@@ -534,7 +534,7 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
 
        /* See IBA oA19-28 */
        if (unlikely(mr->state != RXE_MR_STATE_VALID)) {
-               rxe_dbg_mr(mr, "mr not in valid state");
+               rxe_dbg_mr(mr, "mr not in valid state\n");
                return RESPST_ERR_RKEY_VIOLATION;
        }
 
@@ -548,7 +548,7 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
                /* See IBA oA19-28 */
                err = mr_check_range(mr, iova, sizeof(value));
                if (unlikely(err)) {
-                       rxe_dbg_mr(mr, "iova out of range");
+                       rxe_dbg_mr(mr, "iova out of range\n");
                        return RESPST_ERR_RKEY_VIOLATION;
                }
                page_offset = rxe_mr_iova_to_page_offset(mr, iova);
@@ -560,7 +560,7 @@ int rxe_mr_do_atomic_write(struct rxe_mr *mr, u64 iova, u64 value)
 
        /* See IBA A19.4.2 */
        if (unlikely(page_offset & 0x7)) {
-               rxe_dbg_mr(mr, "misaligned address");
+               rxe_dbg_mr(mr, "misaligned address\n");
                return RESPST_ERR_MISALIGNED_ATOMIC;
        }
 
index d9312b5c9d207ea7864a6705896d6ddb26d8b969..379e65bfcd49af8f3d1389246adabe8763dad82f 100644 (file)
@@ -198,7 +198,7 @@ int rxe_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
        }
 
        if (access & ~RXE_ACCESS_SUPPORTED_MW) {
-               rxe_err_mw(mw, "access %#x not supported", access);
+               rxe_err_mw(mw, "access %#x not supported\n", access);
                ret = -EOPNOTSUPP;
                goto err_drop_mr;
        }
index 28e379c108bce0f63231a7f80d790b80e3ac83fe..e3589c02013ec5de4e183afc682d9818d707aafa 100644 (file)
@@ -201,7 +201,7 @@ static int rxe_init_sq(struct rxe_qp *qp, struct ib_qp_init_attr *init,
        qp->sq.queue = rxe_queue_init(rxe, &qp->sq.max_wr, wqe_size,
                                      QUEUE_TYPE_FROM_CLIENT);
        if (!qp->sq.queue) {
-               rxe_err_qp(qp, "Unable to allocate send queue");
+               rxe_err_qp(qp, "Unable to allocate send queue\n");
                err = -ENOMEM;
                goto err_out;
        }
@@ -211,7 +211,7 @@ static int rxe_init_sq(struct rxe_qp *qp, struct ib_qp_init_attr *init,
                           qp->sq.queue->buf, qp->sq.queue->buf_size,
                           &qp->sq.queue->ip);
        if (err) {
-               rxe_err_qp(qp, "do_mmap_info failed, err = %d", err);
+               rxe_err_qp(qp, "do_mmap_info failed, err = %d\n", err);
                goto err_free;
        }
 
@@ -292,7 +292,7 @@ static int rxe_init_rq(struct rxe_qp *qp, struct ib_qp_init_attr *init,
        qp->rq.queue = rxe_queue_init(rxe, &qp->rq.max_wr, wqe_size,
                                      QUEUE_TYPE_FROM_CLIENT);
        if (!qp->rq.queue) {
-               rxe_err_qp(qp, "Unable to allocate recv queue");
+               rxe_err_qp(qp, "Unable to allocate recv queue\n");
                err = -ENOMEM;
                goto err_out;
        }
@@ -302,7 +302,7 @@ static int rxe_init_rq(struct rxe_qp *qp, struct ib_qp_init_attr *init,
                           qp->rq.queue->buf, qp->rq.queue->buf_size,
                           &qp->rq.queue->ip);
        if (err) {
-               rxe_err_qp(qp, "do_mmap_info failed, err = %d", err);
+               rxe_err_qp(qp, "do_mmap_info failed, err = %d\n", err);
                goto err_free;
        }
 
index da470a925efc7bbbfc051e4855605ae7f4c31eb3..963382f625d7144aab89c5fcebdafe267380f922 100644 (file)
@@ -362,18 +362,18 @@ static enum resp_states rxe_resp_check_length(struct rxe_qp *qp,
                if ((pkt->mask & RXE_START_MASK) &&
                    (pkt->mask & RXE_END_MASK)) {
                        if (unlikely(payload > mtu)) {
-                               rxe_dbg_qp(qp, "only packet too long");
+                               rxe_dbg_qp(qp, "only packet too long\n");
                                return RESPST_ERR_LENGTH;
                        }
                } else if ((pkt->mask & RXE_START_MASK) ||
                           (pkt->mask & RXE_MIDDLE_MASK)) {
                        if (unlikely(payload != mtu)) {
-                               rxe_dbg_qp(qp, "first or middle packet not mtu");
+                               rxe_dbg_qp(qp, "first or middle packet not mtu\n");
                                return RESPST_ERR_LENGTH;
                        }
                } else if (pkt->mask & RXE_END_MASK) {
                        if (unlikely((payload == 0) || (payload > mtu))) {
-                               rxe_dbg_qp(qp, "last packet zero or too long");
+                               rxe_dbg_qp(qp, "last packet zero or too long\n");
                                return RESPST_ERR_LENGTH;
                        }
                }
@@ -382,7 +382,7 @@ static enum resp_states rxe_resp_check_length(struct rxe_qp *qp,
        /* See IBA C9-94 */
        if (pkt->mask & RXE_RETH_MASK) {
                if (reth_len(pkt) > (1U << 31)) {
-                       rxe_dbg_qp(qp, "dma length too long");
+                       rxe_dbg_qp(qp, "dma length too long\n");
                        return RESPST_ERR_LENGTH;
                }
        }
@@ -1133,7 +1133,7 @@ static enum resp_states do_complete(struct rxe_qp *qp,
                }
        } else {
                if (wc->status != IB_WC_WR_FLUSH_ERR)
-                       rxe_err_qp(qp, "non-flush error status = %d",
+                       rxe_err_qp(qp, "non-flush error status = %d\n",
                                wc->status);
        }
 
@@ -1442,7 +1442,7 @@ static int flush_recv_wqe(struct rxe_qp *qp, struct rxe_recv_wqe *wqe)
 
        err = rxe_cq_post(qp->rcq, &cqe, 0);
        if (err)
-               rxe_dbg_cq(qp->rcq, "post cq failed err = %d", err);
+               rxe_dbg_cq(qp->rcq, "post cq failed err = %d\n", err);
 
        return err;
 }
index 1501120d4f5241dcca89120c37cb90883811165c..80332638d9e3acf8f45f885defb20fb6c377a82b 100644 (file)
@@ -156,7 +156,7 @@ static void do_task(struct rxe_task *task)
 
                default:
                        WARN_ON(1);
-                       rxe_dbg_qp(task->qp, "unexpected task state = %d",
+                       rxe_dbg_qp(task->qp, "unexpected task state = %d\n",
                                   task->state);
                        task->state = TASK_STATE_IDLE;
                }
@@ -167,7 +167,7 @@ exit:
                        if (WARN_ON(task->num_done != task->num_sched))
                                rxe_dbg_qp(
                                        task->qp,
-                                       "%ld tasks scheduled, %ld tasks done",
+                                       "%ld tasks scheduled, %ld tasks done\n",
                                        task->num_sched, task->num_done);
                }
                spin_unlock_irqrestore(&task->lock, flags);
index 48f86839d36a8ebba67c5371f9f73d3064b04185..614581989b38160eaa5a3e49b148d6a63148e4b1 100644 (file)
@@ -23,7 +23,7 @@ static int rxe_query_device(struct ib_device *ibdev,
        int err;
 
        if (udata->inlen || udata->outlen) {
-               rxe_dbg_dev(rxe, "malformed udata");
+               rxe_dbg_dev(rxe, "malformed udata\n");
                err = -EINVAL;
                goto err_out;
        }
@@ -33,7 +33,7 @@ static int rxe_query_device(struct ib_device *ibdev,
        return 0;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -45,7 +45,7 @@ static int rxe_query_port(struct ib_device *ibdev,
 
        if (port_num != 1) {
                err = -EINVAL;
-               rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
+               rxe_dbg_dev(rxe, "bad port_num = %d\n", port_num);
                goto err_out;
        }
 
@@ -67,7 +67,7 @@ static int rxe_query_port(struct ib_device *ibdev,
        return ret;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -79,7 +79,7 @@ static int rxe_query_pkey(struct ib_device *ibdev,
 
        if (index != 0) {
                err = -EINVAL;
-               rxe_dbg_dev(rxe, "bad pkey index = %d", index);
+               rxe_dbg_dev(rxe, "bad pkey index = %d\n", index);
                goto err_out;
        }
 
@@ -87,7 +87,7 @@ static int rxe_query_pkey(struct ib_device *ibdev,
        return 0;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -100,7 +100,7 @@ static int rxe_modify_device(struct ib_device *ibdev,
        if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID |
                     IB_DEVICE_MODIFY_NODE_DESC)) {
                err = -EOPNOTSUPP;
-               rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask);
+               rxe_dbg_dev(rxe, "unsupported mask = 0x%x\n", mask);
                goto err_out;
        }
 
@@ -115,7 +115,7 @@ static int rxe_modify_device(struct ib_device *ibdev,
        return 0;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -128,14 +128,14 @@ static int rxe_modify_port(struct ib_device *ibdev, u32 port_num,
 
        if (port_num != 1) {
                err = -EINVAL;
-               rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
+               rxe_dbg_dev(rxe, "bad port_num = %d\n", port_num);
                goto err_out;
        }
 
        //TODO is shutdown useful
        if (mask & ~(IB_PORT_RESET_QKEY_CNTR)) {
                err = -EOPNOTSUPP;
-               rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask);
+               rxe_dbg_dev(rxe, "unsupported mask = 0x%x\n", mask);
                goto err_out;
        }
 
@@ -149,7 +149,7 @@ static int rxe_modify_port(struct ib_device *ibdev, u32 port_num,
        return 0;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -161,14 +161,14 @@ static enum rdma_link_layer rxe_get_link_layer(struct ib_device *ibdev,
 
        if (port_num != 1) {
                err = -EINVAL;
-               rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
+               rxe_dbg_dev(rxe, "bad port_num = %d\n", port_num);
                goto err_out;
        }
 
        return IB_LINK_LAYER_ETHERNET;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -181,7 +181,7 @@ static int rxe_port_immutable(struct ib_device *ibdev, u32 port_num,
 
        if (port_num != 1) {
                err = -EINVAL;
-               rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
+               rxe_dbg_dev(rxe, "bad port_num = %d\n", port_num);
                goto err_out;
        }
 
@@ -197,7 +197,7 @@ static int rxe_port_immutable(struct ib_device *ibdev, u32 port_num,
        return 0;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -210,7 +210,7 @@ static int rxe_alloc_ucontext(struct ib_ucontext *ibuc, struct ib_udata *udata)
 
        err = rxe_add_to_pool(&rxe->uc_pool, uc);
        if (err)
-               rxe_err_dev(rxe, "unable to create uc");
+               rxe_err_dev(rxe, "unable to create uc\n");
 
        return err;
 }
@@ -222,7 +222,7 @@ static void rxe_dealloc_ucontext(struct ib_ucontext *ibuc)
 
        err = rxe_cleanup(uc);
        if (err)
-               rxe_err_uc(uc, "cleanup failed, err = %d", err);
+               rxe_err_uc(uc, "cleanup failed, err = %d\n", err);
 }
 
 /* pd */
@@ -234,14 +234,14 @@ static int rxe_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
 
        err = rxe_add_to_pool(&rxe->pd_pool, pd);
        if (err) {
-               rxe_dbg_dev(rxe, "unable to alloc pd");
+               rxe_dbg_dev(rxe, "unable to alloc pd\n");
                goto err_out;
        }
 
        return 0;
 
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -252,7 +252,7 @@ static int rxe_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
 
        err = rxe_cleanup(pd);
        if (err)
-               rxe_err_pd(pd, "cleanup failed, err = %d", err);
+               rxe_err_pd(pd, "cleanup failed, err = %d\n", err);
 
        return 0;
 }
@@ -279,7 +279,7 @@ static int rxe_create_ah(struct ib_ah *ibah,
        err = rxe_add_to_pool_ah(&rxe->ah_pool, ah,
                        init_attr->flags & RDMA_CREATE_AH_SLEEPABLE);
        if (err) {
-               rxe_dbg_dev(rxe, "unable to create ah");
+               rxe_dbg_dev(rxe, "unable to create ah\n");
                goto err_out;
        }
 
@@ -288,7 +288,7 @@ static int rxe_create_ah(struct ib_ah *ibah,
 
        err = rxe_ah_chk_attr(ah, init_attr->ah_attr);
        if (err) {
-               rxe_dbg_ah(ah, "bad attr");
+               rxe_dbg_ah(ah, "bad attr\n");
                goto err_cleanup;
        }
 
@@ -298,7 +298,7 @@ static int rxe_create_ah(struct ib_ah *ibah,
                                         sizeof(uresp->ah_num));
                if (err) {
                        err = -EFAULT;
-                       rxe_dbg_ah(ah, "unable to copy to user");
+                       rxe_dbg_ah(ah, "unable to copy to user\n");
                        goto err_cleanup;
                }
        } else if (ah->is_user) {
@@ -314,9 +314,9 @@ static int rxe_create_ah(struct ib_ah *ibah,
 err_cleanup:
        cleanup_err = rxe_cleanup(ah);
        if (cleanup_err)
-               rxe_err_ah(ah, "cleanup failed, err = %d", cleanup_err);
+               rxe_err_ah(ah, "cleanup failed, err = %d\n", cleanup_err);
 err_out:
-       rxe_err_ah(ah, "returned err = %d", err);
+       rxe_err_ah(ah, "returned err = %d\n", err);
        return err;
 }
 
@@ -327,7 +327,7 @@ static int rxe_modify_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr)
 
        err = rxe_ah_chk_attr(ah, attr);
        if (err) {
-               rxe_dbg_ah(ah, "bad attr");
+               rxe_dbg_ah(ah, "bad attr\n");
                goto err_out;
        }
 
@@ -336,7 +336,7 @@ static int rxe_modify_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr)
        return 0;
 
 err_out:
-       rxe_err_ah(ah, "returned err = %d", err);
+       rxe_err_ah(ah, "returned err = %d\n", err);
        return err;
 }
 
@@ -358,7 +358,7 @@ static int rxe_destroy_ah(struct ib_ah *ibah, u32 flags)
 
        err = rxe_cleanup_ah(ah, flags & RDMA_DESTROY_AH_SLEEPABLE);
        if (err)
-               rxe_err_ah(ah, "cleanup failed, err = %d", err);
+               rxe_err_ah(ah, "cleanup failed, err = %d\n", err);
 
        return 0;
 }
@@ -376,7 +376,7 @@ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
        if (udata) {
                if (udata->outlen < sizeof(*uresp)) {
                        err = -EINVAL;
-                       rxe_err_dev(rxe, "malformed udata");
+                       rxe_err_dev(rxe, "malformed udata\n");
                        goto err_out;
                }
                uresp = udata->outbuf;
@@ -384,20 +384,20 @@ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
 
        if (init->srq_type != IB_SRQT_BASIC) {
                err = -EOPNOTSUPP;
-               rxe_dbg_dev(rxe, "srq type = %d, not supported",
+               rxe_dbg_dev(rxe, "srq type = %d, not supported\n",
                                init->srq_type);
                goto err_out;
        }
 
        err = rxe_srq_chk_init(rxe, init);
        if (err) {
-               rxe_dbg_dev(rxe, "invalid init attributes");
+               rxe_dbg_dev(rxe, "invalid init attributes\n");
                goto err_out;
        }
 
        err = rxe_add_to_pool(&rxe->srq_pool, srq);
        if (err) {
-               rxe_dbg_dev(rxe, "unable to create srq, err = %d", err);
+               rxe_dbg_dev(rxe, "unable to create srq, err = %d\n", err);
                goto err_out;
        }
 
@@ -406,7 +406,7 @@ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
 
        err = rxe_srq_from_init(rxe, srq, init, udata, uresp);
        if (err) {
-               rxe_dbg_srq(srq, "create srq failed, err = %d", err);
+               rxe_dbg_srq(srq, "create srq failed, err = %d\n", err);
                goto err_cleanup;
        }
 
@@ -415,9 +415,9 @@ static int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
 err_cleanup:
        cleanup_err = rxe_cleanup(srq);
        if (cleanup_err)
-               rxe_err_srq(srq, "cleanup failed, err = %d", cleanup_err);
+               rxe_err_srq(srq, "cleanup failed, err = %d\n", cleanup_err);
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -433,34 +433,34 @@ static int rxe_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
        if (udata) {
                if (udata->inlen < sizeof(cmd)) {
                        err = -EINVAL;
-                       rxe_dbg_srq(srq, "malformed udata");
+                       rxe_dbg_srq(srq, "malformed udata\n");
                        goto err_out;
                }
 
                err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
                if (err) {
                        err = -EFAULT;
-                       rxe_dbg_srq(srq, "unable to read udata");
+                       rxe_dbg_srq(srq, "unable to read udata\n");
                        goto err_out;
                }
        }
 
        err = rxe_srq_chk_attr(rxe, srq, attr, mask);
        if (err) {
-               rxe_dbg_srq(srq, "bad init attributes");
+               rxe_dbg_srq(srq, "bad init attributes\n");
                goto err_out;
        }
 
        err = rxe_srq_from_attr(rxe, srq, attr, mask, &cmd, udata);
        if (err) {
-               rxe_dbg_srq(srq, "bad attr");
+               rxe_dbg_srq(srq, "bad attr\n");
                goto err_out;
        }
 
        return 0;
 
 err_out:
-       rxe_err_srq(srq, "returned err = %d", err);
+       rxe_err_srq(srq, "returned err = %d\n", err);
        return err;
 }
 
@@ -471,7 +471,7 @@ static int rxe_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
 
        if (srq->error) {
                err = -EINVAL;
-               rxe_dbg_srq(srq, "srq in error state");
+               rxe_dbg_srq(srq, "srq in error state\n");
                goto err_out;
        }
 
@@ -481,7 +481,7 @@ static int rxe_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
        return 0;
 
 err_out:
-       rxe_err_srq(srq, "returned err = %d", err);
+       rxe_err_srq(srq, "returned err = %d\n", err);
        return err;
 }
 
@@ -505,7 +505,7 @@ static int rxe_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
 
        if (err) {
                *bad_wr = wr;
-               rxe_err_srq(srq, "returned err = %d", err);
+               rxe_err_srq(srq, "returned err = %d\n", err);
        }
 
        return err;
@@ -518,7 +518,7 @@ static int rxe_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
 
        err = rxe_cleanup(srq);
        if (err)
-               rxe_err_srq(srq, "cleanup failed, err = %d", err);
+               rxe_err_srq(srq, "cleanup failed, err = %d\n", err);
 
        return 0;
 }
@@ -536,13 +536,13 @@ static int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init,
        if (udata) {
                if (udata->inlen) {
                        err = -EINVAL;
-                       rxe_dbg_dev(rxe, "malformed udata, err = %d", err);
+                       rxe_dbg_dev(rxe, "malformed udata, err = %d\n", err);
                        goto err_out;
                }
 
                if (udata->outlen < sizeof(*uresp)) {
                        err = -EINVAL;
-                       rxe_dbg_dev(rxe, "malformed udata, err = %d", err);
+                       rxe_dbg_dev(rxe, "malformed udata, err = %d\n", err);
                        goto err_out;
                }
 
@@ -554,25 +554,25 @@ static int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init,
 
        if (init->create_flags) {
                err = -EOPNOTSUPP;
-               rxe_dbg_dev(rxe, "unsupported create_flags, err = %d", err);
+               rxe_dbg_dev(rxe, "unsupported create_flags, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_qp_chk_init(rxe, init);
        if (err) {
-               rxe_dbg_dev(rxe, "bad init attr, err = %d", err);
+               rxe_dbg_dev(rxe, "bad init attr, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_add_to_pool(&rxe->qp_pool, qp);
        if (err) {
-               rxe_dbg_dev(rxe, "unable to create qp, err = %d", err);
+               rxe_dbg_dev(rxe, "unable to create qp, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_qp_from_init(rxe, qp, pd, init, uresp, ibqp->pd, udata);
        if (err) {
-               rxe_dbg_qp(qp, "create qp failed, err = %d", err);
+               rxe_dbg_qp(qp, "create qp failed, err = %d\n", err);
                goto err_cleanup;
        }
 
@@ -582,9 +582,9 @@ static int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init,
 err_cleanup:
        cleanup_err = rxe_cleanup(qp);
        if (cleanup_err)
-               rxe_err_qp(qp, "cleanup failed, err = %d", cleanup_err);
+               rxe_err_qp(qp, "cleanup failed, err = %d\n", cleanup_err);
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -597,20 +597,20 @@ static int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 
        if (mask & ~IB_QP_ATTR_STANDARD_BITS) {
                err = -EOPNOTSUPP;
-               rxe_dbg_qp(qp, "unsupported mask = 0x%x, err = %d",
+               rxe_dbg_qp(qp, "unsupported mask = 0x%x, err = %d\n",
                           mask, err);
                goto err_out;
        }
 
        err = rxe_qp_chk_attr(rxe, qp, attr, mask);
        if (err) {
-               rxe_dbg_qp(qp, "bad mask/attr, err = %d", err);
+               rxe_dbg_qp(qp, "bad mask/attr, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_qp_from_attr(qp, attr, mask, udata);
        if (err) {
-               rxe_dbg_qp(qp, "modify qp failed, err = %d", err);
+               rxe_dbg_qp(qp, "modify qp failed, err = %d\n", err);
                goto err_out;
        }
 
@@ -622,7 +622,7 @@ static int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        return 0;
 
 err_out:
-       rxe_err_qp(qp, "returned err = %d", err);
+       rxe_err_qp(qp, "returned err = %d\n", err);
        return err;
 }
 
@@ -644,18 +644,18 @@ static int rxe_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
 
        err = rxe_qp_chk_destroy(qp);
        if (err) {
-               rxe_dbg_qp(qp, "unable to destroy qp, err = %d", err);
+               rxe_dbg_qp(qp, "unable to destroy qp, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_cleanup(qp);
        if (err)
-               rxe_err_qp(qp, "cleanup failed, err = %d", err);
+               rxe_err_qp(qp, "cleanup failed, err = %d\n", err);
 
        return 0;
 
 err_out:
-       rxe_err_qp(qp, "returned err = %d", err);
+       rxe_err_qp(qp, "returned err = %d\n", err);
        return err;
 }
 
@@ -675,12 +675,12 @@ static int validate_send_wr(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
        do {
                mask = wr_opcode_mask(ibwr->opcode, qp);
                if (!mask) {
-                       rxe_err_qp(qp, "bad wr opcode for qp type");
+                       rxe_err_qp(qp, "bad wr opcode for qp type\n");
                        break;
                }
 
                if (num_sge > sq->max_sge) {
-                       rxe_err_qp(qp, "num_sge > max_sge");
+                       rxe_err_qp(qp, "num_sge > max_sge\n");
                        break;
                }
 
@@ -689,27 +689,27 @@ static int validate_send_wr(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
                        length += ibwr->sg_list[i].length;
 
                if (length > (1UL << 31)) {
-                       rxe_err_qp(qp, "message length too long");
+                       rxe_err_qp(qp, "message length too long\n");
                        break;
                }
 
                if (mask & WR_ATOMIC_MASK) {
                        if (length != 8) {
-                               rxe_err_qp(qp, "atomic length != 8");
+                               rxe_err_qp(qp, "atomic length != 8\n");
                                break;
                        }
                        if (atomic_wr(ibwr)->remote_addr & 0x7) {
-                               rxe_err_qp(qp, "misaligned atomic address");
+                               rxe_err_qp(qp, "misaligned atomic address\n");
                                break;
                        }
                }
                if (ibwr->send_flags & IB_SEND_INLINE) {
                        if (!(mask & WR_INLINE_MASK)) {
-                               rxe_err_qp(qp, "opcode doesn't support inline data");
+                               rxe_err_qp(qp, "opcode doesn't support inline data\n");
                                break;
                        }
                        if (length > sq->max_inline) {
-                               rxe_err_qp(qp, "inline length too big");
+                               rxe_err_qp(qp, "inline length too big\n");
                                break;
                        }
                }
@@ -747,7 +747,7 @@ static int init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr,
                case IB_WR_SEND:
                        break;
                default:
-                       rxe_err_qp(qp, "bad wr opcode %d for UD/GSI QP",
+                       rxe_err_qp(qp, "bad wr opcode %d for UD/GSI QP\n",
                                        wr->opcode);
                        return -EINVAL;
                }
@@ -795,7 +795,7 @@ static int init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr,
                case IB_WR_ATOMIC_WRITE:
                        break;
                default:
-                       rxe_err_qp(qp, "unsupported wr opcode %d",
+                       rxe_err_qp(qp, "unsupported wr opcode %d\n",
                                        wr->opcode);
                        return -EINVAL;
                }
@@ -870,7 +870,7 @@ static int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr)
 
        full = queue_full(sq->queue, QUEUE_TYPE_FROM_ULP);
        if (unlikely(full)) {
-               rxe_err_qp(qp, "send queue full");
+               rxe_err_qp(qp, "send queue full\n");
                return -ENOMEM;
        }
 
@@ -922,14 +922,14 @@ static int rxe_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
        /* caller has already called destroy_qp */
        if (WARN_ON_ONCE(!qp->valid)) {
                spin_unlock_irqrestore(&qp->state_lock, flags);
-               rxe_err_qp(qp, "qp has been destroyed");
+               rxe_err_qp(qp, "qp has been destroyed\n");
                return -EINVAL;
        }
 
        if (unlikely(qp_state(qp) < IB_QPS_RTS)) {
                spin_unlock_irqrestore(&qp->state_lock, flags);
                *bad_wr = wr;
-               rxe_err_qp(qp, "qp not ready to send");
+               rxe_err_qp(qp, "qp not ready to send\n");
                return -EINVAL;
        }
        spin_unlock_irqrestore(&qp->state_lock, flags);
@@ -959,13 +959,13 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
        full = queue_full(rq->queue, QUEUE_TYPE_FROM_ULP);
        if (unlikely(full)) {
                err = -ENOMEM;
-               rxe_dbg("queue full");
+               rxe_dbg("queue full\n");
                goto err_out;
        }
 
        if (unlikely(num_sge > rq->max_sge)) {
                err = -EINVAL;
-               rxe_dbg("bad num_sge > max_sge");
+               rxe_dbg("bad num_sge > max_sge\n");
                goto err_out;
        }
 
@@ -976,7 +976,7 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
        /* IBA max message size is 2^31 */
        if (length >= (1UL<<31)) {
                err = -EINVAL;
-               rxe_dbg("message length too long");
+               rxe_dbg("message length too long\n");
                goto err_out;
        }
 
@@ -996,7 +996,7 @@ static int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
        return 0;
 
 err_out:
-       rxe_dbg("returned err = %d", err);
+       rxe_dbg("returned err = %d\n", err);
        return err;
 }
 
@@ -1012,7 +1012,7 @@ static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
        /* caller has already called destroy_qp */
        if (WARN_ON_ONCE(!qp->valid)) {
                spin_unlock_irqrestore(&qp->state_lock, flags);
-               rxe_err_qp(qp, "qp has been destroyed");
+               rxe_err_qp(qp, "qp has been destroyed\n");
                return -EINVAL;
        }
 
@@ -1020,14 +1020,14 @@ static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
        if (unlikely((qp_state(qp) < IB_QPS_INIT))) {
                spin_unlock_irqrestore(&qp->state_lock, flags);
                *bad_wr = wr;
-               rxe_dbg_qp(qp, "qp not ready to post recv");
+               rxe_dbg_qp(qp, "qp not ready to post recv\n");
                return -EINVAL;
        }
        spin_unlock_irqrestore(&qp->state_lock, flags);
 
        if (unlikely(qp->srq)) {
                *bad_wr = wr;
-               rxe_dbg_qp(qp, "qp has srq, use post_srq_recv instead");
+               rxe_dbg_qp(qp, "qp has srq, use post_srq_recv instead\n");
                return -EINVAL;
        }
 
@@ -1065,7 +1065,7 @@ static int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
        if (udata) {
                if (udata->outlen < sizeof(*uresp)) {
                        err = -EINVAL;
-                       rxe_dbg_dev(rxe, "malformed udata, err = %d", err);
+                       rxe_dbg_dev(rxe, "malformed udata, err = %d\n", err);
                        goto err_out;
                }
                uresp = udata->outbuf;
@@ -1073,26 +1073,26 @@ static int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
 
        if (attr->flags) {
                err = -EOPNOTSUPP;
-               rxe_dbg_dev(rxe, "bad attr->flags, err = %d", err);
+               rxe_dbg_dev(rxe, "bad attr->flags, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_cq_chk_attr(rxe, NULL, attr->cqe, attr->comp_vector);
        if (err) {
-               rxe_dbg_dev(rxe, "bad init attributes, err = %d", err);
+               rxe_dbg_dev(rxe, "bad init attributes, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_add_to_pool(&rxe->cq_pool, cq);
        if (err) {
-               rxe_dbg_dev(rxe, "unable to create cq, err = %d", err);
+               rxe_dbg_dev(rxe, "unable to create cq, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_cq_from_init(rxe, cq, attr->cqe, attr->comp_vector, udata,
                               uresp);
        if (err) {
-               rxe_dbg_cq(cq, "create cq failed, err = %d", err);
+               rxe_dbg_cq(cq, "create cq failed, err = %d\n", err);
                goto err_cleanup;
        }
 
@@ -1101,9 +1101,9 @@ static int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
 err_cleanup:
        cleanup_err = rxe_cleanup(cq);
        if (cleanup_err)
-               rxe_err_cq(cq, "cleanup failed, err = %d", cleanup_err);
+               rxe_err_cq(cq, "cleanup failed, err = %d\n", cleanup_err);
 err_out:
-       rxe_err_dev(rxe, "returned err = %d", err);
+       rxe_err_dev(rxe, "returned err = %d\n", err);
        return err;
 }
 
@@ -1117,7 +1117,7 @@ static int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
        if (udata) {
                if (udata->outlen < sizeof(*uresp)) {
                        err = -EINVAL;
-                       rxe_dbg_cq(cq, "malformed udata");
+                       rxe_dbg_cq(cq, "malformed udata\n");
                        goto err_out;
                }
                uresp = udata->outbuf;
@@ -1125,20 +1125,20 @@ static int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
 
        err = rxe_cq_chk_attr(rxe, cq, cqe, 0);
        if (err) {
-               rxe_dbg_cq(cq, "bad attr, err = %d", err);
+               rxe_dbg_cq(cq, "bad attr, err = %d\n", err);
                goto err_out;
        }
 
        err = rxe_cq_resize_queue(cq, cqe, uresp, udata);
        if (err) {
-               rxe_dbg_cq(cq, "resize cq failed, err = %d", err);
+               rxe_dbg_cq(cq, "resize cq failed, err = %d\n", err);
                goto err_out;
        }
 
        return 0;
 
 err_out:
-       rxe_err_cq(cq, "returned err = %d", err);
+       rxe_err_cq(cq, "returned err = %d\n", err);
        return err;
 }
 
@@ -1202,18 +1202,18 @@ static int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
         */
        if (atomic_read(&cq->num_wq)) {
                err = -EINVAL;
-               rxe_dbg_cq(cq, "still in use");
+               rxe_dbg_cq(cq, "still in use\n");
                goto err_out;
        }
 
        err = rxe_cleanup(cq);
        if (err)
-               rxe_err_cq(cq, "cleanup failed, err = %d", err);
+               rxe_err_cq(cq, "cleanup failed, err = %d\n", err);
 
        return 0;
 
 err_out:
-       rxe_err_cq(cq, "returned err = %d", err);
+       rxe_err_cq(cq, "returned err = %d\n", err);
        return err;
 }
 
@@ -1231,7 +1231,7 @@ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access)
 
        err = rxe_add_to_pool(&rxe->mr_pool, mr);
        if (err) {
-               rxe_dbg_dev(rxe, "unable to create mr");
+               rxe_dbg_dev(rxe, "unable to create mr\n");
                goto err_free;
        }
 
@@ -1245,7 +1245,7 @@ static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access)
 
 err_free:
        kfree(mr);
-       rxe_err_pd(pd, "returned err = %d", err);
+       rxe_err_pd(pd, "returned err = %d\n", err);
        return ERR_PTR(err);
 }
 
@@ -1259,7 +1259,7 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start,
        int err, cleanup_err;
 
        if (access & ~RXE_ACCESS_SUPPORTED_MR) {
-               rxe_err_pd(pd, "access = %#x not supported (%#x)", access,
+               rxe_err_pd(pd, "access = %#x not supported (%#x)\n", access,
                                RXE_ACCESS_SUPPORTED_MR);
                return ERR_PTR(-EOPNOTSUPP);
        }
@@ -1270,7 +1270,7 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start,
 
        err = rxe_add_to_pool(&rxe->mr_pool, mr);
        if (err) {
-               rxe_dbg_pd(pd, "unable to create mr");
+               rxe_dbg_pd(pd, "unable to create mr\n");
                goto err_free;
        }
 
@@ -1278,9 +1278,9 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start,
        mr->ibmr.pd = ibpd;
        mr->ibmr.device = ibpd->device;
 
-       err = rxe_mr_init_user(rxe, start, length, iova, access, mr);
+       err = rxe_mr_init_user(rxe, start, length, access, mr);
        if (err) {
-               rxe_dbg_mr(mr, "reg_user_mr failed, err = %d", err);
+               rxe_dbg_mr(mr, "reg_user_mr failed, err = %d\n", err);
                goto err_cleanup;
        }
 
@@ -1290,10 +1290,10 @@ static struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start,
 err_cleanup:
        cleanup_err = rxe_cleanup(mr);
        if (cleanup_err)
-               rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err);
+               rxe_err_mr(mr, "cleanup failed, err = %d\n", cleanup_err);
 err_free:
        kfree(mr);
-       rxe_err_pd(pd, "returned err = %d", err);
+       rxe_err_pd(pd, "returned err = %d\n", err);
        return ERR_PTR(err);
 }
 
@@ -1310,7 +1310,7 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
         * rereg_pd and rereg_access
         */
        if (flags & ~RXE_MR_REREG_SUPPORTED) {
-               rxe_err_mr(mr, "flags = %#x not supported", flags);
+               rxe_err_mr(mr, "flags = %#x not supported\n", flags);
                return ERR_PTR(-EOPNOTSUPP);
        }
 
@@ -1322,7 +1322,7 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
 
        if (flags & IB_MR_REREG_ACCESS) {
                if (access & ~RXE_ACCESS_SUPPORTED_MR) {
-                       rxe_err_mr(mr, "access = %#x not supported", access);
+                       rxe_err_mr(mr, "access = %#x not supported\n", access);
                        return ERR_PTR(-EOPNOTSUPP);
                }
                mr->access = access;
@@ -1341,7 +1341,7 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
 
        if (mr_type != IB_MR_TYPE_MEM_REG) {
                err = -EINVAL;
-               rxe_dbg_pd(pd, "mr type %d not supported, err = %d",
+               rxe_dbg_pd(pd, "mr type %d not supported, err = %d\n",
                           mr_type, err);
                goto err_out;
        }
@@ -1360,7 +1360,7 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
 
        err = rxe_mr_init_fast(max_num_sg, mr);
        if (err) {
-               rxe_dbg_mr(mr, "alloc_mr failed, err = %d", err);
+               rxe_dbg_mr(mr, "alloc_mr failed, err = %d\n", err);
                goto err_cleanup;
        }
 
@@ -1370,11 +1370,11 @@ static struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
 err_cleanup:
        cleanup_err = rxe_cleanup(mr);
        if (cleanup_err)
-               rxe_err_mr(mr, "cleanup failed, err = %d", err);
+               rxe_err_mr(mr, "cleanup failed, err = %d\n", err);
 err_free:
        kfree(mr);
 err_out:
-       rxe_err_pd(pd, "returned err = %d", err);
+       rxe_err_pd(pd, "returned err = %d\n", err);
        return ERR_PTR(err);
 }
 
@@ -1386,19 +1386,19 @@ static int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
        /* See IBA 10.6.7.2.6 */
        if (atomic_read(&mr->num_mw) > 0) {
                err = -EINVAL;
-               rxe_dbg_mr(mr, "mr has mw's bound");
+               rxe_dbg_mr(mr, "mr has mw's bound\n");
                goto err_out;
        }
 
        cleanup_err = rxe_cleanup(mr);
        if (cleanup_err)
-               rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err);
+               rxe_err_mr(mr, "cleanup failed, err = %d\n", cleanup_err);
 
        kfree_rcu_mightsleep(mr);
        return 0;
 
 err_out:
-       rxe_err_mr(mr, "returned err = %d", err);
+       rxe_err_mr(mr, "returned err = %d\n", err);
        return err;
 }
 
index 319d4288edddeaca2fb273fa7e1b211ed8619beb..8a4ab9ff0a68109e9a761b573259aa02b7c46b03 100644 (file)
@@ -287,8 +287,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
 
        ah = ipoib_create_ah(dev, priv->pd, &av);
        if (IS_ERR(ah)) {
-               ipoib_warn(priv, "ib_address_create failed %ld\n",
-                          -PTR_ERR(ah));
+               ipoib_warn(priv, "ib_address_create failed %pe\n", ah);
                /* use original error */
                return PTR_ERR(ah);
        }
index d3c436ead69461a9965afd7590f3551dba2c624d..4aa80c9388f058b745fca05b86f532d6a2b3339a 100644 (file)
@@ -133,7 +133,7 @@ static ssize_t mpath_policy_store(struct device *dev,
 
        /* distinguish "mi" and "min-latency" with length */
        len = strnlen(buf, NAME_MAX);
-       if (buf[len - 1] == '\n')
+       if (len && buf[len - 1] == '\n')
                len--;
 
        if (!strncasecmp(buf, "round-robin", 11) ||
index 040234c01be4d5a0cc6fb4a4124af4752f58e181..9632afbd727b64b0ddf0072ab8ce692588ad9803 100644 (file)
@@ -3209,7 +3209,6 @@ static int srpt_add_one(struct ib_device *device)
 
        INIT_IB_EVENT_HANDLER(&sdev->event_handler, sdev->device,
                              srpt_event_handler);
-       ib_register_event_handler(&sdev->event_handler);
 
        for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
                sport = &sdev->port[i - 1];
@@ -3232,6 +3231,7 @@ static int srpt_add_one(struct ib_device *device)
                }
        }
 
+       ib_register_event_handler(&sdev->event_handler);
        spin_lock(&srpt_dev_lock);
        list_add_tail(&sdev->list, &srpt_dev_list);
        spin_unlock(&srpt_dev_lock);
@@ -3242,7 +3242,6 @@ static int srpt_add_one(struct ib_device *device)
 
 err_port:
        srpt_unregister_mad_agent(sdev, i);
-       ib_unregister_event_handler(&sdev->event_handler);
 err_cm:
        if (sdev->cm_id)
                ib_destroy_cm_id(sdev->cm_id);
index e305c44cd0aa9045f4c62f2d3a42db05552ef224..ecfae0b0b6aa2457ae65b55dd40ef4372a6c73bb 100644 (file)
@@ -26,7 +26,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Amiga keyboard driver");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_HW_CONSOLE
+#ifdef CONFIG_VT
 static unsigned char amikbd_keycode[0x78] __initdata = {
        [0]      = KEY_GRAVE,
        [1]      = KEY_1,
@@ -148,9 +148,9 @@ static void __init amikbd_init_console_keymaps(void)
                memcpy(key_maps[i], temp_map, sizeof(temp_map));
        }
 }
-#else /* !CONFIG_HW_CONSOLE */
+#else /* !CONFIG_VT */
 static inline void amikbd_init_console_keymaps(void) {}
-#endif /* !CONFIG_HW_CONSOLE */
+#endif /* !CONFIG_VT */
 
 static const char *amikbd_messages[8] = {
        [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
index 50bac2d79d9b5e4bea6cf76a8ffa32658ebb70ad..5d1010cafed8d3a3b65349dd58a0741d445ffcd7 100644 (file)
@@ -343,7 +343,7 @@ EXPORT_SYMBOL_GPL(icc_std_aggregate);
  * an array of icc nodes specified in the icc_onecell_data struct when
  * registering the provider.
  */
-struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec,
+struct icc_node *of_icc_xlate_onecell(const struct of_phandle_args *spec,
                                      void *data)
 {
        struct icc_onecell_data *icc_data = data;
@@ -368,7 +368,7 @@ EXPORT_SYMBOL_GPL(of_icc_xlate_onecell);
  * Returns a valid pointer to struct icc_node_data on success or ERR_PTR()
  * on failure.
  */
-struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec)
+struct icc_node_data *of_icc_get_from_provider(const struct of_phandle_args *spec)
 {
        struct icc_node *node = ERR_PTR(-EPROBE_DEFER);
        struct icc_node_data *data = NULL;
index 697f96c49f6f4b181c0a43cef3364790b0f5aa2b..1446a839184e17f3cdb3774dc8ef539cbcb0101a 100644 (file)
@@ -8,6 +8,15 @@ config INTERCONNECT_QCOM
 config INTERCONNECT_QCOM_BCM_VOTER
        tristate
 
+config INTERCONNECT_QCOM_MSM8909
+       tristate "Qualcomm MSM8909 interconnect driver"
+       depends on INTERCONNECT_QCOM
+       depends on QCOM_SMD_RPM
+       select INTERCONNECT_QCOM_SMD_RPM
+       help
+         This is a driver for the Qualcomm Network-on-Chip on msm8909-based
+         platforms.
+
 config INTERCONNECT_QCOM_MSM8916
        tristate "Qualcomm MSM8916 interconnect driver"
        depends on INTERCONNECT_QCOM
@@ -209,6 +218,15 @@ config INTERCONNECT_QCOM_SM6350
          This is a driver for the Qualcomm Network-on-Chip on sm6350-based
          platforms.
 
+config INTERCONNECT_QCOM_SM7150
+       tristate "Qualcomm SM7150 interconnect driver"
+       depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+       select INTERCONNECT_QCOM_RPMH
+       select INTERCONNECT_QCOM_BCM_VOTER
+       help
+         This is a driver for the Qualcomm Network-on-Chip on sm7150-based
+         platforms.
+
 config INTERCONNECT_QCOM_SM8150
        tristate "Qualcomm SM8150 interconnect driver"
        depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
index 7048461650221934f186e537010b12ecc061a95d..2ea3113d0a4d5eb4e2722006372457db50d073bd 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o
 
 interconnect_qcom-y                    := icc-common.o
 icc-bcm-voter-objs                     := bcm-voter.o
+qnoc-msm8909-objs                      := msm8909.o
 qnoc-msm8916-objs                      := msm8916.o
 qnoc-msm8939-objs                      := msm8939.o
 qnoc-msm8974-objs                      := msm8974.o
@@ -26,6 +27,7 @@ qnoc-sdx65-objs                               := sdx65.o
 qnoc-sdx75-objs                                := sdx75.o
 qnoc-sm6115-objs                       := sm6115.o
 qnoc-sm6350-objs                       := sm6350.o
+qnoc-sm7150-objs                       := sm7150.o
 qnoc-sm8150-objs                       := sm8150.o
 qnoc-sm8250-objs                       := sm8250.o
 qnoc-sm8350-objs                       := sm8350.o
@@ -36,6 +38,7 @@ qnoc-x1e80100-objs                    := x1e80100.o
 icc-smd-rpm-objs                       := smd-rpm.o icc-rpm.o icc-rpm-clocks.o
 
 obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
 obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
@@ -58,6 +61,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM6115) += qnoc-sm6115.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SM7150) += qnoc-sm7150.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o
 obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o
index f27f4fdc453170fc60bb4cedea2d0004b7dad9f7..9b9ee113f1727fb0aca0c60a350656d161ee4358 100644 (file)
@@ -9,7 +9,8 @@
 
 #include "icc-common.h"
 
-struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec,
+                                             void *data)
 {
        struct icc_node_data *ndata;
        struct icc_node *node;
index 33bb2c38dff339fd6ac1cde49b203abc1da036dd..21c39b1639486b144df856adfb2a4141a53f919b 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/interconnect-provider.h>
 
-struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data);
+struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec,
+                                             void *data);
 
 #endif
diff --git a/drivers/interconnect/qcom/msm8909.c b/drivers/interconnect/qcom/msm8909.c
new file mode 100644 (file)
index 0000000..0d0cd72
--- /dev/null
@@ -0,0 +1,1329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Based on data from msm8909-bus.dtsi in Qualcomm's msm-3.18 release:
+ *   Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/interconnect/qcom,msm8909.h>
+
+#include "icc-rpm.h"
+
+enum {
+       QNOC_MASTER_AMPSS_M0 = 1,
+       QNOC_MASTER_GRAPHICS_3D,
+       QNOC_SNOC_BIMC_0_MAS,
+       QNOC_SNOC_BIMC_1_MAS,
+       QNOC_MASTER_TCU_0,
+       QNOC_MASTER_TCU_1,
+       QNOC_MASTER_AUDIO,
+       QNOC_MASTER_SPDM,
+       QNOC_MASTER_DEHR,
+       QNOC_MASTER_QPIC,
+       QNOC_MASTER_BLSP_1,
+       QNOC_MASTER_USB_HS,
+       QNOC_MASTER_CRYPTO_CORE0,
+       QNOC_MASTER_SDCC_1,
+       QNOC_MASTER_SDCC_2,
+       QNOC_SNOC_PNOC_MAS,
+       QNOC_MASTER_QDSS_BAM,
+       QNOC_BIMC_SNOC_MAS,
+       QNOC_MASTER_MDP_PORT0,
+       QNOC_PNOC_SNOC_MAS,
+       QNOC_MASTER_VIDEO_P0,
+       QNOC_MASTER_VFE,
+       QNOC_MASTER_QDSS_ETR,
+       QNOC_PNOC_M_0,
+       QNOC_PNOC_M_1,
+       QNOC_PNOC_INT_0,
+       QNOC_PNOC_INT_1,
+       QNOC_PNOC_SLV_0,
+       QNOC_PNOC_SLV_1,
+       QNOC_PNOC_SLV_2,
+       QNOC_PNOC_SLV_3,
+       QNOC_PNOC_SLV_4,
+       QNOC_PNOC_SLV_5,
+       QNOC_PNOC_SLV_7,
+       QNOC_SNOC_MM_INT_0,
+       QNOC_SNOC_MM_INT_1,
+       QNOC_SNOC_MM_INT_2,
+       QNOC_SNOC_MM_INT_BIMC,
+       QNOC_SNOC_QDSS_INT,
+       QNOC_SNOC_INT_0,
+       QNOC_SNOC_INT_1,
+       QNOC_SNOC_INT_BIMC,
+       QNOC_SLAVE_EBI_CH0,
+       QNOC_BIMC_SNOC_SLV,
+       QNOC_SLAVE_TCSR,
+       QNOC_SLAVE_SDCC_1,
+       QNOC_SLAVE_BLSP_1,
+       QNOC_SLAVE_CRYPTO_0_CFG,
+       QNOC_SLAVE_MESSAGE_RAM,
+       QNOC_SLAVE_PDM,
+       QNOC_SLAVE_PRNG,
+       QNOC_SLAVE_USB_HS,
+       QNOC_SLAVE_QPIC,
+       QNOC_SLAVE_SPDM,
+       QNOC_SLAVE_SDCC_2,
+       QNOC_SLAVE_AUDIO,
+       QNOC_SLAVE_DEHR_CFG,
+       QNOC_SLAVE_SNOC_CFG,
+       QNOC_SLAVE_QDSS_CFG,
+       QNOC_SLAVE_USB_PHYS_CFG,
+       QNOC_SLAVE_CAMERA_CFG,
+       QNOC_SLAVE_DISPLAY_CFG,
+       QNOC_SLAVE_VENUS_CFG,
+       QNOC_SLAVE_TLMM,
+       QNOC_SLAVE_GRAPHICS_3D_CFG,
+       QNOC_SLAVE_IMEM_CFG,
+       QNOC_SLAVE_BIMC_CFG,
+       QNOC_SLAVE_PMIC_ARB,
+       QNOC_SLAVE_TCU,
+       QNOC_PNOC_SNOC_SLV,
+       QNOC_SLAVE_APPSS,
+       QNOC_SNOC_BIMC_0_SLV,
+       QNOC_SNOC_BIMC_1_SLV,
+       QNOC_SLAVE_SYSTEM_IMEM,
+       QNOC_SNOC_PNOC_SLV,
+       QNOC_SLAVE_QDSS_STM,
+       QNOC_SLAVE_CATS_128,
+       QNOC_SLAVE_OCMEM_64,
+};
+
+static const u16 mas_apps_proc_links[] = {
+       QNOC_BIMC_SNOC_SLV,
+       QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_apps_proc = {
+       .name = "mas_apps_proc",
+       .id = QNOC_MASTER_AMPSS_M0,
+       .buswidth = 8,
+       .mas_rpm_id = 0,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 0,
+       .num_links = ARRAY_SIZE(mas_apps_proc_links),
+       .links = mas_apps_proc_links,
+};
+
+static const u16 mas_oxili_links[] = {
+       QNOC_BIMC_SNOC_SLV,
+       QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_oxili = {
+       .name = "mas_oxili",
+       .id = QNOC_MASTER_GRAPHICS_3D,
+       .buswidth = 8,
+       .mas_rpm_id = 6,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 2,
+       .num_links = ARRAY_SIZE(mas_oxili_links),
+       .links = mas_oxili_links,
+};
+
+static const u16 mas_snoc_bimc_0_links[] = {
+       QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_snoc_bimc_0 = {
+       .name = "mas_snoc_bimc_0",
+       .id = QNOC_SNOC_BIMC_0_MAS,
+       .buswidth = 8,
+       .mas_rpm_id = 3,
+       .slv_rpm_id = -1,
+       .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 3,
+       .num_links = ARRAY_SIZE(mas_snoc_bimc_0_links),
+       .links = mas_snoc_bimc_0_links,
+};
+
+static const u16 mas_snoc_bimc_1_links[] = {
+       QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_snoc_bimc_1 = {
+       .name = "mas_snoc_bimc_1",
+       .id = QNOC_SNOC_BIMC_1_MAS,
+       .buswidth = 8,
+       .mas_rpm_id = 76,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 4,
+       .num_links = ARRAY_SIZE(mas_snoc_bimc_1_links),
+       .links = mas_snoc_bimc_1_links,
+};
+
+static const u16 mas_tcu_0_links[] = {
+       QNOC_BIMC_SNOC_SLV,
+       QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_tcu_0 = {
+       .name = "mas_tcu_0",
+       .id = QNOC_MASTER_TCU_0,
+       .buswidth = 8,
+       .mas_rpm_id = 102,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 2,
+       .qos.qos_port = 5,
+       .num_links = ARRAY_SIZE(mas_tcu_0_links),
+       .links = mas_tcu_0_links,
+};
+
+static const u16 mas_tcu_1_links[] = {
+       QNOC_BIMC_SNOC_SLV,
+       QNOC_SLAVE_EBI_CH0
+};
+
+static struct qcom_icc_node mas_tcu_1 = {
+       .name = "mas_tcu_1",
+       .id = QNOC_MASTER_TCU_1,
+       .buswidth = 8,
+       .mas_rpm_id = 103,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 2,
+       .qos.qos_port = 6,
+       .num_links = ARRAY_SIZE(mas_tcu_1_links),
+       .links = mas_tcu_1_links,
+};
+
+static const u16 mas_audio_links[] = {
+       QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_audio = {
+       .name = "mas_audio",
+       .id = QNOC_MASTER_AUDIO,
+       .buswidth = 4,
+       .mas_rpm_id = 78,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_audio_links),
+       .links = mas_audio_links,
+};
+
+static const u16 mas_spdm_links[] = {
+       QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_spdm = {
+       .name = "mas_spdm",
+       .id = QNOC_MASTER_SPDM,
+       .buswidth = 4,
+       .mas_rpm_id = 50,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_spdm_links),
+       .links = mas_spdm_links,
+};
+
+static const u16 mas_dehr_links[] = {
+       QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_dehr = {
+       .name = "mas_dehr",
+       .id = QNOC_MASTER_DEHR,
+       .buswidth = 4,
+       .mas_rpm_id = 48,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_dehr_links),
+       .links = mas_dehr_links,
+};
+
+static const u16 mas_qpic_links[] = {
+       QNOC_PNOC_M_0
+};
+
+static struct qcom_icc_node mas_qpic = {
+       .name = "mas_qpic",
+       .id = QNOC_MASTER_QPIC,
+       .buswidth = 4,
+       .mas_rpm_id = 58,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_qpic_links),
+       .links = mas_qpic_links,
+};
+
+static const u16 mas_blsp_1_links[] = {
+       QNOC_PNOC_M_1
+};
+
+static struct qcom_icc_node mas_blsp_1 = {
+       .name = "mas_blsp_1",
+       .id = QNOC_MASTER_BLSP_1,
+       .buswidth = 4,
+       .mas_rpm_id = 41,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_blsp_1_links),
+       .links = mas_blsp_1_links,
+};
+
+static const u16 mas_usb_hs_links[] = {
+       QNOC_PNOC_M_1
+};
+
+static struct qcom_icc_node mas_usb_hs = {
+       .name = "mas_usb_hs",
+       .id = QNOC_MASTER_USB_HS,
+       .buswidth = 4,
+       .mas_rpm_id = 42,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_usb_hs_links),
+       .links = mas_usb_hs_links,
+};
+
+static const u16 mas_crypto_links[] = {
+       QNOC_PNOC_INT_1
+};
+
+static struct qcom_icc_node mas_crypto = {
+       .name = "mas_crypto",
+       .id = QNOC_MASTER_CRYPTO_CORE0,
+       .buswidth = 8,
+       .mas_rpm_id = 23,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 0,
+       .num_links = ARRAY_SIZE(mas_crypto_links),
+       .links = mas_crypto_links,
+};
+
+static const u16 mas_sdcc_1_links[] = {
+       QNOC_PNOC_INT_1
+};
+
+static struct qcom_icc_node mas_sdcc_1 = {
+       .name = "mas_sdcc_1",
+       .id = QNOC_MASTER_SDCC_1,
+       .buswidth = 8,
+       .mas_rpm_id = 33,
+       .slv_rpm_id = -1,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 7,
+       .num_links = ARRAY_SIZE(mas_sdcc_1_links),
+       .links = mas_sdcc_1_links,
+};
+
+static const u16 mas_sdcc_2_links[] = {
+       QNOC_PNOC_INT_1
+};
+
+static struct qcom_icc_node mas_sdcc_2 = {
+       .name = "mas_sdcc_2",
+       .id = QNOC_MASTER_SDCC_2,
+       .buswidth = 8,
+       .mas_rpm_id = 35,
+       .slv_rpm_id = -1,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 8,
+       .num_links = ARRAY_SIZE(mas_sdcc_2_links),
+       .links = mas_sdcc_2_links,
+};
+
+static const u16 mas_snoc_pcnoc_links[] = {
+       QNOC_PNOC_INT_0
+};
+
+static struct qcom_icc_node mas_snoc_pcnoc = {
+       .name = "mas_snoc_pcnoc",
+       .id = QNOC_SNOC_PNOC_MAS,
+       .buswidth = 8,
+       .mas_rpm_id = 77,
+       .slv_rpm_id = -1,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 9,
+       .num_links = ARRAY_SIZE(mas_snoc_pcnoc_links),
+       .links = mas_snoc_pcnoc_links,
+};
+
+static const u16 mas_qdss_bam_links[] = {
+       QNOC_SNOC_QDSS_INT
+};
+
+static struct qcom_icc_node mas_qdss_bam = {
+       .name = "mas_qdss_bam",
+       .id = QNOC_MASTER_QDSS_BAM,
+       .buswidth = 4,
+       .mas_rpm_id = 19,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 1,
+       .qos.prio_level = 1,
+       .qos.qos_port = 11,
+       .num_links = ARRAY_SIZE(mas_qdss_bam_links),
+       .links = mas_qdss_bam_links,
+};
+
+static const u16 mas_bimc_snoc_links[] = {
+       QNOC_SNOC_INT_0,
+       QNOC_SNOC_INT_1
+};
+
+static struct qcom_icc_node mas_bimc_snoc = {
+       .name = "mas_bimc_snoc",
+       .id = QNOC_BIMC_SNOC_MAS,
+       .buswidth = 8,
+       .mas_rpm_id = 21,
+       .slv_rpm_id = -1,
+       .num_links = ARRAY_SIZE(mas_bimc_snoc_links),
+       .links = mas_bimc_snoc_links,
+};
+
+static const u16 mas_mdp_links[] = {
+       QNOC_SNOC_MM_INT_1,
+       QNOC_SNOC_MM_INT_2
+};
+
+static struct qcom_icc_node mas_mdp = {
+       .name = "mas_mdp",
+       .id = QNOC_MASTER_MDP_PORT0,
+       .buswidth = 16,
+       .mas_rpm_id = 8,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 7,
+       .num_links = ARRAY_SIZE(mas_mdp_links),
+       .links = mas_mdp_links,
+       .ab_coeff = 167,
+};
+
+static const u16 mas_pcnoc_snoc_links[] = {
+       QNOC_SNOC_INT_0,
+       QNOC_SNOC_INT_1,
+       QNOC_SNOC_INT_BIMC
+};
+
+static struct qcom_icc_node mas_pcnoc_snoc = {
+       .name = "mas_pcnoc_snoc",
+       .id = QNOC_PNOC_SNOC_MAS,
+       .buswidth = 8,
+       .mas_rpm_id = 29,
+       .slv_rpm_id = -1,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 5,
+       .num_links = ARRAY_SIZE(mas_pcnoc_snoc_links),
+       .links = mas_pcnoc_snoc_links,
+};
+
+static const u16 mas_venus_links[] = {
+       QNOC_SNOC_MM_INT_0,
+       QNOC_SNOC_MM_INT_2
+};
+
+static struct qcom_icc_node mas_venus = {
+       .name = "mas_venus",
+       .id = QNOC_MASTER_VIDEO_P0,
+       .buswidth = 16,
+       .mas_rpm_id = 9,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 8,
+       .num_links = ARRAY_SIZE(mas_venus_links),
+       .links = mas_venus_links,
+       .ab_coeff = 167,
+};
+
+static const u16 mas_vfe_links[] = {
+       QNOC_SNOC_MM_INT_1,
+       QNOC_SNOC_MM_INT_2
+};
+
+static struct qcom_icc_node mas_vfe = {
+       .name = "mas_vfe",
+       .id = QNOC_MASTER_VFE,
+       .buswidth = 16,
+       .mas_rpm_id = 11,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 9,
+       .num_links = ARRAY_SIZE(mas_vfe_links),
+       .links = mas_vfe_links,
+       .ab_coeff = 167,
+};
+
+static const u16 mas_qdss_etr_links[] = {
+       QNOC_SNOC_QDSS_INT
+};
+
+static struct qcom_icc_node mas_qdss_etr = {
+       .name = "mas_qdss_etr",
+       .id = QNOC_MASTER_QDSS_ETR,
+       .buswidth = 8,
+       .mas_rpm_id = 31,
+       .slv_rpm_id = -1,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 1,
+       .qos.prio_level = 1,
+       .qos.qos_port = 10,
+       .num_links = ARRAY_SIZE(mas_qdss_etr_links),
+       .links = mas_qdss_etr_links,
+};
+
+static const u16 pcnoc_m_0_links[] = {
+       QNOC_PNOC_SNOC_SLV
+};
+
+static struct qcom_icc_node pcnoc_m_0 = {
+       .name = "pcnoc_m_0",
+       .id = QNOC_PNOC_M_0,
+       .buswidth = 8,
+       .mas_rpm_id = 87,
+       .slv_rpm_id = 116,
+       .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 5,
+       .num_links = ARRAY_SIZE(pcnoc_m_0_links),
+       .links = pcnoc_m_0_links,
+};
+
+static const u16 pcnoc_m_1_links[] = {
+       QNOC_PNOC_SNOC_SLV
+};
+
+static struct qcom_icc_node pcnoc_m_1 = {
+       .name = "pcnoc_m_1",
+       .id = QNOC_PNOC_M_1,
+       .buswidth = 8,
+       .mas_rpm_id = 88,
+       .slv_rpm_id = 117,
+       .qos.qos_mode = NOC_QOS_MODE_FIXED,
+       .qos.areq_prio = 0,
+       .qos.prio_level = 0,
+       .qos.qos_port = 6,
+       .num_links = ARRAY_SIZE(pcnoc_m_1_links),
+       .links = pcnoc_m_1_links,
+};
+
+static const u16 pcnoc_int_0_links[] = {
+       QNOC_PNOC_SLV_3,
+       QNOC_PNOC_SLV_2,
+       QNOC_PNOC_SLV_1,
+       QNOC_PNOC_SLV_0,
+       QNOC_PNOC_SLV_7,
+       QNOC_PNOC_SLV_5,
+       QNOC_PNOC_SLV_4,
+       QNOC_SLAVE_TCU
+};
+
+static struct qcom_icc_node pcnoc_int_0 = {
+       .name = "pcnoc_int_0",
+       .id = QNOC_PNOC_INT_0,
+       .buswidth = 8,
+       .mas_rpm_id = 85,
+       .slv_rpm_id = 114,
+       .num_links = ARRAY_SIZE(pcnoc_int_0_links),
+       .links = pcnoc_int_0_links,
+};
+
+static const u16 pcnoc_int_1_links[] = {
+       QNOC_PNOC_SNOC_SLV
+};
+
+static struct qcom_icc_node pcnoc_int_1 = {
+       .name = "pcnoc_int_1",
+       .id = QNOC_PNOC_INT_1,
+       .buswidth = 8,
+       .mas_rpm_id = 86,
+       .slv_rpm_id = 115,
+       .num_links = ARRAY_SIZE(pcnoc_int_1_links),
+       .links = pcnoc_int_1_links,
+};
+
+static const u16 pcnoc_s_0_links[] = {
+       QNOC_SLAVE_SDCC_1,
+       QNOC_SLAVE_TCSR,
+       QNOC_SLAVE_BLSP_1
+};
+
+static struct qcom_icc_node pcnoc_s_0 = {
+       .name = "pcnoc_s_0",
+       .id = QNOC_PNOC_SLV_0,
+       .buswidth = 4,
+       .mas_rpm_id = 89,
+       .slv_rpm_id = 118,
+       .num_links = ARRAY_SIZE(pcnoc_s_0_links),
+       .links = pcnoc_s_0_links,
+};
+
+static const u16 pcnoc_s_1_links[] = {
+       QNOC_SLAVE_MESSAGE_RAM,
+       QNOC_SLAVE_CRYPTO_0_CFG,
+       QNOC_SLAVE_USB_HS,
+       QNOC_SLAVE_PDM,
+       QNOC_SLAVE_PRNG,
+       QNOC_SLAVE_QPIC
+};
+
+static struct qcom_icc_node pcnoc_s_1 = {
+       .name = "pcnoc_s_1",
+       .id = QNOC_PNOC_SLV_1,
+       .buswidth = 4,
+       .mas_rpm_id = 90,
+       .slv_rpm_id = 119,
+       .num_links = ARRAY_SIZE(pcnoc_s_1_links),
+       .links = pcnoc_s_1_links,
+};
+
+static const u16 pcnoc_s_2_links[] = {
+       QNOC_SLAVE_SPDM,
+       QNOC_SLAVE_SDCC_2,
+       QNOC_SLAVE_AUDIO,
+       QNOC_SLAVE_DEHR_CFG
+};
+
+static struct qcom_icc_node pcnoc_s_2 = {
+       .name = "pcnoc_s_2",
+       .id = QNOC_PNOC_SLV_2,
+       .buswidth = 4,
+       .mas_rpm_id = 91,
+       .slv_rpm_id = 120,
+       .num_links = ARRAY_SIZE(pcnoc_s_2_links),
+       .links = pcnoc_s_2_links,
+};
+
+static const u16 pcnoc_s_3_links[] = {
+       QNOC_SLAVE_QDSS_CFG,
+       QNOC_SLAVE_USB_PHYS_CFG,
+       QNOC_SLAVE_SNOC_CFG
+};
+
+static struct qcom_icc_node pcnoc_s_3 = {
+       .name = "pcnoc_s_3",
+       .id = QNOC_PNOC_SLV_3,
+       .buswidth = 4,
+       .mas_rpm_id = 92,
+       .slv_rpm_id = 121,
+       .num_links = ARRAY_SIZE(pcnoc_s_3_links),
+       .links = pcnoc_s_3_links,
+};
+
+static const u16 pcnoc_s_4_links[] = {
+       QNOC_SLAVE_CAMERA_CFG,
+       QNOC_SLAVE_DISPLAY_CFG,
+       QNOC_SLAVE_VENUS_CFG
+};
+
+static struct qcom_icc_node pcnoc_s_4 = {
+       .name = "pcnoc_s_4",
+       .id = QNOC_PNOC_SLV_4,
+       .buswidth = 4,
+       .mas_rpm_id = 93,
+       .slv_rpm_id = 122,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(pcnoc_s_4_links),
+       .links = pcnoc_s_4_links,
+};
+
+static const u16 pcnoc_s_5_links[] = {
+       QNOC_SLAVE_TLMM
+};
+
+static struct qcom_icc_node pcnoc_s_5 = {
+       .name = "pcnoc_s_5",
+       .id = QNOC_PNOC_SLV_5,
+       .buswidth = 4,
+       .mas_rpm_id = 129,
+       .slv_rpm_id = 189,
+       .num_links = ARRAY_SIZE(pcnoc_s_5_links),
+       .links = pcnoc_s_5_links,
+};
+
+static const u16 pcnoc_s_7_links[] = {
+       QNOC_SLAVE_GRAPHICS_3D_CFG,
+       QNOC_SLAVE_IMEM_CFG,
+       QNOC_SLAVE_BIMC_CFG,
+       QNOC_SLAVE_PMIC_ARB
+};
+
+static struct qcom_icc_node pcnoc_s_7 = {
+       .name = "pcnoc_s_7",
+       .id = QNOC_PNOC_SLV_7,
+       .buswidth = 4,
+       .mas_rpm_id = 95,
+       .slv_rpm_id = 124,
+       .num_links = ARRAY_SIZE(pcnoc_s_7_links),
+       .links = pcnoc_s_7_links,
+};
+
+static const u16 mm_int_0_links[] = {
+       QNOC_SNOC_MM_INT_BIMC
+};
+
+static struct qcom_icc_node mm_int_0 = {
+       .name = "mm_int_0",
+       .id = QNOC_SNOC_MM_INT_0,
+       .buswidth = 16,
+       .mas_rpm_id = 79,
+       .slv_rpm_id = 108,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(mm_int_0_links),
+       .links = mm_int_0_links,
+       .ab_coeff = 167,
+};
+
+static const u16 mm_int_1_links[] = {
+       QNOC_SNOC_MM_INT_BIMC
+};
+
+static struct qcom_icc_node mm_int_1 = {
+       .name = "mm_int_1",
+       .id = QNOC_SNOC_MM_INT_1,
+       .buswidth = 16,
+       .mas_rpm_id = 80,
+       .slv_rpm_id = 109,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(mm_int_1_links),
+       .links = mm_int_1_links,
+       .ab_coeff = 167,
+};
+
+static const u16 mm_int_2_links[] = {
+       QNOC_SNOC_INT_0
+};
+
+static struct qcom_icc_node mm_int_2 = {
+       .name = "mm_int_2",
+       .id = QNOC_SNOC_MM_INT_2,
+       .buswidth = 16,
+       .mas_rpm_id = 81,
+       .slv_rpm_id = 110,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(mm_int_2_links),
+       .links = mm_int_2_links,
+       .ab_coeff = 167,
+};
+
+static const u16 mm_int_bimc_links[] = {
+       QNOC_SNOC_BIMC_1_SLV
+};
+
+static struct qcom_icc_node mm_int_bimc = {
+       .name = "mm_int_bimc",
+       .id = QNOC_SNOC_MM_INT_BIMC,
+       .buswidth = 16,
+       .mas_rpm_id = 82,
+       .slv_rpm_id = 111,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(mm_int_bimc_links),
+       .links = mm_int_bimc_links,
+       .ab_coeff = 167,
+};
+
+static const u16 qdss_int_links[] = {
+       QNOC_SNOC_INT_0,
+       QNOC_SNOC_INT_BIMC
+};
+
+static struct qcom_icc_node qdss_int = {
+       .name = "qdss_int",
+       .id = QNOC_SNOC_QDSS_INT,
+       .buswidth = 8,
+       .mas_rpm_id = 98,
+       .slv_rpm_id = 128,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(qdss_int_links),
+       .links = qdss_int_links,
+};
+
+static const u16 snoc_int_0_links[] = {
+       QNOC_SLAVE_SYSTEM_IMEM,
+       QNOC_SLAVE_QDSS_STM,
+       QNOC_SNOC_PNOC_SLV
+};
+
+static struct qcom_icc_node snoc_int_0 = {
+       .name = "snoc_int_0",
+       .id = QNOC_SNOC_INT_0,
+       .buswidth = 8,
+       .mas_rpm_id = 99,
+       .slv_rpm_id = 130,
+       .num_links = ARRAY_SIZE(snoc_int_0_links),
+       .links = snoc_int_0_links,
+};
+
+static const u16 snoc_int_1_links[] = {
+       QNOC_SLAVE_CATS_128,
+       QNOC_SLAVE_APPSS,
+       QNOC_SLAVE_OCMEM_64
+};
+
+static struct qcom_icc_node snoc_int_1 = {
+       .name = "snoc_int_1",
+       .id = QNOC_SNOC_INT_1,
+       .buswidth = 8,
+       .mas_rpm_id = 100,
+       .slv_rpm_id = 131,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(snoc_int_1_links),
+       .links = snoc_int_1_links,
+};
+
+static const u16 snoc_int_bimc_links[] = {
+       QNOC_SNOC_BIMC_0_SLV
+};
+
+static struct qcom_icc_node snoc_int_bimc = {
+       .name = "snoc_int_bimc",
+       .id = QNOC_SNOC_INT_BIMC,
+       .buswidth = 8,
+       .mas_rpm_id = 101,
+       .slv_rpm_id = 132,
+       .num_links = ARRAY_SIZE(snoc_int_bimc_links),
+       .links = snoc_int_bimc_links,
+};
+
+static struct qcom_icc_node slv_ebi = {
+       .name = "slv_ebi",
+       .id = QNOC_SLAVE_EBI_CH0,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 0,
+};
+
+static const u16 slv_bimc_snoc_links[] = {
+       QNOC_BIMC_SNOC_MAS
+};
+
+static struct qcom_icc_node slv_bimc_snoc = {
+       .name = "slv_bimc_snoc",
+       .id = QNOC_BIMC_SNOC_SLV,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 2,
+       .num_links = ARRAY_SIZE(slv_bimc_snoc_links),
+       .links = slv_bimc_snoc_links,
+};
+
+static struct qcom_icc_node slv_tcsr = {
+       .name = "slv_tcsr",
+       .id = QNOC_SLAVE_TCSR,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 50,
+};
+
+static struct qcom_icc_node slv_sdcc_1 = {
+       .name = "slv_sdcc_1",
+       .id = QNOC_SLAVE_SDCC_1,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 31,
+};
+
+static struct qcom_icc_node slv_blsp_1 = {
+       .name = "slv_blsp_1",
+       .id = QNOC_SLAVE_BLSP_1,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 39,
+};
+
+static struct qcom_icc_node slv_crypto_0_cfg = {
+       .name = "slv_crypto_0_cfg",
+       .id = QNOC_SLAVE_CRYPTO_0_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 52,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_message_ram = {
+       .name = "slv_message_ram",
+       .id = QNOC_SLAVE_MESSAGE_RAM,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 55,
+};
+
+static struct qcom_icc_node slv_pdm = {
+       .name = "slv_pdm",
+       .id = QNOC_SLAVE_PDM,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 41,
+};
+
+static struct qcom_icc_node slv_prng = {
+       .name = "slv_prng",
+       .id = QNOC_SLAVE_PRNG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 44,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_usb_hs = {
+       .name = "slv_usb_hs",
+       .id = QNOC_SLAVE_USB_HS,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 40,
+};
+
+static struct qcom_icc_node slv_qpic = {
+       .name = "slv_qpic",
+       .id = QNOC_SLAVE_QPIC,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 80,
+};
+
+static struct qcom_icc_node slv_spdm = {
+       .name = "slv_spdm",
+       .id = QNOC_SLAVE_SPDM,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 60,
+};
+
+static struct qcom_icc_node slv_sdcc_2 = {
+       .name = "slv_sdcc_2",
+       .id = QNOC_SLAVE_SDCC_2,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 33,
+};
+
+static struct qcom_icc_node slv_audio = {
+       .name = "slv_audio",
+       .id = QNOC_SLAVE_AUDIO,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 105,
+};
+
+static struct qcom_icc_node slv_dehr_cfg = {
+       .name = "slv_dehr_cfg",
+       .id = QNOC_SLAVE_DEHR_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 61,
+};
+
+static struct qcom_icc_node slv_snoc_cfg = {
+       .name = "slv_snoc_cfg",
+       .id = QNOC_SLAVE_SNOC_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 70,
+};
+
+static struct qcom_icc_node slv_qdss_cfg = {
+       .name = "slv_qdss_cfg",
+       .id = QNOC_SLAVE_QDSS_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 63,
+};
+
+static struct qcom_icc_node slv_usb_phy = {
+       .name = "slv_usb_phy",
+       .id = QNOC_SLAVE_USB_PHYS_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 95,
+};
+
+static struct qcom_icc_node slv_camera_ss_cfg = {
+       .name = "slv_camera_ss_cfg",
+       .id = QNOC_SLAVE_CAMERA_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 3,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_disp_ss_cfg = {
+       .name = "slv_disp_ss_cfg",
+       .id = QNOC_SLAVE_DISPLAY_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 4,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_venus_cfg = {
+       .name = "slv_venus_cfg",
+       .id = QNOC_SLAVE_VENUS_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 10,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_tlmm = {
+       .name = "slv_tlmm",
+       .id = QNOC_SLAVE_TLMM,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 51,
+};
+
+static struct qcom_icc_node slv_gpu_cfg = {
+       .name = "slv_gpu_cfg",
+       .id = QNOC_SLAVE_GRAPHICS_3D_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 11,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_imem_cfg = {
+       .name = "slv_imem_cfg",
+       .id = QNOC_SLAVE_IMEM_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 54,
+};
+
+static struct qcom_icc_node slv_bimc_cfg = {
+       .name = "slv_bimc_cfg",
+       .id = QNOC_SLAVE_BIMC_CFG,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 56,
+};
+
+static struct qcom_icc_node slv_pmic_arb = {
+       .name = "slv_pmic_arb",
+       .id = QNOC_SLAVE_PMIC_ARB,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 59,
+};
+
+static struct qcom_icc_node slv_tcu = {
+       .name = "slv_tcu",
+       .id = QNOC_SLAVE_TCU,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 133,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static const u16 slv_pcnoc_snoc_links[] = {
+       QNOC_PNOC_SNOC_MAS
+};
+
+static struct qcom_icc_node slv_pcnoc_snoc = {
+       .name = "slv_pcnoc_snoc",
+       .id = QNOC_PNOC_SNOC_SLV,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 45,
+       .num_links = ARRAY_SIZE(slv_pcnoc_snoc_links),
+       .links = slv_pcnoc_snoc_links,
+};
+
+static struct qcom_icc_node slv_kpss_ahb = {
+       .name = "slv_kpss_ahb",
+       .id = QNOC_SLAVE_APPSS,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 20,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static const u16 slv_snoc_bimc_0_links[] = {
+       QNOC_SNOC_BIMC_0_MAS
+};
+
+static struct qcom_icc_node slv_snoc_bimc_0 = {
+       .name = "slv_snoc_bimc_0",
+       .id = QNOC_SNOC_BIMC_0_SLV,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 24,
+       .num_links = ARRAY_SIZE(slv_snoc_bimc_0_links),
+       .links = slv_snoc_bimc_0_links,
+};
+
+static const u16 slv_snoc_bimc_1_links[] = {
+       QNOC_SNOC_BIMC_1_MAS
+};
+
+static struct qcom_icc_node slv_snoc_bimc_1 = {
+       .name = "slv_snoc_bimc_1",
+       .id = QNOC_SNOC_BIMC_1_SLV,
+       .buswidth = 16,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 104,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+       .num_links = ARRAY_SIZE(slv_snoc_bimc_1_links),
+       .links = slv_snoc_bimc_1_links,
+};
+
+static struct qcom_icc_node slv_imem = {
+       .name = "slv_imem",
+       .id = QNOC_SLAVE_SYSTEM_IMEM,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 26,
+};
+
+static const u16 slv_snoc_pcnoc_links[] = {
+       QNOC_SNOC_PNOC_MAS
+};
+
+static struct qcom_icc_node slv_snoc_pcnoc = {
+       .name = "slv_snoc_pcnoc",
+       .id = QNOC_SNOC_PNOC_SLV,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 28,
+       .num_links = ARRAY_SIZE(slv_snoc_pcnoc_links),
+       .links = slv_snoc_pcnoc_links,
+};
+
+static struct qcom_icc_node slv_qdss_stm = {
+       .name = "slv_qdss_stm",
+       .id = QNOC_SLAVE_QDSS_STM,
+       .buswidth = 4,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 30,
+};
+
+static struct qcom_icc_node slv_cats_0 = {
+       .name = "slv_cats_0",
+       .id = QNOC_SLAVE_CATS_128,
+       .buswidth = 16,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 106,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node slv_cats_1 = {
+       .name = "slv_cats_1",
+       .id = QNOC_SLAVE_OCMEM_64,
+       .buswidth = 8,
+       .mas_rpm_id = -1,
+       .slv_rpm_id = 107,
+       .qos.ap_owned = true,
+       .qos.qos_mode = NOC_QOS_MODE_INVALID,
+};
+
+static struct qcom_icc_node * const msm8909_bimc_nodes[] = {
+       [MAS_APPS_PROC] = &mas_apps_proc,
+       [MAS_OXILI] = &mas_oxili,
+       [MAS_SNOC_BIMC_0] = &mas_snoc_bimc_0,
+       [MAS_SNOC_BIMC_1] = &mas_snoc_bimc_1,
+       [MAS_TCU_0] = &mas_tcu_0,
+       [MAS_TCU_1] = &mas_tcu_1,
+       [SLV_EBI] = &slv_ebi,
+       [SLV_BIMC_SNOC] = &slv_bimc_snoc,
+};
+
+static const struct regmap_config msm8909_bimc_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = 0x62000,
+       .fast_io = true,
+};
+
+static const struct qcom_icc_desc msm8909_bimc = {
+       .type = QCOM_ICC_BIMC,
+       .nodes = msm8909_bimc_nodes,
+       .num_nodes = ARRAY_SIZE(msm8909_bimc_nodes),
+       .bus_clk_desc = &bimc_clk,
+       .regmap_cfg = &msm8909_bimc_regmap_config,
+       .qos_offset = 0x8000,
+       .ab_coeff = 154,
+};
+
+static struct qcom_icc_node * const msm8909_pcnoc_nodes[] = {
+       [MAS_AUDIO] = &mas_audio,
+       [MAS_SPDM] = &mas_spdm,
+       [MAS_DEHR] = &mas_dehr,
+       [MAS_QPIC] = &mas_qpic,
+       [MAS_BLSP_1] = &mas_blsp_1,
+       [MAS_USB_HS] = &mas_usb_hs,
+       [MAS_CRYPTO] = &mas_crypto,
+       [MAS_SDCC_1] = &mas_sdcc_1,
+       [MAS_SDCC_2] = &mas_sdcc_2,
+       [MAS_SNOC_PCNOC] = &mas_snoc_pcnoc,
+       [PCNOC_M_0] = &pcnoc_m_0,
+       [PCNOC_M_1] = &pcnoc_m_1,
+       [PCNOC_INT_0] = &pcnoc_int_0,
+       [PCNOC_INT_1] = &pcnoc_int_1,
+       [PCNOC_S_0] = &pcnoc_s_0,
+       [PCNOC_S_1] = &pcnoc_s_1,
+       [PCNOC_S_2] = &pcnoc_s_2,
+       [PCNOC_S_3] = &pcnoc_s_3,
+       [PCNOC_S_4] = &pcnoc_s_4,
+       [PCNOC_S_5] = &pcnoc_s_5,
+       [PCNOC_S_7] = &pcnoc_s_7,
+       [SLV_TCSR] = &slv_tcsr,
+       [SLV_SDCC_1] = &slv_sdcc_1,
+       [SLV_BLSP_1] = &slv_blsp_1,
+       [SLV_CRYPTO_0_CFG] = &slv_crypto_0_cfg,
+       [SLV_MESSAGE_RAM] = &slv_message_ram,
+       [SLV_PDM] = &slv_pdm,
+       [SLV_PRNG] = &slv_prng,
+       [SLV_USB_HS] = &slv_usb_hs,
+       [SLV_QPIC] = &slv_qpic,
+       [SLV_SPDM] = &slv_spdm,
+       [SLV_SDCC_2] = &slv_sdcc_2,
+       [SLV_AUDIO] = &slv_audio,
+       [SLV_DEHR_CFG] = &slv_dehr_cfg,
+       [SLV_SNOC_CFG] = &slv_snoc_cfg,
+       [SLV_QDSS_CFG] = &slv_qdss_cfg,
+       [SLV_USB_PHY] = &slv_usb_phy,
+       [SLV_CAMERA_SS_CFG] = &slv_camera_ss_cfg,
+       [SLV_DISP_SS_CFG] = &slv_disp_ss_cfg,
+       [SLV_VENUS_CFG] = &slv_venus_cfg,
+       [SLV_TLMM] = &slv_tlmm,
+       [SLV_GPU_CFG] = &slv_gpu_cfg,
+       [SLV_IMEM_CFG] = &slv_imem_cfg,
+       [SLV_BIMC_CFG] = &slv_bimc_cfg,
+       [SLV_PMIC_ARB] = &slv_pmic_arb,
+       [SLV_TCU] = &slv_tcu,
+       [SLV_PCNOC_SNOC] = &slv_pcnoc_snoc,
+};
+
+static const struct regmap_config msm8909_pcnoc_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = 0x11000,
+       .fast_io = true,
+};
+
+static const struct qcom_icc_desc msm8909_pcnoc = {
+       .type = QCOM_ICC_NOC,
+       .nodes = msm8909_pcnoc_nodes,
+       .num_nodes = ARRAY_SIZE(msm8909_pcnoc_nodes),
+       .bus_clk_desc = &bus_0_clk,
+       .regmap_cfg = &msm8909_pcnoc_regmap_config,
+       .qos_offset = 0x7000,
+};
+
+static struct qcom_icc_node * const msm8909_snoc_nodes[] = {
+       [MAS_QDSS_BAM] = &mas_qdss_bam,
+       [MAS_BIMC_SNOC] = &mas_bimc_snoc,
+       [MAS_MDP] = &mas_mdp,
+       [MAS_PCNOC_SNOC] = &mas_pcnoc_snoc,
+       [MAS_VENUS] = &mas_venus,
+       [MAS_VFE] = &mas_vfe,
+       [MAS_QDSS_ETR] = &mas_qdss_etr,
+       [MM_INT_0] = &mm_int_0,
+       [MM_INT_1] = &mm_int_1,
+       [MM_INT_2] = &mm_int_2,
+       [MM_INT_BIMC] = &mm_int_bimc,
+       [QDSS_INT] = &qdss_int,
+       [SNOC_INT_0] = &snoc_int_0,
+       [SNOC_INT_1] = &snoc_int_1,
+       [SNOC_INT_BIMC] = &snoc_int_bimc,
+       [SLV_KPSS_AHB] = &slv_kpss_ahb,
+       [SLV_SNOC_BIMC_0] = &slv_snoc_bimc_0,
+       [SLV_SNOC_BIMC_1] = &slv_snoc_bimc_1,
+       [SLV_IMEM] = &slv_imem,
+       [SLV_SNOC_PCNOC] = &slv_snoc_pcnoc,
+       [SLV_QDSS_STM] = &slv_qdss_stm,
+       [SLV_CATS_0] = &slv_cats_0,
+       [SLV_CATS_1] = &slv_cats_1,
+};
+
+static const struct regmap_config msm8909_snoc_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = 0x13000,
+       .fast_io = true,
+};
+
+static const struct qcom_icc_desc msm8909_snoc = {
+       .type = QCOM_ICC_NOC,
+       .nodes = msm8909_snoc_nodes,
+       .num_nodes = ARRAY_SIZE(msm8909_snoc_nodes),
+       .bus_clk_desc = &bus_1_clk,
+       .regmap_cfg = &msm8909_snoc_regmap_config,
+       .qos_offset = 0x7000,
+};
+
+static const struct of_device_id msm8909_noc_of_match[] = {
+       { .compatible = "qcom,msm8909-bimc", .data = &msm8909_bimc },
+       { .compatible = "qcom,msm8909-pcnoc", .data = &msm8909_pcnoc },
+       { .compatible = "qcom,msm8909-snoc", .data = &msm8909_snoc },
+       { }
+};
+MODULE_DEVICE_TABLE(of, msm8909_noc_of_match);
+
+static struct platform_driver msm8909_noc_driver = {
+       .probe = qnoc_probe,
+       .remove_new = qnoc_remove,
+       .driver = {
+               .name = "qnoc-msm8909",
+               .of_match_table = msm8909_noc_of_match,
+               .sync_state = icc_sync_state,
+       },
+};
+module_platform_driver(msm8909_noc_driver);
+
+MODULE_DESCRIPTION("Qualcomm MSM8909 NoC driver");
+MODULE_LICENSE("GPL");
index dd6281db08adff9545fb33ceaa824585bf1a3aee..a729775c2aa45e52dc27aaf4cedefc88297d551b 100644 (file)
@@ -2092,11 +2092,11 @@ static struct qcom_icc_bcm bcm_sn10 = {
        .nodes = { &xs_qdss_stm },
 };
 
-static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
        &bcm_sn3,
 };
 
-static struct qcom_icc_node *aggre1_noc_nodes[] = {
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
        [MASTER_QUP_3] = &qxm_qup3,
        [MASTER_EMAC] = &xm_emac_0,
        [MASTER_EMAC_1] = &xm_emac_1,
@@ -2115,12 +2115,12 @@ static const struct qcom_icc_desc sa8775p_aggre1_noc = {
        .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
 };
 
-static struct qcom_icc_bcm *aggre2_noc_bcms[] = {
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
        &bcm_ce0,
        &bcm_sn4,
 };
 
-static struct qcom_icc_node *aggre2_noc_nodes[] = {
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
        [MASTER_QDSS_BAM] = &qhm_qdss_bam,
        [MASTER_QUP_0] = &qhm_qup0,
        [MASTER_QUP_1] = &qhm_qup1,
@@ -2142,13 +2142,13 @@ static const struct qcom_icc_desc sa8775p_aggre2_noc = {
        .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
 };
 
-static struct qcom_icc_bcm *clk_virt_bcms[] = {
+static struct qcom_icc_bcm * const clk_virt_bcms[] = {
        &bcm_qup0,
        &bcm_qup1,
        &bcm_qup2,
 };
 
-static struct qcom_icc_node *clk_virt_nodes[] = {
+static struct qcom_icc_node * const clk_virt_nodes[] = {
        [MASTER_QUP_CORE_0] = &qup0_core_master,
        [MASTER_QUP_CORE_1] = &qup1_core_master,
        [MASTER_QUP_CORE_2] = &qup2_core_master,
@@ -2166,7 +2166,7 @@ static const struct qcom_icc_desc sa8775p_clk_virt = {
        .num_bcms = ARRAY_SIZE(clk_virt_bcms),
 };
 
-static struct qcom_icc_bcm *config_noc_bcms[] = {
+static struct qcom_icc_bcm * const config_noc_bcms[] = {
        &bcm_cn0,
        &bcm_cn1,
        &bcm_cn2,
@@ -2175,7 +2175,7 @@ static struct qcom_icc_bcm *config_noc_bcms[] = {
        &bcm_sn10,
 };
 
-static struct qcom_icc_node *config_noc_nodes[] = {
+static struct qcom_icc_node * const config_noc_nodes[] = {
        [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
        [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
        [SLAVE_AHB2PHY_0] = &qhs_ahb2phy0,
@@ -2271,10 +2271,10 @@ static const struct qcom_icc_desc sa8775p_config_noc = {
        .num_bcms = ARRAY_SIZE(config_noc_bcms),
 };
 
-static struct qcom_icc_bcm *dc_noc_bcms[] = {
+static struct qcom_icc_bcm * const dc_noc_bcms[] = {
 };
 
-static struct qcom_icc_node *dc_noc_nodes[] = {
+static struct qcom_icc_node * const dc_noc_nodes[] = {
        [MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc,
        [SLAVE_LLCC_CFG] = &qhs_llcc,
        [SLAVE_GEM_NOC_CFG] = &qns_gemnoc,
@@ -2287,12 +2287,12 @@ static const struct qcom_icc_desc sa8775p_dc_noc = {
        .num_bcms = ARRAY_SIZE(dc_noc_bcms),
 };
 
-static struct qcom_icc_bcm *gem_noc_bcms[] = {
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
        &bcm_sh0,
        &bcm_sh2,
 };
 
-static struct qcom_icc_node *gem_noc_nodes[] = {
+static struct qcom_icc_node * const gem_noc_nodes[] = {
        [MASTER_GPU_TCU] = &alm_gpu_tcu,
        [MASTER_PCIE_TCU] = &alm_pcie_tcu,
        [MASTER_SYS_TCU] = &alm_sys_tcu,
@@ -2323,12 +2323,12 @@ static const struct qcom_icc_desc sa8775p_gem_noc = {
        .num_bcms = ARRAY_SIZE(gem_noc_bcms),
 };
 
-static struct qcom_icc_bcm *gpdsp_anoc_bcms[] = {
+static struct qcom_icc_bcm * const gpdsp_anoc_bcms[] = {
        &bcm_gna0,
        &bcm_gnb0,
 };
 
-static struct qcom_icc_node *gpdsp_anoc_nodes[] = {
+static struct qcom_icc_node * const gpdsp_anoc_nodes[] = {
        [MASTER_DSP0] = &qxm_dsp0,
        [MASTER_DSP1] = &qxm_dsp1,
        [SLAVE_GP_DSP_SAIL_NOC] = &qns_gp_dsp_sail_noc,
@@ -2341,11 +2341,11 @@ static const struct qcom_icc_desc sa8775p_gpdsp_anoc = {
        .num_bcms = ARRAY_SIZE(gpdsp_anoc_bcms),
 };
 
-static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = {
        &bcm_sn9,
 };
 
-static struct qcom_icc_node *lpass_ag_noc_nodes[] = {
+static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
        [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc,
        [MASTER_LPASS_PROC] = &qxm_lpass_dsp,
        [SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core,
@@ -2364,12 +2364,12 @@ static const struct qcom_icc_desc sa8775p_lpass_ag_noc = {
        .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms),
 };
 
-static struct qcom_icc_bcm *mc_virt_bcms[] = {
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
        &bcm_acv,
        &bcm_mc0,
 };
 
-static struct qcom_icc_node *mc_virt_nodes[] = {
+static struct qcom_icc_node * const mc_virt_nodes[] = {
        [MASTER_LLCC] = &llcc_mc,
        [SLAVE_EBI1] = &ebi,
 };
@@ -2381,12 +2381,12 @@ static const struct qcom_icc_desc sa8775p_mc_virt = {
        .num_bcms = ARRAY_SIZE(mc_virt_bcms),
 };
 
-static struct qcom_icc_bcm *mmss_noc_bcms[] = {
+static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
        &bcm_mm0,
        &bcm_mm1,
 };
 
-static struct qcom_icc_node *mmss_noc_nodes[] = {
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
        [MASTER_CAMNOC_HF] = &qnm_camnoc_hf,
        [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp,
        [MASTER_CAMNOC_SF] = &qnm_camnoc_sf,
@@ -2413,12 +2413,12 @@ static const struct qcom_icc_desc sa8775p_mmss_noc = {
        .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
 };
 
-static struct qcom_icc_bcm *nspa_noc_bcms[] = {
+static struct qcom_icc_bcm * const nspa_noc_bcms[] = {
        &bcm_nsa0,
        &bcm_nsa1,
 };
 
-static struct qcom_icc_node *nspa_noc_nodes[] = {
+static struct qcom_icc_node * const nspa_noc_nodes[] = {
        [MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config,
        [MASTER_CDSP_PROC] = &qxm_nsp,
        [SLAVE_HCP_A] = &qns_hcp,
@@ -2433,12 +2433,12 @@ static const struct qcom_icc_desc sa8775p_nspa_noc = {
        .num_bcms = ARRAY_SIZE(nspa_noc_bcms),
 };
 
-static struct qcom_icc_bcm *nspb_noc_bcms[] = {
+static struct qcom_icc_bcm * const nspb_noc_bcms[] = {
        &bcm_nsb0,
        &bcm_nsb1,
 };
 
-static struct qcom_icc_node *nspb_noc_nodes[] = {
+static struct qcom_icc_node * const nspb_noc_nodes[] = {
        [MASTER_CDSPB_NOC_CFG] = &qhm_nspb_noc_config,
        [MASTER_CDSP_PROC_B] = &qxm_nspb,
        [SLAVE_CDSPB_MEM_NOC] = &qns_nspb_gemnoc,
@@ -2453,11 +2453,11 @@ static const struct qcom_icc_desc sa8775p_nspb_noc = {
        .num_bcms = ARRAY_SIZE(nspb_noc_bcms),
 };
 
-static struct qcom_icc_bcm *pcie_anoc_bcms[] = {
+static struct qcom_icc_bcm * const pcie_anoc_bcms[] = {
        &bcm_pci0,
 };
 
-static struct qcom_icc_node *pcie_anoc_nodes[] = {
+static struct qcom_icc_node * const pcie_anoc_nodes[] = {
        [MASTER_PCIE_0] = &xm_pcie3_0,
        [MASTER_PCIE_1] = &xm_pcie3_1,
        [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
@@ -2470,7 +2470,7 @@ static const struct qcom_icc_desc sa8775p_pcie_anoc = {
        .num_bcms = ARRAY_SIZE(pcie_anoc_bcms),
 };
 
-static struct qcom_icc_bcm *system_noc_bcms[] = {
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
        &bcm_sn0,
        &bcm_sn1,
        &bcm_sn3,
@@ -2478,7 +2478,7 @@ static struct qcom_icc_bcm *system_noc_bcms[] = {
        &bcm_sn9,
 };
 
-static struct qcom_icc_node *system_noc_nodes[] = {
+static struct qcom_icc_node * const system_noc_nodes[] = {
        [MASTER_GIC_AHB] = &qhm_gic,
        [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
        [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
index 88b67634aa2f1874825087c129c992436a2fd3f0..7e15ddf0a80a9c3a05ab729956d6cd89c0034911 100644 (file)
@@ -1193,7 +1193,7 @@ static struct qcom_icc_node slv_anoc_snoc = {
        .links = slv_anoc_snoc_links,
 };
 
-static struct qcom_icc_node *bimc_nodes[] = {
+static struct qcom_icc_node * const bimc_nodes[] = {
        [MASTER_AMPSS_M0] = &apps_proc,
        [MASTER_SNOC_BIMC_RT] = &mas_snoc_bimc_rt,
        [MASTER_SNOC_BIMC_NRT] = &mas_snoc_bimc_nrt,
@@ -1223,7 +1223,7 @@ static const struct qcom_icc_desc sm6115_bimc = {
        .ab_coeff = 153,
 };
 
-static struct qcom_icc_node *config_noc_nodes[] = {
+static struct qcom_icc_node * const config_noc_nodes[] = {
        [SNOC_CNOC_MAS] = &mas_snoc_cnoc,
        [MASTER_QDSS_DAP] = &xm_dap,
        [SLAVE_AHB2PHY_USB] = &qhs_ahb2phy_usb,
@@ -1294,7 +1294,7 @@ static const struct qcom_icc_desc sm6115_config_noc = {
        .keep_alive = true,
 };
 
-static struct qcom_icc_node *sys_noc_nodes[] = {
+static struct qcom_icc_node * const sys_noc_nodes[] = {
        [MASTER_CRYPTO_CORE0] = &crypto_c0,
        [MASTER_SNOC_CFG] = &qhm_snoc_cfg,
        [MASTER_TIC] = &qhm_tic,
@@ -1339,7 +1339,7 @@ static const struct qcom_icc_desc sm6115_sys_noc = {
        .keep_alive = true,
 };
 
-static struct qcom_icc_node *clk_virt_nodes[] = {
+static struct qcom_icc_node * const clk_virt_nodes[] = {
        [MASTER_QUP_CORE_0] = &qup0_core_master,
        [SLAVE_QUP_CORE_0] = &qup0_core_slave,
 };
@@ -1353,7 +1353,7 @@ static const struct qcom_icc_desc sm6115_clk_virt = {
        .keep_alive = true,
 };
 
-static struct qcom_icc_node *mmnrt_virt_nodes[] = {
+static struct qcom_icc_node * const mmnrt_virt_nodes[] = {
        [MASTER_CAMNOC_SF] = &qnm_camera_nrt,
        [MASTER_VIDEO_P0] = &qxm_venus0,
        [MASTER_VIDEO_PROC] = &qxm_venus_cpu,
@@ -1370,7 +1370,7 @@ static const struct qcom_icc_desc sm6115_mmnrt_virt = {
        .ab_coeff = 142,
 };
 
-static struct qcom_icc_node *mmrt_virt_nodes[] = {
+static struct qcom_icc_node * const mmrt_virt_nodes[] = {
        [MASTER_CAMNOC_HF] = &qnm_camera_rt,
        [MASTER_MDP_PORT0] = &qxm_mdp0,
        [SLAVE_SNOC_BIMC_RT] = &slv_snoc_bimc_rt,
diff --git a/drivers/interconnect/qcom/sm7150.c b/drivers/interconnect/qcom/sm7150.c
new file mode 100644 (file)
index 0000000..dc0d134
--- /dev/null
@@ -0,0 +1,1754 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/interconnect/qcom,sm7150-rpmh.h>
+
+#include "bcm-voter.h"
+#include "icc-rpmh.h"
+#include "sm7150.h"
+
+static struct qcom_icc_node qhm_a1noc_cfg = {
+       .name = "qhm-a1noc-cfg",
+       .id = SM7150_MASTER_A1NOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_SERVICE_A1NOC },
+};
+
+static struct qcom_icc_node qhm_qup_center = {
+       .name = "qhm_qup_center",
+       .id = SM7150_MASTER_QUP_0,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qhm_tsif = {
+       .name = "qhm_tsif",
+       .id = SM7150_MASTER_TSIF,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_emmc = {
+       .name = "xm_emmc",
+       .id = SM7150_MASTER_EMMC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_sdc2 = {
+       .name = "xm_sdc2",
+       .id = SM7150_MASTER_SDCC_2,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_sdc4 = {
+       .name = "xm_sdc4",
+       .id = SM7150_MASTER_SDCC_4,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_ufs_mem = {
+       .name = "xm_ufs_mem",
+       .id = SM7150_MASTER_UFS_MEM,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qhm_a2noc_cfg = {
+       .name = "qhm_a2noc_cfg",
+       .id = SM7150_MASTER_A2NOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_SERVICE_A2NOC },
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+       .name = "qhm_qdss_bam",
+       .id = SM7150_MASTER_QDSS_BAM,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qhm_qup_north = {
+       .name = "qhm_qup_north",
+       .id = SM7150_MASTER_QUP_1,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qnm_cnoc = {
+       .name = "qnm_cnoc",
+       .id = SM7150_MASTER_CNOC_A2NOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qxm_crypto = {
+       .name = "qxm_crypto",
+       .id = SM7150_MASTER_CRYPTO_CORE_0,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qxm_ipa = {
+       .name = "qxm_ipa",
+       .id = SM7150_MASTER_IPA,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_pcie3_0 = {
+       .name = "xm_pcie3_0",
+       .id = SM7150_MASTER_PCIE,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr = {
+       .name = "xm_qdss_etr",
+       .id = SM7150_MASTER_QDSS_ETR,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+       .name = "xm_usb3_0",
+       .id = SM7150_MASTER_USB3,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_SLV },
+};
+
+static struct qcom_icc_node qxm_camnoc_hf0_uncomp = {
+       .name = "qxm_camnoc_hf0_uncomp",
+       .id = SM7150_MASTER_CAMNOC_HF0_UNCOMP,
+       .channels = 2,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qxm_camnoc_rt_uncomp = {
+       .name = "qxm_camnoc_rt_uncomp",
+       .id = SM7150_MASTER_CAMNOC_RT_UNCOMP,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qxm_camnoc_sf_uncomp = {
+       .name = "qxm_camnoc_sf_uncomp",
+       .id = SM7150_MASTER_CAMNOC_SF_UNCOMP,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qxm_camnoc_nrt_uncomp = {
+       .name = "qxm_camnoc_nrt_uncomp",
+       .id = SM7150_MASTER_CAMNOC_NRT_UNCOMP,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_CAMNOC_UNCOMP },
+};
+
+static struct qcom_icc_node qnm_npu = {
+       .name = "qnm_npu",
+       .id = SM7150_MASTER_NPU,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_CDSP_GEM_NOC },
+};
+
+static struct qcom_icc_node qhm_spdm = {
+       .name = "qhm_spdm",
+       .id = SM7150_MASTER_SPDM,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_CNOC_A2NOC },
+};
+
+static struct qcom_icc_node qnm_snoc = {
+       .name = "qnm_snoc",
+       .id = SM7150_SNOC_CNOC_MAS,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 47,
+       .links = { SM7150_SLAVE_TLMM_SOUTH,
+                  SM7150_SLAVE_CAMERA_CFG,
+                  SM7150_SLAVE_SDCC_4,
+                  SM7150_SLAVE_SDCC_2,
+                  SM7150_SLAVE_CNOC_MNOC_CFG,
+                  SM7150_SLAVE_UFS_MEM_CFG,
+                  SM7150_SLAVE_QUP_0,
+                  SM7150_SLAVE_GLM,
+                  SM7150_SLAVE_PDM,
+                  SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+                  SM7150_SLAVE_A2NOC_CFG,
+                  SM7150_SLAVE_QDSS_CFG,
+                  SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG,
+                  SM7150_SLAVE_DISPLAY_CFG,
+                  SM7150_SLAVE_PCIE_CFG,
+                  SM7150_SLAVE_DISPLAY_THROTTLE_CFG,
+                  SM7150_SLAVE_TCSR,
+                  SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG,
+                  SM7150_SLAVE_CNOC_DDRSS,
+                  SM7150_SLAVE_AHB2PHY_NORTH,
+                  SM7150_SLAVE_SNOC_CFG,
+                  SM7150_SLAVE_GRAPHICS_3D_CFG,
+                  SM7150_SLAVE_VENUS_CFG,
+                  SM7150_SLAVE_TSIF,
+                  SM7150_SLAVE_CDSP_CFG,
+                  SM7150_SLAVE_CLK_CTL,
+                  SM7150_SLAVE_AOP,
+                  SM7150_SLAVE_QUP_1,
+                  SM7150_SLAVE_AHB2PHY_SOUTH,
+                  SM7150_SLAVE_SERVICE_CNOC,
+                  SM7150_SLAVE_AHB2PHY_WEST,
+                  SM7150_SLAVE_USB3,
+                  SM7150_SLAVE_VENUS_THROTTLE_CFG,
+                  SM7150_SLAVE_IPA_CFG,
+                  SM7150_SLAVE_RBCPR_CX_CFG,
+                  SM7150_SLAVE_TLMM_WEST,
+                  SM7150_SLAVE_A1NOC_CFG,
+                  SM7150_SLAVE_AOSS,
+                  SM7150_SLAVE_PRNG,
+                  SM7150_SLAVE_VSENSE_CTRL_CFG,
+                  SM7150_SLAVE_EMMC_CFG,
+                  SM7150_SLAVE_SPDM_WRAPPER,
+                  SM7150_SLAVE_CRYPTO_0_CFG,
+                  SM7150_SLAVE_PIMEM_CFG,
+                  SM7150_SLAVE_TLMM_NORTH,
+                  SM7150_SLAVE_RBCPR_MX_CFG,
+                  SM7150_SLAVE_IMEM_CFG
+       },
+};
+
+static struct qcom_icc_node xm_qdss_dap = {
+       .name = "xm_qdss_dap",
+       .id = SM7150_MASTER_QDSS_DAP,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 48,
+       .links = { SM7150_SLAVE_TLMM_SOUTH,
+                  SM7150_SLAVE_CAMERA_CFG,
+                  SM7150_SLAVE_SDCC_4,
+                  SM7150_SLAVE_SDCC_2,
+                  SM7150_SLAVE_CNOC_MNOC_CFG,
+                  SM7150_SLAVE_UFS_MEM_CFG,
+                  SM7150_SLAVE_QUP_0,
+                  SM7150_SLAVE_GLM,
+                  SM7150_SLAVE_PDM,
+                  SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+                  SM7150_SLAVE_A2NOC_CFG,
+                  SM7150_SLAVE_QDSS_CFG,
+                  SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG,
+                  SM7150_SLAVE_DISPLAY_CFG,
+                  SM7150_SLAVE_PCIE_CFG,
+                  SM7150_SLAVE_DISPLAY_THROTTLE_CFG,
+                  SM7150_SLAVE_TCSR,
+                  SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG,
+                  SM7150_SLAVE_CNOC_DDRSS,
+                  SM7150_SLAVE_CNOC_A2NOC,
+                  SM7150_SLAVE_AHB2PHY_NORTH,
+                  SM7150_SLAVE_SNOC_CFG,
+                  SM7150_SLAVE_GRAPHICS_3D_CFG,
+                  SM7150_SLAVE_VENUS_CFG,
+                  SM7150_SLAVE_TSIF,
+                  SM7150_SLAVE_CDSP_CFG,
+                  SM7150_SLAVE_CLK_CTL,
+                  SM7150_SLAVE_AOP,
+                  SM7150_SLAVE_QUP_1,
+                  SM7150_SLAVE_AHB2PHY_SOUTH,
+                  SM7150_SLAVE_SERVICE_CNOC,
+                  SM7150_SLAVE_AHB2PHY_WEST,
+                  SM7150_SLAVE_USB3,
+                  SM7150_SLAVE_VENUS_THROTTLE_CFG,
+                  SM7150_SLAVE_IPA_CFG,
+                  SM7150_SLAVE_RBCPR_CX_CFG,
+                  SM7150_SLAVE_TLMM_WEST,
+                  SM7150_SLAVE_A1NOC_CFG,
+                  SM7150_SLAVE_AOSS,
+                  SM7150_SLAVE_PRNG,
+                  SM7150_SLAVE_VSENSE_CTRL_CFG,
+                  SM7150_SLAVE_EMMC_CFG,
+                  SM7150_SLAVE_SPDM_WRAPPER,
+                  SM7150_SLAVE_CRYPTO_0_CFG,
+                  SM7150_SLAVE_PIMEM_CFG,
+                  SM7150_SLAVE_TLMM_NORTH,
+                  SM7150_SLAVE_RBCPR_MX_CFG,
+                  SM7150_SLAVE_IMEM_CFG
+       },
+};
+
+static struct qcom_icc_node qhm_cnoc_dc_noc = {
+       .name = "qhm_cnoc_dc_noc",
+       .id = SM7150_MASTER_CNOC_DC_NOC,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC_CFG,
+                  SM7150_SLAVE_GEM_NOC_CFG
+       },
+};
+
+static struct qcom_icc_node acm_apps = {
+       .name = "acm_apps",
+       .id = SM7150_MASTER_AMPSS_M0,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC,
+                  SM7150_SLAVE_GEM_NOC_SNOC
+       },
+};
+
+static struct qcom_icc_node acm_sys_tcu = {
+       .name = "acm_sys_tcu",
+       .id = SM7150_MASTER_SYS_TCU,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC,
+                  SM7150_SLAVE_GEM_NOC_SNOC
+       },
+};
+
+static struct qcom_icc_node qhm_gemnoc_cfg = {
+       .name = "qhm_gemnoc_cfg",
+       .id = SM7150_MASTER_GEM_NOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_SERVICE_GEM_NOC,
+                  SM7150_SLAVE_MSS_PROC_MS_MPU_CFG
+       },
+};
+
+static struct qcom_icc_node qnm_cmpnoc = {
+       .name = "qnm_cmpnoc",
+       .id = SM7150_MASTER_COMPUTE_NOC,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC,
+                  SM7150_SLAVE_GEM_NOC_SNOC
+       },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf = {
+       .name = "qnm_mnoc_hf",
+       .id = SM7150_MASTER_MNOC_HF_MEM_NOC,
+       .channels = 2,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf = {
+       .name = "qnm_mnoc_sf",
+       .id = SM7150_MASTER_MNOC_SF_MEM_NOC,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC,
+                  SM7150_SLAVE_GEM_NOC_SNOC
+       },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+       .name = "qnm_pcie",
+       .id = SM7150_MASTER_GEM_NOC_PCIE_SNOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC,
+                  SM7150_SLAVE_GEM_NOC_SNOC
+       },
+};
+
+static struct qcom_icc_node qnm_snoc_gc = {
+       .name = "qnm_snoc_gc",
+       .id = SM7150_MASTER_SNOC_GC_MEM_NOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+       .name = "qnm_snoc_sf",
+       .id = SM7150_MASTER_SNOC_SF_MEM_NOC,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qxm_gpu = {
+       .name = "qxm_gpu",
+       .id = SM7150_MASTER_GRAPHICS_3D,
+       .channels = 2,
+       .buswidth = 32,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_LLCC,
+                  SM7150_SLAVE_GEM_NOC_SNOC
+       },
+};
+
+static struct qcom_icc_node llcc_mc = {
+       .name = "llcc_mc",
+       .id = SM7150_MASTER_LLCC,
+       .channels = 2,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_EBI_CH0 },
+};
+
+static struct qcom_icc_node qhm_mnoc_cfg = {
+       .name = "qhm_mnoc_cfg",
+       .id = SM7150_MASTER_CNOC_MNOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_SERVICE_MNOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_hf = {
+       .name = "qxm_camnoc_hf",
+       .id = SM7150_MASTER_CAMNOC_HF0,
+       .channels = 2,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_nrt = {
+       .name = "qxm_camnoc_nrt",
+       .id = SM7150_MASTER_CAMNOC_NRT,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_rt = {
+       .name = "qxm_camnoc_rt",
+       .id = SM7150_MASTER_CAMNOC_RT,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_camnoc_sf = {
+       .name = "qxm_camnoc_sf",
+       .id = SM7150_MASTER_CAMNOC_SF,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_mdp0 = {
+       .name = "qxm_mdp0",
+       .id = SM7150_MASTER_MDP_PORT0,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_mdp1 = {
+       .name = "qxm_mdp1",
+       .id = SM7150_MASTER_MDP_PORT1,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_rot = {
+       .name = "qxm_rot",
+       .id = SM7150_MASTER_ROTATOR,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_venus0 = {
+       .name = "qxm_venus0",
+       .id = SM7150_MASTER_VIDEO_P0,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_venus1 = {
+       .name = "qxm_venus1",
+       .id = SM7150_MASTER_VIDEO_P1,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxm_venus_arm9 = {
+       .name = "qxm_venus_arm9",
+       .id = SM7150_MASTER_VIDEO_PROC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qhm_snoc_cfg = {
+       .name = "qhm_snoc_cfg",
+       .id = SM7150_MASTER_SNOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_SLAVE_SERVICE_SNOC },
+};
+
+static struct qcom_icc_node qnm_aggre1_noc = {
+       .name = "qnm_aggre1_noc",
+       .id = SM7150_A1NOC_SNOC_MAS,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 6,
+       .links = { SM7150_SLAVE_SNOC_GEM_NOC_SF,
+                  SM7150_SLAVE_PIMEM,
+                  SM7150_SLAVE_OCIMEM,
+                  SM7150_SLAVE_APPSS,
+                  SM7150_SNOC_CNOC_SLV,
+                  SM7150_SLAVE_QDSS_STM
+       },
+};
+
+static struct qcom_icc_node qnm_aggre2_noc = {
+       .name = "qnm_aggre2_noc",
+       .id = SM7150_A2NOC_SNOC_MAS,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 7,
+       .links = { SM7150_SLAVE_SNOC_GEM_NOC_SF,
+                  SM7150_SLAVE_PIMEM,
+                  SM7150_SLAVE_OCIMEM,
+                  SM7150_SLAVE_APPSS,
+                  SM7150_SNOC_CNOC_SLV,
+                  SM7150_SLAVE_TCU,
+                  SM7150_SLAVE_QDSS_STM
+       },
+};
+
+static struct qcom_icc_node qnm_gemnoc = {
+       .name = "qnm_gemnoc",
+       .id = SM7150_MASTER_GEM_NOC_SNOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 6,
+       .links = { SM7150_SLAVE_PIMEM,
+                  SM7150_SLAVE_OCIMEM,
+                  SM7150_SLAVE_APPSS,
+                  SM7150_SNOC_CNOC_SLV,
+                  SM7150_SLAVE_TCU,
+                  SM7150_SLAVE_QDSS_STM
+       },
+};
+
+static struct qcom_icc_node qxm_pimem = {
+       .name = "qxm_pimem",
+       .id = SM7150_MASTER_PIMEM,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_SNOC_GEM_NOC_GC,
+                  SM7150_SLAVE_OCIMEM
+       },
+};
+
+static struct qcom_icc_node xm_gic = {
+       .name = "xm_gic",
+       .id = SM7150_MASTER_GIC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 2,
+       .links = { SM7150_SLAVE_SNOC_GEM_NOC_GC,
+                  SM7150_SLAVE_OCIMEM
+       },
+};
+
+static struct qcom_icc_node qns_a1noc_snoc = {
+       .name = "qns_a1noc_snoc",
+       .id = SM7150_A1NOC_SNOC_SLV,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 1,
+       .links = { SM7150_A1NOC_SNOC_MAS },
+};
+
+static struct qcom_icc_node srvc_aggre1_noc = {
+       .name = "srvc_aggre1_noc",
+       .id = SM7150_SLAVE_SERVICE_A1NOC,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_a2noc_snoc = {
+       .name = "qns_a2noc_snoc",
+       .id = SM7150_A2NOC_SNOC_SLV,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 1,
+       .links = { SM7150_A2NOC_SNOC_MAS },
+};
+
+static struct qcom_icc_node qns_pcie_gemnoc = {
+       .name = "qns_pcie_gemnoc",
+       .id = SM7150_SLAVE_ANOC_PCIE_GEM_NOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node srvc_aggre2_noc = {
+       .name = "srvc_aggre2_noc",
+       .id = SM7150_SLAVE_SERVICE_A2NOC,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_camnoc_uncomp = {
+       .name = "qns_camnoc_uncomp",
+       .id = SM7150_SLAVE_CAMNOC_UNCOMP,
+       .channels = 1,
+       .buswidth = 32,
+};
+
+static struct qcom_icc_node qns_cdsp_gemnoc = {
+       .name = "qns_cdsp_gemnoc",
+       .id = SM7150_SLAVE_CDSP_GEM_NOC,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_MASTER_COMPUTE_NOC },
+};
+
+static struct qcom_icc_node qhs_a1_noc_cfg = {
+       .name = "qhs_a1_noc_cfg",
+       .id = SM7150_SLAVE_A1NOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_MASTER_A1NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_a2_noc_cfg = {
+       .name = "qhs_a2_noc_cfg",
+       .id = SM7150_SLAVE_A2NOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_MASTER_A2NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_ahb2phy_north = {
+       .name = "qhs_ahb2phy_north",
+       .id = SM7150_SLAVE_AHB2PHY_NORTH,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy_south = {
+       .name = "qhs_ahb2phy_south",
+       .id = SM7150_SLAVE_AHB2PHY_SOUTH,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ahb2phy_west = {
+       .name = "qhs_ahb2phy_west",
+       .id = SM7150_SLAVE_AHB2PHY_WEST,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_aop = {
+       .name = "qhs_aop",
+       .id = SM7150_SLAVE_AOP,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_aoss = {
+       .name = "qhs_aoss",
+       .id = SM7150_SLAVE_AOSS,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_cfg = {
+       .name = "qhs_camera_cfg",
+       .id = SM7150_SLAVE_CAMERA_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_nrt_thrott_cfg = {
+       .name = "qhs_camera_nrt_thrott_cfg",
+       .id = SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_camera_rt_throttle_cfg = {
+       .name = "qhs_camera_rt_throttle_cfg",
+       .id = SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+       .name = "qhs_clk_ctl",
+       .id = SM7150_SLAVE_CLK_CTL,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_compute_dsp_cfg = {
+       .name = "qhs_compute_dsp_cfg",
+       .id = SM7150_SLAVE_CDSP_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_cx = {
+       .name = "qhs_cpr_cx",
+       .id = SM7150_SLAVE_RBCPR_CX_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_cpr_mx = {
+       .name = "qhs_cpr_mx",
+       .id = SM7150_SLAVE_RBCPR_MX_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+       .name = "qhs_crypto0_cfg",
+       .id = SM7150_SLAVE_CRYPTO_0_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ddrss_cfg = {
+       .name = "qhs_ddrss_cfg",
+       .id = SM7150_SLAVE_CNOC_DDRSS,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_MASTER_CNOC_DC_NOC },
+};
+
+static struct qcom_icc_node qhs_display_cfg = {
+       .name = "qhs_display_cfg",
+       .id = SM7150_SLAVE_DISPLAY_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_display_throttle_cfg = {
+       .name = "qhs_display_throttle_cfg",
+       .id = SM7150_SLAVE_DISPLAY_THROTTLE_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_emmc_cfg = {
+       .name = "qhs_emmc_cfg",
+       .id = SM7150_SLAVE_EMMC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_glm = {
+       .name = "qhs_glm",
+       .id = SM7150_SLAVE_GLM,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gpuss_cfg = {
+       .name = "qhs_gpuss_cfg",
+       .id = SM7150_SLAVE_GRAPHICS_3D_CFG,
+       .channels = 1,
+       .buswidth = 8,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+       .name = "qhs_imem_cfg",
+       .id = SM7150_SLAVE_IMEM_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ipa = {
+       .name = "qhs_ipa",
+       .id = SM7150_SLAVE_IPA_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_mnoc_cfg = {
+       .name = "qhs_mnoc_cfg",
+       .id = SM7150_SLAVE_CNOC_MNOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_MASTER_CNOC_MNOC_CFG },
+};
+
+static struct qcom_icc_node qhs_pcie_cfg = {
+       .name = "qhs_pcie_cfg",
+       .id = SM7150_SLAVE_PCIE_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+       .name = "qhs_pdm",
+       .id = SM7150_SLAVE_PDM,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_pimem_cfg = {
+       .name = "qhs_pimem_cfg",
+       .id = SM7150_SLAVE_PIMEM_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_prng = {
+       .name = "qhs_prng",
+       .id = SM7150_SLAVE_PRNG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+       .name = "qhs_qdss_cfg",
+       .id = SM7150_SLAVE_QDSS_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qupv3_center = {
+       .name = "qhs_qupv3_center",
+       .id = SM7150_SLAVE_QUP_0,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_qupv3_north = {
+       .name = "qhs_qupv3_north",
+       .id = SM7150_SLAVE_QUP_1,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_sdc2 = {
+       .name = "qhs_sdc2",
+       .id = SM7150_SLAVE_SDCC_2,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_sdc4 = {
+       .name = "qhs_sdc4",
+       .id = SM7150_SLAVE_SDCC_4,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_snoc_cfg = {
+       .name = "qhs_snoc_cfg",
+       .id = SM7150_SLAVE_SNOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_MASTER_SNOC_CFG },
+};
+
+static struct qcom_icc_node qhs_spdm = {
+       .name = "qhs_spdm",
+       .id = SM7150_SLAVE_SPDM_WRAPPER,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+       .name = "qhs_tcsr",
+       .id = SM7150_SLAVE_TCSR,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm_north = {
+       .name = "qhs_tlmm_north",
+       .id = SM7150_SLAVE_TLMM_NORTH,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm_south = {
+       .name = "qhs_tlmm_south",
+       .id = SM7150_SLAVE_TLMM_SOUTH,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tlmm_west = {
+       .name = "qhs_tlmm_west",
+       .id = SM7150_SLAVE_TLMM_WEST,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_tsif = {
+       .name = "qhs_tsif",
+       .id = SM7150_SLAVE_TSIF,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_ufs_mem_cfg = {
+       .name = "qhs_ufs_mem_cfg",
+       .id = SM7150_SLAVE_UFS_MEM_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_usb3_0 = {
+       .name = "qhs_usb3_0",
+       .id = SM7150_SLAVE_USB3,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+       .name = "qhs_venus_cfg",
+       .id = SM7150_SLAVE_VENUS_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_cvp_throttle_cfg = {
+       .name = "qhs_venus_cvp_throttle_cfg",
+       .id = SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_venus_throttle_cfg = {
+       .name = "qhs_venus_throttle_cfg",
+       .id = SM7150_SLAVE_VENUS_THROTTLE_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_vsense_ctrl_cfg = {
+       .name = "qhs_vsense_ctrl_cfg",
+       .id = SM7150_SLAVE_VSENSE_CTRL_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_cnoc_a2noc = {
+       .name = "qns_cnoc_a2noc",
+       .id = SM7150_SLAVE_CNOC_A2NOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_MASTER_CNOC_A2NOC },
+};
+
+static struct qcom_icc_node srvc_cnoc = {
+       .name = "srvc_cnoc",
+       .id = SM7150_SLAVE_SERVICE_CNOC,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_gemnoc = {
+       .name = "qhs_gemnoc",
+       .id = SM7150_SLAVE_GEM_NOC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+       .num_links = 1,
+       .links = { SM7150_MASTER_GEM_NOC_CFG },
+};
+
+static struct qcom_icc_node qhs_llcc = {
+       .name = "qhs_llcc",
+       .id = SM7150_SLAVE_LLCC_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_mdsp_ms_mpu_cfg = {
+       .name = "qhs_mdsp_ms_mpu_cfg",
+       .id = SM7150_SLAVE_MSS_PROC_MS_MPU_CFG,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qns_gem_noc_snoc = {
+       .name = "qns_gem_noc_snoc",
+       .id = SM7150_SLAVE_GEM_NOC_SNOC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_MASTER_GEM_NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+       .name = "qns_llcc",
+       .id = SM7150_SLAVE_LLCC,
+       .channels = 2,
+       .buswidth = 16,
+       .num_links = 1,
+       .links = { SM7150_MASTER_LLCC },
+};
+
+static struct qcom_icc_node srvc_gemnoc = {
+       .name = "srvc_gemnoc",
+       .id = SM7150_SLAVE_SERVICE_GEM_NOC,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node ebi = {
+       .name = "ebi",
+       .id = SM7150_SLAVE_EBI_CH0,
+       .channels = 2,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qns2_mem_noc = {
+       .name = "qns2_mem_noc",
+       .id = SM7150_SLAVE_MNOC_SF_MEM_NOC,
+       .channels = 1,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_MASTER_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_mem_noc_hf = {
+       .name = "qns_mem_noc_hf",
+       .id = SM7150_SLAVE_MNOC_HF_MEM_NOC,
+       .channels = 2,
+       .buswidth = 32,
+       .num_links = 1,
+       .links = { SM7150_MASTER_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_mnoc = {
+       .name = "srvc_mnoc",
+       .id = SM7150_SLAVE_SERVICE_MNOC,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node qhs_apss = {
+       .name = "qhs_apss",
+       .id = SM7150_SLAVE_APPSS,
+       .channels = 1,
+       .buswidth = 8,
+};
+
+static struct qcom_icc_node qns_cnoc = {
+       .name = "qns_cnoc",
+       .id = SM7150_SNOC_CNOC_SLV,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_SNOC_CNOC_MAS },
+};
+
+static struct qcom_icc_node qns_gemnoc_gc = {
+       .name = "qns_gemnoc_gc",
+       .id = SM7150_SLAVE_SNOC_GEM_NOC_GC,
+       .channels = 1,
+       .buswidth = 8,
+       .num_links = 1,
+       .links = { SM7150_MASTER_SNOC_GC_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+       .name = "qns_gemnoc_sf",
+       .id = SM7150_SLAVE_SNOC_GEM_NOC_SF,
+       .channels = 1,
+       .buswidth = 16,
+       .num_links = 1,
+       .links = { SM7150_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qxs_imem = {
+       .name = "qxs_imem",
+       .id = SM7150_SLAVE_OCIMEM,
+       .channels = 1,
+       .buswidth = 8,
+};
+
+static struct qcom_icc_node qxs_pimem = {
+       .name = "qxs_pimem",
+       .id = SM7150_SLAVE_PIMEM,
+       .channels = 1,
+       .buswidth = 8,
+};
+
+static struct qcom_icc_node srvc_snoc = {
+       .name = "srvc_snoc",
+       .id = SM7150_SLAVE_SERVICE_SNOC,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+       .name = "xs_qdss_stm",
+       .id = SM7150_SLAVE_QDSS_STM,
+       .channels = 1,
+       .buswidth = 4,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+       .name = "xs_sys_tcu_cfg",
+       .id = SM7150_SLAVE_TCU,
+       .channels = 1,
+       .buswidth = 8,
+};
+
+static struct qcom_icc_bcm bcm_acv = {
+       .name = "ACV",
+       .enable_mask = BIT(3),
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+       .name = "MC0",
+       .keepalive = true,
+       .num_nodes = 1,
+       .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+       .name = "SH0",
+       .keepalive = true,
+       .num_nodes = 1,
+       .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_mm0 = {
+       .name = "MM0",
+       .keepalive = true,
+       .num_nodes = 1,
+       .nodes = { &qns_mem_noc_hf },
+};
+
+static struct qcom_icc_bcm bcm_mm1 = {
+       .name = "MM1",
+       .keepalive = true,
+       .num_nodes = 8,
+       .nodes = { &qxm_camnoc_hf0_uncomp,
+                  &qxm_camnoc_rt_uncomp,
+                  &qxm_camnoc_sf_uncomp,
+                  &qxm_camnoc_nrt_uncomp,
+                  &qxm_camnoc_hf,
+                  &qxm_camnoc_rt,
+                  &qxm_mdp0,
+                  &qxm_mdp1
+       },
+};
+
+static struct qcom_icc_bcm bcm_sh2 = {
+       .name = "SH2",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qns_gem_noc_snoc },
+};
+
+static struct qcom_icc_bcm bcm_sh3 = {
+       .name = "SH3",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &acm_sys_tcu },
+};
+
+static struct qcom_icc_bcm bcm_mm2 = {
+       .name = "MM2",
+       .keepalive = false,
+       .num_nodes = 2,
+       .nodes = { &qxm_camnoc_nrt,
+                  &qns2_mem_noc
+       },
+};
+
+static struct qcom_icc_bcm bcm_mm3 = {
+       .name = "MM3",
+       .keepalive = false,
+       .num_nodes = 5,
+       .nodes = { &qxm_camnoc_sf,
+                  &qxm_rot,
+                  &qxm_venus0,
+                  &qxm_venus1,
+                  &qxm_venus_arm9
+       },
+};
+
+static struct qcom_icc_bcm bcm_sh5 = {
+       .name = "SH5",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &acm_apps },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+       .name = "SN0",
+       .keepalive = true,
+       .num_nodes = 1,
+       .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sh8 = {
+       .name = "SH8",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qns_cdsp_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_sh10 = {
+       .name = "SH10",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qnm_npu },
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+       .name = "CE0",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qxm_crypto },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+       .name = "CN0",
+       .keepalive = true,
+       .num_nodes = 54,
+       .nodes = { &qhm_tsif,
+                  &xm_emmc,
+                  &xm_sdc2,
+                  &xm_sdc4,
+                  &qhm_spdm,
+                  &qnm_snoc,
+                  &qhs_a1_noc_cfg,
+                  &qhs_a2_noc_cfg,
+                  &qhs_ahb2phy_north,
+                  &qhs_ahb2phy_south,
+                  &qhs_ahb2phy_west,
+                  &qhs_aop,
+                  &qhs_aoss,
+                  &qhs_camera_cfg,
+                  &qhs_camera_nrt_thrott_cfg,
+                  &qhs_camera_rt_throttle_cfg,
+                  &qhs_clk_ctl,
+                  &qhs_compute_dsp_cfg,
+                  &qhs_cpr_cx,
+                  &qhs_cpr_mx,
+                  &qhs_crypto0_cfg,
+                  &qhs_ddrss_cfg,
+                  &qhs_display_cfg,
+                  &qhs_display_throttle_cfg,
+                  &qhs_emmc_cfg,
+                  &qhs_glm,
+                  &qhs_gpuss_cfg,
+                  &qhs_imem_cfg,
+                  &qhs_ipa,
+                  &qhs_mnoc_cfg,
+                  &qhs_pcie_cfg,
+                  &qhs_pdm,
+                  &qhs_pimem_cfg,
+                  &qhs_prng,
+                  &qhs_qdss_cfg,
+                  &qhs_qupv3_center,
+                  &qhs_qupv3_north,
+                  &qhs_sdc2,
+                  &qhs_sdc4,
+                  &qhs_snoc_cfg,
+                  &qhs_spdm,
+                  &qhs_tcsr,
+                  &qhs_tlmm_north,
+                  &qhs_tlmm_south,
+                  &qhs_tlmm_west,
+                  &qhs_tsif,
+                  &qhs_ufs_mem_cfg,
+                  &qhs_usb3_0,
+                  &qhs_venus_cfg,
+                  &qhs_venus_cvp_throttle_cfg,
+                  &qhs_venus_throttle_cfg,
+                  &qhs_vsense_ctrl_cfg,
+                  &qns_cnoc_a2noc,
+                  &srvc_cnoc
+       },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+       .name = "QUP0",
+       .keepalive = false,
+       .num_nodes = 2,
+       .nodes = { &qhm_qup_center,
+                  &qhm_qup_north
+       },
+};
+
+static struct qcom_icc_bcm bcm_sn1 = {
+       .name = "SN1",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qxs_imem },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+       .name = "SN2",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qns_gemnoc_gc },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+       .name = "SN4",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qxs_pimem },
+};
+
+static struct qcom_icc_bcm bcm_sn9 = {
+       .name = "SN9",
+       .keepalive = false,
+       .num_nodes = 2,
+       .nodes = { &qnm_aggre1_noc,
+                  &qns_a1noc_snoc
+       },
+};
+
+static struct qcom_icc_bcm bcm_sn11 = {
+       .name = "SN11",
+       .keepalive = false,
+       .num_nodes = 2,
+       .nodes = { &qnm_aggre2_noc,
+                  &qns_a2noc_snoc
+       },
+};
+
+static struct qcom_icc_bcm bcm_sn12 = {
+       .name = "SN12",
+       .keepalive = false,
+       .num_nodes = 2,
+       .nodes = { &qxm_pimem,
+                  &xm_gic
+       },
+};
+
+static struct qcom_icc_bcm bcm_sn14 = {
+       .name = "SN14",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qns_pcie_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_sn15 = {
+       .name = "SN15",
+       .keepalive = false,
+       .num_nodes = 1,
+       .nodes = { &qnm_gemnoc },
+};
+
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
+       &bcm_cn0,
+       &bcm_qup0,
+       &bcm_sn9,
+};
+
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
+       [MASTER_A1NOC_CFG] = &qhm_a1noc_cfg,
+       [MASTER_QUP_0] = &qhm_qup_center,
+       [MASTER_TSIF] = &qhm_tsif,
+       [MASTER_EMMC] = &xm_emmc,
+       [MASTER_SDCC_2] = &xm_sdc2,
+       [MASTER_SDCC_4] = &xm_sdc4,
+       [MASTER_UFS_MEM] = &xm_ufs_mem,
+       [A1NOC_SNOC_SLV] = &qns_a1noc_snoc,
+       [SLAVE_SERVICE_A1NOC] = &srvc_aggre1_noc,
+};
+
+static const struct qcom_icc_desc sm7150_aggre1_noc = {
+       .nodes = aggre1_noc_nodes,
+       .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+       .bcms = aggre1_noc_bcms,
+       .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
+       &bcm_ce0,
+       &bcm_qup0,
+       &bcm_sn11,
+       &bcm_sn14,
+};
+
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
+       [MASTER_A2NOC_CFG] = &qhm_a2noc_cfg,
+       [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+       [MASTER_QUP_1] = &qhm_qup_north,
+       [MASTER_CNOC_A2NOC] = &qnm_cnoc,
+       [MASTER_CRYPTO_CORE_0] = &qxm_crypto,
+       [MASTER_IPA] = &qxm_ipa,
+       [MASTER_PCIE] = &xm_pcie3_0,
+       [MASTER_QDSS_ETR] = &xm_qdss_etr,
+       [MASTER_USB3] = &xm_usb3_0,
+       [A2NOC_SNOC_SLV] = &qns_a2noc_snoc,
+       [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_gemnoc,
+       [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc,
+};
+
+static const struct qcom_icc_desc sm7150_aggre2_noc = {
+       .nodes = aggre2_noc_nodes,
+       .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+       .bcms = aggre2_noc_bcms,
+       .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const camnoc_virt_bcms[] = {
+       &bcm_mm1,
+};
+
+static struct qcom_icc_node * const camnoc_virt_nodes[] = {
+       [MASTER_CAMNOC_HF0_UNCOMP] = &qxm_camnoc_hf0_uncomp,
+       [MASTER_CAMNOC_RT_UNCOMP] = &qxm_camnoc_rt_uncomp,
+       [MASTER_CAMNOC_SF_UNCOMP] = &qxm_camnoc_sf_uncomp,
+       [MASTER_CAMNOC_NRT_UNCOMP] = &qxm_camnoc_nrt_uncomp,
+       [SLAVE_CAMNOC_UNCOMP] = &qns_camnoc_uncomp,
+};
+
+static const struct qcom_icc_desc sm7150_camnoc_virt = {
+       .nodes = camnoc_virt_nodes,
+       .num_nodes = ARRAY_SIZE(camnoc_virt_nodes),
+       .bcms = camnoc_virt_bcms,
+       .num_bcms = ARRAY_SIZE(camnoc_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const compute_noc_bcms[] = {
+       &bcm_sh10,
+       &bcm_sh8,
+};
+
+static struct qcom_icc_node * const compute_noc_nodes[] = {
+       [MASTER_NPU] = &qnm_npu,
+       [SLAVE_CDSP_GEM_NOC] = &qns_cdsp_gemnoc,
+};
+
+static const struct qcom_icc_desc sm7150_compute_noc = {
+       .nodes = compute_noc_nodes,
+       .num_nodes = ARRAY_SIZE(compute_noc_nodes),
+       .bcms = compute_noc_bcms,
+       .num_bcms = ARRAY_SIZE(compute_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const config_noc_bcms[] = {
+       &bcm_cn0,
+};
+
+static struct qcom_icc_node * const config_noc_nodes[] = {
+       [MASTER_SPDM] = &qhm_spdm,
+       [SNOC_CNOC_MAS] = &qnm_snoc,
+       [MASTER_QDSS_DAP] = &xm_qdss_dap,
+       [SLAVE_A1NOC_CFG] = &qhs_a1_noc_cfg,
+       [SLAVE_A2NOC_CFG] = &qhs_a2_noc_cfg,
+       [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy_north,
+       [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy_south,
+       [SLAVE_AHB2PHY_WEST] = &qhs_ahb2phy_west,
+       [SLAVE_AOP] = &qhs_aop,
+       [SLAVE_AOSS] = &qhs_aoss,
+       [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+       [SLAVE_CAMERA_NRT_THROTTLE_CFG] = &qhs_camera_nrt_thrott_cfg,
+       [SLAVE_CAMERA_RT_THROTTLE_CFG] = &qhs_camera_rt_throttle_cfg,
+       [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+       [SLAVE_CDSP_CFG] = &qhs_compute_dsp_cfg,
+       [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+       [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx,
+       [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+       [SLAVE_CNOC_DDRSS] = &qhs_ddrss_cfg,
+       [SLAVE_DISPLAY_CFG] = &qhs_display_cfg,
+       [SLAVE_DISPLAY_THROTTLE_CFG] = &qhs_display_throttle_cfg,
+       [SLAVE_EMMC_CFG] = &qhs_emmc_cfg,
+       [SLAVE_GLM] = &qhs_glm,
+       [SLAVE_GRAPHICS_3D_CFG] = &qhs_gpuss_cfg,
+       [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+       [SLAVE_IPA_CFG] = &qhs_ipa,
+       [SLAVE_CNOC_MNOC_CFG] = &qhs_mnoc_cfg,
+       [SLAVE_PCIE_CFG] = &qhs_pcie_cfg,
+       [SLAVE_PDM] = &qhs_pdm,
+       [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg,
+       [SLAVE_PRNG] = &qhs_prng,
+       [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+       [SLAVE_QUP_0] = &qhs_qupv3_center,
+       [SLAVE_QUP_1] = &qhs_qupv3_north,
+       [SLAVE_SDCC_2] = &qhs_sdc2,
+       [SLAVE_SDCC_4] = &qhs_sdc4,
+       [SLAVE_SNOC_CFG] = &qhs_snoc_cfg,
+       [SLAVE_SPDM_WRAPPER] = &qhs_spdm,
+       [SLAVE_TCSR] = &qhs_tcsr,
+       [SLAVE_TLMM_NORTH] = &qhs_tlmm_north,
+       [SLAVE_TLMM_SOUTH] = &qhs_tlmm_south,
+       [SLAVE_TLMM_WEST] = &qhs_tlmm_west,
+       [SLAVE_TSIF] = &qhs_tsif,
+       [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+       [SLAVE_USB3] = &qhs_usb3_0,
+       [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+       [SLAVE_VENUS_CVP_THROTTLE_CFG] = &qhs_venus_cvp_throttle_cfg,
+       [SLAVE_VENUS_THROTTLE_CFG] = &qhs_venus_throttle_cfg,
+       [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg,
+       [SLAVE_CNOC_A2NOC] = &qns_cnoc_a2noc,
+       [SLAVE_SERVICE_CNOC] = &srvc_cnoc,
+};
+
+static const struct qcom_icc_desc sm7150_config_noc = {
+       .nodes = config_noc_nodes,
+       .num_nodes = ARRAY_SIZE(config_noc_nodes),
+       .bcms = config_noc_bcms,
+       .num_bcms = ARRAY_SIZE(config_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const dc_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const dc_noc_nodes[] = {
+       [MASTER_CNOC_DC_NOC] = &qhm_cnoc_dc_noc,
+       [SLAVE_GEM_NOC_CFG] = &qhs_gemnoc,
+       [SLAVE_LLCC_CFG] = &qhs_llcc,
+};
+
+static const struct qcom_icc_desc sm7150_dc_noc = {
+       .nodes = dc_noc_nodes,
+       .num_nodes = ARRAY_SIZE(dc_noc_nodes),
+       .bcms = dc_noc_bcms,
+       .num_bcms = ARRAY_SIZE(dc_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
+       &bcm_sh0,
+       &bcm_sh2,
+       &bcm_sh3,
+       &bcm_sh5,
+};
+
+static struct qcom_icc_node * const gem_noc_nodes[] = {
+       [MASTER_AMPSS_M0] = &acm_apps,
+       [MASTER_SYS_TCU] = &acm_sys_tcu,
+       [MASTER_GEM_NOC_CFG] = &qhm_gemnoc_cfg,
+       [MASTER_COMPUTE_NOC] = &qnm_cmpnoc,
+       [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+       [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+       [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_pcie,
+       [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
+       [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+       [MASTER_GRAPHICS_3D] = &qxm_gpu,
+       [SLAVE_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg,
+       [SLAVE_GEM_NOC_SNOC] = &qns_gem_noc_snoc,
+       [SLAVE_LLCC] = &qns_llcc,
+       [SLAVE_SERVICE_GEM_NOC] = &srvc_gemnoc,
+};
+
+static const struct qcom_icc_desc sm7150_gem_noc = {
+       .nodes = gem_noc_nodes,
+       .num_nodes = ARRAY_SIZE(gem_noc_nodes),
+       .bcms = gem_noc_bcms,
+       .num_bcms = ARRAY_SIZE(gem_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
+       &bcm_acv,
+       &bcm_mc0,
+};
+
+static struct qcom_icc_node * const mc_virt_nodes[] = {
+       [MASTER_LLCC] = &llcc_mc,
+       [SLAVE_EBI_CH0] = &ebi,
+};
+
+static const struct qcom_icc_desc sm7150_mc_virt = {
+       .nodes = mc_virt_nodes,
+       .num_nodes = ARRAY_SIZE(mc_virt_nodes),
+       .bcms = mc_virt_bcms,
+       .num_bcms = ARRAY_SIZE(mc_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
+       &bcm_mm0,
+       &bcm_mm1,
+       &bcm_mm2,
+       &bcm_mm3,
+};
+
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
+       [MASTER_CNOC_MNOC_CFG] = &qhm_mnoc_cfg,
+       [MASTER_CAMNOC_HF0] = &qxm_camnoc_hf,
+       [MASTER_CAMNOC_NRT] = &qxm_camnoc_nrt,
+       [MASTER_CAMNOC_RT] = &qxm_camnoc_rt,
+       [MASTER_CAMNOC_SF] = &qxm_camnoc_sf,
+       [MASTER_MDP_PORT0] = &qxm_mdp0,
+       [MASTER_MDP_PORT1] = &qxm_mdp1,
+       [MASTER_ROTATOR] = &qxm_rot,
+       [MASTER_VIDEO_P0] = &qxm_venus0,
+       [MASTER_VIDEO_P1] = &qxm_venus1,
+       [MASTER_VIDEO_PROC] = &qxm_venus_arm9,
+       [SLAVE_MNOC_SF_MEM_NOC] = &qns2_mem_noc,
+       [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+       [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
+};
+
+static const struct qcom_icc_desc sm7150_mmss_noc = {
+       .nodes = mmss_noc_nodes,
+       .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+       .bcms = mmss_noc_bcms,
+       .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
+       &bcm_sn0,
+       &bcm_sn1,
+       &bcm_sn11,
+       &bcm_sn12,
+       &bcm_sn15,
+       &bcm_sn2,
+       &bcm_sn4,
+       &bcm_sn9,
+};
+
+static struct qcom_icc_node * const system_noc_nodes[] = {
+       [MASTER_SNOC_CFG] = &qhm_snoc_cfg,
+       [A1NOC_SNOC_MAS] = &qnm_aggre1_noc,
+       [A2NOC_SNOC_MAS] = &qnm_aggre2_noc,
+       [MASTER_GEM_NOC_SNOC] = &qnm_gemnoc,
+       [MASTER_PIMEM] = &qxm_pimem,
+       [MASTER_GIC] = &xm_gic,
+       [SLAVE_APPSS] = &qhs_apss,
+       [SNOC_CNOC_SLV] = &qns_cnoc,
+       [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc,
+       [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+       [SLAVE_OCIMEM] = &qxs_imem,
+       [SLAVE_PIMEM] = &qxs_pimem,
+       [SLAVE_SERVICE_SNOC] = &srvc_snoc,
+       [SLAVE_QDSS_STM] = &xs_qdss_stm,
+       [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static const struct qcom_icc_desc sm7150_system_noc = {
+       .nodes = system_noc_nodes,
+       .num_nodes = ARRAY_SIZE(system_noc_nodes),
+       .bcms = system_noc_bcms,
+       .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+       { .compatible = "qcom,sm7150-aggre1-noc", .data = &sm7150_aggre1_noc },
+       { .compatible = "qcom,sm7150-aggre2-noc", .data = &sm7150_aggre2_noc },
+       { .compatible = "qcom,sm7150-camnoc-virt", .data = &sm7150_camnoc_virt },
+       { .compatible = "qcom,sm7150-compute-noc", .data = &sm7150_compute_noc },
+       { .compatible = "qcom,sm7150-config-noc", .data = &sm7150_config_noc },
+       { .compatible = "qcom,sm7150-dc-noc", .data = &sm7150_dc_noc },
+       { .compatible = "qcom,sm7150-gem-noc", .data = &sm7150_gem_noc },
+       { .compatible = "qcom,sm7150-mc-virt", .data = &sm7150_mc_virt },
+       { .compatible = "qcom,sm7150-mmss-noc", .data = &sm7150_mmss_noc },
+       { .compatible = "qcom,sm7150-system-noc", .data = &sm7150_system_noc },
+       { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+       .probe = qcom_icc_rpmh_probe,
+       .remove_new = qcom_icc_rpmh_remove,
+       .driver = {
+               .name = "qnoc-sm7150",
+               .of_match_table = qnoc_of_match,
+               .sync_state = icc_sync_state,
+       },
+};
+
+static int __init qnoc_driver_init(void)
+{
+       return platform_driver_register(&qnoc_driver);
+}
+core_initcall(qnoc_driver_init);
+
+static void __exit qnoc_driver_exit(void)
+{
+       platform_driver_unregister(&qnoc_driver);
+}
+module_exit(qnoc_driver_exit);
+
+MODULE_DESCRIPTION("Qualcomm SM7150 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sm7150.h b/drivers/interconnect/qcom/sm7150.h
new file mode 100644 (file)
index 0000000..e00a9b0
--- /dev/null
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Qualcomm #define SM7150 interconnect IDs
+ *
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SM7150_H
+#define __DRIVERS_INTERCONNECT_QCOM_SM7150_H
+
+#define SM7150_A1NOC_SNOC_MAS                  0
+#define SM7150_A1NOC_SNOC_SLV                  1
+#define SM7150_A2NOC_SNOC_MAS                  2
+#define SM7150_A2NOC_SNOC_SLV                  3
+#define SM7150_MASTER_A1NOC_CFG                        4
+#define SM7150_MASTER_A2NOC_CFG                        5
+#define SM7150_MASTER_AMPSS_M0                 6
+#define SM7150_MASTER_CAMNOC_HF0               7
+#define SM7150_MASTER_CAMNOC_HF0_UNCOMP                8
+#define SM7150_MASTER_CAMNOC_NRT               9
+#define SM7150_MASTER_CAMNOC_NRT_UNCOMP                10
+#define SM7150_MASTER_CAMNOC_RT                        11
+#define SM7150_MASTER_CAMNOC_RT_UNCOMP         12
+#define SM7150_MASTER_CAMNOC_SF                        13
+#define SM7150_MASTER_CAMNOC_SF_UNCOMP         14
+#define SM7150_MASTER_CNOC_A2NOC               15
+#define SM7150_MASTER_CNOC_DC_NOC              16
+#define SM7150_MASTER_CNOC_MNOC_CFG            17
+#define SM7150_MASTER_COMPUTE_NOC              18
+#define SM7150_MASTER_CRYPTO_CORE_0            19
+#define SM7150_MASTER_EMMC                     20
+#define SM7150_MASTER_GEM_NOC_CFG              21
+#define SM7150_MASTER_GEM_NOC_PCIE_SNOC                22
+#define SM7150_MASTER_GEM_NOC_SNOC             23
+#define SM7150_MASTER_GIC                      24
+#define SM7150_MASTER_GRAPHICS_3D              25
+#define SM7150_MASTER_IPA                      26
+#define SM7150_MASTER_LLCC                     27
+#define SM7150_MASTER_MDP_PORT0                        28
+#define SM7150_MASTER_MDP_PORT1                        29
+#define SM7150_MASTER_MNOC_HF_MEM_NOC          30
+#define SM7150_MASTER_MNOC_SF_MEM_NOC          31
+#define SM7150_MASTER_NPU                      32
+#define SM7150_MASTER_PCIE                     33
+#define SM7150_MASTER_PIMEM                    34
+#define SM7150_MASTER_QDSS_BAM                 35
+#define SM7150_MASTER_QDSS_DAP                 36
+#define SM7150_MASTER_QDSS_ETR                 37
+#define SM7150_MASTER_QUP_0                    38
+#define SM7150_MASTER_QUP_1                    39
+#define SM7150_MASTER_ROTATOR                  40
+#define SM7150_MASTER_SDCC_2                   41
+#define SM7150_MASTER_SDCC_4                   42
+#define SM7150_MASTER_SNOC_CFG                 43
+#define SM7150_MASTER_SNOC_GC_MEM_NOC          44
+#define SM7150_MASTER_SNOC_SF_MEM_NOC          45
+#define SM7150_MASTER_SPDM                     46
+#define SM7150_MASTER_SYS_TCU                  47
+#define SM7150_MASTER_TSIF                     48
+#define SM7150_MASTER_UFS_MEM                  49
+#define SM7150_MASTER_USB3                     50
+#define SM7150_MASTER_VIDEO_P0                 51
+#define SM7150_MASTER_VIDEO_P1                 52
+#define SM7150_MASTER_VIDEO_PROC               53
+#define SM7150_SLAVE_A1NOC_CFG                 54
+#define SM7150_SLAVE_A2NOC_CFG                 55
+#define SM7150_SLAVE_AHB2PHY_NORTH             56
+#define SM7150_SLAVE_AHB2PHY_SOUTH             57
+#define SM7150_SLAVE_AHB2PHY_WEST              58
+#define SM7150_SLAVE_ANOC_PCIE_GEM_NOC         59
+#define SM7150_SLAVE_AOP                       60
+#define SM7150_SLAVE_AOSS                      61
+#define SM7150_SLAVE_APPSS                     62
+#define SM7150_SLAVE_CAMERA_CFG                        63
+#define SM7150_SLAVE_CAMERA_NRT_THROTTLE_CFG   64
+#define SM7150_SLAVE_CAMERA_RT_THROTTLE_CFG    65
+#define SM7150_SLAVE_CAMNOC_UNCOMP             66
+#define SM7150_SLAVE_CDSP_CFG                  67
+#define SM7150_SLAVE_CDSP_GEM_NOC              68
+#define SM7150_SLAVE_CLK_CTL                   69
+#define SM7150_SLAVE_CNOC_A2NOC                        70
+#define SM7150_SLAVE_CNOC_DDRSS                        71
+#define SM7150_SLAVE_CNOC_MNOC_CFG             72
+#define SM7150_SLAVE_CRYPTO_0_CFG              73
+#define SM7150_SLAVE_DISPLAY_CFG               74
+#define SM7150_SLAVE_DISPLAY_THROTTLE_CFG      75
+#define SM7150_SLAVE_EBI_CH0                   76
+#define SM7150_SLAVE_EMMC_CFG                  77
+#define SM7150_SLAVE_GEM_NOC_CFG               78
+#define SM7150_SLAVE_GEM_NOC_SNOC              79
+#define SM7150_SLAVE_GLM                       80
+#define SM7150_SLAVE_GRAPHICS_3D_CFG           81
+#define SM7150_SLAVE_IMEM_CFG                  82
+#define SM7150_SLAVE_IPA_CFG                   83
+#define SM7150_SLAVE_LLCC                      84
+#define SM7150_SLAVE_LLCC_CFG                  85
+#define SM7150_SLAVE_MNOC_HF_MEM_NOC           86
+#define SM7150_SLAVE_MNOC_SF_MEM_NOC           87
+#define SM7150_SLAVE_MSS_PROC_MS_MPU_CFG       88
+#define SM7150_SLAVE_OCIMEM                    89
+#define SM7150_SLAVE_PCIE_CFG                  90
+#define SM7150_SLAVE_PDM                       91
+#define SM7150_SLAVE_PIMEM                     92
+#define SM7150_SLAVE_PIMEM_CFG                 93
+#define SM7150_SLAVE_PRNG                      94
+#define SM7150_SLAVE_QDSS_CFG                  95
+#define SM7150_SLAVE_QDSS_STM                  96
+#define SM7150_SLAVE_QUP_0                     97
+#define SM7150_SLAVE_QUP_1                     98
+#define SM7150_SLAVE_RBCPR_CX_CFG              99
+#define SM7150_SLAVE_RBCPR_MX_CFG              100
+#define SM7150_SLAVE_SDCC_2                    101
+#define SM7150_SLAVE_SDCC_4                    102
+#define SM7150_SLAVE_SERVICE_A1NOC             103
+#define SM7150_SLAVE_SERVICE_A2NOC             104
+#define SM7150_SLAVE_SERVICE_CNOC              105
+#define SM7150_SLAVE_SERVICE_GEM_NOC           106
+#define SM7150_SLAVE_SERVICE_MNOC              107
+#define SM7150_SLAVE_SERVICE_SNOC              108
+#define SM7150_SLAVE_SNOC_CFG                  109
+#define SM7150_SLAVE_SNOC_GEM_NOC_GC           110
+#define SM7150_SLAVE_SNOC_GEM_NOC_SF           111
+#define SM7150_SLAVE_SPDM_WRAPPER              112
+#define SM7150_SLAVE_TCSR                      113
+#define SM7150_SLAVE_TCU                       114
+#define SM7150_SLAVE_TLMM_NORTH                        115
+#define SM7150_SLAVE_TLMM_SOUTH                        116
+#define SM7150_SLAVE_TLMM_WEST                 117
+#define SM7150_SLAVE_TSIF                      118
+#define SM7150_SLAVE_UFS_MEM_CFG               119
+#define SM7150_SLAVE_USB3                      120
+#define SM7150_SLAVE_VENUS_CFG                 121
+#define SM7150_SLAVE_VENUS_CVP_THROTTLE_CFG    122
+#define SM7150_SLAVE_VENUS_THROTTLE_CFG                123
+#define SM7150_SLAVE_VSENSE_CTRL_CFG           124
+#define SM7150_SNOC_CNOC_MAS                   125
+#define SM7150_SNOC_CNOC_SLV                   126
+
+#endif
index 02d40eea0d6964de9a24bdf766eb51095f009981..1879fa15761f5e73ad45852130da72750b5713b6 100644 (file)
@@ -1673,7 +1673,7 @@ static struct qcom_icc_bcm * const qup_virt_bcms[] = {
        &bcm_qup0,
 };
 
-static struct qcom_icc_node *qup_virt_nodes[] = {
+static struct qcom_icc_node * const qup_virt_nodes[] = {
        [MASTER_QUP_CORE_0] = &qup0_core_master,
        [MASTER_QUP_CORE_1] = &qup1_core_master,
        [MASTER_QUP_CORE_2] = &qup2_core_master,
index fc22cecf650fc4eedaf3970a6a8f025f7e9d849e..4d0e6fa9e003bde70eecbe154863743aeb33632a 100644 (file)
@@ -524,231 +524,6 @@ static struct qcom_icc_node xm_gic = {
        .links = { SM8550_SLAVE_SNOC_GEM_NOC_GC },
 };
 
-static struct qcom_icc_node qnm_mnoc_hf_disp = {
-       .name = "qnm_mnoc_hf_disp",
-       .id = SM8550_MASTER_MNOC_HF_MEM_NOC_DISP,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node qnm_pcie_disp = {
-       .name = "qnm_pcie_disp",
-       .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_DISP,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node llcc_mc_disp = {
-       .name = "llcc_mc_disp",
-       .id = SM8550_MASTER_LLCC_DISP,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_EBI1_DISP },
-};
-
-static struct qcom_icc_node qnm_mdp_disp = {
-       .name = "qnm_mdp_disp",
-       .id = SM8550_MASTER_MDP_DISP,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qnm_mnoc_hf_cam_ife_0 = {
-       .name = "qnm_mnoc_hf_cam_ife_0",
-       .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_mnoc_sf_cam_ife_0 = {
-       .name = "qnm_mnoc_sf_cam_ife_0",
-       .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_pcie_cam_ife_0 = {
-       .name = "qnm_pcie_cam_ife_0",
-       .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node llcc_mc_cam_ife_0 = {
-       .name = "llcc_mc_cam_ife_0",
-       .id = SM8550_MASTER_LLCC_CAM_IFE_0,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_EBI1_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_camnoc_hf_cam_ife_0 = {
-       .name = "qnm_camnoc_hf_cam_ife_0",
-       .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_0,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_camnoc_icp_cam_ife_0 = {
-       .name = "qnm_camnoc_icp_cam_ife_0",
-       .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_0,
-       .channels = 1,
-       .buswidth = 8,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_camnoc_sf_cam_ife_0 = {
-       .name = "qnm_camnoc_sf_cam_ife_0",
-       .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_0,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qnm_mnoc_hf_cam_ife_1 = {
-       .name = "qnm_mnoc_hf_cam_ife_1",
-       .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_mnoc_sf_cam_ife_1 = {
-       .name = "qnm_mnoc_sf_cam_ife_1",
-       .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_pcie_cam_ife_1 = {
-       .name = "qnm_pcie_cam_ife_1",
-       .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node llcc_mc_cam_ife_1 = {
-       .name = "llcc_mc_cam_ife_1",
-       .id = SM8550_MASTER_LLCC_CAM_IFE_1,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_EBI1_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_camnoc_hf_cam_ife_1 = {
-       .name = "qnm_camnoc_hf_cam_ife_1",
-       .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_1,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_camnoc_icp_cam_ife_1 = {
-       .name = "qnm_camnoc_icp_cam_ife_1",
-       .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_1,
-       .channels = 1,
-       .buswidth = 8,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_camnoc_sf_cam_ife_1 = {
-       .name = "qnm_camnoc_sf_cam_ife_1",
-       .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_1,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qnm_mnoc_hf_cam_ife_2 = {
-       .name = "qnm_mnoc_hf_cam_ife_2",
-       .id = SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_mnoc_sf_cam_ife_2 = {
-       .name = "qnm_mnoc_sf_cam_ife_2",
-       .id = SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_pcie_cam_ife_2 = {
-       .name = "qnm_pcie_cam_ife_2",
-       .id = SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node llcc_mc_cam_ife_2 = {
-       .name = "llcc_mc_cam_ife_2",
-       .id = SM8550_MASTER_LLCC_CAM_IFE_2,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_EBI1_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_camnoc_hf_cam_ife_2 = {
-       .name = "qnm_camnoc_hf_cam_ife_2",
-       .id = SM8550_MASTER_CAMNOC_HF_CAM_IFE_2,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_camnoc_icp_cam_ife_2 = {
-       .name = "qnm_camnoc_icp_cam_ife_2",
-       .id = SM8550_MASTER_CAMNOC_ICP_CAM_IFE_2,
-       .channels = 1,
-       .buswidth = 8,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qnm_camnoc_sf_cam_ife_2 = {
-       .name = "qnm_camnoc_sf_cam_ife_2",
-       .id = SM8550_MASTER_CAMNOC_SF_CAM_IFE_2,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2 },
-};
-
 static struct qcom_icc_node qns_a1noc_snoc = {
        .name = "qns_a1noc_snoc",
        .id = SM8550_SLAVE_A1NOC_SNOC,
@@ -1342,137 +1117,6 @@ static struct qcom_icc_node qns_gemnoc_sf = {
        .links = { SM8550_MASTER_SNOC_SF_MEM_NOC },
 };
 
-static struct qcom_icc_node qns_llcc_disp = {
-       .name = "qns_llcc_disp",
-       .id = SM8550_SLAVE_LLCC_DISP,
-       .channels = 4,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_MASTER_LLCC_DISP },
-};
-
-static struct qcom_icc_node ebi_disp = {
-       .name = "ebi_disp",
-       .id = SM8550_SLAVE_EBI1_DISP,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_disp = {
-       .name = "qns_mem_noc_hf_disp",
-       .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qns_llcc_cam_ife_0 = {
-       .name = "qns_llcc_cam_ife_0",
-       .id = SM8550_SLAVE_LLCC_CAM_IFE_0,
-       .channels = 4,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_MASTER_LLCC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node ebi_cam_ife_0 = {
-       .name = "ebi_cam_ife_0",
-       .id = SM8550_SLAVE_EBI1_CAM_IFE_0,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_cam_ife_0 = {
-       .name = "qns_mem_noc_hf_cam_ife_0",
-       .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qns_mem_noc_sf_cam_ife_0 = {
-       .name = "qns_mem_noc_sf_cam_ife_0",
-       .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0 },
-};
-
-static struct qcom_icc_node qns_llcc_cam_ife_1 = {
-       .name = "qns_llcc_cam_ife_1",
-       .id = SM8550_SLAVE_LLCC_CAM_IFE_1,
-       .channels = 4,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_MASTER_LLCC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node ebi_cam_ife_1 = {
-       .name = "ebi_cam_ife_1",
-       .id = SM8550_SLAVE_EBI1_CAM_IFE_1,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_cam_ife_1 = {
-       .name = "qns_mem_noc_hf_cam_ife_1",
-       .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qns_mem_noc_sf_cam_ife_1 = {
-       .name = "qns_mem_noc_sf_cam_ife_1",
-       .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1 },
-};
-
-static struct qcom_icc_node qns_llcc_cam_ife_2 = {
-       .name = "qns_llcc_cam_ife_2",
-       .id = SM8550_SLAVE_LLCC_CAM_IFE_2,
-       .channels = 4,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { SM8550_MASTER_LLCC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node ebi_cam_ife_2 = {
-       .name = "ebi_cam_ife_2",
-       .id = SM8550_SLAVE_EBI1_CAM_IFE_2,
-       .channels = 4,
-       .buswidth = 4,
-       .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_cam_ife_2 = {
-       .name = "qns_mem_noc_hf_cam_ife_2",
-       .id = SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2 },
-};
-
-static struct qcom_icc_node qns_mem_noc_sf_cam_ife_2 = {
-       .name = "qns_mem_noc_sf_cam_ife_2",
-       .id = SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2 },
-};
-
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
        .enable_mask = 0x8,
@@ -1639,161 +1283,6 @@ static struct qcom_icc_bcm bcm_sn7 = {
        .nodes = { &qns_pcie_mem_noc },
 };
 
-static struct qcom_icc_bcm bcm_acv_disp = {
-       .name = "ACV",
-       .enable_mask = 0x1,
-       .num_nodes = 1,
-       .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mc0_disp = {
-       .name = "MC0",
-       .num_nodes = 1,
-       .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mm0_disp = {
-       .name = "MM0",
-       .num_nodes = 1,
-       .nodes = { &qns_mem_noc_hf_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh0_disp = {
-       .name = "SH0",
-       .num_nodes = 1,
-       .nodes = { &qns_llcc_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh1_disp = {
-       .name = "SH1",
-       .enable_mask = 0x1,
-       .num_nodes = 2,
-       .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp },
-};
-
-static struct qcom_icc_bcm bcm_acv_cam_ife_0 = {
-       .name = "ACV",
-       .enable_mask = 0x0,
-       .num_nodes = 1,
-       .nodes = { &ebi_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_mc0_cam_ife_0 = {
-       .name = "MC0",
-       .num_nodes = 1,
-       .nodes = { &ebi_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_mm0_cam_ife_0 = {
-       .name = "MM0",
-       .num_nodes = 1,
-       .nodes = { &qns_mem_noc_hf_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_mm1_cam_ife_0 = {
-       .name = "MM1",
-       .enable_mask = 0x1,
-       .num_nodes = 4,
-       .nodes = { &qnm_camnoc_hf_cam_ife_0, &qnm_camnoc_icp_cam_ife_0,
-                  &qnm_camnoc_sf_cam_ife_0, &qns_mem_noc_sf_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_sh0_cam_ife_0 = {
-       .name = "SH0",
-       .num_nodes = 1,
-       .nodes = { &qns_llcc_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = {
-       .name = "SH1",
-       .enable_mask = 0x1,
-       .num_nodes = 3,
-       .nodes = { &qnm_mnoc_hf_cam_ife_0, &qnm_mnoc_sf_cam_ife_0,
-                  &qnm_pcie_cam_ife_0 },
-};
-
-static struct qcom_icc_bcm bcm_acv_cam_ife_1 = {
-       .name = "ACV",
-       .enable_mask = 0x0,
-       .num_nodes = 1,
-       .nodes = { &ebi_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_mc0_cam_ife_1 = {
-       .name = "MC0",
-       .num_nodes = 1,
-       .nodes = { &ebi_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_mm0_cam_ife_1 = {
-       .name = "MM0",
-       .num_nodes = 1,
-       .nodes = { &qns_mem_noc_hf_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_mm1_cam_ife_1 = {
-       .name = "MM1",
-       .enable_mask = 0x1,
-       .num_nodes = 4,
-       .nodes = { &qnm_camnoc_hf_cam_ife_1, &qnm_camnoc_icp_cam_ife_1,
-                  &qnm_camnoc_sf_cam_ife_1, &qns_mem_noc_sf_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_sh0_cam_ife_1 = {
-       .name = "SH0",
-       .num_nodes = 1,
-       .nodes = { &qns_llcc_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = {
-       .name = "SH1",
-       .enable_mask = 0x1,
-       .num_nodes = 3,
-       .nodes = { &qnm_mnoc_hf_cam_ife_1, &qnm_mnoc_sf_cam_ife_1,
-                  &qnm_pcie_cam_ife_1 },
-};
-
-static struct qcom_icc_bcm bcm_acv_cam_ife_2 = {
-       .name = "ACV",
-       .enable_mask = 0x0,
-       .num_nodes = 1,
-       .nodes = { &ebi_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_mc0_cam_ife_2 = {
-       .name = "MC0",
-       .num_nodes = 1,
-       .nodes = { &ebi_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_mm0_cam_ife_2 = {
-       .name = "MM0",
-       .num_nodes = 1,
-       .nodes = { &qns_mem_noc_hf_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_mm1_cam_ife_2 = {
-       .name = "MM1",
-       .enable_mask = 0x1,
-       .num_nodes = 4,
-       .nodes = { &qnm_camnoc_hf_cam_ife_2, &qnm_camnoc_icp_cam_ife_2,
-                  &qnm_camnoc_sf_cam_ife_2, &qns_mem_noc_sf_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_sh0_cam_ife_2 = {
-       .name = "SH0",
-       .num_nodes = 1,
-       .nodes = { &qns_llcc_cam_ife_2 },
-};
-
-static struct qcom_icc_bcm bcm_sh1_cam_ife_2 = {
-       .name = "SH1",
-       .enable_mask = 0x1,
-       .num_nodes = 3,
-       .nodes = { &qnm_mnoc_hf_cam_ife_2, &qnm_mnoc_sf_cam_ife_2,
-                  &qnm_pcie_cam_ife_2 },
-};
-
 static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
 };
 
@@ -1945,14 +1434,6 @@ static const struct qcom_icc_desc sm8550_cnoc_main = {
 static struct qcom_icc_bcm * const gem_noc_bcms[] = {
        &bcm_sh0,
        &bcm_sh1,
-       &bcm_sh0_disp,
-       &bcm_sh1_disp,
-       &bcm_sh0_cam_ife_0,
-       &bcm_sh1_cam_ife_0,
-       &bcm_sh0_cam_ife_1,
-       &bcm_sh1_cam_ife_1,
-       &bcm_sh0_cam_ife_2,
-       &bcm_sh1_cam_ife_2,
 };
 
 static struct qcom_icc_node * const gem_noc_nodes[] = {
@@ -1971,21 +1452,6 @@ static struct qcom_icc_node * const gem_noc_nodes[] = {
        [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
        [SLAVE_LLCC] = &qns_llcc,
        [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
-       [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp,
-       [MASTER_ANOC_PCIE_GEM_NOC_DISP] = &qnm_pcie_disp,
-       [SLAVE_LLCC_DISP] = &qns_llcc_disp,
-       [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0] = &qnm_mnoc_hf_cam_ife_0,
-       [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0] = &qnm_mnoc_sf_cam_ife_0,
-       [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0] = &qnm_pcie_cam_ife_0,
-       [SLAVE_LLCC_CAM_IFE_0] = &qns_llcc_cam_ife_0,
-       [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1] = &qnm_mnoc_hf_cam_ife_1,
-       [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1] = &qnm_mnoc_sf_cam_ife_1,
-       [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1] = &qnm_pcie_cam_ife_1,
-       [SLAVE_LLCC_CAM_IFE_1] = &qns_llcc_cam_ife_1,
-       [MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2] = &qnm_mnoc_hf_cam_ife_2,
-       [MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2] = &qnm_mnoc_sf_cam_ife_2,
-       [MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2] = &qnm_pcie_cam_ife_2,
-       [SLAVE_LLCC_CAM_IFE_2] = &qns_llcc_cam_ife_2,
 };
 
 static const struct qcom_icc_desc sm8550_gem_noc = {
@@ -2044,27 +1510,11 @@ static const struct qcom_icc_desc sm8550_lpass_lpicx_noc = {
 static struct qcom_icc_bcm * const mc_virt_bcms[] = {
        &bcm_acv,
        &bcm_mc0,
-       &bcm_acv_disp,
-       &bcm_mc0_disp,
-       &bcm_acv_cam_ife_0,
-       &bcm_mc0_cam_ife_0,
-       &bcm_acv_cam_ife_1,
-       &bcm_mc0_cam_ife_1,
-       &bcm_acv_cam_ife_2,
-       &bcm_mc0_cam_ife_2,
 };
 
 static struct qcom_icc_node * const mc_virt_nodes[] = {
        [MASTER_LLCC] = &llcc_mc,
        [SLAVE_EBI1] = &ebi,
-       [MASTER_LLCC_DISP] = &llcc_mc_disp,
-       [SLAVE_EBI1_DISP] = &ebi_disp,
-       [MASTER_LLCC_CAM_IFE_0] = &llcc_mc_cam_ife_0,
-       [SLAVE_EBI1_CAM_IFE_0] = &ebi_cam_ife_0,
-       [MASTER_LLCC_CAM_IFE_1] = &llcc_mc_cam_ife_1,
-       [SLAVE_EBI1_CAM_IFE_1] = &ebi_cam_ife_1,
-       [MASTER_LLCC_CAM_IFE_2] = &llcc_mc_cam_ife_2,
-       [SLAVE_EBI1_CAM_IFE_2] = &ebi_cam_ife_2,
 };
 
 static const struct qcom_icc_desc sm8550_mc_virt = {
@@ -2077,13 +1527,6 @@ static const struct qcom_icc_desc sm8550_mc_virt = {
 static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
        &bcm_mm0,
        &bcm_mm1,
-       &bcm_mm0_disp,
-       &bcm_mm0_cam_ife_0,
-       &bcm_mm1_cam_ife_0,
-       &bcm_mm0_cam_ife_1,
-       &bcm_mm1_cam_ife_1,
-       &bcm_mm0_cam_ife_2,
-       &bcm_mm1_cam_ife_2,
 };
 
 static struct qcom_icc_node * const mmss_noc_nodes[] = {
@@ -2100,23 +1543,6 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = {
        [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
        [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
        [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
-       [MASTER_MDP_DISP] = &qnm_mdp_disp,
-       [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp,
-       [MASTER_CAMNOC_HF_CAM_IFE_0] = &qnm_camnoc_hf_cam_ife_0,
-       [MASTER_CAMNOC_ICP_CAM_IFE_0] = &qnm_camnoc_icp_cam_ife_0,
-       [MASTER_CAMNOC_SF_CAM_IFE_0] = &qnm_camnoc_sf_cam_ife_0,
-       [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0] = &qns_mem_noc_hf_cam_ife_0,
-       [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0] = &qns_mem_noc_sf_cam_ife_0,
-       [MASTER_CAMNOC_HF_CAM_IFE_1] = &qnm_camnoc_hf_cam_ife_1,
-       [MASTER_CAMNOC_ICP_CAM_IFE_1] = &qnm_camnoc_icp_cam_ife_1,
-       [MASTER_CAMNOC_SF_CAM_IFE_1] = &qnm_camnoc_sf_cam_ife_1,
-       [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1] = &qns_mem_noc_hf_cam_ife_1,
-       [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1] = &qns_mem_noc_sf_cam_ife_1,
-       [MASTER_CAMNOC_HF_CAM_IFE_2] = &qnm_camnoc_hf_cam_ife_2,
-       [MASTER_CAMNOC_ICP_CAM_IFE_2] = &qnm_camnoc_icp_cam_ife_2,
-       [MASTER_CAMNOC_SF_CAM_IFE_2] = &qnm_camnoc_sf_cam_ife_2,
-       [SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2] = &qns_mem_noc_hf_cam_ife_2,
-       [SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2] = &qns_mem_noc_sf_cam_ife_2,
 };
 
 static const struct qcom_icc_desc sm8550_mmss_noc = {
index 8d5862c04bca2bdca8e110e7c893c61773d37aab..c9b2986e129337c8b8e0dec208b950bea20d213f 100644 (file)
 #define SM8550_MASTER_A1NOC_SNOC                       0
 #define SM8550_MASTER_A2NOC_SNOC                       1
 #define SM8550_MASTER_ANOC_PCIE_GEM_NOC                        2
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_0      3
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_1      4
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_CAM_IFE_2      5
-#define SM8550_MASTER_ANOC_PCIE_GEM_NOC_DISP           6
-#define SM8550_MASTER_APPSS_PROC                       7
-#define SM8550_MASTER_CAMNOC_HF                                8
-#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_0              9
-#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_1              10
-#define SM8550_MASTER_CAMNOC_HF_CAM_IFE_2              11
-#define SM8550_MASTER_CAMNOC_ICP                       12
-#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_0             13
-#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_1             14
-#define SM8550_MASTER_CAMNOC_ICP_CAM_IFE_2             15
-#define SM8550_MASTER_CAMNOC_SF                                16
-#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_0              17
-#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_1              18
-#define SM8550_MASTER_CAMNOC_SF_CAM_IFE_2              19
-#define SM8550_MASTER_CDSP_HCP                         20
-#define SM8550_MASTER_CDSP_PROC                                21
-#define SM8550_MASTER_CNOC_CFG                         22
-#define SM8550_MASTER_CNOC_MNOC_CFG                    23
-#define SM8550_MASTER_COMPUTE_NOC                      24
-#define SM8550_MASTER_CRYPTO                           25
-#define SM8550_MASTER_GEM_NOC_CNOC                     26
-#define SM8550_MASTER_GEM_NOC_PCIE_SNOC                        27
-#define SM8550_MASTER_GFX3D                            28
-#define SM8550_MASTER_GIC                              29
-#define SM8550_MASTER_GIC_AHB                          30
-#define SM8550_MASTER_GPU_TCU                          31
-#define SM8550_MASTER_IPA                              32
-#define SM8550_MASTER_LLCC                             33
-#define SM8550_MASTER_LLCC_CAM_IFE_0                   34
-#define SM8550_MASTER_LLCC_CAM_IFE_1                   35
-#define SM8550_MASTER_LLCC_CAM_IFE_2                   36
-#define SM8550_MASTER_LLCC_DISP                                37
-#define SM8550_MASTER_LPASS_GEM_NOC                    38
-#define SM8550_MASTER_LPASS_LPINOC                     39
-#define SM8550_MASTER_LPASS_PROC                       40
-#define SM8550_MASTER_LPIAON_NOC                       41
-#define SM8550_MASTER_MDP                              42
-#define SM8550_MASTER_MDP_DISP                         43
-#define SM8550_MASTER_MNOC_HF_MEM_NOC                  44
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_0                45
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_1                46
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_CAM_IFE_2                47
-#define SM8550_MASTER_MNOC_HF_MEM_NOC_DISP             48
-#define SM8550_MASTER_MNOC_SF_MEM_NOC                  49
-#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_0                50
-#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_1                51
-#define SM8550_MASTER_MNOC_SF_MEM_NOC_CAM_IFE_2                52
-#define SM8550_MASTER_MSS_PROC                         53
-#define SM8550_MASTER_PCIE_0                           54
-#define SM8550_MASTER_PCIE_1                           55
-#define SM8550_MASTER_PCIE_ANOC_CFG                    56
-#define SM8550_MASTER_QDSS_BAM                         57
-#define SM8550_MASTER_QDSS_ETR                         58
-#define SM8550_MASTER_QDSS_ETR_1                       59
-#define SM8550_MASTER_QSPI_0                           60
-#define SM8550_MASTER_QUP_1                            61
-#define SM8550_MASTER_QUP_2                            62
-#define SM8550_MASTER_QUP_CORE_0                       63
-#define SM8550_MASTER_QUP_CORE_1                       64
-#define SM8550_MASTER_QUP_CORE_2                       65
-#define SM8550_MASTER_SDCC_2                           66
-#define SM8550_MASTER_SDCC_4                           67
-#define SM8550_MASTER_SNOC_GC_MEM_NOC                  68
-#define SM8550_MASTER_SNOC_SF_MEM_NOC                  69
-#define SM8550_MASTER_SP                               70
-#define SM8550_MASTER_SYS_TCU                          71
-#define SM8550_MASTER_UFS_MEM                          72
-#define SM8550_MASTER_USB3_0                           73
-#define SM8550_MASTER_VIDEO                            74
-#define SM8550_MASTER_VIDEO_CV_PROC                    75
-#define SM8550_MASTER_VIDEO_PROC                       76
-#define SM8550_MASTER_VIDEO_V_PROC                     77
-#define SM8550_SLAVE_A1NOC_SNOC                                78
-#define SM8550_SLAVE_A2NOC_SNOC                                79
-#define SM8550_SLAVE_AHB2PHY_NORTH                     80
-#define SM8550_SLAVE_AHB2PHY_SOUTH                     81
-#define SM8550_SLAVE_ANOC_PCIE_GEM_NOC                 82
-#define SM8550_SLAVE_AOSS                              83
-#define SM8550_SLAVE_APPSS                             84
-#define SM8550_SLAVE_BOOT_IMEM                         85
-#define SM8550_SLAVE_CAMERA_CFG                                86
-#define SM8550_SLAVE_CDSP_MEM_NOC                      87
-#define SM8550_SLAVE_CLK_CTL                           88
-#define SM8550_SLAVE_CNOC_CFG                          89
-#define SM8550_SLAVE_CNOC_MNOC_CFG                     90
-#define SM8550_SLAVE_CNOC_MSS                          91
-#define SM8550_SLAVE_CPR_NSPCX                         92
-#define SM8550_SLAVE_CRYPTO_0_CFG                      93
-#define SM8550_SLAVE_CX_RDPM                           94
-#define SM8550_SLAVE_DDRSS_CFG                         95
-#define SM8550_SLAVE_DISPLAY_CFG                       96
-#define SM8550_SLAVE_EBI1                              97
-#define SM8550_SLAVE_EBI1_CAM_IFE_0                    98
-#define SM8550_SLAVE_EBI1_CAM_IFE_1                    99
-#define SM8550_SLAVE_EBI1_CAM_IFE_2                    100
-#define SM8550_SLAVE_EBI1_DISP                         101
-#define SM8550_SLAVE_GEM_NOC_CNOC                      102
-#define SM8550_SLAVE_GFX3D_CFG                         103
-#define SM8550_SLAVE_I2C                               104
-#define SM8550_SLAVE_IMEM                              105
-#define SM8550_SLAVE_IMEM_CFG                          106
-#define SM8550_SLAVE_IPA_CFG                           107
-#define SM8550_SLAVE_IPC_ROUTER_CFG                    108
-#define SM8550_SLAVE_LLCC                              109
-#define SM8550_SLAVE_LLCC_CAM_IFE_0                    110
-#define SM8550_SLAVE_LLCC_CAM_IFE_1                    111
-#define SM8550_SLAVE_LLCC_CAM_IFE_2                    112
-#define SM8550_SLAVE_LLCC_DISP                         113
-#define SM8550_SLAVE_LPASS_GEM_NOC                     114
-#define SM8550_SLAVE_LPASS_QTB_CFG                     115
-#define SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC           116
-#define SM8550_SLAVE_LPICX_NOC_LPIAON_NOC              117
-#define SM8550_SLAVE_MEM_NOC_PCIE_SNOC                 118
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC                   119
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_0         120
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_1         121
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_CAM_IFE_2         122
-#define SM8550_SLAVE_MNOC_HF_MEM_NOC_DISP              123
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC                   124
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_0         125
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_1         126
-#define SM8550_SLAVE_MNOC_SF_MEM_NOC_CAM_IFE_2         127
-#define SM8550_SLAVE_MX_RDPM                           128
-#define SM8550_SLAVE_NSP_QTB_CFG                       129
-#define SM8550_SLAVE_PCIE_0                            130
-#define SM8550_SLAVE_PCIE_0_CFG                                131
-#define SM8550_SLAVE_PCIE_1                            132
-#define SM8550_SLAVE_PCIE_1_CFG                                133
-#define SM8550_SLAVE_PCIE_ANOC_CFG                     134
-#define SM8550_SLAVE_PDM                               135
-#define SM8550_SLAVE_PIMEM_CFG                         136
-#define SM8550_SLAVE_PRNG                              137
-#define SM8550_SLAVE_QDSS_CFG                          138
-#define SM8550_SLAVE_QDSS_STM                          139
-#define SM8550_SLAVE_QSPI_0                            140
-#define SM8550_SLAVE_QUP_1                             141
-#define SM8550_SLAVE_QUP_2                             142
-#define SM8550_SLAVE_QUP_CORE_0                                143
-#define SM8550_SLAVE_QUP_CORE_1                                144
-#define SM8550_SLAVE_QUP_CORE_2                                145
-#define SM8550_SLAVE_RBCPR_CX_CFG                      146
-#define SM8550_SLAVE_RBCPR_MMCX_CFG                    147
-#define SM8550_SLAVE_RBCPR_MXA_CFG                     148
-#define SM8550_SLAVE_RBCPR_MXC_CFG                     149
-#define SM8550_SLAVE_SDCC_2                            150
-#define SM8550_SLAVE_SDCC_4                            151
-#define SM8550_SLAVE_SERVICE_MNOC                      152
-#define SM8550_SLAVE_SERVICE_PCIE_ANOC                 153
-#define SM8550_SLAVE_SNOC_GEM_NOC_GC                   154
-#define SM8550_SLAVE_SNOC_GEM_NOC_SF                   155
-#define SM8550_SLAVE_SPSS_CFG                          156
-#define SM8550_SLAVE_TCSR                              157
-#define SM8550_SLAVE_TCU                               158
-#define SM8550_SLAVE_TLMM                              159
-#define SM8550_SLAVE_TME_CFG                           160
-#define SM8550_SLAVE_UFS_MEM_CFG                       161
-#define SM8550_SLAVE_USB3_0                            162
-#define SM8550_SLAVE_VENUS_CFG                         163
-#define SM8550_SLAVE_VSENSE_CTRL_CFG                   164
+#define SM8550_MASTER_APPSS_PROC                       3
+#define SM8550_MASTER_CAMNOC_HF                                4
+#define SM8550_MASTER_CAMNOC_ICP                       5
+#define SM8550_MASTER_CAMNOC_SF                                6
+#define SM8550_MASTER_CDSP_HCP                         7
+#define SM8550_MASTER_CDSP_PROC                                8
+#define SM8550_MASTER_CNOC_CFG                         9
+#define SM8550_MASTER_CNOC_MNOC_CFG                    10
+#define SM8550_MASTER_COMPUTE_NOC                      11
+#define SM8550_MASTER_CRYPTO                           12
+#define SM8550_MASTER_GEM_NOC_CNOC                     13
+#define SM8550_MASTER_GEM_NOC_PCIE_SNOC                        14
+#define SM8550_MASTER_GFX3D                            15
+#define SM8550_MASTER_GIC                              16
+#define SM8550_MASTER_GIC_AHB                          17
+#define SM8550_MASTER_GPU_TCU                          18
+#define SM8550_MASTER_IPA                              19
+#define SM8550_MASTER_LLCC                             20
+#define SM8550_MASTER_LPASS_GEM_NOC                    21
+#define SM8550_MASTER_LPASS_LPINOC                     22
+#define SM8550_MASTER_LPASS_PROC                       23
+#define SM8550_MASTER_LPIAON_NOC                       24
+#define SM8550_MASTER_MDP                              25
+#define SM8550_MASTER_MNOC_HF_MEM_NOC                  26
+#define SM8550_MASTER_MNOC_SF_MEM_NOC                  27
+#define SM8550_MASTER_MSS_PROC                         28
+#define SM8550_MASTER_PCIE_0                           29
+#define SM8550_MASTER_PCIE_1                           30
+#define SM8550_MASTER_PCIE_ANOC_CFG                    31
+#define SM8550_MASTER_QDSS_BAM                         32
+#define SM8550_MASTER_QDSS_ETR                         33
+#define SM8550_MASTER_QDSS_ETR_1                       34
+#define SM8550_MASTER_QSPI_0                           35
+#define SM8550_MASTER_QUP_1                            36
+#define SM8550_MASTER_QUP_2                            37
+#define SM8550_MASTER_QUP_CORE_0                       38
+#define SM8550_MASTER_QUP_CORE_1                       39
+#define SM8550_MASTER_QUP_CORE_2                       40
+#define SM8550_MASTER_SDCC_2                           41
+#define SM8550_MASTER_SDCC_4                           42
+#define SM8550_MASTER_SNOC_GC_MEM_NOC                  43
+#define SM8550_MASTER_SNOC_SF_MEM_NOC                  44
+#define SM8550_MASTER_SP                               45
+#define SM8550_MASTER_SYS_TCU                          46
+#define SM8550_MASTER_UFS_MEM                          47
+#define SM8550_MASTER_USB3_0                           48
+#define SM8550_MASTER_VIDEO                            49
+#define SM8550_MASTER_VIDEO_CV_PROC                    50
+#define SM8550_MASTER_VIDEO_PROC                       51
+#define SM8550_MASTER_VIDEO_V_PROC                     52
+#define SM8550_SLAVE_A1NOC_SNOC                                53
+#define SM8550_SLAVE_A2NOC_SNOC                                54
+#define SM8550_SLAVE_AHB2PHY_NORTH                     55
+#define SM8550_SLAVE_AHB2PHY_SOUTH                     56
+#define SM8550_SLAVE_ANOC_PCIE_GEM_NOC                 57
+#define SM8550_SLAVE_AOSS                              58
+#define SM8550_SLAVE_APPSS                             59
+#define SM8550_SLAVE_BOOT_IMEM                         60
+#define SM8550_SLAVE_CAMERA_CFG                                61
+#define SM8550_SLAVE_CDSP_MEM_NOC                      62
+#define SM8550_SLAVE_CLK_CTL                           63
+#define SM8550_SLAVE_CNOC_CFG                          64
+#define SM8550_SLAVE_CNOC_MNOC_CFG                     65
+#define SM8550_SLAVE_CNOC_MSS                          66
+#define SM8550_SLAVE_CPR_NSPCX                         67
+#define SM8550_SLAVE_CRYPTO_0_CFG                      68
+#define SM8550_SLAVE_CX_RDPM                           69
+#define SM8550_SLAVE_DDRSS_CFG                         70
+#define SM8550_SLAVE_DISPLAY_CFG                       71
+#define SM8550_SLAVE_EBI1                              72
+#define SM8550_SLAVE_GEM_NOC_CNOC                      73
+#define SM8550_SLAVE_GFX3D_CFG                         74
+#define SM8550_SLAVE_I2C                               75
+#define SM8550_SLAVE_IMEM                              76
+#define SM8550_SLAVE_IMEM_CFG                          77
+#define SM8550_SLAVE_IPA_CFG                           78
+#define SM8550_SLAVE_IPC_ROUTER_CFG                    79
+#define SM8550_SLAVE_LLCC                              80
+#define SM8550_SLAVE_LPASS_GEM_NOC                     81
+#define SM8550_SLAVE_LPASS_QTB_CFG                     82
+#define SM8550_SLAVE_LPIAON_NOC_LPASS_AG_NOC           83
+#define SM8550_SLAVE_LPICX_NOC_LPIAON_NOC              84
+#define SM8550_SLAVE_MEM_NOC_PCIE_SNOC                 85
+#define SM8550_SLAVE_MNOC_HF_MEM_NOC                   86
+#define SM8550_SLAVE_MNOC_SF_MEM_NOC                   87
+#define SM8550_SLAVE_MX_RDPM                           88
+#define SM8550_SLAVE_NSP_QTB_CFG                       89
+#define SM8550_SLAVE_PCIE_0                            90
+#define SM8550_SLAVE_PCIE_0_CFG                                91
+#define SM8550_SLAVE_PCIE_1                            92
+#define SM8550_SLAVE_PCIE_1_CFG                                93
+#define SM8550_SLAVE_PCIE_ANOC_CFG                     94
+#define SM8550_SLAVE_PDM                               95
+#define SM8550_SLAVE_PIMEM_CFG                         96
+#define SM8550_SLAVE_PRNG                              97
+#define SM8550_SLAVE_QDSS_CFG                          98
+#define SM8550_SLAVE_QDSS_STM                          99
+#define SM8550_SLAVE_QSPI_0                            100
+#define SM8550_SLAVE_QUP_1                             101
+#define SM8550_SLAVE_QUP_2                             102
+#define SM8550_SLAVE_QUP_CORE_0                                103
+#define SM8550_SLAVE_QUP_CORE_1                                104
+#define SM8550_SLAVE_QUP_CORE_2                                105
+#define SM8550_SLAVE_RBCPR_CX_CFG                      106
+#define SM8550_SLAVE_RBCPR_MMCX_CFG                    107
+#define SM8550_SLAVE_RBCPR_MXA_CFG                     108
+#define SM8550_SLAVE_RBCPR_MXC_CFG                     109
+#define SM8550_SLAVE_SDCC_2                            110
+#define SM8550_SLAVE_SDCC_4                            111
+#define SM8550_SLAVE_SERVICE_MNOC                      112
+#define SM8550_SLAVE_SERVICE_PCIE_ANOC                 113
+#define SM8550_SLAVE_SNOC_GEM_NOC_GC                   114
+#define SM8550_SLAVE_SNOC_GEM_NOC_SF                   115
+#define SM8550_SLAVE_SPSS_CFG                          116
+#define SM8550_SLAVE_TCSR                              117
+#define SM8550_SLAVE_TCU                               118
+#define SM8550_SLAVE_TLMM                              119
+#define SM8550_SLAVE_TME_CFG                           120
+#define SM8550_SLAVE_UFS_MEM_CFG                       121
+#define SM8550_SLAVE_USB3_0                            122
+#define SM8550_SLAVE_VENUS_CFG                         123
+#define SM8550_SLAVE_VSENSE_CTRL_CFG                   124
 
 #endif
index cbaf4f9c41be656212b50dce683273911e1e1cd6..99824675ee3f495cb8adeabae6c01c185c3a60c1 100644 (file)
@@ -670,150 +670,6 @@ static struct qcom_icc_node xm_usb4_2 = {
        .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
 };
 
-static struct qcom_icc_node qnm_mnoc_hf_disp = {
-       .name = "qnm_mnoc_hf_disp",
-       .id = X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node qnm_pcie_disp = {
-       .name = "qnm_pcie_disp",
-       .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC_DISP,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_LLCC_DISP },
-};
-
-static struct qcom_icc_node llcc_mc_disp = {
-       .name = "llcc_mc_disp",
-       .id = X1E80100_MASTER_LLCC_DISP,
-       .channels = 8,
-       .buswidth = 4,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_EBI1_DISP },
-};
-
-static struct qcom_icc_node qnm_mdp_disp = {
-       .name = "qnm_mdp_disp",
-       .id = X1E80100_MASTER_MDP_DISP,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qnm_pcie_pcie = {
-       .name = "qnm_pcie_pcie",
-       .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_LLCC_PCIE },
-};
-
-static struct qcom_icc_node llcc_mc_pcie = {
-       .name = "llcc_mc_pcie",
-       .id = X1E80100_MASTER_LLCC_PCIE,
-       .channels = 8,
-       .buswidth = 4,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_EBI1_PCIE },
-};
-
-static struct qcom_icc_node qnm_pcie_north_gem_noc_pcie = {
-       .name = "qnm_pcie_north_gem_noc_pcie",
-       .id = X1E80100_MASTER_PCIE_NORTH_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE },
-};
-
-static struct qcom_icc_node qnm_pcie_south_gem_noc_pcie = {
-       .name = "qnm_pcie_south_gem_noc_pcie",
-       .id = X1E80100_MASTER_PCIE_SOUTH_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_3_pcie = {
-       .name = "xm_pcie_3_pcie",
-       .id = X1E80100_MASTER_PCIE_3_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_4_pcie = {
-       .name = "xm_pcie_4_pcie",
-       .id = X1E80100_MASTER_PCIE_4_PCIE,
-       .channels = 1,
-       .buswidth = 8,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_5_pcie = {
-       .name = "xm_pcie_5_pcie",
-       .id = X1E80100_MASTER_PCIE_5_PCIE,
-       .channels = 1,
-       .buswidth = 8,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_0_pcie = {
-       .name = "xm_pcie_0_pcie",
-       .id = X1E80100_MASTER_PCIE_0_PCIE,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_1_pcie = {
-       .name = "xm_pcie_1_pcie",
-       .id = X1E80100_MASTER_PCIE_1_PCIE,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_2_pcie = {
-       .name = "xm_pcie_2_pcie",
-       .id = X1E80100_MASTER_PCIE_2_PCIE,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_6a_pcie = {
-       .name = "xm_pcie_6a_pcie",
-       .id = X1E80100_MASTER_PCIE_6A_PCIE,
-       .channels = 1,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
-static struct qcom_icc_node xm_pcie_6b_pcie = {
-       .name = "xm_pcie_6b_pcie",
-       .id = X1E80100_MASTER_PCIE_6B_PCIE,
-       .channels = 1,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
-};
-
 static struct qcom_icc_node qns_a1noc_snoc = {
        .name = "qns_a1noc_snoc",
        .id = X1E80100_SLAVE_A1NOC_SNOC,
@@ -1514,76 +1370,6 @@ static struct qcom_icc_node qns_aggre_usb_south_snoc = {
        .links = { X1E80100_MASTER_AGGRE_USB_SOUTH },
 };
 
-static struct qcom_icc_node qns_llcc_disp = {
-       .name = "qns_llcc_disp",
-       .id = X1E80100_SLAVE_LLCC_DISP,
-       .channels = 8,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { X1E80100_MASTER_LLCC_DISP },
-};
-
-static struct qcom_icc_node ebi_disp = {
-       .name = "ebi_disp",
-       .id = X1E80100_SLAVE_EBI1_DISP,
-       .channels = 8,
-       .buswidth = 4,
-       .num_links = 0,
-};
-
-static struct qcom_icc_node qns_mem_noc_hf_disp = {
-       .name = "qns_mem_noc_hf_disp",
-       .id = X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP,
-       .channels = 2,
-       .buswidth = 32,
-       .num_links = 1,
-       .links = { X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP },
-};
-
-static struct qcom_icc_node qns_llcc_pcie = {
-       .name = "qns_llcc_pcie",
-       .id = X1E80100_SLAVE_LLCC_PCIE,
-       .channels = 8,
-       .buswidth = 16,
-       .num_links = 1,
-       .links = { X1E80100_MASTER_LLCC_PCIE },
-};
-
-static struct qcom_icc_node ebi_pcie = {
-       .name = "ebi_pcie",
-       .id = X1E80100_SLAVE_EBI1_PCIE,
-       .channels = 8,
-       .buswidth = 4,
-       .num_links = 0,
-};
-
-static struct qcom_icc_node qns_pcie_mem_noc_pcie = {
-       .name = "qns_pcie_mem_noc_pcie",
-       .id = X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE },
-};
-
-static struct qcom_icc_node qns_pcie_north_gem_noc_pcie = {
-       .name = "qns_pcie_north_gem_noc_pcie",
-       .id = X1E80100_SLAVE_PCIE_NORTH_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_MASTER_PCIE_NORTH_PCIE },
-};
-
-static struct qcom_icc_node qns_pcie_south_gem_noc_pcie = {
-       .name = "qns_pcie_south_gem_noc_pcie",
-       .id = X1E80100_SLAVE_PCIE_SOUTH_PCIE,
-       .channels = 1,
-       .buswidth = 64,
-       .num_links = 1,
-       .links = { X1E80100_MASTER_PCIE_SOUTH_PCIE },
-};
-
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
        .enable_mask = BIT(3),
@@ -1756,73 +1542,7 @@ static struct qcom_icc_bcm bcm_sn4 = {
        .nodes = { &qnm_usb_anoc },
 };
 
-static struct qcom_icc_bcm bcm_acv_disp = {
-       .name = "ACV",
-       .num_nodes = 1,
-       .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mc0_disp = {
-       .name = "MC0",
-       .num_nodes = 1,
-       .nodes = { &ebi_disp },
-};
-
-static struct qcom_icc_bcm bcm_mm0_disp = {
-       .name = "MM0",
-       .num_nodes = 1,
-       .nodes = { &qns_mem_noc_hf_disp },
-};
-
-static struct qcom_icc_bcm bcm_mm1_disp = {
-       .name = "MM1",
-       .num_nodes = 1,
-       .nodes = { &qnm_mdp_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh0_disp = {
-       .name = "SH0",
-       .num_nodes = 1,
-       .nodes = { &qns_llcc_disp },
-};
-
-static struct qcom_icc_bcm bcm_sh1_disp = {
-       .name = "SH1",
-       .num_nodes = 2,
-       .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp },
-};
-
-static struct qcom_icc_bcm bcm_acv_pcie = {
-       .name = "ACV",
-       .num_nodes = 1,
-       .nodes = { &ebi_pcie },
-};
-
-static struct qcom_icc_bcm bcm_mc0_pcie = {
-       .name = "MC0",
-       .num_nodes = 1,
-       .nodes = { &ebi_pcie },
-};
-
-static struct qcom_icc_bcm bcm_pc0_pcie = {
-       .name = "PC0",
-       .num_nodes = 1,
-       .nodes = { &qns_pcie_mem_noc_pcie },
-};
-
-static struct qcom_icc_bcm bcm_sh0_pcie = {
-       .name = "SH0",
-       .num_nodes = 1,
-       .nodes = { &qns_llcc_pcie },
-};
-
-static struct qcom_icc_bcm bcm_sh1_pcie = {
-       .name = "SH1",
-       .num_nodes = 1,
-       .nodes = { &qnm_pcie_pcie },
-};
-
-static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+static struct qcom_icc_bcm * const aggre1_noc_bcms[] = {
 };
 
 static struct qcom_icc_node * const aggre1_noc_nodes[] = {
@@ -1983,10 +1703,6 @@ static const struct qcom_icc_desc x1e80100_cnoc_main = {
 static struct qcom_icc_bcm * const gem_noc_bcms[] = {
        &bcm_sh0,
        &bcm_sh1,
-       &bcm_sh0_disp,
-       &bcm_sh1_disp,
-       &bcm_sh0_pcie,
-       &bcm_sh1_pcie,
 };
 
 static struct qcom_icc_node * const gem_noc_nodes[] = {
@@ -2005,11 +1721,6 @@ static struct qcom_icc_node * const gem_noc_nodes[] = {
        [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
        [SLAVE_LLCC] = &qns_llcc,
        [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
-       [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp,
-       [MASTER_ANOC_PCIE_GEM_NOC_DISP] = &qnm_pcie_disp,
-       [SLAVE_LLCC_DISP] = &qns_llcc_disp,
-       [MASTER_ANOC_PCIE_GEM_NOC_PCIE] = &qnm_pcie_pcie,
-       [SLAVE_LLCC_PCIE] = &qns_llcc_pcie,
 };
 
 static const struct qcom_icc_desc x1e80100_gem_noc = {
@@ -2019,7 +1730,7 @@ static const struct qcom_icc_desc x1e80100_gem_noc = {
        .num_bcms = ARRAY_SIZE(gem_noc_bcms),
 };
 
-static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = {
 };
 
 static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
@@ -2068,19 +1779,11 @@ static const struct qcom_icc_desc x1e80100_lpass_lpicx_noc = {
 static struct qcom_icc_bcm * const mc_virt_bcms[] = {
        &bcm_acv,
        &bcm_mc0,
-       &bcm_acv_disp,
-       &bcm_mc0_disp,
-       &bcm_acv_pcie,
-       &bcm_mc0_pcie,
 };
 
 static struct qcom_icc_node * const mc_virt_nodes[] = {
        [MASTER_LLCC] = &llcc_mc,
        [SLAVE_EBI1] = &ebi,
-       [MASTER_LLCC_DISP] = &llcc_mc_disp,
-       [SLAVE_EBI1_DISP] = &ebi_disp,
-       [MASTER_LLCC_PCIE] = &llcc_mc_pcie,
-       [SLAVE_EBI1_PCIE] = &ebi_pcie,
 };
 
 static const struct qcom_icc_desc x1e80100_mc_virt = {
@@ -2093,8 +1796,6 @@ static const struct qcom_icc_desc x1e80100_mc_virt = {
 static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
        &bcm_mm0,
        &bcm_mm1,
-       &bcm_mm0_disp,
-       &bcm_mm1_disp,
 };
 
 static struct qcom_icc_node * const mmss_noc_nodes[] = {
@@ -2111,8 +1812,6 @@ static struct qcom_icc_node * const mmss_noc_nodes[] = {
        [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
        [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
        [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
-       [MASTER_MDP_DISP] = &qnm_mdp_disp,
-       [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp,
 };
 
 static const struct qcom_icc_desc x1e80100_mmss_noc = {
@@ -2140,16 +1839,12 @@ static const struct qcom_icc_desc x1e80100_nsp_noc = {
 
 static struct qcom_icc_bcm * const pcie_center_anoc_bcms[] = {
        &bcm_pc0,
-       &bcm_pc0_pcie,
 };
 
 static struct qcom_icc_node * const pcie_center_anoc_nodes[] = {
        [MASTER_PCIE_NORTH] = &qnm_pcie_north_gem_noc,
        [MASTER_PCIE_SOUTH] = &qnm_pcie_south_gem_noc,
        [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
-       [MASTER_PCIE_NORTH_PCIE] = &qnm_pcie_north_gem_noc_pcie,
-       [MASTER_PCIE_SOUTH_PCIE] = &qnm_pcie_south_gem_noc_pcie,
-       [SLAVE_ANOC_PCIE_GEM_NOC_PCIE] = &qns_pcie_mem_noc_pcie,
 };
 
 static const struct qcom_icc_desc x1e80100_pcie_center_anoc = {
@@ -2167,10 +1862,6 @@ static struct qcom_icc_node * const pcie_north_anoc_nodes[] = {
        [MASTER_PCIE_4] = &xm_pcie_4,
        [MASTER_PCIE_5] = &xm_pcie_5,
        [SLAVE_PCIE_NORTH] = &qns_pcie_north_gem_noc,
-       [MASTER_PCIE_3_PCIE] = &xm_pcie_3_pcie,
-       [MASTER_PCIE_4_PCIE] = &xm_pcie_4_pcie,
-       [MASTER_PCIE_5_PCIE] = &xm_pcie_5_pcie,
-       [SLAVE_PCIE_NORTH_PCIE] = &qns_pcie_north_gem_noc_pcie,
 };
 
 static const struct qcom_icc_desc x1e80100_pcie_north_anoc = {
@@ -2180,7 +1871,7 @@ static const struct qcom_icc_desc x1e80100_pcie_north_anoc = {
        .num_bcms = ARRAY_SIZE(pcie_north_anoc_bcms),
 };
 
-static struct qcom_icc_bcm *pcie_south_anoc_bcms[] = {
+static struct qcom_icc_bcm * const pcie_south_anoc_bcms[] = {
 };
 
 static struct qcom_icc_node * const pcie_south_anoc_nodes[] = {
@@ -2190,12 +1881,6 @@ static struct qcom_icc_node * const pcie_south_anoc_nodes[] = {
        [MASTER_PCIE_6A] = &xm_pcie_6a,
        [MASTER_PCIE_6B] = &xm_pcie_6b,
        [SLAVE_PCIE_SOUTH] = &qns_pcie_south_gem_noc,
-       [MASTER_PCIE_0_PCIE] = &xm_pcie_0_pcie,
-       [MASTER_PCIE_1_PCIE] = &xm_pcie_1_pcie,
-       [MASTER_PCIE_2_PCIE] = &xm_pcie_2_pcie,
-       [MASTER_PCIE_6A_PCIE] = &xm_pcie_6a_pcie,
-       [MASTER_PCIE_6B_PCIE] = &xm_pcie_6b_pcie,
-       [SLAVE_PCIE_SOUTH_PCIE] = &qns_pcie_south_gem_noc_pcie,
 };
 
 static const struct qcom_icc_desc x1e80100_pcie_south_anoc = {
@@ -2205,7 +1890,7 @@ static const struct qcom_icc_desc x1e80100_pcie_south_anoc = {
        .num_bcms = ARRAY_SIZE(pcie_south_anoc_bcms),
 };
 
-static struct qcom_icc_bcm *system_noc_bcms[] = {
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
        &bcm_sn0,
        &bcm_sn2,
        &bcm_sn3,
@@ -2243,7 +1928,7 @@ static const struct qcom_icc_desc x1e80100_usb_center_anoc = {
        .num_bcms = ARRAY_SIZE(usb_center_anoc_bcms),
 };
 
-static struct qcom_icc_bcm *usb_north_anoc_bcms[] = {
+static struct qcom_icc_bcm * const usb_north_anoc_bcms[] = {
 };
 
 static struct qcom_icc_node * const usb_north_anoc_nodes[] = {
@@ -2259,7 +1944,7 @@ static const struct qcom_icc_desc x1e80100_usb_north_anoc = {
        .num_bcms = ARRAY_SIZE(usb_north_anoc_bcms),
 };
 
-static struct qcom_icc_bcm *usb_south_anoc_bcms[] = {
+static struct qcom_icc_bcm * const usb_south_anoc_bcms[] = {
 };
 
 static struct qcom_icc_node * const usb_south_anoc_nodes[] = {
index 1ba14cb45d5a2a42378802feaf293c798b893ad2..c9e5361e17c5b03c2c250e601d6ee6a63c88064e 100644 (file)
@@ -82,7 +82,7 @@ static int exynos_generic_icc_set(struct icc_node *src, struct icc_node *dst)
        return 0;
 }
 
-static struct icc_node *exynos_generic_icc_xlate(struct of_phandle_args *spec,
+static struct icc_node *exynos_generic_icc_xlate(const struct of_phandle_args *spec,
                                                 void *data)
 {
        struct exynos_icc_priv *priv = data;
index b58f5a3311c3a82a53374655024dc570ca181f5d..e4cb26f6a9434e37b8a9e2da872bc80071229520 100644 (file)
@@ -1711,6 +1711,14 @@ static size_t iommu_dma_opt_mapping_size(void)
        return iova_rcache_range();
 }
 
+static size_t iommu_dma_max_mapping_size(struct device *dev)
+{
+       if (dev_is_untrusted(dev))
+               return swiotlb_max_mapping_size(dev);
+
+       return SIZE_MAX;
+}
+
 static const struct dma_map_ops iommu_dma_ops = {
        .flags                  = DMA_F_PCI_P2PDMA_SUPPORTED,
        .alloc                  = iommu_dma_alloc,
@@ -1733,6 +1741,7 @@ static const struct dma_map_ops iommu_dma_ops = {
        .unmap_resource         = iommu_dma_unmap_resource,
        .get_merge_boundary     = iommu_dma_get_merge_boundary,
        .opt_mapping_size       = iommu_dma_opt_mapping_size,
+       .max_mapping_size       = iommu_dma_max_mapping_size,
 };
 
 /*
index 6cf9f48e7d8c8e954dd0dd026a35f6fb40d7e9dc..f52fb39c968eb1e7b38ce808cade3a0da6b32f0c 100644 (file)
@@ -87,8 +87,8 @@ config INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON
          the default value.
 
 config INTEL_IOMMU_PERF_EVENTS
-       def_bool y
        bool "Intel IOMMU performance events"
+       default y
        depends on INTEL_IOMMU && PERF_EVENTS
        help
          Selecting this option will enable the performance monitoring
index b1471ba016a515b11abf87a5987905174f8aaf6d..866bf48d803bc18a656f8c63b55acac2db66ad42 100644 (file)
@@ -187,7 +187,7 @@ static struct attribute *ipack_attrs[] = {
 };
 ATTRIBUTE_GROUPS(ipack);
 
-static struct bus_type ipack_bus_type = {
+static const struct bus_type ipack_bus_type = {
        .name      = "ipack",
        .probe     = ipack_bus_probe,
        .match     = ipack_bus_match,
index 9494fc26259c357ca09a52698bbbb568c25cbbba..ae67fec2ab468ff61daf3ca46679e3239289ed83 100644 (file)
@@ -85,10 +85,9 @@ static struct rzg2l_irqc_priv *irq_data_to_priv(struct irq_data *data)
        return data->domain->host_data;
 }
 
-static void rzg2l_irq_eoi(struct irq_data *d)
+static void rzg2l_clear_irq_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq)
 {
-       unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
-       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       unsigned int hw_irq = hwirq - IRQC_IRQ_START;
        u32 bit = BIT(hw_irq);
        u32 iitsr, iscr;
 
@@ -99,20 +98,30 @@ static void rzg2l_irq_eoi(struct irq_data *d)
         * ISCR can only be cleared if the type is falling-edge, rising-edge or
         * falling/rising-edge.
         */
-       if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq)))
+       if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq))) {
                writel_relaxed(iscr & ~bit, priv->base + ISCR);
+               /*
+                * Enforce that the posted write is flushed to prevent that the
+                * just handled interrupt is raised again.
+                */
+               readl_relaxed(priv->base + ISCR);
+       }
 }
 
-static void rzg2l_tint_eoi(struct irq_data *d)
+static void rzg2l_clear_tint_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq)
 {
-       unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_TINT_START;
-       struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
-       u32 bit = BIT(hw_irq);
+       u32 bit = BIT(hwirq - IRQC_TINT_START);
        u32 reg;
 
        reg = readl_relaxed(priv->base + TSCR);
-       if (reg & bit)
+       if (reg & bit) {
                writel_relaxed(reg & ~bit, priv->base + TSCR);
+               /*
+                * Enforce that the posted write is flushed to prevent that the
+                * just handled interrupt is raised again.
+                */
+               readl_relaxed(priv->base + TSCR);
+       }
 }
 
 static void rzg2l_irqc_eoi(struct irq_data *d)
@@ -122,9 +131,9 @@ static void rzg2l_irqc_eoi(struct irq_data *d)
 
        raw_spin_lock(&priv->lock);
        if (hw_irq >= IRQC_IRQ_START && hw_irq <= IRQC_IRQ_COUNT)
-               rzg2l_irq_eoi(d);
+               rzg2l_clear_irq_int(priv, hw_irq);
        else if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ)
-               rzg2l_tint_eoi(d);
+               rzg2l_clear_tint_int(priv, hw_irq);
        raw_spin_unlock(&priv->lock);
        irq_chip_eoi_parent(d);
 }
@@ -142,7 +151,7 @@ static void rzg2l_irqc_irq_disable(struct irq_data *d)
 
                raw_spin_lock(&priv->lock);
                reg = readl_relaxed(priv->base + TSSR(tssr_index));
-               reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
+               reg &= ~(TIEN << TSSEL_SHIFT(tssr_offset));
                writel_relaxed(reg, priv->base + TSSR(tssr_index));
                raw_spin_unlock(&priv->lock);
        }
@@ -154,7 +163,6 @@ static void rzg2l_irqc_irq_enable(struct irq_data *d)
        unsigned int hw_irq = irqd_to_hwirq(d);
 
        if (hw_irq >= IRQC_TINT_START && hw_irq < IRQC_NUM_IRQ) {
-               unsigned long tint = (uintptr_t)irq_data_get_irq_chip_data(d);
                struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
                u32 offset = hw_irq - IRQC_TINT_START;
                u32 tssr_offset = TSSR_OFFSET(offset);
@@ -163,7 +171,7 @@ static void rzg2l_irqc_irq_enable(struct irq_data *d)
 
                raw_spin_lock(&priv->lock);
                reg = readl_relaxed(priv->base + TSSR(tssr_index));
-               reg |= (TIEN | tint) << TSSEL_SHIFT(tssr_offset);
+               reg |= TIEN << TSSEL_SHIFT(tssr_offset);
                writel_relaxed(reg, priv->base + TSSR(tssr_index));
                raw_spin_unlock(&priv->lock);
        }
@@ -172,8 +180,10 @@ static void rzg2l_irqc_irq_enable(struct irq_data *d)
 
 static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
 {
-       unsigned int hw_irq = irqd_to_hwirq(d) - IRQC_IRQ_START;
        struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
+       unsigned int hwirq = irqd_to_hwirq(d);
+       u32 iitseln = hwirq - IRQC_IRQ_START;
+       bool clear_irq_int = false;
        u16 sense, tmp;
 
        switch (type & IRQ_TYPE_SENSE_MASK) {
@@ -183,14 +193,17 @@ static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
 
        case IRQ_TYPE_EDGE_FALLING:
                sense = IITSR_IITSEL_EDGE_FALLING;
+               clear_irq_int = true;
                break;
 
        case IRQ_TYPE_EDGE_RISING:
                sense = IITSR_IITSEL_EDGE_RISING;
+               clear_irq_int = true;
                break;
 
        case IRQ_TYPE_EDGE_BOTH:
                sense = IITSR_IITSEL_EDGE_BOTH;
+               clear_irq_int = true;
                break;
 
        default:
@@ -199,21 +212,40 @@ static int rzg2l_irq_set_type(struct irq_data *d, unsigned int type)
 
        raw_spin_lock(&priv->lock);
        tmp = readl_relaxed(priv->base + IITSR);
-       tmp &= ~IITSR_IITSEL_MASK(hw_irq);
-       tmp |= IITSR_IITSEL(hw_irq, sense);
+       tmp &= ~IITSR_IITSEL_MASK(iitseln);
+       tmp |= IITSR_IITSEL(iitseln, sense);
+       if (clear_irq_int)
+               rzg2l_clear_irq_int(priv, hwirq);
        writel_relaxed(tmp, priv->base + IITSR);
        raw_spin_unlock(&priv->lock);
 
        return 0;
 }
 
+static u32 rzg2l_disable_tint_and_set_tint_source(struct irq_data *d, struct rzg2l_irqc_priv *priv,
+                                                 u32 reg, u32 tssr_offset, u8 tssr_index)
+{
+       u32 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d);
+       u32 tien = reg & (TIEN << TSSEL_SHIFT(tssr_offset));
+
+       /* Clear the relevant byte in reg */
+       reg &= ~(TSSEL_MASK << TSSEL_SHIFT(tssr_offset));
+       /* Set TINT and leave TIEN clear */
+       reg |= tint << TSSEL_SHIFT(tssr_offset);
+       writel_relaxed(reg, priv->base + TSSR(tssr_index));
+
+       return reg | tien;
+}
+
 static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
 {
        struct rzg2l_irqc_priv *priv = irq_data_to_priv(d);
        unsigned int hwirq = irqd_to_hwirq(d);
        u32 titseln = hwirq - IRQC_TINT_START;
+       u32 tssr_offset = TSSR_OFFSET(titseln);
+       u8 tssr_index = TSSR_INDEX(titseln);
        u8 index, sense;
-       u32 reg;
+       u32 reg, tssr;
 
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_RISING:
@@ -235,10 +267,14 @@ static int rzg2l_tint_set_edge(struct irq_data *d, unsigned int type)
        }
 
        raw_spin_lock(&priv->lock);
+       tssr = readl_relaxed(priv->base + TSSR(tssr_index));
+       tssr = rzg2l_disable_tint_and_set_tint_source(d, priv, tssr, tssr_offset, tssr_index);
        reg = readl_relaxed(priv->base + TITSR(index));
        reg &= ~(IRQ_MASK << (titseln * TITSEL_WIDTH));
        reg |= sense << (titseln * TITSEL_WIDTH);
        writel_relaxed(reg, priv->base + TITSR(index));
+       rzg2l_clear_tint_int(priv, hwirq);
+       writel_relaxed(tssr, priv->base + TSSR(tssr_index));
        raw_spin_unlock(&priv->lock);
 
        return 0;
index 61994da7bad01fe38f7254a07c77ae4224b44b96..267045b765059db91809226fea95460502e73e79 100644 (file)
@@ -156,7 +156,7 @@ static const struct attribute_group *mcb_carrier_groups[] = {
 };
 
 
-static struct bus_type mcb_bus_type = {
+static const struct bus_type mcb_bus_type = {
        .name = "mcb",
        .match = mcb_match,
        .uevent = mcb_uevent,
@@ -165,7 +165,7 @@ static struct bus_type mcb_bus_type = {
        .shutdown = mcb_shutdown,
 };
 
-static struct device_type mcb_carrier_device_type = {
+static const struct device_type mcb_carrier_device_type = {
        .name = "mcb-carrier",
        .groups = mcb_carrier_groups,
 };
index 68ce56fc61d0a4ba7fcc62a6b394c0a7d71d169d..35b1080752cd7517f481313c26667e9d2154f36b 100644 (file)
@@ -519,7 +519,6 @@ config DM_VERITY
          If unsure, say N.
 
 config DM_VERITY_VERIFY_ROOTHASH_SIG
-       def_bool n
        bool "Verity data device root hash signature verification support"
        depends on DM_VERITY
        select SYSTEM_DATA_VERIFICATION
index d822ab2f739b070154193296934fb72e0200e36f..37b9f8f1ae1a275763b974a8547ab37efd93eb21 100644 (file)
@@ -1699,7 +1699,6 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
        struct bio_vec bv;
        sector_t sector, logical_sector, area, offset;
        struct page *page;
-       void *buffer;
 
        get_area_and_offset(ic, dio->range.logical_sector, &area, &offset);
        dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset,
@@ -1708,13 +1707,14 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
        logical_sector = dio->range.logical_sector;
 
        page = mempool_alloc(&ic->recheck_pool, GFP_NOIO);
-       buffer = page_to_virt(page);
 
        __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
                unsigned pos = 0;
 
                do {
+                       sector_t alignment;
                        char *mem;
+                       char *buffer = page_to_virt(page);
                        int r;
                        struct dm_io_request io_req;
                        struct dm_io_region io_loc;
@@ -1727,6 +1727,14 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
                        io_loc.sector = sector;
                        io_loc.count = ic->sectors_per_block;
 
+                       /* Align the bio to logical block size */
+                       alignment = dio->range.logical_sector | bio_sectors(bio) | (PAGE_SIZE >> SECTOR_SHIFT);
+                       alignment &= -alignment;
+                       io_loc.sector = round_down(io_loc.sector, alignment);
+                       io_loc.count += sector - io_loc.sector;
+                       buffer += (sector - io_loc.sector) << SECTOR_SHIFT;
+                       io_loc.count = round_up(io_loc.count, alignment);
+
                        r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT);
                        if (unlikely(r)) {
                                dio->bi_status = errno_to_blk_status(r);
@@ -1848,12 +1856,12 @@ again:
                        r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
                                                checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE);
                        if (unlikely(r)) {
+                               if (likely(checksums != checksums_onstack))
+                                       kfree(checksums);
                                if (r > 0) {
-                                       integrity_recheck(dio, checksums);
+                                       integrity_recheck(dio, checksums_onstack);
                                        goto skip_io;
                                }
-                               if (likely(checksums != checksums_onstack))
-                                       kfree(checksums);
                                goto error;
                        }
 
index bf7a574499a34d3aba7d23cc93507abe4fca528d..0ace06d1bee384a1f87048c61d78213ffc82fee1 100644 (file)
@@ -684,8 +684,10 @@ static void dm_exception_table_exit(struct dm_exception_table *et,
        for (i = 0; i < size; i++) {
                slot = et->table + i;
 
-               hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list)
+               hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list) {
                        kmem_cache_free(mem, ex);
+                       cond_resched();
+               }
        }
 
        kvfree(et->table);
index a083921a8968ba8471b440fe1259e00ac4f3c812..224b488794e5bcb1ad58fdfe23713e4e93b894d3 100644 (file)
@@ -755,7 +755,7 @@ const char *const tegra_mc_error_names[8] = {
        [6] = "SMMU translation error",
 };
 
-struct icc_node *tegra_mc_icc_xlate(struct of_phandle_args *spec, void *data)
+struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *data)
 {
        struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
        struct icc_node *node;
index 00ed2b6a0d1b27e0466bd2ab14e82b7efc6c1ae0..47c0c19e13fd5a3af043836d29119a4db5feed7b 100644 (file)
@@ -1285,7 +1285,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
 }
 
 static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
 {
        struct icc_provider *provider = data;
        struct icc_node_data *ndata;
index 470b7dbab2c2fc0904a0a035d59508f660665398..9d7393e19f125663a0e03e9c56137ef6baf22b01 100644 (file)
@@ -1170,7 +1170,7 @@ static int tegra124_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
 }
 
 static struct icc_node_data *
-tegra124_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra124_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
 {
        struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
        const struct tegra_mc_client *client;
index fcd4aea48bda9cec22c02c970a987c3ca9cbb76b..57d9ae12fcfe1a8e0fe04ceff0e9f94350c8a3e2 100644 (file)
@@ -236,7 +236,7 @@ static int tegra_emc_icc_set_bw(struct icc_node *src, struct icc_node *dst)
 }
 
 static struct icc_node *
-tegra_emc_of_icc_xlate(struct of_phandle_args *spec, void *data)
+tegra_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data)
 {
        struct icc_provider *provider = data;
        struct icc_node *node;
index fd595c851a27865bb9044818596062e797ed80f6..97cf59523b0b1705d3bd6e23c0176756c89d58ba 100644 (file)
@@ -950,7 +950,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
 }
 
 static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
 {
        struct icc_provider *provider = data;
        struct icc_node_data *ndata;
index aa4b97d5e73236f2c5185430d06a6fcf69f32c09..a3022e715deef14e31490f1456f4dd102459afe3 100644 (file)
@@ -390,7 +390,7 @@ static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
 }
 
 static struct icc_node_data *
-tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra20_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
 {
        struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
        unsigned int i, idx = spec->args[0];
index 9eae25c57ec6ec1ca2e1b39cfb794f01a6541291..d7b0a23c2d7dbdd6f095ef3f3cee6691dba60e3c 100644 (file)
@@ -1468,7 +1468,7 @@ to_tegra_emc_provider(struct icc_provider *provider)
 }
 
 static struct icc_node_data *
-emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
 {
        struct icc_provider *provider = data;
        struct icc_node_data *ndata;
index 06f8b35e0a149d703929f4d15bfbbbf0f6ffc34b..d3e685c8431ffaa30ee099f5e09df23585b3e1e1 100644 (file)
@@ -1332,7 +1332,7 @@ static int tegra30_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw,
 }
 
 static struct icc_node_data *
-tegra30_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data)
+tegra30_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
 {
        struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
        const struct tegra_mc_client *client;
index ea5fbcbbe4a56f8a7ba9dd3e57a87c54b97db56d..ef326d6d566e691603cd20604b863c6de091a246 100644 (file)
@@ -471,8 +471,8 @@ static void rave_sp_receive_frame(struct rave_sp *sp,
                rave_sp_receive_reply(sp, data, length);
 }
 
-static ssize_t rave_sp_receive_buf(struct serdev_device *serdev,
-                                  const u8 *buf, size_t size)
+static size_t rave_sp_receive_buf(struct serdev_device *serdev,
+                                 const u8 *buf, size_t size)
 {
        struct device *dev = &serdev->dev;
        struct rave_sp *sp = dev_get_drvdata(dev);
index ee590c4a15379d2898b3cefc87afb260c6299fbd..6eac0f33591524f9b76ad912a3ceb1c62556fc48 100644 (file)
@@ -251,7 +251,7 @@ static int ssc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int ssc_remove(struct platform_device *pdev)
+static void ssc_remove(struct platform_device *pdev)
 {
        struct ssc_device *ssc = platform_get_drvdata(pdev);
 
@@ -260,8 +260,6 @@ static int ssc_remove(struct platform_device *pdev)
        mutex_lock(&user_lock);
        list_del(&ssc->list);
        mutex_unlock(&user_lock);
-
-       return 0;
 }
 
 static struct platform_driver ssc_driver = {
@@ -271,7 +269,7 @@ static struct platform_driver ssc_driver = {
        },
        .id_table       = atmel_ssc_devtypes,
        .probe          = ssc_probe,
-       .remove         = ssc_remove,
+       .remove_new     = ssc_remove,
 };
 module_platform_driver(ssc_driver);
 
index 25ce725035e77b81197fe4efc26dab599a799180..bcc005dff1c0fa5735c2b4757828f26b68491889 100644 (file)
@@ -431,7 +431,7 @@ int cxl_of_read_adapter_properties(struct cxl *adapter, struct device_node *np)
        return 0;
 }
 
-static int cxl_of_remove(struct platform_device *pdev)
+static void cxl_of_remove(struct platform_device *pdev)
 {
        struct cxl *adapter;
        int afu;
@@ -441,7 +441,6 @@ static int cxl_of_remove(struct platform_device *pdev)
                cxl_guest_remove_afu(adapter->afu[afu]);
 
        cxl_guest_remove_adapter(adapter);
-       return 0;
 }
 
 static void cxl_of_shutdown(struct platform_device *pdev)
@@ -501,6 +500,6 @@ struct platform_driver cxl_of_driver = {
                .owner = THIS_MODULE
        },
        .probe = cxl_of_probe,
-       .remove = cxl_of_remove,
+       .remove_new = cxl_of_remove,
        .shutdown = cxl_of_shutdown,
 };
index b630625b3024ba6a95fbc0255f5f171b23265737..e78a76d74ff4fd6576b4e2e211504b1bcc22faa1 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/nvmem-provider.h>
index d807d08e26144f861c99b42544d4b7ae54a8517c..327afb866b218adc441e5ba62c816e269286d8a4 100644 (file)
@@ -129,7 +129,7 @@ struct idt_smb_seq {
 struct idt_eeprom_seq {
        u8 cmd;
        u8 eeaddr;
-       u16 memaddr;
+       __le16 memaddr;
        u8 data;
 } __packed;
 
@@ -141,8 +141,8 @@ struct idt_eeprom_seq {
  */
 struct idt_csr_seq {
        u8 cmd;
-       u16 csraddr;
-       u32 data;
+       __le16 csraddr;
+       __le32 data;
 } __packed;
 
 /*
index dbd26c3b245bca56adffc8288d5657dd3c61d3b8..4c67e2c5a82e1f85f3e6e07e20b22d14b25f3051 100644 (file)
@@ -2186,7 +2186,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int fastrpc_cb_remove(struct platform_device *pdev)
+static void fastrpc_cb_remove(struct platform_device *pdev)
 {
        struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent);
        struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev);
@@ -2201,8 +2201,6 @@ static int fastrpc_cb_remove(struct platform_device *pdev)
                }
        }
        spin_unlock_irqrestore(&cctx->lock, flags);
-
-       return 0;
 }
 
 static const struct of_device_id fastrpc_match_table[] = {
@@ -2212,7 +2210,7 @@ static const struct of_device_id fastrpc_match_table[] = {
 
 static struct platform_driver fastrpc_cb_driver = {
        .probe = fastrpc_cb_probe,
-       .remove = fastrpc_cb_remove,
+       .remove_new = fastrpc_cb_remove,
        .driver = {
                .name = "qcom,fastrpc-cb",
                .of_match_table = fastrpc_match_table,
index b075d803a2c2078074d2962d8d6778e693057eee..69ee4f39af2a7c4c4ec0740d1e2ada020be3b145 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/irqdomain.h>
index 2165ec35a3438dde1306daa401af942b10a7903c..fb9be37057a8dde5916c15ddbef6029a0d71df81 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/regulator/consumer.h>
@@ -239,7 +238,7 @@ static int hisi_hikey_usb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int  hisi_hikey_usb_remove(struct platform_device *pdev)
+static void hisi_hikey_usb_remove(struct platform_device *pdev)
 {
        struct hisi_hikey_usb *hisi_hikey_usb = platform_get_drvdata(pdev);
 
@@ -251,8 +250,6 @@ static int  hisi_hikey_usb_remove(struct platform_device *pdev)
        } else {
                hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
        }
-
-       return 0;
 }
 
 static const struct of_device_id id_table_hisi_hikey_usb[] = {
@@ -263,7 +260,7 @@ MODULE_DEVICE_TABLE(of, id_table_hisi_hikey_usb);
 
 static struct platform_driver hisi_hikey_usb_driver = {
        .probe = hisi_hikey_usb_probe,
-       .remove = hisi_hikey_usb_remove,
+       .remove_new = hisi_hikey_usb_remove,
        .driver = {
                .name = DEVICE_DRIVER_NAME,
                .of_match_table = id_table_hisi_hikey_usb,
index f1b74d3f895862a3cb6239fa6e8ad7f34a642672..04bd34c8c5069d36965f6c519fe5ff255a0b3d32 100644 (file)
@@ -770,7 +770,7 @@ static void ilo_remove(struct pci_dev *pdev)
 static int ilo_probe(struct pci_dev *pdev,
                               const struct pci_device_id *ent)
 {
-       int devnum, minor, start, error = 0;
+       int devnum, slot, start, error = 0;
        struct ilo_hwinfo *ilo_hw;
 
        if (pci_match_id(ilo_blacklist, pdev)) {
@@ -839,11 +839,11 @@ static int ilo_probe(struct pci_dev *pdev,
                goto remove_isr;
        }
 
-       for (minor = 0 ; minor < max_ccb; minor++) {
+       for (slot = 0; slot < max_ccb; slot++) {
                struct device *dev;
                dev = device_create(&ilo_class, &pdev->dev,
-                                   MKDEV(ilo_major, minor), NULL,
-                                   "hpilo!d%dccb%d", devnum, minor);
+                                   MKDEV(ilo_major, start + slot), NULL,
+                                   "hpilo!d%dccb%d", devnum, slot);
                if (IS_ERR(dev))
                        dev_err(&pdev->dev, "Could not create files\n");
        }
index b92767d6bdd24462c583c8f3d2dc7c09f08a4ad1..5178c02b21eba9c6898790cac69b878f3f562783 100644 (file)
@@ -417,7 +417,7 @@ static void lkdtm_FAM_BOUNDS(void)
        pr_err("FAIL: survived access of invalid flexible array member index!\n");
 
        if (!__has_attribute(__counted_by__))
-               pr_warn("This is expected since this %s was built a compiler supporting __counted_by\n",
+               pr_warn("This is expected since this %s was built with a compiler that does not support __counted_by\n",
                        lkdtm_kernel_info);
        else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))
                pr_expected_config(CONFIG_UBSAN_TRAP);
index 6be8f1cc052c13be3607432f6a4f2ca141cd1aa1..5a8c26c3df13da4c3fc5dfc93d1685e3220bae4c 100644 (file)
@@ -144,9 +144,6 @@ static void mei_gsc_remove(struct auxiliary_device *aux_dev)
        struct mei_me_hw *hw;
 
        dev = dev_get_drvdata(&aux_dev->dev);
-       if (!dev)
-               return;
-
        hw = to_me_hw(dev);
 
        mei_stop(dev);
@@ -168,9 +165,6 @@ static int __maybe_unused mei_gsc_pm_suspend(struct device *device)
 {
        struct mei_device *dev = dev_get_drvdata(device);
 
-       if (!dev)
-               return -ENODEV;
-
        mei_stop(dev);
 
        mei_disable_interrupts(dev);
@@ -186,9 +180,6 @@ static int __maybe_unused mei_gsc_pm_resume(struct device *device)
        int err;
        struct mei_me_hw *hw;
 
-       if (!dev)
-               return -ENODEV;
-
        hw = to_me_hw(dev);
        aux_dev = to_auxiliary_dev(device);
        adev = auxiliary_dev_to_mei_aux_dev(aux_dev);
@@ -211,8 +202,6 @@ static int __maybe_unused mei_gsc_pm_runtime_idle(struct device *device)
 {
        struct mei_device *dev = dev_get_drvdata(device);
 
-       if (!dev)
-               return -ENODEV;
        if (mei_write_is_idle(dev))
                pm_runtime_autosuspend(device);
 
@@ -225,9 +214,6 @@ static int  __maybe_unused mei_gsc_pm_runtime_suspend(struct device *device)
        struct mei_me_hw *hw;
        int ret;
 
-       if (!dev)
-               return -ENODEV;
-
        mutex_lock(&dev->device_lock);
 
        if (mei_write_is_idle(dev)) {
@@ -252,9 +238,6 @@ static int __maybe_unused mei_gsc_pm_runtime_resume(struct device *device)
        struct mei_me_hw *hw;
        irqreturn_t irq_ret;
 
-       if (!dev)
-               return -ENODEV;
-
        mutex_lock(&dev->device_lock);
 
        hw = to_me_hw(dev);
@@ -292,6 +275,10 @@ static const struct auxiliary_device_id mei_gsc_id_table[] = {
                .name = "i915.mei-gscfi",
                .driver_data = MEI_ME_GSCFI_CFG,
        },
+       {
+               .name = "xe.mei-gscfi",
+               .driver_data = MEI_ME_GSCFI_CFG,
+       },
        {
                /* sentinel */
        }
@@ -312,5 +299,6 @@ module_auxiliary_driver(mei_gsc_driver);
 MODULE_AUTHOR("Intel Corporation");
 MODULE_ALIAS("auxiliary:i915.mei-gsc");
 MODULE_ALIAS("auxiliary:i915.mei-gscfi");
+MODULE_ALIAS("auxiliary:xe.mei-gscfi");
 MODULE_DESCRIPTION("Intel(R) Graphics System Controller");
 MODULE_LICENSE("GPL");
index 9be312ec798de96fb362e0dce25ec3ad587d8834..631dd9651d7c9dbc0f812725f1537f367c82300c 100644 (file)
@@ -4,7 +4,7 @@
 config INTEL_MEI_HDCP
        tristate "Intel HDCP2.2 services of ME Interface"
        depends on INTEL_MEI_ME
-       depends on DRM_I915
+       depends on DRM_I915 || DRM_XE
        help
          MEI Support for HDCP2.2 Services on Intel platforms.
 
index 51359cc5ece9a109d1d3dc96c32baf49e95500c4..f8759a6c9ed331f2316cb6bdc4be29042c9a3043 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/mei.h>
 #include <linux/mei_cl_bus.h>
@@ -781,9 +782,18 @@ static int mei_hdcp_component_match(struct device *dev, int subcomponent,
                                    void *data)
 {
        struct device *base = data;
+       struct pci_dev *pdev;
 
-       if (!dev->driver || strcmp(dev->driver->name, "i915") ||
-           subcomponent != I915_COMPONENT_HDCP)
+       if (!dev_is_pci(dev))
+               return 0;
+
+       pdev = to_pci_dev(dev);
+
+       if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) ||
+           pdev->vendor != PCI_VENDOR_ID_INTEL)
+               return 0;
+
+       if (subcomponent != I915_COMPONENT_HDCP)
                return 0;
 
        base = base->parent;
index 8cf636c5403225f7588a2428318cec1ff7fd2700..b5757993c9b2af992c54468a75e630c080bcad61 100644 (file)
@@ -297,11 +297,7 @@ end:
  */
 static void mei_me_shutdown(struct pci_dev *pdev)
 {
-       struct mei_device *dev;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return;
+       struct mei_device *dev = pci_get_drvdata(pdev);
 
        dev_dbg(&pdev->dev, "shutdown\n");
        mei_stop(dev);
@@ -322,11 +318,7 @@ static void mei_me_shutdown(struct pci_dev *pdev)
  */
 static void mei_me_remove(struct pci_dev *pdev)
 {
-       struct mei_device *dev;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return;
+       struct mei_device *dev = pci_get_drvdata(pdev);
 
        if (mei_pg_is_enabled(dev))
                pm_runtime_get_noresume(&pdev->dev);
@@ -355,9 +347,6 @@ static int mei_me_pci_suspend(struct device *device)
        struct pci_dev *pdev = to_pci_dev(device);
        struct mei_device *dev = pci_get_drvdata(pdev);
 
-       if (!dev)
-               return -ENODEV;
-
        dev_dbg(&pdev->dev, "suspend\n");
 
        mei_stop(dev);
@@ -373,14 +362,10 @@ static int mei_me_pci_suspend(struct device *device)
 static int mei_me_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
-       struct mei_device *dev;
+       struct mei_device *dev = pci_get_drvdata(pdev);
        unsigned int irqflags;
        int err;
 
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return -ENODEV;
-
        pci_enable_msi(pdev);
 
        irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED;
@@ -421,13 +406,10 @@ static void mei_me_pci_complete(struct device *device)
 #ifdef CONFIG_PM
 static int mei_me_pm_runtime_idle(struct device *device)
 {
-       struct mei_device *dev;
+       struct mei_device *dev = dev_get_drvdata(device);
 
        dev_dbg(device, "rpm: me: runtime_idle\n");
 
-       dev = dev_get_drvdata(device);
-       if (!dev)
-               return -ENODEV;
        if (mei_write_is_idle(dev))
                pm_runtime_autosuspend(device);
 
@@ -436,15 +418,11 @@ static int mei_me_pm_runtime_idle(struct device *device)
 
 static int mei_me_pm_runtime_suspend(struct device *device)
 {
-       struct mei_device *dev;
+       struct mei_device *dev = dev_get_drvdata(device);
        int ret;
 
        dev_dbg(device, "rpm: me: runtime suspend\n");
 
-       dev = dev_get_drvdata(device);
-       if (!dev)
-               return -ENODEV;
-
        mutex_lock(&dev->device_lock);
 
        if (mei_write_is_idle(dev))
@@ -464,15 +442,11 @@ static int mei_me_pm_runtime_suspend(struct device *device)
 
 static int mei_me_pm_runtime_resume(struct device *device)
 {
-       struct mei_device *dev;
+       struct mei_device *dev = dev_get_drvdata(device);
        int ret;
 
        dev_dbg(device, "rpm: me: runtime resume\n");
 
-       dev = dev_get_drvdata(device);
-       if (!dev)
-               return -ENODEV;
-
        mutex_lock(&dev->device_lock);
 
        ret = mei_me_pg_exit_sync(dev);
index fa20d9a27813b715e06b42de7c3c5075cd0709a8..2a584104ba388fa8a2b1477dd8c31bcb946f6560 100644 (file)
@@ -166,11 +166,7 @@ end:
  */
 static void mei_txe_shutdown(struct pci_dev *pdev)
 {
-       struct mei_device *dev;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return;
+       struct mei_device *dev = pci_get_drvdata(pdev);
 
        dev_dbg(&pdev->dev, "shutdown\n");
        mei_stop(dev);
@@ -191,13 +187,7 @@ static void mei_txe_shutdown(struct pci_dev *pdev)
  */
 static void mei_txe_remove(struct pci_dev *pdev)
 {
-       struct mei_device *dev;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev) {
-               dev_err(&pdev->dev, "mei: dev == NULL\n");
-               return;
-       }
+       struct mei_device *dev = pci_get_drvdata(pdev);
 
        pm_runtime_get_noresume(&pdev->dev);
 
@@ -218,9 +208,6 @@ static int mei_txe_pci_suspend(struct device *device)
        struct pci_dev *pdev = to_pci_dev(device);
        struct mei_device *dev = pci_get_drvdata(pdev);
 
-       if (!dev)
-               return -ENODEV;
-
        dev_dbg(&pdev->dev, "suspend\n");
 
        mei_stop(dev);
@@ -236,13 +223,9 @@ static int mei_txe_pci_suspend(struct device *device)
 static int mei_txe_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
-       struct mei_device *dev;
+       struct mei_device *dev = pci_get_drvdata(pdev);
        int err;
 
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return -ENODEV;
-
        pci_enable_msi(pdev);
 
        mei_clear_interrupts(dev);
@@ -273,13 +256,10 @@ static int mei_txe_pci_resume(struct device *device)
 #ifdef CONFIG_PM
 static int mei_txe_pm_runtime_idle(struct device *device)
 {
-       struct mei_device *dev;
+       struct mei_device *dev = dev_get_drvdata(device);
 
        dev_dbg(device, "rpm: txe: runtime_idle\n");
 
-       dev = dev_get_drvdata(device);
-       if (!dev)
-               return -ENODEV;
        if (mei_write_is_idle(dev))
                pm_runtime_autosuspend(device);
 
@@ -287,15 +267,11 @@ static int mei_txe_pm_runtime_idle(struct device *device)
 }
 static int mei_txe_pm_runtime_suspend(struct device *device)
 {
-       struct mei_device *dev;
+       struct mei_device *dev = dev_get_drvdata(device);
        int ret;
 
        dev_dbg(device, "rpm: txe: runtime suspend\n");
 
-       dev = dev_get_drvdata(device);
-       if (!dev)
-               return -ENODEV;
-
        mutex_lock(&dev->device_lock);
 
        if (mei_write_is_idle(dev))
@@ -317,15 +293,11 @@ static int mei_txe_pm_runtime_suspend(struct device *device)
 
 static int mei_txe_pm_runtime_resume(struct device *device)
 {
-       struct mei_device *dev;
+       struct mei_device *dev = dev_get_drvdata(device);
        int ret;
 
        dev_dbg(device, "rpm: txe: runtime resume\n");
 
-       dev = dev_get_drvdata(device);
-       if (!dev)
-               return -ENODEV;
-
        mutex_lock(&dev->device_lock);
 
        mei_enable_interrupts(dev);
index 8d303c6c000062ee2d7280f6df4d95f022e80bf8..6c9f00bcb94b1857588b3bc6a0ada02421d9f87a 100644 (file)
@@ -384,7 +384,7 @@ err_cancel:
        return ret;
 }
 
-static int mei_vsc_remove(struct platform_device *pdev)
+static void mei_vsc_remove(struct platform_device *pdev)
 {
        struct mei_device *mei_dev = platform_get_drvdata(pdev);
 
@@ -395,8 +395,6 @@ static int mei_vsc_remove(struct platform_device *pdev)
        mei_disable_interrupts(mei_dev);
 
        mei_deregister(mei_dev);
-
-       return 0;
 }
 
 static int mei_vsc_suspend(struct device *dev)
@@ -433,7 +431,7 @@ MODULE_DEVICE_TABLE(platform, mei_vsc_id_table);
 
 static struct platform_driver mei_vsc_drv = {
        .probe = mei_vsc_probe,
-       .remove = mei_vsc_remove,
+       .remove_new = mei_vsc_remove,
        .id_table = mei_vsc_id_table,
        .driver = {
                .name = MEI_VSC_DRV_NAME,
index e9219b61cd92fb76fcabe89d2c6d0cf1f234390d..aa2dece4a927a570c1e325fad8607424b935434c 100644 (file)
@@ -4,7 +4,7 @@
 config INTEL_MEI_PXP
        tristate "Intel PXP services of ME Interface"
        depends on INTEL_MEI_ME
-       depends on DRM_I915
+       depends on DRM_I915 || DRM_XE
        help
          MEI Support for PXP Services on Intel platforms.
 
index 787c6a27a4be60f9322c6aad9e1d7143da24e47e..b1e4c23b31a32957c616f0edcdf74dc086c44a89 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/mei.h>
 #include <linux/mei_cl_bus.h>
@@ -225,12 +226,21 @@ static int mei_pxp_component_match(struct device *dev, int subcomponent,
                                   void *data)
 {
        struct device *base = data;
+       struct pci_dev *pdev;
 
        if (!dev)
                return 0;
 
-       if (!dev->driver || strcmp(dev->driver->name, "i915") ||
-           subcomponent != I915_COMPONENT_PXP)
+       if (!dev_is_pci(dev))
+               return 0;
+
+       pdev = to_pci_dev(dev);
+
+       if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) ||
+           pdev->vendor != PCI_VENDOR_ID_INTEL)
+               return 0;
+
+       if (subcomponent != I915_COMPONENT_PXP)
                return 0;
 
        base = base->parent;
index 55f7db490d3bbbabd08b7bd2ba6ff078abb93ad6..ecfb70cd057ca01eb33e544ef242ab1aee2cd25a 100644 (file)
@@ -25,7 +25,8 @@
 #define VSC_TP_ROM_BOOTUP_DELAY_MS             10
 #define VSC_TP_ROM_XFER_POLL_TIMEOUT_US                (500 * USEC_PER_MSEC)
 #define VSC_TP_ROM_XFER_POLL_DELAY_US          (20 * USEC_PER_MSEC)
-#define VSC_TP_WAIT_FW_ASSERTED_TIMEOUT                (2 * HZ)
+#define VSC_TP_WAIT_FW_POLL_TIMEOUT            (2 * HZ)
+#define VSC_TP_WAIT_FW_POLL_DELAY_US           (20 * USEC_PER_MSEC)
 #define VSC_TP_MAX_XFER_COUNT                  5
 
 #define VSC_TP_PACKET_SYNC                     0x31
@@ -101,13 +102,15 @@ static int vsc_tp_wakeup_request(struct vsc_tp *tp)
        gpiod_set_value_cansleep(tp->wakeupfw, 0);
 
        ret = wait_event_timeout(tp->xfer_wait,
-                                atomic_read(&tp->assert_cnt) &&
-                                gpiod_get_value_cansleep(tp->wakeuphost),
-                                VSC_TP_WAIT_FW_ASSERTED_TIMEOUT);
+                                atomic_read(&tp->assert_cnt),
+                                VSC_TP_WAIT_FW_POLL_TIMEOUT);
        if (!ret)
                return -ETIMEDOUT;
 
-       return 0;
+       return read_poll_timeout(gpiod_get_value_cansleep, ret, ret,
+                                VSC_TP_WAIT_FW_POLL_DELAY_US,
+                                VSC_TP_WAIT_FW_POLL_TIMEOUT, false,
+                                tp->wakeuphost);
 }
 
 static void vsc_tp_wakeup_release(struct vsc_tp *tp)
@@ -416,8 +419,6 @@ static irqreturn_t vsc_tp_isr(int irq, void *data)
 
        atomic_inc(&tp->assert_cnt);
 
-       wake_up(&tp->xfer_wait);
-
        return IRQ_WAKE_THREAD;
 }
 
@@ -425,6 +426,8 @@ static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
 {
        struct vsc_tp *tp = data;
 
+       wake_up(&tp->xfer_wait);
+
        if (tp->event_notify)
                tp->event_notify(tp->event_notify_context);
 
@@ -442,11 +445,16 @@ static int vsc_tp_match_any(struct acpi_device *adev, void *data)
 
 static int vsc_tp_probe(struct spi_device *spi)
 {
-       struct platform_device_info pinfo = { 0 };
+       struct vsc_tp *tp;
+       struct platform_device_info pinfo = {
+               .name = "intel_vsc",
+               .data = &tp,
+               .size_data = sizeof(tp),
+               .id = PLATFORM_DEVID_NONE,
+       };
        struct device *dev = &spi->dev;
        struct platform_device *pdev;
        struct acpi_device *adev;
-       struct vsc_tp *tp;
        int ret;
 
        tp = devm_kzalloc(dev, sizeof(*tp), GFP_KERNEL);
@@ -498,13 +506,8 @@ static int vsc_tp_probe(struct spi_device *spi)
                ret = -ENODEV;
                goto err_destroy_lock;
        }
-       pinfo.fwnode = acpi_fwnode_handle(adev);
-
-       pinfo.name = "intel_vsc";
-       pinfo.data = &tp;
-       pinfo.size_data = sizeof(tp);
-       pinfo.id = PLATFORM_DEVID_NONE;
 
+       pinfo.fwnode = acpi_fwnode_handle(adev);
        pdev = platform_device_register_full(&pinfo);
        if (IS_ERR(pdev)) {
                ret = PTR_ERR(pdev);
index d279a4f195e2a343a8332d25c25e85a89b6ac88f..1e3eb2aa44d9d9cc0ba51f1518471da507a2fc07 100644 (file)
@@ -165,12 +165,11 @@ static int __init open_dice_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int open_dice_remove(struct platform_device *pdev)
+static void open_dice_remove(struct platform_device *pdev)
 {
        struct open_dice_drvdata *drvdata = platform_get_drvdata(pdev);
 
        misc_deregister(&drvdata->misc);
-       return 0;
 }
 
 static const struct of_device_id open_dice_of_match[] = {
@@ -179,7 +178,7 @@ static const struct of_device_id open_dice_of_match[] = {
 };
 
 static struct platform_driver open_dice_driver = {
-       .remove = open_dice_remove,
+       .remove_new = open_dice_remove,
        .driver = {
                .name = DRIVER_NAME,
                .of_match_table = open_dice_of_match,
index e248c0a8882f237f934edec01af96ddf355d3133..546eb06a40d045b610e954da156258aeb23fadf3 100644 (file)
@@ -435,7 +435,7 @@ err_free_partitions:
        return ret;
 }
 
-static int sram_remove(struct platform_device *pdev)
+static void sram_remove(struct platform_device *pdev)
 {
        struct sram_dev *sram = platform_get_drvdata(pdev);
 
@@ -443,8 +443,6 @@ static int sram_remove(struct platform_device *pdev)
 
        if (sram->pool && gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
                dev_err(sram->dev, "removed while SRAM allocated\n");
-
-       return 0;
 }
 
 static struct platform_driver sram_driver = {
@@ -453,7 +451,7 @@ static struct platform_driver sram_driver = {
                .of_match_table = sram_dt_ids,
        },
        .probe = sram_probe,
-       .remove = sram_remove,
+       .remove_new = sram_remove,
 };
 
 static int __init sram_init(void)
index 4b1be0bb6ac099fdfadb7e136440655693ba4fab..47ebe80bf849987e4f0918a2f16b64d35bda522b 100644 (file)
@@ -774,7 +774,7 @@ err_core_init:
        return err;
 }
 
-static int kim_remove(struct platform_device *pdev)
+static void kim_remove(struct platform_device *pdev)
 {
        /* free the GPIOs requested */
        struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
@@ -798,7 +798,6 @@ static int kim_remove(struct platform_device *pdev)
 
        kfree(kim_gdata);
        kim_gdata = NULL;
-       return 0;
 }
 
 static int kim_suspend(struct platform_device *pdev, pm_message_t state)
@@ -825,7 +824,7 @@ static int kim_resume(struct platform_device *pdev)
 /* entry point for ST KIM module, called in from ST Core */
 static struct platform_driver kim_platform_driver = {
        .probe = kim_probe,
-       .remove = kim_remove,
+       .remove_new = kim_remove,
        .suspend = kim_suspend,
        .resume = kim_resume,
        .driver = {
index eee9b6581604ee8394c685a400e85392a06aa767..d2eb31f39aa7d00d397469fbcdfe051660310193 100644 (file)
@@ -166,7 +166,7 @@ static void tifm_free(struct device *dev)
        kfree(fm);
 }
 
-static struct class tifm_adapter_class = {
+static const struct class tifm_adapter_class = {
        .name    = "tifm_adapter",
        .dev_release = tifm_free
 };
index 6479c962da1acef7a5b816825f43be3a5c2ddb67..e2015c87f03fc538db083de55167bef3799d84ca 100644 (file)
@@ -187,7 +187,7 @@ err:
        return ret;
 }
 
-static int vcpu_stall_detect_remove(struct platform_device *pdev)
+static void vcpu_stall_detect_remove(struct platform_device *pdev)
 {
        int cpu;
 
@@ -195,8 +195,6 @@ static int vcpu_stall_detect_remove(struct platform_device *pdev)
 
        for_each_possible_cpu(cpu)
                stop_stall_detector_cpu(cpu);
-
-       return 0;
 }
 
 static const struct of_device_id vcpu_stall_detect_of_match[] = {
@@ -208,7 +206,7 @@ MODULE_DEVICE_TABLE(of, vcpu_stall_detect_of_match);
 
 static struct platform_driver vcpu_stall_detect_driver = {
        .probe  = vcpu_stall_detect_probe,
-       .remove = vcpu_stall_detect_remove,
+       .remove_new = vcpu_stall_detect_remove,
        .driver = {
                .name           = KBUILD_MODNAME,
                .of_match_table = vcpu_stall_detect_of_match,
index 94a0ee19bf20a97fda8df1b2939589a845663c83..ea433695f4c470549fdb307b1ca86f6f2846af9d 100644 (file)
@@ -1420,7 +1420,7 @@ err_xsdfec_dev:
        return err;
 }
 
-static int xsdfec_remove(struct platform_device *pdev)
+static void xsdfec_remove(struct platform_device *pdev)
 {
        struct xsdfec_dev *xsdfec;
 
@@ -1428,7 +1428,6 @@ static int xsdfec_remove(struct platform_device *pdev)
        misc_deregister(&xsdfec->miscdev);
        ida_free(&dev_nrs, xsdfec->dev_id);
        xsdfec_disable_all_clks(&xsdfec->clks);
-       return 0;
 }
 
 static const struct of_device_id xsdfec_of_match[] = {
@@ -1445,7 +1444,7 @@ static struct platform_driver xsdfec_driver = {
                .of_match_table = xsdfec_of_match,
        },
        .probe = xsdfec_probe,
-       .remove =  xsdfec_remove,
+       .remove_new =  xsdfec_remove,
 };
 
 module_platform_driver(xsdfec_driver);
index 9fc5835bfebc2f7c4feed38805024c0bbadac8ec..73c6da7d09631088261cfb4e70a70650fd8cc1dc 100644 (file)
@@ -143,11 +143,10 @@ static int xtmr_inject_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int xtmr_inject_remove(struct platform_device *pdev)
+static void xtmr_inject_remove(struct platform_device *pdev)
 {
        debugfs_remove_recursive(dbgfs_root);
        dbgfs_root = NULL;
-       return 0;
 }
 
 static const struct of_device_id xtmr_inject_of_match[] = {
@@ -164,7 +163,7 @@ static struct platform_driver xtmr_inject_driver = {
                .of_match_table = xtmr_inject_of_match,
        },
        .probe = xtmr_inject_probe,
-       .remove = xtmr_inject_remove,
+       .remove_new = xtmr_inject_remove,
 };
 module_platform_driver(xtmr_inject_driver);
 MODULE_AUTHOR("Advanced Micro Devices, Inc");
index e4412c7d25b0e057303927a3c81c56ce4269a35d..f13d0e14a48b6474c7f0134eaadaefeb727ebc85 100644 (file)
@@ -499,7 +499,7 @@ static int most_match(struct device *dev, struct device_driver *drv)
                return 1;
 }
 
-static struct bus_type mostbus = {
+static const struct bus_type mostbus = {
        .name = "most",
        .match = most_match,
 };
index 7499a540121e8b2b41e2941f1448e0691028b1e0..e28a3af83c0eb8dd6d13c382049c188bdaa8fd04 100644 (file)
@@ -113,4 +113,17 @@ config MTD_UBI_FAULT_INJECTION
           testing purposes.
 
           If in doubt, say "N".
+
+config MTD_UBI_NVMEM
+       tristate "UBI virtual NVMEM"
+       default n
+       depends on NVMEM
+       help
+          This option enabled an additional driver exposing UBI volumes as NVMEM
+          providers, intended for platforms where UBI is part of the firmware
+          specification and used to store also e.g. MAC addresses or board-
+          specific Wi-Fi calibration data.
+
+          If in doubt, say "N".
+
 endif # MTD_UBI
index 543673605ca7298c4804874b82a3907397499f4e..4b51aaf00d1a2aa8bb591bd281ccf7e96c18e7ff 100644 (file)
@@ -7,3 +7,4 @@ ubi-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o
 ubi-$(CONFIG_MTD_UBI_BLOCK) += block.o
 
 obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
+obj-$(CONFIG_MTD_UBI_NVMEM) += nvmem.o
index 5c8fdcc088a0df73e4ee4684a4406780fddd978e..f82e3423acb9fb92c3d46bc92a1a1f6d31e66e83 100644 (file)
@@ -65,10 +65,10 @@ struct ubiblock_pdu {
 };
 
 /* Numbers of elements set in the @ubiblock_param array */
-static int ubiblock_devs __initdata;
+static int ubiblock_devs;
 
 /* MTD devices specification parameters */
-static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES] __initdata;
+static struct ubiblock_param ubiblock_param[UBIBLOCK_MAX_DEVICES];
 
 struct ubiblock {
        struct ubi_volume_desc *desc;
@@ -536,6 +536,70 @@ static int ubiblock_resize(struct ubi_volume_info *vi)
        return 0;
 }
 
+static bool
+match_volume_desc(struct ubi_volume_info *vi, const char *name, int ubi_num, int vol_id)
+{
+       int err, len, cur_ubi_num, cur_vol_id;
+
+       if (ubi_num == -1) {
+               /* No ubi num, name must be a vol device path */
+               err = ubi_get_num_by_path(name, &cur_ubi_num, &cur_vol_id);
+               if (err || vi->ubi_num != cur_ubi_num || vi->vol_id != cur_vol_id)
+                       return false;
+
+               return true;
+       }
+
+       if (vol_id == -1) {
+               /* Got ubi_num, but no vol_id, name must be volume name */
+               if (vi->ubi_num != ubi_num)
+                       return false;
+
+               len = strnlen(name, UBI_VOL_NAME_MAX + 1);
+               if (len < 1 || vi->name_len != len)
+                       return false;
+
+               if (strcmp(name, vi->name))
+                       return false;
+
+               return true;
+       }
+
+       if (vi->ubi_num != ubi_num)
+               return false;
+
+       if (vi->vol_id != vol_id)
+               return false;
+
+       return true;
+}
+
+static void
+ubiblock_create_from_param(struct ubi_volume_info *vi)
+{
+       int i, ret = 0;
+       struct ubiblock_param *p;
+
+       /*
+        * Iterate over ubiblock cmdline parameters. If a parameter matches the
+        * newly added volume create the ubiblock device for it.
+        */
+       for (i = 0; i < ubiblock_devs; i++) {
+               p = &ubiblock_param[i];
+
+               if (!match_volume_desc(vi, p->name, p->ubi_num, p->vol_id))
+                       continue;
+
+               ret = ubiblock_create(vi);
+               if (ret) {
+                       pr_err(
+                              "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
+                              vi->name, p->ubi_num, p->vol_id, ret);
+               }
+               break;
+       }
+}
+
 static int ubiblock_notify(struct notifier_block *nb,
                         unsigned long notification_type, void *ns_ptr)
 {
@@ -543,10 +607,7 @@ static int ubiblock_notify(struct notifier_block *nb,
 
        switch (notification_type) {
        case UBI_VOLUME_ADDED:
-               /*
-                * We want to enforce explicit block device creation for
-                * volumes, so when a volume is added we do nothing.
-                */
+               ubiblock_create_from_param(&nt->vi);
                break;
        case UBI_VOLUME_REMOVED:
                ubiblock_remove(&nt->vi);
@@ -572,56 +633,6 @@ static struct notifier_block ubiblock_notifier = {
        .notifier_call = ubiblock_notify,
 };
 
-static struct ubi_volume_desc * __init
-open_volume_desc(const char *name, int ubi_num, int vol_id)
-{
-       if (ubi_num == -1)
-               /* No ubi num, name must be a vol device path */
-               return ubi_open_volume_path(name, UBI_READONLY);
-       else if (vol_id == -1)
-               /* No vol_id, must be vol_name */
-               return ubi_open_volume_nm(ubi_num, name, UBI_READONLY);
-       else
-               return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
-}
-
-static void __init ubiblock_create_from_param(void)
-{
-       int i, ret = 0;
-       struct ubiblock_param *p;
-       struct ubi_volume_desc *desc;
-       struct ubi_volume_info vi;
-
-       /*
-        * If there is an error creating one of the ubiblocks, continue on to
-        * create the following ubiblocks. This helps in a circumstance where
-        * the kernel command-line specifies multiple block devices and some
-        * may be broken, but we still want the working ones to come up.
-        */
-       for (i = 0; i < ubiblock_devs; i++) {
-               p = &ubiblock_param[i];
-
-               desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
-               if (IS_ERR(desc)) {
-                       pr_err(
-                              "UBI: block: can't open volume on ubi%d_%d, err=%ld\n",
-                              p->ubi_num, p->vol_id, PTR_ERR(desc));
-                       continue;
-               }
-
-               ubi_get_volume_info(desc, &vi);
-               ubi_close_volume(desc);
-
-               ret = ubiblock_create(&vi);
-               if (ret) {
-                       pr_err(
-                              "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d\n",
-                              vi.name, p->ubi_num, p->vol_id, ret);
-                       continue;
-               }
-       }
-}
-
 static void ubiblock_remove_all(void)
 {
        struct ubiblock *next;
@@ -647,18 +658,7 @@ int __init ubiblock_init(void)
        if (ubiblock_major < 0)
                return ubiblock_major;
 
-       /*
-        * Attach block devices from 'block=' module param.
-        * Even if one block device in the param list fails to come up,
-        * still allow the module to load and leave any others up.
-        */
-       ubiblock_create_from_param();
-
-       /*
-        * Block devices are only created upon user requests, so we ignore
-        * existing volumes.
-        */
-       ret = ubi_register_volume_notifier(&ubiblock_notifier, 1);
+       ret = ubi_register_volume_notifier(&ubiblock_notifier, 0);
        if (ret)
                goto err_unreg;
        return 0;
index 7d4ff1193db6f04a114b1e0fcdde3984644607d1..a7e3a6246c0e93309805c588391640936993bce5 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/log2.h>
 #include <linux/kthread.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/major.h>
 #include "ubi.h"
@@ -92,7 +93,7 @@ static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
 /* Serializes UBI devices creations and removals */
 DEFINE_MUTEX(ubi_devices_mutex);
 
-/* Protects @ubi_devices and @ubi->ref_count */
+/* Protects @ubi_devices, @ubi->ref_count and @ubi->is_dead */
 static DEFINE_SPINLOCK(ubi_devices_lock);
 
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
@@ -260,6 +261,9 @@ struct ubi_device *ubi_get_device(int ubi_num)
 
        spin_lock(&ubi_devices_lock);
        ubi = ubi_devices[ubi_num];
+       if (ubi && ubi->is_dead)
+               ubi = NULL;
+
        if (ubi) {
                ubi_assert(ubi->ref_count >= 0);
                ubi->ref_count += 1;
@@ -297,7 +301,7 @@ struct ubi_device *ubi_get_by_major(int major)
        spin_lock(&ubi_devices_lock);
        for (i = 0; i < UBI_MAX_DEVICES; i++) {
                ubi = ubi_devices[i];
-               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+               if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
                        ubi_assert(ubi->ref_count >= 0);
                        ubi->ref_count += 1;
                        get_device(&ubi->dev);
@@ -326,7 +330,7 @@ int ubi_major2num(int major)
        for (i = 0; i < UBI_MAX_DEVICES; i++) {
                struct ubi_device *ubi = ubi_devices[i];
 
-               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+               if (ubi && !ubi->is_dead && MAJOR(ubi->cdev.dev) == major) {
                        ubi_num = ubi->ubi_num;
                        break;
                }
@@ -513,7 +517,7 @@ static void ubi_free_volumes_from(struct ubi_device *ubi, int from)
        int i;
 
        for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
-               if (!ubi->volumes[i])
+               if (!ubi->volumes[i] || ubi->volumes[i]->is_dead)
                        continue;
                ubi_eba_replace_table(ubi->volumes[i], NULL);
                ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
@@ -1098,7 +1102,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
                return -EINVAL;
 
        spin_lock(&ubi_devices_lock);
-       put_device(&ubi->dev);
        ubi->ref_count -= 1;
        if (ubi->ref_count) {
                if (!anyway) {
@@ -1109,6 +1112,13 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
                ubi_err(ubi, "%s reference count %d, destroy anyway",
                        ubi->ubi_name, ubi->ref_count);
        }
+       ubi->is_dead = true;
+       spin_unlock(&ubi_devices_lock);
+
+       ubi_notify_all(ubi, UBI_VOLUME_SHUTDOWN, NULL);
+
+       spin_lock(&ubi_devices_lock);
+       put_device(&ubi->dev);
        ubi_devices[ubi_num] = NULL;
        spin_unlock(&ubi_devices_lock);
 
@@ -1219,43 +1229,43 @@ static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
        return mtd;
 }
 
-static int __init ubi_init(void)
+static void ubi_notify_add(struct mtd_info *mtd)
 {
-       int err, i, k;
+       struct device_node *np = mtd_get_of_node(mtd);
+       int err;
 
-       /* Ensure that EC and VID headers have correct size */
-       BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
-       BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+       if (!of_device_is_compatible(np, "linux,ubi"))
+               return;
 
-       if (mtd_devs > UBI_MAX_DEVICES) {
-               pr_err("UBI error: too many MTD devices, maximum is %d\n",
-                      UBI_MAX_DEVICES);
-               return -EINVAL;
-       }
+       /*
+        * we are already holding &mtd_table_mutex, but still need
+        * to bump refcount
+        */
+       err = __get_mtd_device(mtd);
+       if (err)
+               return;
 
-       /* Create base sysfs directory and sysfs files */
-       err = class_register(&ubi_class);
+       /* called while holding mtd_table_mutex */
+       mutex_lock_nested(&ubi_devices_mutex, SINGLE_DEPTH_NESTING);
+       err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false, false);
+       mutex_unlock(&ubi_devices_mutex);
        if (err < 0)
-               return err;
-
-       err = misc_register(&ubi_ctrl_cdev);
-       if (err) {
-               pr_err("UBI error: cannot register device\n");
-               goto out;
-       }
+               __put_mtd_device(mtd);
+}
 
-       ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
-                                             sizeof(struct ubi_wl_entry),
-                                             0, 0, NULL);
-       if (!ubi_wl_entry_slab) {
-               err = -ENOMEM;
-               goto out_dev_unreg;
-       }
+static void ubi_notify_remove(struct mtd_info *mtd)
+{
+       /* do nothing for now */
+}
 
-       err = ubi_debugfs_init();
-       if (err)
-               goto out_slab;
+static struct mtd_notifier ubi_mtd_notifier = {
+       .add = ubi_notify_add,
+       .remove = ubi_notify_remove,
+};
 
+static int __init ubi_init_attach(void)
+{
+       int err, i, k;
 
        /* Attach MTD devices */
        for (i = 0; i < mtd_devs; i++) {
@@ -1304,25 +1314,79 @@ static int __init ubi_init(void)
                }
        }
 
+       return 0;
+
+out_detach:
+       for (k = 0; k < i; k++)
+               if (ubi_devices[k]) {
+                       mutex_lock(&ubi_devices_mutex);
+                       ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
+       return err;
+}
+#ifndef CONFIG_MTD_UBI_MODULE
+late_initcall(ubi_init_attach);
+#endif
+
+static int __init ubi_init(void)
+{
+       int err;
+
+       /* Ensure that EC and VID headers have correct size */
+       BUILD_BUG_ON(sizeof(struct ubi_ec_hdr) != 64);
+       BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
+
+       if (mtd_devs > UBI_MAX_DEVICES) {
+               pr_err("UBI error: too many MTD devices, maximum is %d\n",
+                      UBI_MAX_DEVICES);
+               return -EINVAL;
+       }
+
+       /* Create base sysfs directory and sysfs files */
+       err = class_register(&ubi_class);
+       if (err < 0)
+               return err;
+
+       err = misc_register(&ubi_ctrl_cdev);
+       if (err) {
+               pr_err("UBI error: cannot register device\n");
+               goto out;
+       }
+
+       ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+                                             sizeof(struct ubi_wl_entry),
+                                             0, 0, NULL);
+       if (!ubi_wl_entry_slab) {
+               err = -ENOMEM;
+               goto out_dev_unreg;
+       }
+
+       err = ubi_debugfs_init();
+       if (err)
+               goto out_slab;
+
        err = ubiblock_init();
        if (err) {
                pr_err("UBI error: block: cannot initialize, error %d\n", err);
 
                /* See comment above re-ubi_is_module(). */
                if (ubi_is_module())
-                       goto out_detach;
+                       goto out_slab;
+       }
+
+       register_mtd_user(&ubi_mtd_notifier);
+
+       if (ubi_is_module()) {
+               err = ubi_init_attach();
+               if (err)
+                       goto out_mtd_notifier;
        }
 
        return 0;
 
-out_detach:
-       for (k = 0; k < i; k++)
-               if (ubi_devices[k]) {
-                       mutex_lock(&ubi_devices_mutex);
-                       ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
-                       mutex_unlock(&ubi_devices_mutex);
-               }
-       ubi_debugfs_exit();
+out_mtd_notifier:
+       unregister_mtd_user(&ubi_mtd_notifier);
 out_slab:
        kmem_cache_destroy(ubi_wl_entry_slab);
 out_dev_unreg:
@@ -1332,13 +1396,15 @@ out:
        pr_err("UBI error: cannot initialize UBI, error %d\n", err);
        return err;
 }
-late_initcall(ubi_init);
+device_initcall(ubi_init);
+
 
 static void __exit ubi_exit(void)
 {
        int i;
 
        ubiblock_exit();
+       unregister_mtd_user(&ubi_mtd_notifier);
 
        for (i = 0; i < UBI_MAX_DEVICES; i++)
                if (ubi_devices[i]) {
index 8d1f0e05892c1fa6d869b2e9c86a096295c2736c..e5ac3cd0bbae62494846a3514548ff163439163f 100644 (file)
@@ -1456,7 +1456,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        }
 
        ubi_assert(vol->eba_tbl->entries[lnum].pnum == from);
+
+       /**
+        * The volumes_lock lock is needed here to prevent the expired old eba_tbl
+        * being updated when the eba_tbl is copied in the ubi_resize_volume() process.
+        */
+       spin_lock(&ubi->volumes_lock);
        vol->eba_tbl->entries[lnum].pnum = to;
+       spin_unlock(&ubi->volumes_lock);
 
 out_unlock_buf:
        mutex_unlock(&ubi->buf_mutex);
index 2a728c31e6b8549353a60c38abb387d123821bc5..9a4940874be5bae4f1288209e1e38583a39b495d 100644 (file)
@@ -85,9 +85,10 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi)
                sizeof(struct ubi_fm_scan_pool) +
                sizeof(struct ubi_fm_scan_pool) +
                (ubi->peb_count * sizeof(struct ubi_fm_ec)) +
-               (sizeof(struct ubi_fm_eba) +
-               (ubi->peb_count * sizeof(__be32))) +
-               sizeof(struct ubi_fm_volhdr) * UBI_MAX_VOLUMES;
+               ((sizeof(struct ubi_fm_eba) +
+                 sizeof(struct ubi_fm_volhdr)) *
+                (UBI_MAX_VOLUMES + UBI_INT_VOL_COUNT)) +
+               (ubi->peb_count * sizeof(__be32));
        return roundup(size, ubi->leb_size);
 }
 
index 5db653eacbd451ba6efc08e4ce96c192159fef44..f1ea8677467fbfc6f3585d54544a50ed2c17c99d 100644 (file)
@@ -152,7 +152,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
 
        spin_lock(&ubi->volumes_lock);
        vol = ubi->volumes[vol_id];
-       if (!vol)
+       if (!vol || vol->is_dead)
                goto out_unlock;
 
        err = -EBUSY;
@@ -279,6 +279,41 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 
+/**
+ * ubi_get_num_by_path - get UBI device and volume number from device path
+ * @pathname: volume character device node path
+ * @ubi_num: pointer to UBI device number to be set
+ * @vol_id: pointer to UBI volume ID to be set
+ *
+ * Returns 0 on success and sets ubi_num and vol_id, returns error otherwise.
+ */
+int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id)
+{
+       int error;
+       struct path path;
+       struct kstat stat;
+
+       error = kern_path(pathname, LOOKUP_FOLLOW, &path);
+       if (error)
+               return error;
+
+       error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
+       path_put(&path);
+       if (error)
+               return error;
+
+       if (!S_ISCHR(stat.mode))
+               return -EINVAL;
+
+       *ubi_num = ubi_major2num(MAJOR(stat.rdev));
+       *vol_id = MINOR(stat.rdev) - 1;
+
+       if (*vol_id < 0 || *ubi_num < 0)
+               return -ENODEV;
+
+       return 0;
+}
+
 /**
  * ubi_open_volume_path - open UBI volume by its character device node path.
  * @pathname: volume character device node path
@@ -290,32 +325,17 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
 struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode)
 {
        int error, ubi_num, vol_id;
-       struct path path;
-       struct kstat stat;
 
        dbg_gen("open volume %s, mode %d", pathname, mode);
 
        if (!pathname || !*pathname)
                return ERR_PTR(-EINVAL);
 
-       error = kern_path(pathname, LOOKUP_FOLLOW, &path);
-       if (error)
-               return ERR_PTR(error);
-
-       error = vfs_getattr(&path, &stat, STATX_TYPE, AT_STATX_SYNC_AS_STAT);
-       path_put(&path);
+       error = ubi_get_num_by_path(pathname, &ubi_num, &vol_id);
        if (error)
                return ERR_PTR(error);
 
-       if (!S_ISCHR(stat.mode))
-               return ERR_PTR(-EINVAL);
-
-       ubi_num = ubi_major2num(MAJOR(stat.rdev));
-       vol_id = MINOR(stat.rdev) - 1;
-
-       if (vol_id >= 0 && ubi_num >= 0)
-               return ubi_open_volume(ubi_num, vol_id, mode);
-       return ERR_PTR(-ENODEV);
+       return ubi_open_volume(ubi_num, vol_id, mode);
 }
 EXPORT_SYMBOL_GPL(ubi_open_volume_path);
 
diff --git a/drivers/mtd/ubi/nvmem.c b/drivers/mtd/ubi/nvmem.c
new file mode 100644 (file)
index 0000000..8aeb9c4
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Daniel Golle <daniel@makrotopia.org>
+ */
+
+/* UBI NVMEM provider */
+#include "ubi.h"
+#include <linux/nvmem-provider.h>
+#include <asm/div64.h>
+
+/* List of all NVMEM devices */
+static LIST_HEAD(nvmem_devices);
+static DEFINE_MUTEX(devices_mutex);
+
+struct ubi_nvmem {
+       struct nvmem_device *nvmem;
+       int ubi_num;
+       int vol_id;
+       int usable_leb_size;
+       struct list_head list;
+};
+
+static int ubi_nvmem_reg_read(void *priv, unsigned int from,
+                             void *val, size_t bytes)
+{
+       size_t to_read, bytes_left = bytes;
+       struct ubi_nvmem *unv = priv;
+       struct ubi_volume_desc *desc;
+       uint32_t offs;
+       uint64_t lnum = from;
+       int err = 0;
+
+       desc = ubi_open_volume(unv->ubi_num, unv->vol_id, UBI_READONLY);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       offs = do_div(lnum, unv->usable_leb_size);
+       while (bytes_left) {
+               to_read = unv->usable_leb_size - offs;
+
+               if (to_read > bytes_left)
+                       to_read = bytes_left;
+
+               err = ubi_read(desc, lnum, val, offs, to_read);
+               if (err)
+                       break;
+
+               lnum += 1;
+               offs = 0;
+               bytes_left -= to_read;
+               val += to_read;
+       }
+       ubi_close_volume(desc);
+
+       if (err)
+               return err;
+
+       return bytes_left == 0 ? 0 : -EIO;
+}
+
+static int ubi_nvmem_add(struct ubi_volume_info *vi)
+{
+       struct device_node *np = dev_of_node(vi->dev);
+       struct nvmem_config config = {};
+       struct ubi_nvmem *unv;
+       int ret;
+
+       if (!np)
+               return 0;
+
+       if (!of_get_child_by_name(np, "nvmem-layout"))
+               return 0;
+
+       if (WARN_ON_ONCE(vi->usable_leb_size <= 0) ||
+           WARN_ON_ONCE(vi->size <= 0))
+               return -EINVAL;
+
+       unv = kzalloc(sizeof(struct ubi_nvmem), GFP_KERNEL);
+       if (!unv)
+               return -ENOMEM;
+
+       config.id = NVMEM_DEVID_NONE;
+       config.dev = vi->dev;
+       config.name = dev_name(vi->dev);
+       config.owner = THIS_MODULE;
+       config.priv = unv;
+       config.reg_read = ubi_nvmem_reg_read;
+       config.size = vi->usable_leb_size * vi->size;
+       config.word_size = 1;
+       config.stride = 1;
+       config.read_only = true;
+       config.root_only = true;
+       config.ignore_wp = true;
+       config.of_node = np;
+
+       unv->ubi_num = vi->ubi_num;
+       unv->vol_id = vi->vol_id;
+       unv->usable_leb_size = vi->usable_leb_size;
+       unv->nvmem = nvmem_register(&config);
+       if (IS_ERR(unv->nvmem)) {
+               ret = dev_err_probe(vi->dev, PTR_ERR(unv->nvmem),
+                                   "Failed to register NVMEM device\n");
+               kfree(unv);
+               return ret;
+       }
+
+       mutex_lock(&devices_mutex);
+       list_add_tail(&unv->list, &nvmem_devices);
+       mutex_unlock(&devices_mutex);
+
+       return 0;
+}
+
+static void ubi_nvmem_remove(struct ubi_volume_info *vi)
+{
+       struct ubi_nvmem *unv_c, *unv = NULL;
+
+       mutex_lock(&devices_mutex);
+       list_for_each_entry(unv_c, &nvmem_devices, list)
+               if (unv_c->ubi_num == vi->ubi_num && unv_c->vol_id == vi->vol_id) {
+                       unv = unv_c;
+                       break;
+               }
+
+       if (!unv) {
+               mutex_unlock(&devices_mutex);
+               return;
+       }
+
+       list_del(&unv->list);
+       mutex_unlock(&devices_mutex);
+       nvmem_unregister(unv->nvmem);
+       kfree(unv);
+}
+
+/**
+ * nvmem_notify - UBI notification handler.
+ * @nb: registered notifier block
+ * @l: notification type
+ * @ns_ptr: pointer to the &struct ubi_notification object
+ */
+static int nvmem_notify(struct notifier_block *nb, unsigned long l,
+                        void *ns_ptr)
+{
+       struct ubi_notification *nt = ns_ptr;
+
+       switch (l) {
+       case UBI_VOLUME_RESIZED:
+               ubi_nvmem_remove(&nt->vi);
+               fallthrough;
+       case UBI_VOLUME_ADDED:
+               ubi_nvmem_add(&nt->vi);
+               break;
+       case UBI_VOLUME_SHUTDOWN:
+               ubi_nvmem_remove(&nt->vi);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block nvmem_notifier = {
+       .notifier_call = nvmem_notify,
+};
+
+static int __init ubi_nvmem_init(void)
+{
+       return ubi_register_volume_notifier(&nvmem_notifier, 0);
+}
+
+static void __exit ubi_nvmem_exit(void)
+{
+       struct ubi_nvmem *unv, *tmp;
+
+       mutex_lock(&devices_mutex);
+       list_for_each_entry_safe(unv, tmp, &nvmem_devices, list) {
+               nvmem_unregister(unv->nvmem);
+               list_del(&unv->list);
+               kfree(unv);
+       }
+       mutex_unlock(&devices_mutex);
+
+       ubi_unregister_volume_notifier(&nvmem_notifier);
+}
+
+module_init(ubi_nvmem_init);
+module_exit(ubi_nvmem_exit);
+MODULE_DESCRIPTION("NVMEM layer over UBI volumes");
+MODULE_AUTHOR("Daniel Golle");
+MODULE_LICENSE("GPL");
index 0b42bb45dd840bf28689a72056ec2760ea7d1ef4..32009a24869e7e49584e352ef37c52bba8c2cc4c 100644 (file)
@@ -337,6 +337,7 @@ struct ubi_volume {
        int writers;
        int exclusive;
        int metaonly;
+       bool is_dead;
 
        int reserved_pebs;
        int vol_type;
@@ -561,6 +562,7 @@ struct ubi_device {
        spinlock_t volumes_lock;
        int ref_count;
        int image_seq;
+       bool is_dead;
 
        int rsvd_pebs;
        int avail_pebs;
@@ -955,6 +957,7 @@ void ubi_free_internal_volumes(struct ubi_device *ubi);
 void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
 void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
                            struct ubi_volume_info *vi);
+int ubi_get_num_by_path(const char *pathname, int *ubi_num, int *vol_id);
 /* scan.c */
 int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
                      int pnum, const struct ubi_vid_hdr *vid_hdr);
index 2c867d16f89f7de2942f0db6db9b194bd92ee945..5a3558bbb90356f0e1394b9b882b8992e4c8d019 100644 (file)
@@ -59,7 +59,7 @@ static ssize_t vol_attribute_show(struct device *dev,
        struct ubi_device *ubi = vol->ubi;
 
        spin_lock(&ubi->volumes_lock);
-       if (!ubi->volumes[vol->vol_id]) {
+       if (!ubi->volumes[vol->vol_id] || ubi->volumes[vol->vol_id]->is_dead) {
                spin_unlock(&ubi->volumes_lock);
                return -ENODEV;
        }
@@ -124,6 +124,31 @@ static void vol_release(struct device *dev)
        kfree(vol);
 }
 
+static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol)
+{
+       struct fwnode_handle *fw_vols, *fw_vol;
+       const char *volname;
+       u32 volid;
+
+       fw_vols = device_get_named_child_node(vol->dev.parent->parent, "volumes");
+       if (!fw_vols)
+               return NULL;
+
+       fwnode_for_each_child_node(fw_vols, fw_vol) {
+               if (!fwnode_property_read_string(fw_vol, "volname", &volname) &&
+                   strncmp(volname, vol->name, vol->name_len))
+                       continue;
+
+               if (!fwnode_property_read_u32(fw_vol, "volid", &volid) &&
+                   vol->vol_id != volid)
+                       continue;
+
+               return fw_vol;
+       }
+
+       return NULL;
+}
+
 /**
  * ubi_create_volume - create volume.
  * @ubi: UBI device description object
@@ -189,7 +214,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
 
        /* Ensure that the name is unique */
        for (i = 0; i < ubi->vtbl_slots; i++)
-               if (ubi->volumes[i] &&
+               if (ubi->volumes[i] && !ubi->volumes[i]->is_dead &&
                    ubi->volumes[i]->name_len == req->name_len &&
                    !strcmp(ubi->volumes[i]->name, req->name)) {
                        ubi_err(ubi, "volume \"%s\" exists (ID %d)",
@@ -223,6 +248,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        vol->name_len  = req->name_len;
        memcpy(vol->name, req->name, vol->name_len);
        vol->ubi = ubi;
+       device_set_node(&vol->dev, find_volume_fwnode(vol));
 
        /*
         * Finish all pending erases because there may be some LEBs belonging
@@ -352,6 +378,19 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
                err = -EBUSY;
                goto out_unlock;
        }
+
+       /*
+        * Mark volume as dead at this point to prevent that anyone
+        * can take a reference to the volume from now on.
+        * This is necessary as we have to release the spinlock before
+        * calling ubi_volume_notify.
+        */
+       vol->is_dead = true;
+       spin_unlock(&ubi->volumes_lock);
+
+       ubi_volume_notify(ubi, vol, UBI_VOLUME_SHUTDOWN);
+
+       spin_lock(&ubi->volumes_lock);
        ubi->volumes[vol_id] = NULL;
        spin_unlock(&ubi->volumes_lock);
 
@@ -408,6 +447,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
        struct ubi_device *ubi = vol->ubi;
        struct ubi_vtbl_record vtbl_rec;
        struct ubi_eba_table *new_eba_tbl = NULL;
+       struct ubi_eba_table *old_eba_tbl = NULL;
        int vol_id = vol->vol_id;
 
        if (ubi->ro_mode)
@@ -453,10 +493,13 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                        err = -ENOSPC;
                        goto out_free;
                }
+
                ubi->avail_pebs -= pebs;
                ubi->rsvd_pebs += pebs;
                ubi_eba_copy_table(vol, new_eba_tbl, vol->reserved_pebs);
-               ubi_eba_replace_table(vol, new_eba_tbl);
+               old_eba_tbl = vol->eba_tbl;
+               vol->eba_tbl = new_eba_tbl;
+               vol->reserved_pebs = reserved_pebs;
                spin_unlock(&ubi->volumes_lock);
        }
 
@@ -471,7 +514,9 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                ubi->avail_pebs -= pebs;
                ubi_update_reserved(ubi);
                ubi_eba_copy_table(vol, new_eba_tbl, reserved_pebs);
-               ubi_eba_replace_table(vol, new_eba_tbl);
+               old_eba_tbl = vol->eba_tbl;
+               vol->eba_tbl = new_eba_tbl;
+               vol->reserved_pebs = reserved_pebs;
                spin_unlock(&ubi->volumes_lock);
        }
 
@@ -493,7 +538,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
        if (err)
                goto out_acc;
 
-       vol->reserved_pebs = reserved_pebs;
        if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
                vol->used_ebs = reserved_pebs;
                vol->last_eb_bytes = vol->usable_leb_size;
@@ -501,19 +545,23 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                        (long long)vol->used_ebs * vol->usable_leb_size;
        }
 
+       /* destroy old table */
+       ubi_eba_destroy_table(old_eba_tbl);
        ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
        self_check_volumes(ubi);
        return err;
 
 out_acc:
-       if (pebs > 0) {
-               spin_lock(&ubi->volumes_lock);
-               ubi->rsvd_pebs -= pebs;
-               ubi->avail_pebs += pebs;
-               spin_unlock(&ubi->volumes_lock);
-       }
-       return err;
-
+       spin_lock(&ubi->volumes_lock);
+       vol->reserved_pebs = reserved_pebs - pebs;
+       ubi->rsvd_pebs -= pebs;
+       ubi->avail_pebs += pebs;
+       if (pebs > 0)
+               ubi_eba_copy_table(vol, old_eba_tbl, vol->reserved_pebs);
+       else
+               ubi_eba_copy_table(vol, old_eba_tbl, reserved_pebs);
+       vol->eba_tbl = old_eba_tbl;
+       spin_unlock(&ubi->volumes_lock);
 out_free:
        ubi_eba_destroy_table(new_eba_tbl);
        return err;
@@ -592,6 +640,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
        vol->dev.class = &ubi_class;
        vol->dev.groups = volume_dev_groups;
        dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id);
+       device_set_node(&vol->dev, find_volume_fwnode(vol));
        err = device_register(&vol->dev);
        if (err) {
                cdev_del(&vol->cdev);
index f700f0e4f2ec4d7c700a2428fd83e54129992c24..6e5489e233dd2afadc99e150ac9476ec622c38d3 100644 (file)
@@ -791,6 +791,12 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
         * The number of supported volumes is limited by the eraseblock size
         * and by the UBI_MAX_VOLUMES constant.
         */
+
+       if (ubi->leb_size < UBI_VTBL_RECORD_SIZE) {
+               ubi_err(ubi, "LEB size too small for a volume record");
+               return -EINVAL;
+       }
+
        ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE;
        if (ubi->vtbl_slots > UBI_MAX_VOLUMES)
                ubi->vtbl_slots = UBI_MAX_VOLUMES;
index f81b598147b3062b453a246f27032c23f9e0d2cb..7b5028b67cd5cb56943c86c946f14d838b25b531 100644 (file)
@@ -370,8 +370,8 @@ static const struct kvaser_pciefd_irq_mask kvaser_pciefd_sf2_irq_mask = {
 
 static const struct kvaser_pciefd_irq_mask kvaser_pciefd_xilinx_irq_mask = {
        .kcan_rx0 = BIT(4),
-       .kcan_tx = { BIT(16), BIT(17), BIT(18), BIT(19) },
-       .all = GENMASK(19, 16) | BIT(4),
+       .kcan_tx = { BIT(16), BIT(17), BIT(18), BIT(19), BIT(20), BIT(21), BIT(22), BIT(23) },
+       .all = GENMASK(23, 16) | BIT(4),
 };
 
 static const struct kvaser_pciefd_dev_ops kvaser_pciefd_altera_dev_ops = {
index 678b51f9cea61512641b1b4c14891b57b5d6434a..767f66c37f6b5cf63db379232af407b9813428a1 100644 (file)
@@ -950,20 +950,56 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
        mutex_unlock(&priv->reg_mutex);
 }
 
+/* On page 205, section "8.6.3 Frame filtering" of the active standard, IEEE Std
+ * 802.1Q™-2022, it is stated that frames with 01:80:C2:00:00:00-0F as MAC DA
+ * must only be propagated to C-VLAN and MAC Bridge components. That means
+ * VLAN-aware and VLAN-unaware bridges. On the switch designs with CPU ports,
+ * these frames are supposed to be processed by the CPU (software). So we make
+ * the switch only forward them to the CPU port. And if received from a CPU
+ * port, forward to a single port. The software is responsible of making the
+ * switch conform to the latter by setting a single port as destination port on
+ * the special tag.
+ *
+ * This switch intellectual property cannot conform to this part of the standard
+ * fully. Whilst the REV_UN frame tag covers the remaining :04-0D and :0F MAC
+ * DAs, it also includes :22-FF which the scope of propagation is not supposed
+ * to be restricted for these MAC DAs.
+ */
 static void
 mt753x_trap_frames(struct mt7530_priv *priv)
 {
-       /* Trap BPDUs to the CPU port(s) */
-       mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
+       /* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them
+        * VLAN-untagged.
+        */
+       mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_EG_TAG_MASK |
+                  MT753X_PAE_PORT_FW_MASK | MT753X_BPDU_EG_TAG_MASK |
+                  MT753X_BPDU_PORT_FW_MASK,
+                  MT753X_PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+                  MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY) |
+                  MT753X_BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
                   MT753X_BPDU_CPU_ONLY);
 
-       /* Trap 802.1X PAE frames to the CPU port(s) */
-       mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_PORT_FW_MASK,
-                  MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY));
+       /* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress
+        * them VLAN-untagged.
+        */
+       mt7530_rmw(priv, MT753X_RGAC1, MT753X_R02_EG_TAG_MASK |
+                  MT753X_R02_PORT_FW_MASK | MT753X_R01_EG_TAG_MASK |
+                  MT753X_R01_PORT_FW_MASK,
+                  MT753X_R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+                  MT753X_R02_PORT_FW(MT753X_BPDU_CPU_ONLY) |
+                  MT753X_R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+                  MT753X_BPDU_CPU_ONLY);
 
-       /* Trap LLDP frames with :0E MAC DA to the CPU port(s) */
-       mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_PORT_FW_MASK,
-                  MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY));
+       /* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress
+        * them VLAN-untagged.
+        */
+       mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_EG_TAG_MASK |
+                  MT753X_R0E_PORT_FW_MASK | MT753X_R03_EG_TAG_MASK |
+                  MT753X_R03_PORT_FW_MASK,
+                  MT753X_R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+                  MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY) |
+                  MT753X_R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+                  MT753X_BPDU_CPU_ONLY);
 }
 
 static void
@@ -2192,22 +2228,16 @@ mt7530_setup(struct dsa_switch *ds)
                }
        }
 
-       /* Disable LEDs before reset to prevent the MT7530 sampling a
-        * potentially incorrect HT_XTAL_FSEL value.
-        */
-       mt7530_write(priv, MT7530_LED_EN, 0);
-       usleep_range(1000, 1100);
-
        /* Reset whole chip through gpio pin or memory-mapped registers for
         * different type of hardware
         */
        if (priv->mcm) {
                reset_control_assert(priv->rstc);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                reset_control_deassert(priv->rstc);
        } else {
                gpiod_set_value_cansleep(priv->reset, 0);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                gpiod_set_value_cansleep(priv->reset, 1);
        }
 
@@ -2420,11 +2450,11 @@ mt7531_setup(struct dsa_switch *ds)
         */
        if (priv->mcm) {
                reset_control_assert(priv->rstc);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                reset_control_deassert(priv->rstc);
        } else {
                gpiod_set_value_cansleep(priv->reset, 0);
-               usleep_range(1000, 1100);
+               usleep_range(5000, 5100);
                gpiod_set_value_cansleep(priv->reset, 1);
        }
 
index a71166e0a7fcf2411292bc713f0bcbd75c2db32c..d17b318e6ee4882ed8b6f6668eaa57a99a38d184 100644 (file)
@@ -65,14 +65,33 @@ enum mt753x_id {
 
 /* Registers for BPDU and PAE frame control*/
 #define MT753X_BPC                     0x24
-#define  MT753X_BPDU_PORT_FW_MASK      GENMASK(2, 0)
+#define  MT753X_PAE_EG_TAG_MASK                GENMASK(24, 22)
+#define  MT753X_PAE_EG_TAG(x)          FIELD_PREP(MT753X_PAE_EG_TAG_MASK, x)
 #define  MT753X_PAE_PORT_FW_MASK       GENMASK(18, 16)
 #define  MT753X_PAE_PORT_FW(x)         FIELD_PREP(MT753X_PAE_PORT_FW_MASK, x)
+#define  MT753X_BPDU_EG_TAG_MASK       GENMASK(8, 6)
+#define  MT753X_BPDU_EG_TAG(x)         FIELD_PREP(MT753X_BPDU_EG_TAG_MASK, x)
+#define  MT753X_BPDU_PORT_FW_MASK      GENMASK(2, 0)
+
+/* Register for :01 and :02 MAC DA frame control */
+#define MT753X_RGAC1                   0x28
+#define  MT753X_R02_EG_TAG_MASK                GENMASK(24, 22)
+#define  MT753X_R02_EG_TAG(x)          FIELD_PREP(MT753X_R02_EG_TAG_MASK, x)
+#define  MT753X_R02_PORT_FW_MASK       GENMASK(18, 16)
+#define  MT753X_R02_PORT_FW(x)         FIELD_PREP(MT753X_R02_PORT_FW_MASK, x)
+#define  MT753X_R01_EG_TAG_MASK                GENMASK(8, 6)
+#define  MT753X_R01_EG_TAG(x)          FIELD_PREP(MT753X_R01_EG_TAG_MASK, x)
+#define  MT753X_R01_PORT_FW_MASK       GENMASK(2, 0)
 
 /* Register for :03 and :0E MAC DA frame control */
 #define MT753X_RGAC2                   0x2c
+#define  MT753X_R0E_EG_TAG_MASK                GENMASK(24, 22)
+#define  MT753X_R0E_EG_TAG(x)          FIELD_PREP(MT753X_R0E_EG_TAG_MASK, x)
 #define  MT753X_R0E_PORT_FW_MASK       GENMASK(18, 16)
 #define  MT753X_R0E_PORT_FW(x)         FIELD_PREP(MT753X_R0E_PORT_FW_MASK, x)
+#define  MT753X_R03_EG_TAG_MASK                GENMASK(8, 6)
+#define  MT753X_R03_EG_TAG(x)          FIELD_PREP(MT753X_R03_EG_TAG_MASK, x)
+#define  MT753X_R03_PORT_FW_MASK       GENMASK(2, 0)
 
 enum mt753x_bpdu_port_fw {
        MT753X_BPDU_FOLLOW_MFC,
@@ -253,6 +272,7 @@ enum mt7530_port_mode {
 enum mt7530_vlan_port_eg_tag {
        MT7530_VLAN_EG_DISABLED = 0,
        MT7530_VLAN_EG_CONSISTENT = 1,
+       MT7530_VLAN_EG_UNTAGGED = 4,
 };
 
 enum mt7530_vlan_port_attr {
index 0d917a9699c586809ed6529bc01366a0bee17f29..b65b8592ad759b9ab3133f0d806a7d268f48c7ed 100644 (file)
@@ -367,6 +367,7 @@ static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
        cp->irq_arr[0].status_blk = (void *)
                ((unsigned long) bnapi->status_blk.msi +
                (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
+       cp->irq_arr[0].status_blk_map = bp->status_blk_mapping;
        cp->irq_arr[0].status_blk_num = sb_id;
        cp->num_irq = 1;
 }
index d8b1824c334d3b0d7b515b8f5dd11aa34190a909..0bc1367fd64924b2338cf6c1483f8b80119ee421 100644 (file)
@@ -1002,9 +1002,6 @@ static inline void bnx2x_set_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid,
 static inline void bnx2x_free_rx_mem_pool(struct bnx2x *bp,
                                          struct bnx2x_alloc_pool *pool)
 {
-       if (!pool->page)
-               return;
-
        put_page(pool->page);
 
        pool->page = NULL;
@@ -1015,6 +1012,9 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
 {
        int i;
 
+       if (!fp->page_pool.page)
+               return;
+
        if (fp->mode == TPA_MODE_DISABLED)
                return;
 
index 0d8e61c63c7c6b37d3b855488f7e5a6cf954dcd3..678829646cec393cc1bffd844866b5fdf591e472 100644 (file)
@@ -14912,9 +14912,11 @@ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
        else
                cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e1x_sb;
 
+       cp->irq_arr[0].status_blk_map = bp->cnic_sb_mapping;
        cp->irq_arr[0].status_blk_num =  bnx2x_cnic_fw_sb_id(bp);
        cp->irq_arr[0].status_blk_num2 = bnx2x_cnic_igu_sb_id(bp);
        cp->irq_arr[1].status_blk = bp->def_status_blk;
+       cp->irq_arr[1].status_blk_map = bp->def_status_blk_mapping;
        cp->irq_arr[1].status_blk_num = DEF_SB_ID;
        cp->irq_arr[1].status_blk_num2 = DEF_SB_IGU_ID;
 
index 7926aaef8f0c525aff2af191ad48d61106513d93..3d63177e7e52b6d44fd1fd49fbdd3af388eb73d0 100644 (file)
@@ -1107,10 +1107,11 @@ static int cnic_init_uio(struct cnic_dev *dev)
                                                     TX_MAX_TSS_RINGS + 1);
                uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
                                        CNIC_PAGE_MASK;
+               uinfo->mem[1].dma_addr = cp->status_blk_map;
                if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
-                       uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
+                       uinfo->mem[1].size = PAGE_ALIGN(BNX2_SBLK_MSIX_ALIGN_SIZE * 9);
                else
-                       uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
+                       uinfo->mem[1].size = PAGE_ALIGN(BNX2_SBLK_MSIX_ALIGN_SIZE);
 
                uinfo->name = "bnx2_cnic";
        } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
@@ -1118,20 +1119,26 @@ static int cnic_init_uio(struct cnic_dev *dev)
 
                uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
                        CNIC_PAGE_MASK;
-               uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
+               uinfo->mem[1].dma_addr = cp->status_blk_map;
+               uinfo->mem[1].size = PAGE_ALIGN(sizeof(*cp->bnx2x_def_status_blk));
 
                uinfo->name = "bnx2x_cnic";
        }
 
-       uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
+       uinfo->mem[1].dma_device = &dev->pcidev->dev;
+       uinfo->mem[1].memtype = UIO_MEM_DMA_COHERENT;
 
        uinfo->mem[2].addr = (unsigned long) udev->l2_ring;
-       uinfo->mem[2].size = udev->l2_ring_size;
-       uinfo->mem[2].memtype = UIO_MEM_LOGICAL;
+       uinfo->mem[2].dma_addr = udev->l2_ring_map;
+       uinfo->mem[2].size = PAGE_ALIGN(udev->l2_ring_size);
+       uinfo->mem[2].dma_device = &dev->pcidev->dev;
+       uinfo->mem[2].memtype = UIO_MEM_DMA_COHERENT;
 
        uinfo->mem[3].addr = (unsigned long) udev->l2_buf;
-       uinfo->mem[3].size = udev->l2_buf_size;
-       uinfo->mem[3].memtype = UIO_MEM_LOGICAL;
+       uinfo->mem[3].dma_addr = udev->l2_buf_map;
+       uinfo->mem[3].size = PAGE_ALIGN(udev->l2_buf_size);
+       uinfo->mem[3].dma_device = &dev->pcidev->dev;
+       uinfo->mem[3].memtype = UIO_MEM_DMA_COHERENT;
 
        uinfo->version = CNIC_MODULE_VERSION;
        uinfo->irq = UIO_IRQ_CUSTOM;
@@ -1313,6 +1320,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
                return 0;
 
        cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
+       cp->status_blk_map = cp->ethdev->irq_arr[1].status_blk_map;
 
        cp->l2_rx_ring_size = 15;
 
@@ -5323,6 +5331,7 @@ static int cnic_start_hw(struct cnic_dev *dev)
        pci_dev_get(dev->pcidev);
        cp->func = PCI_FUNC(dev->pcidev->devfn);
        cp->status_blk.gen = ethdev->irq_arr[0].status_blk;
+       cp->status_blk_map = ethdev->irq_arr[0].status_blk_map;
        cp->status_blk_num = ethdev->irq_arr[0].status_blk_num;
 
        err = cp->alloc_resc(dev);
index 4baea81bae7a35dd43cde54a07eb25d0ae40883e..fedc84ada937d9710dead561f086cafda8eac4fa 100644 (file)
@@ -260,6 +260,7 @@ struct cnic_local {
                #define SM_RX_ID                0
                #define SM_TX_ID                1
        } status_blk;
+       dma_addr_t status_blk_map;
 
        struct host_sp_status_block     *bnx2x_def_status_blk;
 
index 789e5c7e93116ab29d944e57296d511789bfedb0..49a11ec80b3645300786e14720d188a767a95fcd 100644 (file)
@@ -190,6 +190,7 @@ struct cnic_ops {
 struct cnic_irq {
        unsigned int    vector;
        void            *status_blk;
+       dma_addr_t      status_blk_map;
        u32             status_blk_num;
        u32             status_blk_num2;
        u32             irq_flags;
index 8510b88d49820acf3ef81c34ee263d6eaebd2591..f3cd5a376eca90493395687fc40f9da27715a674 100644 (file)
@@ -24,7 +24,7 @@ TRACE_EVENT(hclge_pf_mbx_get,
                __field(u8, code)
                __field(u8, subcode)
                __string(pciname, pci_name(hdev->pdev))
-               __string(devname, &hdev->vport[0].nic.kinfo.netdev->name)
+               __string(devname, hdev->vport[0].nic.kinfo.netdev->name)
                __array(u32, mbx_data, PF_GET_MBX_LEN)
        ),
 
@@ -33,7 +33,7 @@ TRACE_EVENT(hclge_pf_mbx_get,
                __entry->code = req->msg.code;
                __entry->subcode = req->msg.subcode;
                __assign_str(pciname, pci_name(hdev->pdev));
-               __assign_str(devname, &hdev->vport[0].nic.kinfo.netdev->name);
+               __assign_str(devname, hdev->vport[0].nic.kinfo.netdev->name);
                memcpy(__entry->mbx_data, req,
                       sizeof(struct hclge_mbx_vf_to_pf_cmd));
        ),
@@ -56,7 +56,7 @@ TRACE_EVENT(hclge_pf_mbx_send,
                __field(u8, vfid)
                __field(u16, code)
                __string(pciname, pci_name(hdev->pdev))
-               __string(devname, &hdev->vport[0].nic.kinfo.netdev->name)
+               __string(devname, hdev->vport[0].nic.kinfo.netdev->name)
                __array(u32, mbx_data, PF_SEND_MBX_LEN)
        ),
 
@@ -64,7 +64,7 @@ TRACE_EVENT(hclge_pf_mbx_send,
                __entry->vfid = req->dest_vfid;
                __entry->code = le16_to_cpu(req->msg.code);
                __assign_str(pciname, pci_name(hdev->pdev));
-               __assign_str(devname, &hdev->vport[0].nic.kinfo.netdev->name);
+               __assign_str(devname, hdev->vport[0].nic.kinfo.netdev->name);
                memcpy(__entry->mbx_data, req,
                       sizeof(struct hclge_mbx_pf_to_vf_cmd));
        ),
index 5d4895bb57a17d9a01b29545af427ae760c0d578..b259e95dd53c263819af84e280d1aa2133165c59 100644 (file)
@@ -23,7 +23,7 @@ TRACE_EVENT(hclge_vf_mbx_get,
                __field(u8, vfid)
                __field(u16, code)
                __string(pciname, pci_name(hdev->pdev))
-               __string(devname, &hdev->nic.kinfo.netdev->name)
+               __string(devname, hdev->nic.kinfo.netdev->name)
                __array(u32, mbx_data, VF_GET_MBX_LEN)
        ),
 
@@ -31,7 +31,7 @@ TRACE_EVENT(hclge_vf_mbx_get,
                __entry->vfid = req->dest_vfid;
                __entry->code = le16_to_cpu(req->msg.code);
                __assign_str(pciname, pci_name(hdev->pdev));
-               __assign_str(devname, &hdev->nic.kinfo.netdev->name);
+               __assign_str(devname, hdev->nic.kinfo.netdev->name);
                memcpy(__entry->mbx_data, req,
                       sizeof(struct hclge_mbx_pf_to_vf_cmd));
        ),
@@ -55,7 +55,7 @@ TRACE_EVENT(hclge_vf_mbx_send,
                __field(u8, code)
                __field(u8, subcode)
                __string(pciname, pci_name(hdev->pdev))
-               __string(devname, &hdev->nic.kinfo.netdev->name)
+               __string(devname, hdev->nic.kinfo.netdev->name)
                __array(u32, mbx_data, VF_SEND_MBX_LEN)
        ),
 
@@ -64,7 +64,7 @@ TRACE_EVENT(hclge_vf_mbx_send,
                __entry->code = req->msg.code;
                __entry->subcode = req->msg.subcode;
                __assign_str(pciname, pci_name(hdev->pdev));
-               __assign_str(devname, &hdev->nic.kinfo.netdev->name);
+               __assign_str(devname, hdev->nic.kinfo.netdev->name);
                memcpy(__entry->mbx_data, req,
                       sizeof(struct hclge_mbx_vf_to_pf_cmd));
        ),
index d2fd315556a39dc7da84abdf69b68e918ef16191..a545a7917e4fc1098f504a88e6f76a0929fb3027 100644 (file)
@@ -956,7 +956,7 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
 int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings,
                           u16 q_idx)
 {
-       DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1);
 
        if (q_idx >= vsi->alloc_txq || !tx_rings || !tx_rings[q_idx])
                return -EINVAL;
@@ -978,7 +978,7 @@ int ice_vsi_cfg_single_txq(struct ice_vsi *vsi, struct ice_tx_ring **tx_rings,
 static int
 ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_tx_ring **rings, u16 count)
 {
-       DEFINE_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_add_tx_qgrp, qg_buf, txqs, 1);
        int err = 0;
        u16 q_idx;
 
index 4d8111aeb0ff0ccf101ee1560b70ee2a9d064194..db4b2844e1f71820494ffe30cb67d87e8af91edc 100644 (file)
@@ -4695,7 +4695,7 @@ ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
                enum ice_disq_rst_src rst_src, u16 vmvf_num,
                struct ice_sq_cd *cd)
 {
-       DEFINE_FLEX(struct ice_aqc_dis_txq_item, qg_list, q_id, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_dis_txq_item, qg_list, q_id, 1);
        u16 i, buf_size = __struct_size(qg_list);
        struct ice_q_ctx *q_ctx;
        int status = -ENOENT;
@@ -4917,7 +4917,7 @@ int
 ice_dis_vsi_rdma_qset(struct ice_port_info *pi, u16 count, u32 *qset_teid,
                      u16 *q_id)
 {
-       DEFINE_FLEX(struct ice_aqc_dis_txq_item, qg_list, q_id, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_dis_txq_item, qg_list, q_id, 1);
        u16 qg_size = __struct_size(qg_list);
        struct ice_hw *hw;
        int status = 0;
index 7532d11ad7f337db473eb9e3a9edeee1d8f7e85b..fc91c4d411863ecd8bc446006e065694b26c4225 100644 (file)
@@ -1938,8 +1938,8 @@ static enum ice_ddp_state ice_init_pkg_info(struct ice_hw *hw,
  */
 static enum ice_ddp_state ice_get_pkg_info(struct ice_hw *hw)
 {
-       DEFINE_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info,
-                   ICE_PKG_CNT);
+       DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg_info, pkg_info,
+                       ICE_PKG_CNT);
        u16 size = __struct_size(pkg_info);
        u32 i;
 
@@ -1990,8 +1990,8 @@ static enum ice_ddp_state ice_chk_pkg_compat(struct ice_hw *hw,
                                             struct ice_pkg_hdr *ospkg,
                                             struct ice_seg **seg)
 {
-       DEFINE_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info,
-                   ICE_PKG_CNT);
+       DEFINE_RAW_FLEX(struct ice_aqc_get_pkg_info_resp, pkg, pkg_info,
+                       ICE_PKG_CNT);
        u16 size = __struct_size(pkg);
        enum ice_ddp_state state;
        u32 i;
index 467372d541d21f9c26416275f945b12e684079ef..f97128b69f87ecb26d17d81a44486eab3d194470 100644 (file)
@@ -491,7 +491,7 @@ static void
 ice_lag_move_vf_node_tc(struct ice_lag *lag, u8 oldport, u8 newport,
                        u16 vsi_num, u8 tc)
 {
-       DEFINE_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
        struct device *dev = ice_pf_to_dev(lag->pf);
        u16 numq, valq, num_moved, qbuf_size;
        u16 buf_size = __struct_size(buf);
@@ -849,7 +849,7 @@ static void
 ice_lag_reclaim_vf_tc(struct ice_lag *lag, struct ice_hw *src_hw, u16 vsi_num,
                      u8 tc)
 {
-       DEFINE_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
        struct device *dev = ice_pf_to_dev(lag->pf);
        u16 numq, valq, num_moved, qbuf_size;
        u16 buf_size = __struct_size(buf);
@@ -1873,7 +1873,7 @@ static void
 ice_lag_move_vf_nodes_tc_sync(struct ice_lag *lag, struct ice_hw *dest_hw,
                              u16 vsi_num, u8 tc)
 {
-       DEFINE_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
        struct device *dev = ice_pf_to_dev(lag->pf);
        u16 numq, valq, num_moved, qbuf_size;
        u16 buf_size = __struct_size(buf);
index d174a4eeb899ccdf45ea1f6c2bafdbd6193c1dea..a1525992d14bc791c1753fe6b60725a78009afca 100644 (file)
@@ -237,7 +237,7 @@ static int
 ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
                       u32 node_teid)
 {
-       DEFINE_FLEX(struct ice_aqc_delete_elem, buf, teid, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_delete_elem, buf, teid, 1);
        u16 buf_size = __struct_size(buf);
        u16 num_groups_removed = 0;
        int status;
@@ -2219,7 +2219,7 @@ int
 ice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent,
                     u16 num_items, u32 *list)
 {
-       DEFINE_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_move_elem, buf, teid, 1);
        u16 buf_len = __struct_size(buf);
        struct ice_sched_node *node;
        u16 i, grps_movd = 0;
index f84bab80ca42376482e2ea504aa90e3ebf6a8f98..d4baae8c3b720ae7fca91b87a43400b858c046b6 100644 (file)
@@ -1812,7 +1812,7 @@ ice_aq_alloc_free_vsi_list(struct ice_hw *hw, u16 *vsi_list_id,
                           enum ice_sw_lkup_type lkup_type,
                           enum ice_adminq_opc opc)
 {
-       DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
        u16 buf_len = __struct_size(sw_buf);
        struct ice_aqc_res_elem *vsi_ele;
        int status;
@@ -2081,7 +2081,7 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap,
  */
 int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
 {
-       DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
        u16 buf_len = __struct_size(sw_buf);
        int status;
 
@@ -4418,7 +4418,7 @@ int
 ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
                   u16 *counter_id)
 {
-       DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
        u16 buf_len = __struct_size(buf);
        int status;
 
@@ -4446,7 +4446,7 @@ int
 ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
                  u16 counter_id)
 {
-       DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
        u16 buf_len = __struct_size(buf);
        int status;
 
@@ -4476,7 +4476,7 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
  */
 int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id)
 {
-       DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
+       DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
        u16 buf_len = __struct_size(buf);
        u16 res_type;
        int status;
index 6c70c849869043602c2a02e7898f981fc11c5925..3c0f55b3e48ea402959df74c28637a9ca169a382 100644 (file)
@@ -1338,7 +1338,7 @@ static irqreturn_t cgx_fwi_event_handler(int irq, void *data)
 
                /* Release thread waiting for completion  */
                lmac->cmd_pend = false;
-               wake_up_interruptible(&lmac->wq_cmd_cmplt);
+               wake_up(&lmac->wq_cmd_cmplt);
                break;
        case CGX_EVT_ASYNC:
                if (cgx_event_is_linkevent(event))
index b92264d0a77e71075495f5cc0e02c330e3c279bd..1e5aa539750404e14ba40c7581218a2541efce00 100644 (file)
@@ -214,11 +214,12 @@ int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
 }
 EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
 
-void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
+static void otx2_mbox_msg_send_data(struct otx2_mbox *mbox, int devid, u64 data)
 {
        struct otx2_mbox_dev *mdev = &mbox->dev[devid];
        struct mbox_hdr *tx_hdr, *rx_hdr;
        void *hw_mbase = mdev->hwbase;
+       u64 intr_val;
 
        tx_hdr = hw_mbase + mbox->tx_start;
        rx_hdr = hw_mbase + mbox->rx_start;
@@ -254,14 +255,52 @@ void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
 
        spin_unlock(&mdev->mbox_lock);
 
+       /* Check if interrupt pending */
+       intr_val = readq((void __iomem *)mbox->reg_base +
+                    (mbox->trigger | (devid << mbox->tr_shift)));
+
+       intr_val |= data;
        /* The interrupt should be fired after num_msgs is written
         * to the shared memory
         */
-       writeq(1, (void __iomem *)mbox->reg_base +
+       writeq(intr_val, (void __iomem *)mbox->reg_base +
               (mbox->trigger | (devid << mbox->tr_shift)));
 }
+
+void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
+{
+       otx2_mbox_msg_send_data(mbox, devid, MBOX_DOWN_MSG);
+}
 EXPORT_SYMBOL(otx2_mbox_msg_send);
 
+void otx2_mbox_msg_send_up(struct otx2_mbox *mbox, int devid)
+{
+       otx2_mbox_msg_send_data(mbox, devid, MBOX_UP_MSG);
+}
+EXPORT_SYMBOL(otx2_mbox_msg_send_up);
+
+bool otx2_mbox_wait_for_zero(struct otx2_mbox *mbox, int devid)
+{
+       u64 data;
+
+       data = readq((void __iomem *)mbox->reg_base +
+                    (mbox->trigger | (devid << mbox->tr_shift)));
+
+       /* If data is non-zero wait for ~1ms and return to caller
+        * whether data has changed to zero or not after the wait.
+        */
+       if (!data)
+               return true;
+
+       usleep_range(950, 1000);
+
+       data = readq((void __iomem *)mbox->reg_base +
+                    (mbox->trigger | (devid << mbox->tr_shift)));
+
+       return data == 0;
+}
+EXPORT_SYMBOL(otx2_mbox_wait_for_zero);
+
 struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
                                            int size, int size_rsp)
 {
index 61ab7f66f053cca307f77fa94302c8453818aef6..eb2a20b5a0d0c6c9cb15cbfcf98a45f253eb12fc 100644 (file)
@@ -16,6 +16,9 @@
 
 #define MBOX_SIZE              SZ_64K
 
+#define MBOX_DOWN_MSG          1
+#define MBOX_UP_MSG            2
+
 /* AF/PF: PF initiated, PF/VF VF initiated */
 #define MBOX_DOWN_RX_START     0
 #define MBOX_DOWN_RX_SIZE      (46 * SZ_1K)
@@ -101,6 +104,7 @@ int otx2_mbox_regions_init(struct otx2_mbox *mbox, void __force **hwbase,
                           struct pci_dev *pdev, void __force *reg_base,
                           int direction, int ndevs, unsigned long *bmap);
 void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid);
+void otx2_mbox_msg_send_up(struct otx2_mbox *mbox, int devid);
 int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid);
 int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid);
 struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
@@ -118,6 +122,8 @@ static inline struct mbox_msghdr *otx2_mbox_alloc_msg(struct otx2_mbox *mbox,
        return otx2_mbox_alloc_msg_rsp(mbox, devid, size, 0);
 }
 
+bool otx2_mbox_wait_for_zero(struct otx2_mbox *mbox, int devid);
+
 /* Mailbox message types */
 #define MBOX_MSG_MASK                          0xFFFF
 #define MBOX_MSG_INVALID                       0xFFFE
index dfd23580e3b8e1fc88e3597e3eaf04832ad18dc7..d39d86e694ccf7530237a904315a294726cf55f8 100644 (file)
@@ -121,13 +121,17 @@ int mcs_add_intr_wq_entry(struct mcs *mcs, struct mcs_intr_event *event)
 static int mcs_notify_pfvf(struct mcs_intr_event *event, struct rvu *rvu)
 {
        struct mcs_intr_info *req;
-       int err, pf;
+       int pf;
 
        pf = rvu_get_pf(event->pcifunc);
 
+       mutex_lock(&rvu->mbox_lock);
+
        req = otx2_mbox_alloc_msg_mcs_intr_notify(rvu, pf);
-       if (!req)
+       if (!req) {
+               mutex_unlock(&rvu->mbox_lock);
                return -ENOMEM;
+       }
 
        req->mcs_id = event->mcs_id;
        req->intr_mask = event->intr_mask;
@@ -135,10 +139,11 @@ static int mcs_notify_pfvf(struct mcs_intr_event *event, struct rvu *rvu)
        req->hdr.pcifunc = event->pcifunc;
        req->lmac_id = event->lmac_id;
 
-       otx2_mbox_msg_send(&rvu->afpf_wq_info.mbox_up, pf);
-       err = otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pf);
-       if (err)
-               dev_warn(rvu->dev, "MCS notification to pf %d failed\n", pf);
+       otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf);
+
+       otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf);
+
+       mutex_unlock(&rvu->mbox_lock);
 
        return 0;
 }
index 07d4859de53ade0a68ff5fedaed22ec9640e8f96..ff78251f92d4480a72f9c1ce0c268bf8aaa76f4f 100644 (file)
@@ -2119,7 +2119,7 @@ bad_message:
        }
 }
 
-static void __rvu_mbox_handler(struct rvu_work *mwork, int type)
+static void __rvu_mbox_handler(struct rvu_work *mwork, int type, bool poll)
 {
        struct rvu *rvu = mwork->rvu;
        int offset, err, id, devid;
@@ -2186,6 +2186,9 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type)
        }
        mw->mbox_wrk[devid].num_msgs = 0;
 
+       if (poll)
+               otx2_mbox_wait_for_zero(mbox, devid);
+
        /* Send mbox responses to VF/PF */
        otx2_mbox_msg_send(mbox, devid);
 }
@@ -2193,15 +2196,18 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type)
 static inline void rvu_afpf_mbox_handler(struct work_struct *work)
 {
        struct rvu_work *mwork = container_of(work, struct rvu_work, work);
+       struct rvu *rvu = mwork->rvu;
 
-       __rvu_mbox_handler(mwork, TYPE_AFPF);
+       mutex_lock(&rvu->mbox_lock);
+       __rvu_mbox_handler(mwork, TYPE_AFPF, true);
+       mutex_unlock(&rvu->mbox_lock);
 }
 
 static inline void rvu_afvf_mbox_handler(struct work_struct *work)
 {
        struct rvu_work *mwork = container_of(work, struct rvu_work, work);
 
-       __rvu_mbox_handler(mwork, TYPE_AFVF);
+       __rvu_mbox_handler(mwork, TYPE_AFVF, false);
 }
 
 static void __rvu_mbox_up_handler(struct rvu_work *mwork, int type)
@@ -2376,6 +2382,8 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw,
                }
        }
 
+       mutex_init(&rvu->mbox_lock);
+
        mbox_regions = kcalloc(num, sizeof(void *), GFP_KERNEL);
        if (!mbox_regions) {
                err = -ENOMEM;
@@ -2525,10 +2533,9 @@ static void rvu_queue_work(struct mbox_wq_info *mw, int first,
        }
 }
 
-static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq)
+static irqreturn_t rvu_mbox_pf_intr_handler(int irq, void *rvu_irq)
 {
        struct rvu *rvu = (struct rvu *)rvu_irq;
-       int vfs = rvu->vfs;
        u64 intr;
 
        intr = rvu_read64(rvu, BLKADDR_RVUM, RVU_AF_PFAF_MBOX_INT);
@@ -2542,6 +2549,18 @@ static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq)
 
        rvu_queue_work(&rvu->afpf_wq_info, 0, rvu->hw->total_pfs, intr);
 
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rvu_mbox_intr_handler(int irq, void *rvu_irq)
+{
+       struct rvu *rvu = (struct rvu *)rvu_irq;
+       int vfs = rvu->vfs;
+       u64 intr;
+
+       /* Sync with mbox memory region */
+       rmb();
+
        /* Handle VF interrupts */
        if (vfs > 64) {
                intr = rvupf_read64(rvu, RVU_PF_VFPF_MBOX_INTX(1));
@@ -2886,7 +2905,7 @@ static int rvu_register_interrupts(struct rvu *rvu)
        /* Register mailbox interrupt handler */
        sprintf(&rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], "RVUAF Mbox");
        ret = request_irq(pci_irq_vector(rvu->pdev, RVU_AF_INT_VEC_MBOX),
-                         rvu_mbox_intr_handler, 0,
+                         rvu_mbox_pf_intr_handler, 0,
                          &rvu->irq_name[RVU_AF_INT_VEC_MBOX * NAME_SIZE], rvu);
        if (ret) {
                dev_err(rvu->dev,
index f390525a621772924a83460802840f442cc553d7..35834687e40fe9877f5f575ee17f0ead42ee3726 100644 (file)
@@ -591,6 +591,8 @@ struct rvu {
        spinlock_t              mcs_intrq_lock;
        /* CPT interrupt lock */
        spinlock_t              cpt_intr_lock;
+
+       struct mutex            mbox_lock; /* Serialize mbox up and down msgs */
 };
 
 static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val)
index 38acdc7a73bbec54a8e158e707b3b2d2952898f2..72e060cf6b6181d9ccd22b2f3a126c6b7f063a83 100644 (file)
@@ -232,7 +232,7 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu)
        struct cgx_link_user_info *linfo;
        struct cgx_link_info_msg *msg;
        unsigned long pfmap;
-       int err, pfid;
+       int pfid;
 
        linfo = &event->link_uinfo;
        pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id);
@@ -255,16 +255,22 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu)
                        continue;
                }
 
+               mutex_lock(&rvu->mbox_lock);
+
                /* Send mbox message to PF */
                msg = otx2_mbox_alloc_msg_cgx_link_event(rvu, pfid);
-               if (!msg)
+               if (!msg) {
+                       mutex_unlock(&rvu->mbox_lock);
                        continue;
+               }
+
                msg->link_info = *linfo;
-               otx2_mbox_msg_send(&rvu->afpf_wq_info.mbox_up, pfid);
-               err = otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pfid);
-               if (err)
-                       dev_warn(rvu->dev, "notification to pf %d failed\n",
-                                pfid);
+
+               otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pfid);
+
+               otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pfid);
+
+               mutex_unlock(&rvu->mbox_lock);
        } while (pfmap);
 }
 
index 02d0b707aea5bd6b9dea286180914b5aaba4a51d..a85ac039d779be0681b7339c291cf02a616d1d37 100644 (file)
@@ -1592,7 +1592,7 @@ int otx2_detach_resources(struct mbox *mbox)
        detach->partial = false;
 
        /* Send detach request to AF */
-       otx2_mbox_msg_send(&mbox->mbox, 0);
+       otx2_sync_mbox_msg(mbox);
        mutex_unlock(&mbox->lock);
        return 0;
 }
index 06910307085efa83cc386e8e180805bef0ee539e..7e16a341ec588f2818154827cf7a08cbe9d256a9 100644 (file)
@@ -815,7 +815,7 @@ static inline int otx2_sync_mbox_up_msg(struct mbox *mbox, int devid)
 
        if (!otx2_mbox_nonempty(&mbox->mbox_up, devid))
                return 0;
-       otx2_mbox_msg_send(&mbox->mbox_up, devid);
+       otx2_mbox_msg_send_up(&mbox->mbox_up, devid);
        err = otx2_mbox_wait_for_rsp(&mbox->mbox_up, devid);
        if (err)
                return err;
index e5fe67e7386551e321949dc3b42074067eb4b3a9..b40bd0e467514848fee22f1e32f86cb4c9d129c3 100644 (file)
@@ -292,8 +292,8 @@ static int otx2_pf_flr_init(struct otx2_nic *pf, int num_vfs)
        return 0;
 }
 
-static void otx2_queue_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
-                           int first, int mdevs, u64 intr, int type)
+static void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
+                              int first, int mdevs, u64 intr)
 {
        struct otx2_mbox_dev *mdev;
        struct otx2_mbox *mbox;
@@ -307,40 +307,26 @@ static void otx2_queue_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
 
                mbox = &mw->mbox;
                mdev = &mbox->dev[i];
-               if (type == TYPE_PFAF)
-                       otx2_sync_mbox_bbuf(mbox, i);
                hdr = mdev->mbase + mbox->rx_start;
                /* The hdr->num_msgs is set to zero immediately in the interrupt
-                * handler to  ensure that it holds a correct value next time
-                * when the interrupt handler is called.
-                * pf->mbox.num_msgs holds the data for use in pfaf_mbox_handler
-                * pf>mbox.up_num_msgs holds the data for use in
-                * pfaf_mbox_up_handler.
+                * handler to ensure that it holds a correct value next time
+                * when the interrupt handler is called. pf->mw[i].num_msgs
+                * holds the data for use in otx2_pfvf_mbox_handler and
+                * pf->mw[i].up_num_msgs holds the data for use in
+                * otx2_pfvf_mbox_up_handler.
                 */
                if (hdr->num_msgs) {
                        mw[i].num_msgs = hdr->num_msgs;
                        hdr->num_msgs = 0;
-                       if (type == TYPE_PFAF)
-                               memset(mbox->hwbase + mbox->rx_start, 0,
-                                      ALIGN(sizeof(struct mbox_hdr),
-                                            sizeof(u64)));
-
                        queue_work(mbox_wq, &mw[i].mbox_wrk);
                }
 
                mbox = &mw->mbox_up;
                mdev = &mbox->dev[i];
-               if (type == TYPE_PFAF)
-                       otx2_sync_mbox_bbuf(mbox, i);
                hdr = mdev->mbase + mbox->rx_start;
                if (hdr->num_msgs) {
                        mw[i].up_num_msgs = hdr->num_msgs;
                        hdr->num_msgs = 0;
-                       if (type == TYPE_PFAF)
-                               memset(mbox->hwbase + mbox->rx_start, 0,
-                                      ALIGN(sizeof(struct mbox_hdr),
-                                            sizeof(u64)));
-
                        queue_work(mbox_wq, &mw[i].mbox_up_wrk);
                }
        }
@@ -356,8 +342,10 @@ static void otx2_forward_msg_pfvf(struct otx2_mbox_dev *mdev,
        /* Msgs are already copied, trigger VF's mbox irq */
        smp_wmb();
 
+       otx2_mbox_wait_for_zero(pfvf_mbox, devid);
+
        offset = pfvf_mbox->trigger | (devid << pfvf_mbox->tr_shift);
-       writeq(1, (void __iomem *)pfvf_mbox->reg_base + offset);
+       writeq(MBOX_DOWN_MSG, (void __iomem *)pfvf_mbox->reg_base + offset);
 
        /* Restore VF's mbox bounce buffer region address */
        src_mdev->mbase = bbuf_base;
@@ -547,7 +535,7 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work)
 end:
                offset = mbox->rx_start + msg->next_msgoff;
                if (mdev->msgs_acked == (vf_mbox->up_num_msgs - 1))
-                       __otx2_mbox_reset(mbox, 0);
+                       __otx2_mbox_reset(mbox, vf_idx);
                mdev->msgs_acked++;
        }
 }
@@ -564,8 +552,7 @@ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq)
        if (vfs > 64) {
                intr = otx2_read64(pf, RVU_PF_VFPF_MBOX_INTX(1));
                otx2_write64(pf, RVU_PF_VFPF_MBOX_INTX(1), intr);
-               otx2_queue_work(mbox, pf->mbox_pfvf_wq, 64, vfs, intr,
-                               TYPE_PFVF);
+               otx2_queue_vf_work(mbox, pf->mbox_pfvf_wq, 64, vfs, intr);
                if (intr)
                        trace_otx2_msg_interrupt(mbox->mbox.pdev, "VF(s) to PF", intr);
                vfs = 64;
@@ -574,7 +561,7 @@ static irqreturn_t otx2_pfvf_mbox_intr_handler(int irq, void *pf_irq)
        intr = otx2_read64(pf, RVU_PF_VFPF_MBOX_INTX(0));
        otx2_write64(pf, RVU_PF_VFPF_MBOX_INTX(0), intr);
 
-       otx2_queue_work(mbox, pf->mbox_pfvf_wq, 0, vfs, intr, TYPE_PFVF);
+       otx2_queue_vf_work(mbox, pf->mbox_pfvf_wq, 0, vfs, intr);
 
        if (intr)
                trace_otx2_msg_interrupt(mbox->mbox.pdev, "VF(s) to PF", intr);
@@ -597,8 +584,9 @@ static int otx2_pfvf_mbox_init(struct otx2_nic *pf, int numvfs)
        if (!pf->mbox_pfvf)
                return -ENOMEM;
 
-       pf->mbox_pfvf_wq = alloc_ordered_workqueue("otx2_pfvf_mailbox",
-                                                  WQ_HIGHPRI | WQ_MEM_RECLAIM);
+       pf->mbox_pfvf_wq = alloc_workqueue("otx2_pfvf_mailbox",
+                                          WQ_UNBOUND | WQ_HIGHPRI |
+                                          WQ_MEM_RECLAIM, 0);
        if (!pf->mbox_pfvf_wq)
                return -ENOMEM;
 
@@ -821,20 +809,22 @@ static void otx2_pfaf_mbox_handler(struct work_struct *work)
        struct mbox *af_mbox;
        struct otx2_nic *pf;
        int offset, id;
+       u16 num_msgs;
 
        af_mbox = container_of(work, struct mbox, mbox_wrk);
        mbox = &af_mbox->mbox;
        mdev = &mbox->dev[0];
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+       num_msgs = rsp_hdr->num_msgs;
 
        offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
        pf = af_mbox->pfvf;
 
-       for (id = 0; id < af_mbox->num_msgs; id++) {
+       for (id = 0; id < num_msgs; id++) {
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
                otx2_process_pfaf_mbox_msg(pf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
-               if (mdev->msgs_acked == (af_mbox->num_msgs - 1))
+               if (mdev->msgs_acked == (num_msgs - 1))
                        __otx2_mbox_reset(mbox, 0);
                mdev->msgs_acked++;
        }
@@ -945,12 +935,14 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work)
        int offset, id, devid = 0;
        struct mbox_hdr *rsp_hdr;
        struct mbox_msghdr *msg;
+       u16 num_msgs;
 
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+       num_msgs = rsp_hdr->num_msgs;
 
        offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
 
-       for (id = 0; id < af_mbox->up_num_msgs; id++) {
+       for (id = 0; id < num_msgs; id++) {
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
 
                devid = msg->pcifunc & RVU_PFVF_FUNC_MASK;
@@ -959,10 +951,11 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work)
                        otx2_process_mbox_msg_up(pf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
        }
-       if (devid) {
+       /* Forward to VF iff VFs are really present */
+       if (devid && pci_num_vf(pf->pdev)) {
                otx2_forward_vf_mbox_msgs(pf, &pf->mbox.mbox_up,
                                          MBOX_DIR_PFVF_UP, devid - 1,
-                                         af_mbox->up_num_msgs);
+                                         num_msgs);
                return;
        }
 
@@ -972,16 +965,49 @@ static void otx2_pfaf_mbox_up_handler(struct work_struct *work)
 static irqreturn_t otx2_pfaf_mbox_intr_handler(int irq, void *pf_irq)
 {
        struct otx2_nic *pf = (struct otx2_nic *)pf_irq;
-       struct mbox *mbox;
+       struct mbox *mw = &pf->mbox;
+       struct otx2_mbox_dev *mdev;
+       struct otx2_mbox *mbox;
+       struct mbox_hdr *hdr;
+       u64 mbox_data;
 
        /* Clear the IRQ */
        otx2_write64(pf, RVU_PF_INT, BIT_ULL(0));
 
-       mbox = &pf->mbox;
 
-       trace_otx2_msg_interrupt(mbox->mbox.pdev, "AF to PF", BIT_ULL(0));
+       mbox_data = otx2_read64(pf, RVU_PF_PFAF_MBOX0);
+
+       if (mbox_data & MBOX_UP_MSG) {
+               mbox_data &= ~MBOX_UP_MSG;
+               otx2_write64(pf, RVU_PF_PFAF_MBOX0, mbox_data);
+
+               mbox = &mw->mbox_up;
+               mdev = &mbox->dev[0];
+               otx2_sync_mbox_bbuf(mbox, 0);
+
+               hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+               if (hdr->num_msgs)
+                       queue_work(pf->mbox_wq, &mw->mbox_up_wrk);
+
+               trace_otx2_msg_interrupt(pf->pdev, "UP message from AF to PF",
+                                        BIT_ULL(0));
+       }
+
+       if (mbox_data & MBOX_DOWN_MSG) {
+               mbox_data &= ~MBOX_DOWN_MSG;
+               otx2_write64(pf, RVU_PF_PFAF_MBOX0, mbox_data);
+
+               mbox = &mw->mbox;
+               mdev = &mbox->dev[0];
+               otx2_sync_mbox_bbuf(mbox, 0);
+
+               hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+               if (hdr->num_msgs)
+                       queue_work(pf->mbox_wq, &mw->mbox_wrk);
 
-       otx2_queue_work(mbox, pf->mbox_wq, 0, 1, 1, TYPE_PFAF);
+               trace_otx2_msg_interrupt(pf->pdev, "DOWN reply from AF to PF",
+                                        BIT_ULL(0));
+       }
 
        return IRQ_HANDLED;
 }
@@ -3087,6 +3113,7 @@ static void otx2_vf_link_event_task(struct work_struct *work)
        struct otx2_vf_config *config;
        struct cgx_link_info_msg *req;
        struct mbox_msghdr *msghdr;
+       struct delayed_work *dwork;
        struct otx2_nic *pf;
        int vf_idx;
 
@@ -3095,10 +3122,24 @@ static void otx2_vf_link_event_task(struct work_struct *work)
        vf_idx = config - config->pf->vf_configs;
        pf = config->pf;
 
+       if (config->intf_down)
+               return;
+
+       mutex_lock(&pf->mbox.lock);
+
+       dwork = &config->link_event_work;
+
+       if (!otx2_mbox_wait_for_zero(&pf->mbox_pfvf[0].mbox_up, vf_idx)) {
+               schedule_delayed_work(dwork, msecs_to_jiffies(100));
+               mutex_unlock(&pf->mbox.lock);
+               return;
+       }
+
        msghdr = otx2_mbox_alloc_msg_rsp(&pf->mbox_pfvf[0].mbox_up, vf_idx,
                                         sizeof(*req), sizeof(struct msg_rsp));
        if (!msghdr) {
                dev_err(pf->dev, "Failed to create VF%d link event\n", vf_idx);
+               mutex_unlock(&pf->mbox.lock);
                return;
        }
 
@@ -3107,7 +3148,11 @@ static void otx2_vf_link_event_task(struct work_struct *work)
        req->hdr.sig = OTX2_MBOX_REQ_SIG;
        memcpy(&req->link_info, &pf->linfo, sizeof(req->link_info));
 
+       otx2_mbox_wait_for_zero(&pf->mbox_pfvf[0].mbox_up, vf_idx);
+
        otx2_sync_mbox_up_msg(&pf->mbox_pfvf[0], vf_idx);
+
+       mutex_unlock(&pf->mbox.lock);
 }
 
 static int otx2_sriov_enable(struct pci_dev *pdev, int numvfs)
index 35e06048356f4d545298b4bfc34ae848168734f1..cf0aa16d754070ebf2d9e05e7146b604674bcbfd 100644 (file)
@@ -89,16 +89,20 @@ static void otx2vf_vfaf_mbox_handler(struct work_struct *work)
        struct otx2_mbox *mbox;
        struct mbox *af_mbox;
        int offset, id;
+       u16 num_msgs;
 
        af_mbox = container_of(work, struct mbox, mbox_wrk);
        mbox = &af_mbox->mbox;
        mdev = &mbox->dev[0];
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
-       if (af_mbox->num_msgs == 0)
+       num_msgs = rsp_hdr->num_msgs;
+
+       if (num_msgs == 0)
                return;
+
        offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
 
-       for (id = 0; id < af_mbox->num_msgs; id++) {
+       for (id = 0; id < num_msgs; id++) {
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
                otx2vf_process_vfaf_mbox_msg(af_mbox->pfvf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
@@ -151,6 +155,7 @@ static void otx2vf_vfaf_mbox_up_handler(struct work_struct *work)
        struct mbox *vf_mbox;
        struct otx2_nic *vf;
        int offset, id;
+       u16 num_msgs;
 
        vf_mbox = container_of(work, struct mbox, mbox_up_wrk);
        vf = vf_mbox->pfvf;
@@ -158,12 +163,14 @@ static void otx2vf_vfaf_mbox_up_handler(struct work_struct *work)
        mdev = &mbox->dev[0];
 
        rsp_hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
-       if (vf_mbox->up_num_msgs == 0)
+       num_msgs = rsp_hdr->num_msgs;
+
+       if (num_msgs == 0)
                return;
 
        offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN);
 
-       for (id = 0; id < vf_mbox->up_num_msgs; id++) {
+       for (id = 0; id < num_msgs; id++) {
                msg = (struct mbox_msghdr *)(mdev->mbase + offset);
                otx2vf_process_mbox_msg_up(vf, msg);
                offset = mbox->rx_start + msg->next_msgoff;
@@ -178,40 +185,48 @@ static irqreturn_t otx2vf_vfaf_mbox_intr_handler(int irq, void *vf_irq)
        struct otx2_mbox_dev *mdev;
        struct otx2_mbox *mbox;
        struct mbox_hdr *hdr;
+       u64 mbox_data;
 
        /* Clear the IRQ */
        otx2_write64(vf, RVU_VF_INT, BIT_ULL(0));
 
+       mbox_data = otx2_read64(vf, RVU_VF_VFPF_MBOX0);
+
        /* Read latest mbox data */
        smp_rmb();
 
-       /* Check for PF => VF response messages */
-       mbox = &vf->mbox.mbox;
-       mdev = &mbox->dev[0];
-       otx2_sync_mbox_bbuf(mbox, 0);
+       if (mbox_data & MBOX_DOWN_MSG) {
+               mbox_data &= ~MBOX_DOWN_MSG;
+               otx2_write64(vf, RVU_VF_VFPF_MBOX0, mbox_data);
+
+               /* Check for PF => VF response messages */
+               mbox = &vf->mbox.mbox;
+               mdev = &mbox->dev[0];
+               otx2_sync_mbox_bbuf(mbox, 0);
 
-       trace_otx2_msg_interrupt(mbox->pdev, "PF to VF", BIT_ULL(0));
+               hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+               if (hdr->num_msgs)
+                       queue_work(vf->mbox_wq, &vf->mbox.mbox_wrk);
 
-       hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
-       if (hdr->num_msgs) {
-               vf->mbox.num_msgs = hdr->num_msgs;
-               hdr->num_msgs = 0;
-               memset(mbox->hwbase + mbox->rx_start, 0,
-                      ALIGN(sizeof(struct mbox_hdr), sizeof(u64)));
-               queue_work(vf->mbox_wq, &vf->mbox.mbox_wrk);
+               trace_otx2_msg_interrupt(mbox->pdev, "DOWN reply from PF to VF",
+                                        BIT_ULL(0));
        }
-       /* Check for PF => VF notification messages */
-       mbox = &vf->mbox.mbox_up;
-       mdev = &mbox->dev[0];
-       otx2_sync_mbox_bbuf(mbox, 0);
 
-       hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
-       if (hdr->num_msgs) {
-               vf->mbox.up_num_msgs = hdr->num_msgs;
-               hdr->num_msgs = 0;
-               memset(mbox->hwbase + mbox->rx_start, 0,
-                      ALIGN(sizeof(struct mbox_hdr), sizeof(u64)));
-               queue_work(vf->mbox_wq, &vf->mbox.mbox_up_wrk);
+       if (mbox_data & MBOX_UP_MSG) {
+               mbox_data &= ~MBOX_UP_MSG;
+               otx2_write64(vf, RVU_VF_VFPF_MBOX0, mbox_data);
+
+               /* Check for PF => VF notification messages */
+               mbox = &vf->mbox.mbox_up;
+               mdev = &mbox->dev[0];
+               otx2_sync_mbox_bbuf(mbox, 0);
+
+               hdr = (struct mbox_hdr *)(mdev->mbase + mbox->rx_start);
+               if (hdr->num_msgs)
+                       queue_work(vf->mbox_wq, &vf->mbox.mbox_up_wrk);
+
+               trace_otx2_msg_interrupt(mbox->pdev, "UP message from PF to VF",
+                                        BIT_ULL(0));
        }
 
        return IRQ_HANDLED;
@@ -760,8 +775,8 @@ static void otx2vf_remove(struct pci_dev *pdev)
        otx2_mcam_flow_del(vf);
        otx2_shutdown_tc(vf);
        otx2_shutdown_qos(vf);
-       otx2vf_disable_mbox_intr(vf);
        otx2_detach_resources(&vf->mbox);
+       otx2vf_disable_mbox_intr(vf);
        free_percpu(vf->hw.lmt_info);
        if (test_bit(CN10K_LMTST, &vf->hw.cap_flag))
                qmem_free(vf->dev, vf->dync_lmt);
index de123350bd46b6e55ee5ea83737f79a4bceb6867..caa13b9cedff09ca507f1ed9375d4553adeb9f8a 100644 (file)
@@ -677,8 +677,7 @@ static int mtk_mac_finish(struct phylink_config *config, unsigned int mode,
        mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
        mcr_new = mcr_cur;
        mcr_new |= MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE |
-                  MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_LINK |
-                  MAC_MCR_RX_FIFO_CLR_DIS;
+                  MAC_MCR_BACKOFF_EN | MAC_MCR_BACKPR_EN | MAC_MCR_RX_FIFO_CLR_DIS;
 
        /* Only update control register when needed! */
        if (mcr_new != mcr_cur)
@@ -694,7 +693,7 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
                                           phylink_config);
        u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
 
-       mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN);
+       mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK);
        mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
 }
 
@@ -803,7 +802,7 @@ static void mtk_mac_link_up(struct phylink_config *config,
        if (rx_pause)
                mcr |= MAC_MCR_FORCE_RX_FC;
 
-       mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN;
+       mcr |= MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK;
        mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
 }
 
index b2a5d9c3733d4823a977cd635d67e707286e9f50..6ce0db3a1a920857016c17b7e7bc4be1f2045a0f 100644 (file)
@@ -994,7 +994,7 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
                         MTK_PPE_KEEPALIVE_DISABLE) |
              FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) |
              FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE,
-                        MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) |
+                        MTK_PPE_SCAN_MODE_CHECK_AGE) |
              FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM,
                         MTK_PPE_ENTRIES_SHIFT);
        if (mtk_is_netsys_v2_or_greater(ppe->eth))
@@ -1090,17 +1090,21 @@ int mtk_ppe_stop(struct mtk_ppe *ppe)
 
        mtk_ppe_cache_enable(ppe, false);
 
-       /* disable offload engine */
-       ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN);
-       ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0);
-
        /* disable aging */
        val = MTK_PPE_TB_CFG_AGE_NON_L4 |
              MTK_PPE_TB_CFG_AGE_UNBIND |
              MTK_PPE_TB_CFG_AGE_TCP |
              MTK_PPE_TB_CFG_AGE_UDP |
-             MTK_PPE_TB_CFG_AGE_TCP_FIN;
+             MTK_PPE_TB_CFG_AGE_TCP_FIN |
+                 MTK_PPE_TB_CFG_SCAN_MODE;
        ppe_clear(ppe, MTK_PPE_TB_CFG, val);
 
-       return mtk_ppe_wait_busy(ppe);
+       if (mtk_ppe_wait_busy(ppe))
+               return -ETIMEDOUT;
+
+       /* disable offload engine */
+       ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN);
+       ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0);
+
+       return 0;
 }
index 321fd8d00730410bc53c9c2e8d8f1fec30947dab..37efb1ea9fcd9ca91067b98b2e2310e9d8881545 100644 (file)
@@ -45,7 +45,7 @@ struct qcauart {
        unsigned char *tx_buffer;
 };
 
-static ssize_t
+static size_t
 qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
 {
        struct qcauart *qca = serdev_device_get_drvdata(serdev);
index 93295916b1d2b80751637dee4a0006688958c428..5b5d5e4310d127189cfdea18223f02460a6af149 100644 (file)
@@ -571,7 +571,7 @@ static int txgbe_clock_register(struct txgbe *txgbe)
        char clk_name[32];
        struct clk *clk;
 
-       snprintf(clk_name, sizeof(clk_name), "i2c_designware.%d",
+       snprintf(clk_name, sizeof(clk_name), "i2c_dw.%d",
                 pci_dev_id(pdev));
 
        clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000);
index 8297ef681bf5dc6d7c09aacf76c2edc8a59d9a3c..6c6ec947570929536fe321c4063eefd32afb6649 100644 (file)
@@ -2831,8 +2831,8 @@ EXPORT_SYMBOL(genphy_resume);
 int genphy_loopback(struct phy_device *phydev, bool enable)
 {
        if (enable) {
-               u16 val, ctl = BMCR_LOOPBACK;
-               int ret;
+               u16 ctl = BMCR_LOOPBACK;
+               int ret, val;
 
                ctl |= mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
 
index 13d902462d8ec12993f9aa8a0463aa2a21c972ba..bcdfbf61eb66b859b2db7199a06a95619a49dcb5 100644 (file)
@@ -1464,8 +1464,6 @@ static netdev_features_t veth_fix_features(struct net_device *dev,
                if (peer_priv->_xdp_prog)
                        features &= ~NETIF_F_GSO_SOFTWARE;
        }
-       if (priv->_xdp_prog)
-               features |= NETIF_F_GRO;
 
        return features;
 }
@@ -1569,14 +1567,6 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                }
 
                if (!old_prog) {
-                       if (!veth_gro_requested(dev)) {
-                               /* user-space did not require GRO, but adding
-                                * XDP is supposed to get GRO working
-                                */
-                               dev->features |= NETIF_F_GRO;
-                               netdev_features_change(dev);
-                       }
-
                        peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
                        peer->max_mtu = max_mtu;
                }
@@ -1592,14 +1582,6 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                        if (dev->flags & IFF_UP)
                                veth_disable_xdp(dev);
 
-                       /* if user-space did not require GRO, since adding XDP
-                        * enabled it, clear it now
-                        */
-                       if (!veth_gro_requested(dev)) {
-                               dev->features &= ~NETIF_F_GRO;
-                               netdev_features_change(dev);
-                       }
-
                        if (peer) {
                                peer->hw_features |= NETIF_F_GSO_SOFTWARE;
                                peer->max_mtu = ETH_MAX_MTU;
index d7ce4a1011ea2585bca21ab3fb86978f7fee364d..c22d1118a13333702c41d0b11148eb067700965b 100644 (file)
@@ -80,6 +80,11 @@ struct virtnet_stat_desc {
        size_t offset;
 };
 
+struct virtnet_sq_free_stats {
+       u64 packets;
+       u64 bytes;
+};
+
 struct virtnet_sq_stats {
        struct u64_stats_sync syncp;
        u64_stats_t packets;
@@ -304,6 +309,12 @@ struct virtnet_info {
        /* Work struct for config space updates */
        struct work_struct config_work;
 
+       /* Work struct for setting rx mode */
+       struct work_struct rx_mode_work;
+
+       /* OK to queue work setting RX mode? */
+       bool rx_mode_work_enabled;
+
        /* Does the affinity hint is set for virtqueues? */
        bool affinity_hint_set;
 
@@ -366,6 +377,31 @@ static struct xdp_frame *ptr_to_xdp(void *ptr)
        return (struct xdp_frame *)((unsigned long)ptr & ~VIRTIO_XDP_FLAG);
 }
 
+static void __free_old_xmit(struct send_queue *sq, bool in_napi,
+                           struct virtnet_sq_free_stats *stats)
+{
+       unsigned int len;
+       void *ptr;
+
+       while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) {
+               ++stats->packets;
+
+               if (!is_xdp_frame(ptr)) {
+                       struct sk_buff *skb = ptr;
+
+                       pr_debug("Sent skb %p\n", skb);
+
+                       stats->bytes += skb->len;
+                       napi_consume_skb(skb, in_napi);
+               } else {
+                       struct xdp_frame *frame = ptr_to_xdp(ptr);
+
+                       stats->bytes += xdp_get_frame_len(frame);
+                       xdp_return_frame(frame);
+               }
+       }
+}
+
 /* Converting between virtqueue no. and kernel tx/rx queue no.
  * 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq
  */
@@ -447,6 +483,20 @@ static void disable_delayed_refill(struct virtnet_info *vi)
        spin_unlock_bh(&vi->refill_lock);
 }
 
+static void enable_rx_mode_work(struct virtnet_info *vi)
+{
+       rtnl_lock();
+       vi->rx_mode_work_enabled = true;
+       rtnl_unlock();
+}
+
+static void disable_rx_mode_work(struct virtnet_info *vi)
+{
+       rtnl_lock();
+       vi->rx_mode_work_enabled = false;
+       rtnl_unlock();
+}
+
 static void virtqueue_napi_schedule(struct napi_struct *napi,
                                    struct virtqueue *vq)
 {
@@ -776,39 +826,21 @@ static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf)
        virtnet_rq_free_buf(vi, rq, buf);
 }
 
-static void free_old_xmit_skbs(struct send_queue *sq, bool in_napi)
+static void free_old_xmit(struct send_queue *sq, bool in_napi)
 {
-       unsigned int len;
-       unsigned int packets = 0;
-       unsigned int bytes = 0;
-       void *ptr;
-
-       while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) {
-               if (likely(!is_xdp_frame(ptr))) {
-                       struct sk_buff *skb = ptr;
-
-                       pr_debug("Sent skb %p\n", skb);
+       struct virtnet_sq_free_stats stats = {0};
 
-                       bytes += skb->len;
-                       napi_consume_skb(skb, in_napi);
-               } else {
-                       struct xdp_frame *frame = ptr_to_xdp(ptr);
-
-                       bytes += xdp_get_frame_len(frame);
-                       xdp_return_frame(frame);
-               }
-               packets++;
-       }
+       __free_old_xmit(sq, in_napi, &stats);
 
        /* Avoid overhead when no packets have been processed
         * happens when called speculatively from start_xmit.
         */
-       if (!packets)
+       if (!stats.packets)
                return;
 
        u64_stats_update_begin(&sq->stats.syncp);
-       u64_stats_add(&sq->stats.bytes, bytes);
-       u64_stats_add(&sq->stats.packets, packets);
+       u64_stats_add(&sq->stats.bytes, stats.bytes);
+       u64_stats_add(&sq->stats.packets, stats.packets);
        u64_stats_update_end(&sq->stats.syncp);
 }
 
@@ -848,7 +880,7 @@ static void check_sq_full_and_disable(struct virtnet_info *vi,
                                virtqueue_napi_schedule(&sq->napi, sq->vq);
                } else if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) {
                        /* More just got used, free them then recheck. */
-                       free_old_xmit_skbs(sq, false);
+                       free_old_xmit(sq, false);
                        if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) {
                                netif_start_subqueue(dev, qnum);
                                virtqueue_disable_cb(sq->vq);
@@ -947,15 +979,12 @@ static int virtnet_xdp_xmit(struct net_device *dev,
                            int n, struct xdp_frame **frames, u32 flags)
 {
        struct virtnet_info *vi = netdev_priv(dev);
+       struct virtnet_sq_free_stats stats = {0};
        struct receive_queue *rq = vi->rq;
        struct bpf_prog *xdp_prog;
        struct send_queue *sq;
-       unsigned int len;
-       int packets = 0;
-       int bytes = 0;
        int nxmit = 0;
        int kicks = 0;
-       void *ptr;
        int ret;
        int i;
 
@@ -974,20 +1003,7 @@ static int virtnet_xdp_xmit(struct net_device *dev,
        }
 
        /* Free up any pending old buffers before queueing new ones. */
-       while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) {
-               if (likely(is_xdp_frame(ptr))) {
-                       struct xdp_frame *frame = ptr_to_xdp(ptr);
-
-                       bytes += xdp_get_frame_len(frame);
-                       xdp_return_frame(frame);
-               } else {
-                       struct sk_buff *skb = ptr;
-
-                       bytes += skb->len;
-                       napi_consume_skb(skb, false);
-               }
-               packets++;
-       }
+       __free_old_xmit(sq, false, &stats);
 
        for (i = 0; i < n; i++) {
                struct xdp_frame *xdpf = frames[i];
@@ -1007,8 +1023,8 @@ static int virtnet_xdp_xmit(struct net_device *dev,
        }
 out:
        u64_stats_update_begin(&sq->stats.syncp);
-       u64_stats_add(&sq->stats.bytes, bytes);
-       u64_stats_add(&sq->stats.packets, packets);
+       u64_stats_add(&sq->stats.bytes, stats.bytes);
+       u64_stats_add(&sq->stats.packets, stats.packets);
        u64_stats_add(&sq->stats.xdp_tx, n);
        u64_stats_add(&sq->stats.xdp_tx_drops, n - nxmit);
        u64_stats_add(&sq->stats.kicks, kicks);
@@ -2160,7 +2176,7 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)
 
                do {
                        virtqueue_disable_cb(sq->vq);
-                       free_old_xmit_skbs(sq, true);
+                       free_old_xmit(sq, true);
                } while (unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
 
                if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS)
@@ -2308,7 +2324,7 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget)
        txq = netdev_get_tx_queue(vi->dev, index);
        __netif_tx_lock(txq, raw_smp_processor_id());
        virtqueue_disable_cb(sq->vq);
-       free_old_xmit_skbs(sq, true);
+       free_old_xmit(sq, true);
 
        if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS)
                netif_tx_wake_queue(txq);
@@ -2398,7 +2414,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                if (use_napi)
                        virtqueue_disable_cb(sq->vq);
 
-               free_old_xmit_skbs(sq, false);
+               free_old_xmit(sq, false);
 
        } while (use_napi && kick &&
               unlikely(!virtqueue_enable_cb_delayed(sq->vq)));
@@ -2550,8 +2566,10 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
         * into the hypervisor, so the request should be handled immediately.
         */
        while (!virtqueue_get_buf(vi->cvq, &tmp) &&
-              !virtqueue_is_broken(vi->cvq))
+              !virtqueue_is_broken(vi->cvq)) {
+               cond_resched();
                cpu_relax();
+       }
 
        return vi->ctrl->status == VIRTIO_NET_OK;
 }
@@ -2706,9 +2724,11 @@ static int virtnet_close(struct net_device *dev)
        return 0;
 }
 
-static void virtnet_set_rx_mode(struct net_device *dev)
+static void virtnet_rx_mode_work(struct work_struct *work)
 {
-       struct virtnet_info *vi = netdev_priv(dev);
+       struct virtnet_info *vi =
+               container_of(work, struct virtnet_info, rx_mode_work);
+       struct net_device *dev = vi->dev;
        struct scatterlist sg[2];
        struct virtio_net_ctrl_mac *mac_data;
        struct netdev_hw_addr *ha;
@@ -2721,6 +2741,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
                return;
 
+       rtnl_lock();
+
        vi->ctrl->promisc = ((dev->flags & IFF_PROMISC) != 0);
        vi->ctrl->allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
 
@@ -2738,14 +2760,19 @@ static void virtnet_set_rx_mode(struct net_device *dev)
                dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
                         vi->ctrl->allmulti ? "en" : "dis");
 
+       netif_addr_lock_bh(dev);
+
        uc_count = netdev_uc_count(dev);
        mc_count = netdev_mc_count(dev);
        /* MAC filter - use one buffer for both lists */
        buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) +
                      (2 * sizeof(mac_data->entries)), GFP_ATOMIC);
        mac_data = buf;
-       if (!buf)
+       if (!buf) {
+               netif_addr_unlock_bh(dev);
+               rtnl_unlock();
                return;
+       }
 
        sg_init_table(sg, 2);
 
@@ -2766,6 +2793,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        netdev_for_each_mc_addr(ha, dev)
                memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
 
+       netif_addr_unlock_bh(dev);
+
        sg_set_buf(&sg[1], mac_data,
                   sizeof(mac_data->entries) + (mc_count * ETH_ALEN));
 
@@ -2773,9 +2802,19 @@ static void virtnet_set_rx_mode(struct net_device *dev)
                                  VIRTIO_NET_CTRL_MAC_TABLE_SET, sg))
                dev_warn(&dev->dev, "Failed to set MAC filter table.\n");
 
+       rtnl_unlock();
+
        kfree(buf);
 }
 
+static void virtnet_set_rx_mode(struct net_device *dev)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+
+       if (vi->rx_mode_work_enabled)
+               schedule_work(&vi->rx_mode_work);
+}
+
 static int virtnet_vlan_rx_add_vid(struct net_device *dev,
                                   __be16 proto, u16 vid)
 {
@@ -3856,6 +3895,8 @@ static void virtnet_freeze_down(struct virtio_device *vdev)
 
        /* Make sure no work handler is accessing the device */
        flush_work(&vi->config_work);
+       disable_rx_mode_work(vi);
+       flush_work(&vi->rx_mode_work);
 
        netif_tx_lock_bh(vi->dev);
        netif_device_detach(vi->dev);
@@ -3878,6 +3919,7 @@ static int virtnet_restore_up(struct virtio_device *vdev)
        virtio_device_ready(vdev);
 
        enable_delayed_refill(vi);
+       enable_rx_mode_work(vi);
 
        if (netif_running(vi->dev)) {
                err = virtnet_open(vi->dev);
@@ -4676,6 +4718,7 @@ static int virtnet_probe(struct virtio_device *vdev)
        vdev->priv = vi;
 
        INIT_WORK(&vi->config_work, virtnet_config_changed_work);
+       INIT_WORK(&vi->rx_mode_work, virtnet_rx_mode_work);
        spin_lock_init(&vi->refill_lock);
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) {
@@ -4798,6 +4841,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (vi->has_rss || vi->has_rss_hash_report)
                virtnet_init_default_rss(vi);
 
+       enable_rx_mode_work(vi);
+
        /* serialize netdev register + virtio_device_ready() with ndo_open() */
        rtnl_lock();
 
@@ -4895,6 +4940,8 @@ static void virtnet_remove(struct virtio_device *vdev)
 
        /* Make sure no work handler is accessing the device. */
        flush_work(&vi->config_work);
+       disable_rx_mode_work(vi);
+       flush_work(&vi->rx_mode_work);
 
        unregister_netdev(vi->dev);
 
index 80ddaff759d47a00d3749495928d515e8be9ecea..a6c787454a1aebcad356fe44f61e16a5b5a6b8eb 100644 (file)
@@ -382,12 +382,12 @@ vmxnet3_process_xdp(struct vmxnet3_adapter *adapter,
        page = rbi->page;
        dma_sync_single_for_cpu(&adapter->pdev->dev,
                                page_pool_get_dma_addr(page) +
-                               rq->page_pool->p.offset, rcd->len,
+                               rq->page_pool->p.offset, rbi->len,
                                page_pool_get_dma_dir(rq->page_pool));
 
-       xdp_init_buff(&xdp, rbi->len, &rq->xdp_rxq);
+       xdp_init_buff(&xdp, PAGE_SIZE, &rq->xdp_rxq);
        xdp_prepare_buff(&xdp, page_address(page), rq->page_pool->p.offset,
-                        rcd->len, false);
+                        rbi->len, false);
        xdp_buff_clear_frags_flag(&xdp);
 
        xdp_prog = rcu_dereference(rq->adapter->xdp_bpf_prog);
index 960371df470a02e667bb2b6d87c9a9a77728028a..f69b1f579a0ca314fd53f6aa55876b43d795bd49 100644 (file)
@@ -780,7 +780,7 @@ static const struct of_device_id qmc_hdlc_id_table[] = {
        { .compatible = "fsl,qmc-hdlc" },
        {} /* sentinel */
 };
-MODULE_DEVICE_TABLE(of, qmc_hdlc_driver);
+MODULE_DEVICE_TABLE(of, qmc_hdlc_id_table);
 
 static struct platform_driver qmc_hdlc_driver = {
        .driver = {
index deb9636b0ecf8f47e832a0b07e9e049ba19bdf16..3feb36ee5bfb44726eecee6db3b9463c62087a95 100644 (file)
@@ -237,7 +237,6 @@ static const struct net_device_ops netdev_ops = {
        .ndo_open               = wg_open,
        .ndo_stop               = wg_stop,
        .ndo_start_xmit         = wg_xmit,
-       .ndo_get_stats64        = dev_get_tstats64
 };
 
 static void wg_destruct(struct net_device *dev)
@@ -262,7 +261,6 @@ static void wg_destruct(struct net_device *dev)
        rcu_barrier(); /* Wait for all the peers to be actually freed. */
        wg_ratelimiter_uninit();
        memzero_explicit(&wg->static_identity, sizeof(wg->static_identity));
-       free_percpu(dev->tstats);
        kvfree(wg->index_hashtable);
        kvfree(wg->peer_hashtable);
        mutex_unlock(&wg->device_update_lock);
@@ -297,6 +295,7 @@ static void wg_setup(struct net_device *dev)
        dev->hw_enc_features |= WG_NETDEV_FEATURES;
        dev->mtu = ETH_DATA_LEN - overhead;
        dev->max_mtu = round_down(INT_MAX, MESSAGE_PADDING_MULTIPLE) - overhead;
+       dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
 
        SET_NETDEV_DEVTYPE(dev, &device_type);
 
@@ -331,14 +330,10 @@ static int wg_newlink(struct net *src_net, struct net_device *dev,
        if (!wg->index_hashtable)
                goto err_free_peer_hashtable;
 
-       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
-       if (!dev->tstats)
-               goto err_free_index_hashtable;
-
        wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
                        WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
        if (!wg->handshake_receive_wq)
-               goto err_free_tstats;
+               goto err_free_index_hashtable;
 
        wg->handshake_send_wq = alloc_workqueue("wg-kex-%s",
                        WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);
@@ -397,8 +392,6 @@ err_destroy_handshake_send:
        destroy_workqueue(wg->handshake_send_wq);
 err_destroy_handshake_receive:
        destroy_workqueue(wg->handshake_receive_wq);
-err_free_tstats:
-       free_percpu(dev->tstats);
 err_free_index_hashtable:
        kvfree(wg->index_hashtable);
 err_free_peer_hashtable:
index e220d761b1f27aa31eab3ad1b9211ddfe55eaabd..f7055180ba4aab5a0952357a334217e3cd6af078 100644 (file)
@@ -164,8 +164,8 @@ get_peer(struct wg_peer *peer, struct sk_buff *skb, struct dump_ctx *ctx)
        if (!allowedips_node)
                goto no_allowedips;
        if (!ctx->allowedips_seq)
-               ctx->allowedips_seq = peer->device->peer_allowedips.seq;
-       else if (ctx->allowedips_seq != peer->device->peer_allowedips.seq)
+               ctx->allowedips_seq = ctx->wg->peer_allowedips.seq;
+       else if (ctx->allowedips_seq != ctx->wg->peer_allowedips.seq)
                goto no_allowedips;
 
        allowedips_nest = nla_nest_start(skb, WGPEER_A_ALLOWEDIPS);
@@ -255,17 +255,17 @@ static int wg_get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
        if (!peers_nest)
                goto out;
        ret = 0;
-       /* If the last cursor was removed via list_del_init in peer_remove, then
+       lockdep_assert_held(&wg->device_update_lock);
+       /* If the last cursor was removed in peer_remove or peer_remove_all, then
         * we just treat this the same as there being no more peers left. The
         * reason is that seq_nr should indicate to userspace that this isn't a
         * coherent dump anyway, so they'll try again.
         */
        if (list_empty(&wg->peer_list) ||
-           (ctx->next_peer && list_empty(&ctx->next_peer->peer_list))) {
+           (ctx->next_peer && ctx->next_peer->is_dead)) {
                nla_nest_cancel(skb, peers_nest);
                goto out;
        }
-       lockdep_assert_held(&wg->device_update_lock);
        peer = list_prepare_entry(ctx->next_peer, &wg->peer_list, peer_list);
        list_for_each_entry_continue(peer, &wg->peer_list, peer_list) {
                if (get_peer(peer, skb, ctx)) {
index df275b4fccb6d01a3bc22bc5bcc418b569a728e5..eb8851113654f5332219ffde63b61c8c470df759 100644 (file)
@@ -251,7 +251,7 @@ static bool decrypt_packet(struct sk_buff *skb, struct noise_keypair *keypair)
 
        if (unlikely(!READ_ONCE(keypair->receiving.is_valid) ||
                  wg_birthdate_has_expired(keypair->receiving.birthdate, REJECT_AFTER_TIME) ||
-                 keypair->receiving_counter.counter >= REJECT_AFTER_MESSAGES)) {
+                 READ_ONCE(keypair->receiving_counter.counter) >= REJECT_AFTER_MESSAGES)) {
                WRITE_ONCE(keypair->receiving.is_valid, false);
                return false;
        }
@@ -318,7 +318,7 @@ static bool counter_validate(struct noise_replay_counter *counter, u64 their_cou
                for (i = 1; i <= top; ++i)
                        counter->backtrack[(i + index_current) &
                                ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0;
-               counter->counter = their_counter;
+               WRITE_ONCE(counter->counter, their_counter);
        }
 
        index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1;
@@ -463,7 +463,7 @@ int wg_packet_rx_poll(struct napi_struct *napi, int budget)
                        net_dbg_ratelimited("%s: Packet has invalid nonce %llu (max %llu)\n",
                                            peer->device->dev->name,
                                            PACKET_CB(skb)->nonce,
-                                           keypair->receiving_counter.counter);
+                                           READ_ONCE(keypair->receiving_counter.counter));
                        goto next;
                }
 
index 2eb5978bd79e1b5114bb34bab409fbeaae00faf8..cfbbe0713317f8e5ca9b3a4942373376febfa248 100644 (file)
@@ -203,8 +203,8 @@ static int pn532_uart_rx_is_frame(struct sk_buff *skb)
        return 0;
 }
 
-static ssize_t pn532_receive_buf(struct serdev_device *serdev,
-                                const u8 *data, size_t count)
+static size_t pn532_receive_buf(struct serdev_device *serdev,
+                               const u8 *data, size_t count)
 {
        struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev);
        size_t i;
index 456d3947116c1c4029fa2477bdf1c12f508927aa..9c09c10c2a4640e626c4f62fc8800c9d2ccc1e5c 100644 (file)
@@ -51,8 +51,8 @@ static const struct s3fwrn5_phy_ops uart_phy_ops = {
        .write = s3fwrn82_uart_write,
 };
 
-static ssize_t s3fwrn82_uart_read(struct serdev_device *serdev,
-                                 const u8 *data, size_t count)
+static size_t s3fwrn82_uart_read(struct serdev_device *serdev,
+                                const u8 *data, size_t count)
 {
        struct s3fwrn82_uart_phy *phy = serdev_device_get_drvdata(serdev);
        size_t i;
index a480cdeac2883c0eb08dbfd32fc4c1adaece7a88..dd6ec0865141a9f8a3e6e90fdfb7888e7e56f810 100644 (file)
@@ -1532,7 +1532,7 @@ put_dev:
        return ret;
 }
 
-static int apple_nvme_remove(struct platform_device *pdev)
+static void apple_nvme_remove(struct platform_device *pdev)
 {
        struct apple_nvme *anv = platform_get_drvdata(pdev);
 
@@ -1547,8 +1547,6 @@ static int apple_nvme_remove(struct platform_device *pdev)
                apple_rtkit_shutdown(anv->rtk);
 
        apple_nvme_detach_genpd(anv);
-
-       return 0;
 }
 
 static void apple_nvme_shutdown(struct platform_device *pdev)
@@ -1598,7 +1596,7 @@ static struct platform_driver apple_nvme_driver = {
                .pm = pm_sleep_ptr(&apple_nvme_pm_ops),
        },
        .probe = apple_nvme_probe,
-       .remove = apple_nvme_remove,
+       .remove_new = apple_nvme_remove,
        .shutdown = apple_nvme_shutdown,
 };
 module_platform_driver(apple_nvme_driver);
index 00864a63447099bca59fa45f8f6076933b58f836..943d72bdd794ca5e6258cb02841447ca38898251 100644 (file)
@@ -1807,9 +1807,6 @@ static void nvme_config_discard(struct nvme_ns *ns, struct queue_limits *lim)
 {
        struct nvme_ctrl *ctrl = ns->ctrl;
 
-       BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
-                       NVME_DSM_MAX_RANGES);
-
        if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns->head, UINT_MAX))
                lim->max_hw_discard_sectors =
                        nvme_lba_to_sect(ns->head, ctrl->dmrsl);
@@ -3237,7 +3234,7 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
 
                if (ctrl->shutdown_timeout != shutdown_timeout)
                        dev_info(ctrl->device,
-                                "Shutdown timeout set to %u seconds\n",
+                                "D3 entry latency set to %u seconds\n",
                                 ctrl->shutdown_timeout);
        } else
                ctrl->shutdown_timeout = shutdown_timeout;
@@ -4391,7 +4388,8 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
        set->ops = ops;
        set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
        if (ctrl->ops->flags & NVME_F_FABRICS)
-               set->reserved_tags = NVMF_RESERVED_TAGS;
+               /* Reserved for fabric connect and keep alive */
+               set->reserved_tags = 2;
        set->numa_node = ctrl->numa_node;
        set->flags = BLK_MQ_F_NO_SCHED;
        if (ctrl->ops->flags & NVME_F_BLOCKING)
@@ -4460,7 +4458,8 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
        if (ctrl->quirks & NVME_QUIRK_SHARED_TAGS)
                set->reserved_tags = NVME_AQ_DEPTH;
        else if (ctrl->ops->flags & NVME_F_FABRICS)
-               set->reserved_tags = NVMF_RESERVED_TAGS;
+               /* Reserved for fabric connect */
+               set->reserved_tags = 1;
        set->numa_node = ctrl->numa_node;
        set->flags = BLK_MQ_F_SHOULD_MERGE;
        if (ctrl->ops->flags & NVME_F_BLOCKING)
index 06cc54851b1be39615cdfa6eed1a935dec472f82..37c974c38dcb077a5018c728c8f33ffc421e53b9 100644 (file)
 /* default is -1: the fail fast mechanism is disabled  */
 #define NVMF_DEF_FAIL_FAST_TMO         -1
 
-/*
- * Reserved one command for internal usage.  This command is used for sending
- * the connect command, as well as for the keep alive command on the admin
- * queue once live.
- */
-#define NVMF_RESERVED_TAGS     1
-
 /*
  * Define a host as seen by the target.  We allocate one at boot, but also
  * allow the override it when creating controllers.  This is both to provide
index e6267a6aa3801e5d76e7d1dc4a509ba0e9fc0159..8e0bb9692685d4638bd21dad44fe1fbbbb147a77 100644 (file)
@@ -3363,6 +3363,9 @@ static const struct pci_device_id nvme_id_table[] = {
                                NVME_QUIRK_BOGUS_NID, },
        { PCI_VDEVICE(REDHAT, 0x0010),  /* Qemu emulated controller */
                .driver_data = NVME_QUIRK_BOGUS_NID, },
+       { PCI_DEVICE(0x126f, 0x2262),   /* Silicon Motion generic */
+               .driver_data = NVME_QUIRK_NO_DEEPEST_PS |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x126f, 0x2263),   /* Silicon Motion unidentified */
                .driver_data = NVME_QUIRK_NO_NS_DESC_LIST |
                                NVME_QUIRK_BOGUS_NID, },
index fc3eed00f9ff1196189415ef1bccd0a6c1e02551..e05571b2a1b0c95deaf5c042f0baca4d490c3562 100644 (file)
@@ -97,8 +97,7 @@ static int nvme_sc_to_pr_err(int nvme_sc)
 static int nvme_send_pr_command(struct block_device *bdev,
                struct nvme_command *c, void *data, unsigned int data_len)
 {
-       if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
-           nvme_disk_is_ns_head(bdev->bd_disk))
+       if (nvme_disk_is_ns_head(bdev->bd_disk))
                return nvme_send_ns_head_pr_command(bdev, c, data, data_len);
 
        return nvme_send_ns_pr_command(bdev->bd_disk->private_data, c, data,
index 09fcaa519e5bc26618eae900a0830a89e6aebbb5..3c55f7edd181939fc8a37b47e0ce56fdb271e434 100644 (file)
@@ -236,8 +236,7 @@ static ssize_t nuse_show(struct device *dev, struct device_attribute *attr,
        struct block_device *bdev = disk->part0;
        int ret;
 
-       if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
-           bdev->bd_disk->fops == &nvme_ns_head_ops)
+       if (nvme_disk_is_ns_head(bdev->bd_disk))
                ret = ns_head_update_nuse(head);
        else
                ret = ns_update_nuse(bdev->bd_disk->private_data);
index 3692b56cb58dbacf53eba56aef841dc50063557a..fdbcdcedcee99f064cc7258d22b7fe737d285eda 100644 (file)
@@ -36,6 +36,14 @@ static int so_priority;
 module_param(so_priority, int, 0644);
 MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority");
 
+/*
+ * Use the unbound workqueue for nvme_tcp_wq, then we can set the cpu affinity
+ * from sysfs.
+ */
+static bool wq_unbound;
+module_param(wq_unbound, bool, 0644);
+MODULE_PARM_DESC(wq_unbound, "Use unbound workqueue for nvme-tcp IO context (default false)");
+
 /*
  * TLS handshake timeout
  */
@@ -1546,7 +1554,10 @@ static void nvme_tcp_set_queue_io_cpu(struct nvme_tcp_queue *queue)
        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);
+       if (wq_unbound)
+               queue->io_cpu = WORK_CPU_UNBOUND;
+       else
+               queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false);
 }
 
 static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid)
@@ -2785,6 +2796,8 @@ static struct nvmf_transport_ops nvme_tcp_transport = {
 
 static int __init nvme_tcp_init_module(void)
 {
+       unsigned int wq_flags = WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_SYSFS;
+
        BUILD_BUG_ON(sizeof(struct nvme_tcp_hdr) != 8);
        BUILD_BUG_ON(sizeof(struct nvme_tcp_cmd_pdu) != 72);
        BUILD_BUG_ON(sizeof(struct nvme_tcp_data_pdu) != 24);
@@ -2794,8 +2807,10 @@ static int __init nvme_tcp_init_module(void)
        BUILD_BUG_ON(sizeof(struct nvme_tcp_icresp_pdu) != 128);
        BUILD_BUG_ON(sizeof(struct nvme_tcp_term_pdu) != 24);
 
-       nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq",
-                       WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+       if (wq_unbound)
+               wq_flags |= WQ_UNBOUND;
+
+       nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq", wq_flags, 0);
        if (!nvme_tcp_wq)
                return -ENOMEM;
 
index 1c36fcedea2008777140891d7f6b941ed080d8f1..0288315f00502872eb8d3a3a6b47027f32059042 100644 (file)
@@ -119,7 +119,10 @@ static const char *nvme_trace_get_lba_status(struct trace_seq *p,
 static const char *nvme_trace_admin_format_nvm(struct trace_seq *p, u8 *cdw10)
 {
        const char *ret = trace_seq_buffer_ptr(p);
-       u8 lbaf = cdw10[0] & 0xF;
+       /*
+        * lbafu(bit 13:12) is already in the upper 4 bits, lbafl: bit 03:00.
+        */
+       u8 lbaf = (cdw10[1] & 0x30) | (cdw10[0] & 0xF);
        u8 mset = (cdw10[0] >> 4) & 0x1;
        u8 pi = (cdw10[0] >> 5) & 0x7;
        u8 pil = cdw10[1] & 0x1;
@@ -164,12 +167,27 @@ static const char *nvme_trace_dsm(struct trace_seq *p, u8 *cdw10)
 
 static const char *nvme_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10)
 {
+       static const char * const zsa_strs[] = {
+               [0x01] = "close zone",
+               [0x02] = "finish zone",
+               [0x03] = "open zone",
+               [0x04] = "reset zone",
+               [0x05] = "offline zone",
+               [0x10] = "set zone descriptor extension"
+       };
        const char *ret = trace_seq_buffer_ptr(p);
        u64 slba = get_unaligned_le64(cdw10);
+       const char *zsa_str;
        u8 zsa = cdw10[12];
        u8 all = cdw10[13];
 
-       trace_seq_printf(p, "slba=%llu, zsa=%u, all=%u", slba, zsa, all);
+       if (zsa < ARRAY_SIZE(zsa_strs) && zsa_strs[zsa])
+               zsa_str = zsa_strs[zsa];
+       else
+               zsa_str = "reserved";
+
+       trace_seq_printf(p, "slba=%llu, zsa=%u:%s, all=%u",
+               slba, zsa, zsa_str, all);
        trace_seq_putc(p, 0);
 
        return ret;
@@ -177,15 +195,86 @@ static const char *nvme_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10)
 
 static const char *nvme_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10)
 {
+       static const char * const zrasf_strs[] = {
+               [0x00] = "list all zones",
+               [0x01] = "list the zones in the ZSE: Empty state",
+               [0x02] = "list the zones in the ZSIO: Implicitly Opened state",
+               [0x03] = "list the zones in the ZSEO: Explicitly Opened state",
+               [0x04] = "list the zones in the ZSC: Closed state",
+               [0x05] = "list the zones in the ZSF: Full state",
+               [0x06] = "list the zones in the ZSRO: Read Only state",
+               [0x07] = "list the zones in the ZSO: Offline state",
+               [0x09] = "list the zones that have the zone attribute"
+       };
        const char *ret = trace_seq_buffer_ptr(p);
        u64 slba = get_unaligned_le64(cdw10);
        u32 numd = get_unaligned_le32(cdw10 + 8);
        u8 zra = cdw10[12];
        u8 zrasf = cdw10[13];
+       const char *zrasf_str;
        u8 pr = cdw10[14];
 
-       trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u, pr=%u",
-                        slba, numd, zra, zrasf, pr);
+       if (zrasf < ARRAY_SIZE(zrasf_strs) && zrasf_strs[zrasf])
+               zrasf_str = zrasf_strs[zrasf];
+       else
+               zrasf_str = "reserved";
+
+       trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u:%s, pr=%u",
+               slba, numd, zra, zrasf, zrasf_str, pr);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *nvme_trace_resv_reg(struct trace_seq *p, u8 *cdw10)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       u8 rrega = cdw10[0] & 0x7;
+       u8 iekey = (cdw10[0] >> 3) & 0x1;
+       u8 ptpl = (cdw10[3] >> 6) & 0x3;
+
+       trace_seq_printf(p, "rrega=%u, iekey=%u, ptpl=%u",
+                        rrega, iekey, ptpl);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *nvme_trace_resv_acq(struct trace_seq *p, u8 *cdw10)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       u8 racqa = cdw10[0] & 0x7;
+       u8 iekey = (cdw10[0] >> 3) & 0x1;
+       u8 rtype = cdw10[1];
+
+       trace_seq_printf(p, "racqa=%u, iekey=%u, rtype=%u",
+                        racqa, iekey, rtype);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *nvme_trace_resv_rel(struct trace_seq *p, u8 *cdw10)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       u8 rrela = cdw10[0] & 0x7;
+       u8 iekey = (cdw10[0] >> 3) & 0x1;
+       u8 rtype = cdw10[1];
+
+       trace_seq_printf(p, "rrela=%u, iekey=%u, rtype=%u",
+                        rrela, iekey, rtype);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *nvme_trace_resv_report(struct trace_seq *p, u8 *cdw10)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       u32 numd = get_unaligned_le32(cdw10);
+       u8 eds = cdw10[4] & 0x1;
+
+       trace_seq_printf(p, "numd=%u, eds=%u", numd, eds);
        trace_seq_putc(p, 0);
 
        return ret;
@@ -243,6 +332,14 @@ const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p,
                return nvme_trace_zone_mgmt_send(p, cdw10);
        case nvme_cmd_zone_mgmt_recv:
                return nvme_trace_zone_mgmt_recv(p, cdw10);
+       case nvme_cmd_resv_register:
+               return nvme_trace_resv_reg(p, cdw10);
+       case nvme_cmd_resv_acquire:
+               return nvme_trace_resv_acq(p, cdw10);
+       case nvme_cmd_resv_release:
+               return nvme_trace_resv_rel(p, cdw10);
+       case nvme_cmd_resv_report:
+               return nvme_trace_resv_report(p, cdw10);
        default:
                return nvme_trace_common(p, cdw10);
        }
index f2bb9d95ecf4bc6cde907d1f9af3e2d89998f376..5b8c63e74639d7485fe7feedf514e06d7e7c1d4e 100644 (file)
@@ -53,7 +53,6 @@ struct nvmet_rdma_cmd {
 
 enum {
        NVMET_RDMA_REQ_INLINE_DATA      = (1 << 0),
-       NVMET_RDMA_REQ_INVALIDATE_RKEY  = (1 << 1),
 };
 
 struct nvmet_rdma_rsp {
@@ -722,7 +721,7 @@ static void nvmet_rdma_queue_response(struct nvmet_req *req)
        struct rdma_cm_id *cm_id = rsp->queue->cm_id;
        struct ib_send_wr *first_wr;
 
-       if (rsp->flags & NVMET_RDMA_REQ_INVALIDATE_RKEY) {
+       if (rsp->invalidate_rkey) {
                rsp->send_wr.opcode = IB_WR_SEND_WITH_INV;
                rsp->send_wr.ex.invalidate_rkey = rsp->invalidate_rkey;
        } else {
@@ -905,10 +904,8 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp,
                goto error_out;
        rsp->n_rdma += ret;
 
-       if (invalidate) {
+       if (invalidate)
                rsp->invalidate_rkey = key;
-               rsp->flags |= NVMET_RDMA_REQ_INVALIDATE_RKEY;
-       }
 
        return 0;
 
@@ -1047,6 +1044,7 @@ static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc)
        rsp->req.cmd = cmd->nvme_cmd;
        rsp->req.port = queue->port;
        rsp->n_rdma = 0;
+       rsp->invalidate_rkey = 0;
 
        if (unlikely(queue->state != NVMET_RDMA_Q_LIVE)) {
                unsigned long flags;
index 2aa5762e9f50d0d3ae3c6cfceb9cd03ce1ad8df4..a5422e2c979addca1f219777b47f61f5817e302a 100644 (file)
@@ -898,6 +898,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
                pr_err("bad nvme-tcp pdu length (%d)\n",
                        le32_to_cpu(icreq->hdr.plen));
                nvmet_tcp_fatal_error(queue);
+               return -EPROTO;
        }
 
        if (icreq->pfv != NVME_TCP_PFV_1_0) {
index 6ee1f3db81d04071e761b39640e573c9770aa32f..8d1806a828879a28b8ef1ba25e0437d695c0f56b 100644 (file)
@@ -119,6 +119,67 @@ const char *nvmet_trace_parse_admin_cmd(struct trace_seq *p,
        }
 }
 
+static const char *nvmet_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10)
+{
+       static const char * const zsa_strs[] = {
+               [0x01] = "close zone",
+               [0x02] = "finish zone",
+               [0x03] = "open zone",
+               [0x04] = "reset zone",
+               [0x05] = "offline zone",
+               [0x10] = "set zone descriptor extension"
+       };
+       const char *ret = trace_seq_buffer_ptr(p);
+       u64 slba = get_unaligned_le64(cdw10);
+       const char *zsa_str;
+       u8 zsa = cdw10[12];
+       u8 all = cdw10[13];
+
+       if (zsa < ARRAY_SIZE(zsa_strs) && zsa_strs[zsa])
+               zsa_str = zsa_strs[zsa];
+       else
+               zsa_str = "reserved";
+
+       trace_seq_printf(p, "slba=%llu, zsa=%u:%s, all=%u",
+               slba, zsa, zsa_str, all);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *nvmet_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10)
+{
+       static const char * const zrasf_strs[] = {
+               [0x00] = "list all zones",
+               [0x01] = "list the zones in the ZSE: Empty state",
+               [0x02] = "list the zones in the ZSIO: Implicitly Opened state",
+               [0x03] = "list the zones in the ZSEO: Explicitly Opened state",
+               [0x04] = "list the zones in the ZSC: Closed state",
+               [0x05] = "list the zones in the ZSF: Full state",
+               [0x06] = "list the zones in the ZSRO: Read Only state",
+               [0x07] = "list the zones in the ZSO: Offline state",
+               [0x09] = "list the zones that have the zone attribute"
+       };
+       const char *ret = trace_seq_buffer_ptr(p);
+       u64 slba = get_unaligned_le64(cdw10);
+       u32 numd = get_unaligned_le32(&cdw10[8]);
+       u8 zra = cdw10[12];
+       u8 zrasf = cdw10[13];
+       const char *zrasf_str;
+       u8 pr = cdw10[14];
+
+       if (zrasf < ARRAY_SIZE(zrasf_strs) && zrasf_strs[zrasf])
+               zrasf_str = zrasf_strs[zrasf];
+       else
+               zrasf_str = "reserved";
+
+       trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u:%s, pr=%u",
+               slba, numd, zra, zrasf, zrasf_str, pr);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
 const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p,
                u8 opcode, u8 *cdw10)
 {
@@ -126,9 +187,14 @@ const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p,
        case nvme_cmd_read:
        case nvme_cmd_write:
        case nvme_cmd_write_zeroes:
+       case nvme_cmd_zone_append:
                return nvmet_trace_read_write(p, cdw10);
        case nvme_cmd_dsm:
                return nvmet_trace_dsm(p, cdw10);
+       case nvme_cmd_zone_mgmt_send:
+               return nvmet_trace_zone_mgmt_send(p, cdw10);
+       case nvme_cmd_zone_mgmt_recv:
+               return nvmet_trace_zone_mgmt_recv(p, cdw10);
        default:
                return nvmet_trace_common(p, cdw10);
        }
@@ -176,6 +242,34 @@ static const char *nvmet_trace_fabrics_property_get(struct trace_seq *p,
        return ret;
 }
 
+static const char *nvmet_trace_fabrics_auth_send(struct trace_seq *p, u8 *spc)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       u8 spsp0 = spc[1];
+       u8 spsp1 = spc[2];
+       u8 secp = spc[3];
+       u32 tl = get_unaligned_le32(spc + 4);
+
+       trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, tl=%u",
+                        spsp0, spsp1, secp, tl);
+       trace_seq_putc(p, 0);
+       return ret;
+}
+
+static const char *nvmet_trace_fabrics_auth_receive(struct trace_seq *p, u8 *spc)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       u8 spsp0 = spc[1];
+       u8 spsp1 = spc[2];
+       u8 secp = spc[3];
+       u32 al = get_unaligned_le32(spc + 4);
+
+       trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, al=%u",
+                        spsp0, spsp1, secp, al);
+       trace_seq_putc(p, 0);
+       return ret;
+}
+
 static const char *nvmet_trace_fabrics_common(struct trace_seq *p, u8 *spc)
 {
        const char *ret = trace_seq_buffer_ptr(p);
@@ -195,6 +289,10 @@ const char *nvmet_trace_parse_fabrics_cmd(struct trace_seq *p,
                return nvmet_trace_fabrics_connect(p, spc);
        case nvme_fabrics_type_property_get:
                return nvmet_trace_fabrics_property_get(p, spc);
+       case nvme_fabrics_type_auth_send:
+               return nvmet_trace_fabrics_auth_send(p, spc);
+       case nvme_fabrics_type_auth_receive:
+               return nvmet_trace_fabrics_auth_receive(p, spc);
        default:
                return nvmet_trace_fabrics_common(p, spc);
        }
index eb357ac2e54a2a827ad07b9a073d3e76415a000f..2c6b99402df8a76011c2165fb8841ae2ff7fcc1f 100644 (file)
@@ -807,6 +807,11 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
                if (addr && len == (2 * sizeof(u32))) {
                        info.bit_offset = be32_to_cpup(addr++);
                        info.nbits = be32_to_cpup(addr);
+                       if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
+                               dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
+                               of_node_put(child);
+                               return -EINVAL;
+                       }
                }
 
                info.np = of_node_get(child);
index 6a6aa58369ff24162a15538449e50216947aa00d..8b5e2de138eb513df62c13f65518420b7a0698f8 100644 (file)
@@ -45,7 +45,7 @@ static void nvmem_layout_bus_remove(struct device *dev)
        return drv->remove(layout);
 }
 
-static struct bus_type nvmem_layout_bus_type = {
+static const struct bus_type nvmem_layout_bus_type = {
        .name           = "nvmem-layout",
        .match          = nvmem_layout_bus_match,
        .probe          = nvmem_layout_bus_probe,
index b922df99f9bc3df457df742123b3c8d970ffa9a5..33678d0af2c2455abff8b18acf0d92c180848d83 100644 (file)
@@ -47,7 +47,6 @@ static int meson_efuse_probe(struct platform_device *pdev)
        struct nvmem_config *econfig;
        struct clk *clk;
        unsigned int size;
-       int ret;
 
        sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0);
        if (!sm_np) {
@@ -60,27 +59,9 @@ static int meson_efuse_probe(struct platform_device *pdev)
        if (!fw)
                return -EPROBE_DEFER;
 
-       clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(clk)) {
-               ret = PTR_ERR(clk);
-               if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "failed to get efuse gate");
-               return ret;
-       }
-
-       ret = clk_prepare_enable(clk);
-       if (ret) {
-               dev_err(dev, "failed to enable gate");
-               return ret;
-       }
-
-       ret = devm_add_action_or_reset(dev,
-                                      (void(*)(void *))clk_disable_unprepare,
-                                      clk);
-       if (ret) {
-               dev_err(dev, "failed to add disable callback");
-               return ret;
-       }
+       clk = devm_clk_get_enabled(dev, NULL);
+       if (IS_ERR(clk))
+               return dev_err_probe(dev, PTR_ERR(clk), "failed to get efuse gate");
 
        if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) {
                dev_err(dev, "failed to get max user");
index 84f05b40a4112ed7878e94504de48eec3737e3ad..9caf046673410129e5fd595e23adceb6bd0772a8 100644 (file)
@@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platform_device *pdev)
        struct nvmem_config econfig = {};
        struct mtk_efuse_priv *priv;
        const struct mtk_efuse_pdata *pdata;
+       struct platform_device *socinfo;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -88,8 +89,16 @@ static int mtk_efuse_probe(struct platform_device *pdev)
        if (pdata->uses_post_processing)
                econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
        nvmem = devm_nvmem_register(dev, &econfig);
+       if (IS_ERR(nvmem))
+               return PTR_ERR(nvmem);
 
-       return PTR_ERR_OR_ZERO(nvmem);
+       socinfo = platform_device_register_data(&pdev->dev, "mtk-socinfo",
+                                               PLATFORM_DEVID_AUTO, NULL, 0);
+       if (IS_ERR(socinfo))
+               dev_info(dev, "MediaTek SoC Information will be unavailable\n");
+
+       platform_set_drvdata(pdev, socinfo);
+       return 0;
 }
 
 static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
@@ -108,8 +117,17 @@ static const struct of_device_id mtk_efuse_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
 
+static void mtk_efuse_remove(struct platform_device *pdev)
+{
+       struct platform_device *socinfo = platform_get_drvdata(pdev);
+
+       if (!IS_ERR_OR_NULL(socinfo))
+               platform_device_unregister(socinfo);
+}
+
 static struct platform_driver mtk_efuse_driver = {
        .probe = mtk_efuse_probe,
+       .remove_new = mtk_efuse_remove,
        .driver = {
                .name = "mediatek,efuse",
                .of_match_table = mtk_efuse_of_match,
index 7f15aa89a9d09145078c75451a4186f3114b6097..8682adaacd692dd14d03b451ab24c5f43a8ce922 100644 (file)
@@ -1,8 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of.h>
 #include <linux/firmware/xlnx-zynqmp.h>
 
 #define SILICON_REVISION_MASK 0xF
+#define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
+#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
+#define WORD_INBYTES           4
+#define SOC_VER_SIZE           0x4
+#define EFUSE_MEMORY_SIZE      0x177
+#define UNUSED_SPACE           0x8
+#define ZYNQMP_NVMEM_SIZE      (SOC_VER_SIZE + UNUSED_SPACE + \
+                                EFUSE_MEMORY_SIZE)
+#define SOC_VERSION_OFFSET     0x0
+#define EFUSE_START_OFFSET     0xC
+#define EFUSE_END_OFFSET       0xFC
+#define EFUSE_PUF_START_OFFSET 0x100
+#define EFUSE_PUF_MID_OFFSET   0x140
+#define EFUSE_PUF_END_OFFSET   0x17F
+#define EFUSE_NOT_ENABLED      29
 
-struct zynqmp_nvmem_data {
-       struct device *dev;
-       struct nvmem_device *nvmem;
+/*
+ * efuse access type
+ */
+enum efuse_access {
+       EFUSE_READ = 0,
+       EFUSE_WRITE
+};
+
+/**
+ * struct xilinx_efuse - the basic structure
+ * @src:       address of the buffer to store the data to be write/read
+ * @size:      read/write word count
+ * @offset:    read/write offset
+ * @flag:      0 - represents efuse read and 1- represents efuse write
+ * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
+ *             1 - represents puf user fuse row number.
+ *
+ * this structure stores all the required details to
+ * read/write efuse memory.
+ */
+struct xilinx_efuse {
+       u64 src;
+       u32 size;
+       u32 offset;
+       enum efuse_access flag;
+       u32 pufuserfuse;
 };
 
-static int zynqmp_nvmem_read(void *context, unsigned int offset,
-                            void *val, size_t bytes)
+static int zynqmp_efuse_access(void *context, unsigned int offset,
+                              void *val, size_t bytes, enum efuse_access flag,
+                              unsigned int pufflag)
 {
+       struct device *dev = context;
+       struct xilinx_efuse *efuse;
+       dma_addr_t dma_addr;
+       dma_addr_t dma_buf;
+       size_t words = bytes / WORD_INBYTES;
        int ret;
-       int idcode, version;
-       struct zynqmp_nvmem_data *priv = context;
-
-       ret = zynqmp_pm_get_chipid(&idcode, &version);
-       if (ret < 0)
-               return ret;
+       int value;
+       char *data;
+
+       if (bytes % WORD_INBYTES != 0) {
+               dev_err(dev, "Bytes requested should be word aligned\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (pufflag == 0 && offset % WORD_INBYTES) {
+               dev_err(dev, "Offset requested should be word aligned\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (pufflag == 1 && flag == EFUSE_WRITE) {
+               memcpy(&value, val, bytes);
+               if ((offset == EFUSE_PUF_START_OFFSET ||
+                    offset == EFUSE_PUF_MID_OFFSET) &&
+                   value & P_USER_0_64_UPPER_MASK) {
+                       dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
+                       return -EOPNOTSUPP;
+               }
+
+               if (offset == EFUSE_PUF_END_OFFSET &&
+                   (value & P_USER_127_LOWER_4_BIT_MASK)) {
+                       dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
+                                  &dma_addr, GFP_KERNEL);
+       if (!efuse)
+               return -ENOMEM;
 
-       dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
-       *(int *)val = version & SILICON_REVISION_MASK;
+       data = dma_alloc_coherent(dev, sizeof(bytes),
+                                 &dma_buf, GFP_KERNEL);
+       if (!data) {
+               ret = -ENOMEM;
+               goto efuse_data_fail;
+       }
+
+       if (flag == EFUSE_WRITE) {
+               memcpy(data, val, bytes);
+               efuse->flag = EFUSE_WRITE;
+       } else {
+               efuse->flag = EFUSE_READ;
+       }
+
+       efuse->src = dma_buf;
+       efuse->size = words;
+       efuse->offset = offset;
+       efuse->pufuserfuse = pufflag;
+
+       zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
+       if (ret != 0) {
+               if (ret == EFUSE_NOT_ENABLED) {
+                       dev_err(dev, "efuse access is not enabled\n");
+                       ret = -EOPNOTSUPP;
+               } else {
+                       dev_err(dev, "Error in efuse read %x\n", ret);
+                       ret = -EPERM;
+               }
+               goto efuse_access_err;
+       }
+
+       if (flag == EFUSE_READ)
+               memcpy(val, data, bytes);
+efuse_access_err:
+       dma_free_coherent(dev, sizeof(bytes),
+                         data, dma_buf);
+efuse_data_fail:
+       dma_free_coherent(dev, sizeof(struct xilinx_efuse),
+                         efuse, dma_addr);
+
+       return ret;
+}
 
-       return 0;
+static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
+{
+       struct device *dev = context;
+       int ret;
+       int pufflag = 0;
+       int idcode;
+       int version;
+
+       if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+               pufflag = 1;
+
+       switch (offset) {
+       /* Soc version offset is zero */
+       case SOC_VERSION_OFFSET:
+               if (bytes != SOC_VER_SIZE)
+                       return -EOPNOTSUPP;
+
+               ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
+               if (ret < 0)
+                       return ret;
+
+               dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
+               *(int *)val = version & SILICON_REVISION_MASK;
+               break;
+       /* Efuse offset starts from 0xc */
+       case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
+       case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
+               ret = zynqmp_efuse_access(context, offset, val,
+                                         bytes, EFUSE_READ, pufflag);
+               break;
+       default:
+               *(u32 *)val = 0xDEADBEEF;
+               ret = 0;
+               break;
+       }
+
+       return ret;
 }
 
-static struct nvmem_config econfig = {
-       .name = "zynqmp-nvmem",
-       .owner = THIS_MODULE,
-       .word_size = 1,
-       .size = 1,
-       .read_only = true,
-};
+static int zynqmp_nvmem_write(void *context,
+                             unsigned int offset, void *val, size_t bytes)
+{
+       int pufflag = 0;
+
+       if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
+               return -EOPNOTSUPP;
+
+       if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+               pufflag = 1;
+
+       return zynqmp_efuse_access(context, offset,
+                                  val, bytes, EFUSE_WRITE, pufflag);
+}
 
 static const struct of_device_id zynqmp_nvmem_match[] = {
        { .compatible = "xlnx,zynqmp-nvmem-fw", },
@@ -50,21 +206,18 @@ MODULE_DEVICE_TABLE(of, zynqmp_nvmem_match);
 static int zynqmp_nvmem_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct zynqmp_nvmem_data *priv;
-
-       priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
+       struct nvmem_config econfig = {};
 
-       priv->dev = dev;
+       econfig.name = "zynqmp-nvmem";
+       econfig.owner = THIS_MODULE;
+       econfig.word_size = 1;
+       econfig.size = ZYNQMP_NVMEM_SIZE;
        econfig.dev = dev;
        econfig.add_legacy_fixed_of_cells = true;
        econfig.reg_read = zynqmp_nvmem_read;
-       econfig.priv = priv;
-
-       priv->nvmem = devm_nvmem_register(dev, &econfig);
+       econfig.reg_write = zynqmp_nvmem_write;
 
-       return PTR_ERR_OR_ZERO(priv->nvmem);
+       return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
 }
 
 static struct platform_driver zynqmp_nvmem_driver = {
index c907478ef89e67157763d26ea5cddbabfb02ec16..a6358ee99b74b99a90df38c63e08943b628a7b80 100644 (file)
@@ -1072,7 +1072,8 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
 }
 
 static void of_link_to_phandle(struct device_node *con_np,
-                             struct device_node *sup_np)
+                             struct device_node *sup_np,
+                             u8 flags)
 {
        struct device_node *tmp_np = of_node_get(sup_np);
 
@@ -1091,7 +1092,7 @@ static void of_link_to_phandle(struct device_node *con_np,
                tmp_np = of_get_next_parent(tmp_np);
        }
 
-       fwnode_link_add(of_fwnode_handle(con_np), of_fwnode_handle(sup_np));
+       fwnode_link_add(of_fwnode_handle(con_np), of_fwnode_handle(sup_np), flags);
 }
 
 /**
@@ -1204,6 +1205,8 @@ static struct device_node *parse_##fname(struct device_node *np,       \
  *              to a struct device, implement this ops so fw_devlink can use it
  *              to find the true consumer.
  * @optional: Describes whether a supplier is mandatory or not
+ * @fwlink_flags: Optional fwnode link flags to use when creating a fwnode link
+ *               for this property.
  *
  * Returns:
  * parse_prop() return values are
@@ -1216,6 +1219,7 @@ struct supplier_bindings {
                                          const char *prop_name, int index);
        struct device_node *(*get_con_dev)(struct device_node *np);
        bool optional;
+       u8 fwlink_flags;
 };
 
 DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells")
@@ -1223,6 +1227,7 @@ DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells")
 DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells")
 DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells")
 DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells")
+DEFINE_SIMPLE_PROP(io_backends, "io-backends", "#io-backend-cells")
 DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL)
 DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
 DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells")
@@ -1246,6 +1251,7 @@ DEFINE_SIMPLE_PROP(leds, "leds", NULL)
 DEFINE_SIMPLE_PROP(backlight, "backlight", NULL)
 DEFINE_SIMPLE_PROP(panel, "panel", NULL)
 DEFINE_SIMPLE_PROP(msi_parent, "msi-parent", "#msi-cells")
+DEFINE_SIMPLE_PROP(post_init_providers, "post-init-providers", NULL)
 DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
 DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
 
@@ -1323,6 +1329,7 @@ static const struct supplier_bindings of_supplier_bindings[] = {
        { .parse_prop = parse_iommu_maps, .optional = true, },
        { .parse_prop = parse_mboxes, },
        { .parse_prop = parse_io_channels, },
+       { .parse_prop = parse_io_backends, },
        { .parse_prop = parse_interrupt_parent, },
        { .parse_prop = parse_dmas, .optional = true, },
        { .parse_prop = parse_power_domains, },
@@ -1355,6 +1362,10 @@ static const struct supplier_bindings of_supplier_bindings[] = {
        { .parse_prop = parse_regulators, },
        { .parse_prop = parse_gpio, },
        { .parse_prop = parse_gpios, },
+       {
+               .parse_prop = parse_post_init_providers,
+               .fwlink_flags = FWLINK_FLAG_IGNORE,
+       },
        {}
 };
 
@@ -1399,7 +1410,7 @@ static int of_link_property(struct device_node *con_np, const char *prop_name)
                                        : of_node_get(con_np);
                        matched = true;
                        i++;
-                       of_link_to_phandle(con_dev_np, phandle);
+                       of_link_to_phandle(con_dev_np, phandle, s->fwlink_flags);
                        of_node_put(phandle);
                        of_node_put(con_dev_np);
                }
index 84d5701d606ce9b16f0d870df22a82e23ed770d4..e6dc857aac3febc30845de49dc69e917b186bbd3 100644 (file)
@@ -219,7 +219,7 @@ out_irq:
        return err;
 }
 
-static int __exit amiga_parallel_remove(struct platform_device *pdev)
+static void __exit amiga_parallel_remove(struct platform_device *pdev)
 {
        struct parport *port = platform_get_drvdata(pdev);
 
@@ -227,11 +227,10 @@ static int __exit amiga_parallel_remove(struct platform_device *pdev)
        if (port->irq != PARPORT_IRQ_NONE)
                free_irq(IRQ_AMIGA_CIAA_FLG, port);
        parport_put_port(port);
-       return 0;
 }
 
 static struct platform_driver amiga_parallel_driver = {
-       .remove = __exit_p(amiga_parallel_remove),
+       .remove_new = __exit_p(amiga_parallel_remove),
        .driver   = {
                .name   = "amiga-parallel",
        },
index c81d4d86994b1bde321232318acaf433f6354f31..949236a7a27c97b7fcd7a85599320fa38af21edc 100644 (file)
@@ -334,7 +334,7 @@ out_unmap:
        return err;
 }
 
-static int bpp_remove(struct platform_device *op)
+static void bpp_remove(struct platform_device *op)
 {
        struct parport *p = dev_get_drvdata(&op->dev);
        struct parport_operations *ops = p->ops;
@@ -351,8 +351,6 @@ static int bpp_remove(struct platform_device *op)
        kfree(ops);
 
        dev_set_drvdata(&op->dev, NULL);
-
-       return 0;
 }
 
 static const struct of_device_id bpp_match[] = {
@@ -370,7 +368,7 @@ static struct platform_driver bpp_sbus_driver = {
                .of_match_table = bpp_match,
        },
        .probe          = bpp_probe,
-       .remove         = bpp_remove,
+       .remove_new     = bpp_remove,
 };
 
 module_platform_driver(bpp_sbus_driver);
index 004d86230aa6308a07823f267cfebce6e4ac39f5..7526a9e714fa985d79d20b77003483a81f7b60a7 100644 (file)
@@ -87,7 +87,8 @@ config RISCV_PMU_SBI
          filtering, counter configuration.
 
 config STARFIVE_STARLINK_PMU
-       depends on ARCH_STARFIVE || (COMPILE_TEST && 64BIT)
+       depends on ARCH_STARFIVE || COMPILE_TEST
+       depends on 64BIT
        bool "StarFive StarLink PMU"
        help
           Provide support for StarLink Performance Monitor Unit.
@@ -95,6 +96,20 @@ config STARFIVE_STARLINK_PMU
           an L3 memory system. The L3 cache events are added into perf event
           subsystem, allowing monitoring of various L3 cache perf events.
 
+config ANDES_CUSTOM_PMU
+       bool "Andes custom PMU support"
+       depends on ARCH_RENESAS && RISCV_ALTERNATIVE && RISCV_PMU_SBI
+       default y
+       help
+         The Andes cores implement the PMU overflow extension very
+         similar to the standard Sscofpmf and Smcntrpmf extension.
+
+         This will patch the overflow and pending CSRs and handle the
+         non-standard behaviour via the regular SBI PMU driver and
+         interface.
+
+         If you don't know what to do here, say "Y".
+
 config ARM_PMU_ACPI
        depends on ARM_PMU && ACPI
        def_bool y
index 452aab49db1e8ccc35a6bb0b76661ca7cb6fb71f..8cbe6e5f9c39a6f5b585251b02908b8b7309e23d 100644 (file)
 #include <linux/of.h>
 #include <linux/cpu_pm.h>
 #include <linux/sched/clock.h>
+#include <linux/soc/andes/irq.h>
 
 #include <asm/errata_list.h>
 #include <asm/sbi.h>
 #include <asm/cpufeature.h>
 
+#define ALT_SBI_PMU_OVERFLOW(__ovl)                                    \
+asm volatile(ALTERNATIVE_2(                                            \
+       "csrr %0, " __stringify(CSR_SSCOUNTOVF),                        \
+       "csrr %0, " __stringify(THEAD_C9XX_CSR_SCOUNTEROF),             \
+               THEAD_VENDOR_ID, ERRATA_THEAD_PMU,                      \
+               CONFIG_ERRATA_THEAD_PMU,                                \
+       "csrr %0, " __stringify(ANDES_CSR_SCOUNTEROF),                  \
+               0, RISCV_ISA_EXT_XANDESPMU,                             \
+               CONFIG_ANDES_CUSTOM_PMU)                                \
+       : "=r" (__ovl) :                                                \
+       : "memory")
+
+#define ALT_SBI_PMU_OVF_CLEAR_PENDING(__irq_mask)                      \
+asm volatile(ALTERNATIVE(                                              \
+       "csrc " __stringify(CSR_IP) ", %0\n\t",                         \
+       "csrc " __stringify(ANDES_CSR_SLIP) ", %0\n\t",                 \
+               0, RISCV_ISA_EXT_XANDESPMU,                             \
+               CONFIG_ANDES_CUSTOM_PMU)                                \
+       : : "r"(__irq_mask)                                             \
+       : "memory")
+
 #define SYSCTL_NO_USER_ACCESS  0
 #define SYSCTL_USER_ACCESS     1
 #define SYSCTL_LEGACY          2
@@ -61,6 +83,7 @@ static int sysctl_perf_user_access __read_mostly = SYSCTL_USER_ACCESS;
 static union sbi_pmu_ctr_info *pmu_ctr_list;
 static bool riscv_pmu_use_irq;
 static unsigned int riscv_pmu_irq_num;
+static unsigned int riscv_pmu_irq_mask;
 static unsigned int riscv_pmu_irq;
 
 /* Cache the available counters in a bitmask */
@@ -694,7 +717,7 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 
        event = cpu_hw_evt->events[fidx];
        if (!event) {
-               csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
+               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
                return IRQ_NONE;
        }
 
@@ -708,7 +731,7 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
         * Overflow interrupt pending bit should only be cleared after stopping
         * all the counters to avoid any race condition.
         */
-       csr_clear(CSR_SIP, BIT(riscv_pmu_irq_num));
+       ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
 
        /* No overflow bit is set */
        if (!overflow)
@@ -780,8 +803,7 @@ static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
 
        if (riscv_pmu_use_irq) {
                cpu_hw_evt->irq = riscv_pmu_irq;
-               csr_clear(CSR_IP, BIT(riscv_pmu_irq_num));
-               csr_set(CSR_IE, BIT(riscv_pmu_irq_num));
+               ALT_SBI_PMU_OVF_CLEAR_PENDING(riscv_pmu_irq_mask);
                enable_percpu_irq(riscv_pmu_irq, IRQ_TYPE_NONE);
        }
 
@@ -792,7 +814,6 @@ static int pmu_sbi_dying_cpu(unsigned int cpu, struct hlist_node *node)
 {
        if (riscv_pmu_use_irq) {
                disable_percpu_irq(riscv_pmu_irq);
-               csr_clear(CSR_IE, BIT(riscv_pmu_irq_num));
        }
 
        /* Disable all counters access for user mode now */
@@ -816,8 +837,14 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
                   riscv_cached_mimpid(0) == 0) {
                riscv_pmu_irq_num = THEAD_C9XX_RV_IRQ_PMU;
                riscv_pmu_use_irq = true;
+       } else if (riscv_isa_extension_available(NULL, XANDESPMU) &&
+                  IS_ENABLED(CONFIG_ANDES_CUSTOM_PMU)) {
+               riscv_pmu_irq_num = ANDES_SLI_CAUSE_BASE + ANDES_RV_IRQ_PMOVI;
+               riscv_pmu_use_irq = true;
        }
 
+       riscv_pmu_irq_mask = BIT(riscv_pmu_irq_num % BITS_PER_LONG);
+
        if (!riscv_pmu_use_irq)
                return -EOPNOTSUPP;
 
index 4cef568231bf08cde753a83901c0a14be0b97c1d..787354b849c75c34614c41e4bec3a9da235f60ac 100644 (file)
@@ -87,6 +87,7 @@ source "drivers/phy/motorola/Kconfig"
 source "drivers/phy/mscc/Kconfig"
 source "drivers/phy/qualcomm/Kconfig"
 source "drivers/phy/ralink/Kconfig"
+source "drivers/phy/realtek/Kconfig"
 source "drivers/phy/renesas/Kconfig"
 source "drivers/phy/rockchip/Kconfig"
 source "drivers/phy/samsung/Kconfig"
index fb3dc9de611154abf78ebcf51c055eba03d263b5..868a220ed0f6df60ee478df391777a212a210716 100644 (file)
@@ -26,6 +26,7 @@ obj-y                                 += allwinner/   \
                                           mscc/        \
                                           qualcomm/    \
                                           ralink/      \
+                                          realtek/     \
                                           renesas/     \
                                           rockchip/    \
                                           samsung/     \
index 7f9b4de772eedfb9f28448511dccfd0a462b658a..c5c8d70bc8533e6d1f863a2e696ecb91bf0b2fba 100644 (file)
@@ -489,6 +489,53 @@ int phy_calibrate(struct phy *phy)
 }
 EXPORT_SYMBOL_GPL(phy_calibrate);
 
+/**
+ * phy_notify_connect() - phy connect notification
+ * @phy: the phy returned by phy_get()
+ * @port: the port index for connect
+ *
+ * If the phy needs to get connection status, the callback can be used.
+ * Returns: %0 if successful, a negative error code otherwise
+ */
+int phy_notify_connect(struct phy *phy, int port)
+{
+       int ret;
+
+       if (!phy || !phy->ops->connect)
+               return 0;
+
+       mutex_lock(&phy->mutex);
+       ret = phy->ops->connect(phy, port);
+       mutex_unlock(&phy->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_notify_connect);
+
+/**
+ * phy_notify_disconnect() - phy disconnect notification
+ * @phy: the phy returned by phy_get()
+ * @port: the port index for disconnect
+ *
+ * If the phy needs to get connection status, the callback can be used.
+ *
+ * Returns: %0 if successful, a negative error code otherwise
+ */
+int phy_notify_disconnect(struct phy *phy, int port)
+{
+       int ret;
+
+       if (!phy || !phy->ops->disconnect)
+               return 0;
+
+       mutex_lock(&phy->mutex);
+       ret = phy->ops->disconnect(phy, port);
+       mutex_unlock(&phy->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_notify_disconnect);
+
 /**
  * phy_configure() - Changes the phy parameters
  * @phy: the phy returned by phy_get()
diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig
new file mode 100644 (file)
index 0000000..75ac7e7
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Phy drivers for Realtek platforms
+#
+
+if ARCH_REALTEK || COMPILE_TEST
+
+config PHY_RTK_RTD_USB2PHY
+       tristate "Realtek RTD USB2 PHY Transceiver Driver"
+       depends on USB_SUPPORT
+       select GENERIC_PHY
+       select USB_PHY
+       select USB_COMMON
+       help
+         Enable this to support Realtek SoC USB2 phy transceiver.
+         The DHC (digital home center) RTD series SoCs used the Synopsys
+         DWC3 USB IP. This driver will do the PHY initialization
+         of the parameters.
+
+config PHY_RTK_RTD_USB3PHY
+       tristate "Realtek RTD USB3 PHY Transceiver Driver"
+       depends on USB_SUPPORT
+       select GENERIC_PHY
+       select USB_PHY
+       select USB_COMMON
+       help
+         Enable this to support Realtek SoC USB3 phy transceiver.
+         The DHC (digital home center) RTD series SoCs used the Synopsys
+         DWC3 USB IP. This driver will do the PHY initialization
+         of the parameters.
+
+endif # ARCH_REALTEK || COMPILE_TEST
diff --git a/drivers/phy/realtek/Makefile b/drivers/phy/realtek/Makefile
new file mode 100644 (file)
index 0000000..ed7b47f
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_PHY_RTK_RTD_USB2PHY)      += phy-rtk-usb2.o
+obj-$(CONFIG_PHY_RTK_RTD_USB3PHY)      += phy-rtk-usb3.o
diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c
new file mode 100644 (file)
index 0000000..e3ad7ce
--- /dev/null
@@ -0,0 +1,1312 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  phy-rtk-usb2.c RTK usb2.0 PHY driver
+ *
+ * Copyright (C) 2023 Realtek Semiconductor Corporation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/regmap.h>
+#include <linux/sys_soc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phy/phy.h>
+#include <linux/usb.h>
+
+/* GUSB2PHYACCn register */
+#define PHY_NEW_REG_REQ BIT(25)
+#define PHY_VSTS_BUSY   BIT(23)
+#define PHY_VCTRL_SHIFT 8
+#define PHY_REG_DATA_MASK 0xff
+
+#define GET_LOW_NIBBLE(addr) ((addr) & 0x0f)
+#define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4)
+
+#define EFUS_USB_DC_CAL_RATE 2
+#define EFUS_USB_DC_CAL_MAX 7
+
+#define EFUS_USB_DC_DIS_RATE 1
+#define EFUS_USB_DC_DIS_MAX 7
+
+#define MAX_PHY_DATA_SIZE 20
+#define OFFEST_PHY_READ 0x20
+
+#define MAX_USB_PHY_NUM 4
+#define MAX_USB_PHY_PAGE0_DATA_SIZE 16
+#define MAX_USB_PHY_PAGE1_DATA_SIZE 16
+#define MAX_USB_PHY_PAGE2_DATA_SIZE 8
+
+#define SET_PAGE_OFFSET 0xf4
+#define SET_PAGE_0 0x9b
+#define SET_PAGE_1 0xbb
+#define SET_PAGE_2 0xdb
+
+#define PAGE_START 0xe0
+#define PAGE0_0XE4 0xe4
+#define PAGE0_0XE6 0xe6
+#define PAGE0_0XE7 0xe7
+#define PAGE1_0XE0 0xe0
+#define PAGE1_0XE2 0xe2
+
+#define SENSITIVITY_CTRL (BIT(4) | BIT(5) | BIT(6))
+#define ENABLE_AUTO_SENSITIVITY_CALIBRATION BIT(2)
+#define DEFAULT_DC_DRIVING_VALUE (0x8)
+#define DEFAULT_DC_DISCONNECTION_VALUE (0x6)
+#define HS_CLK_SELECT BIT(6)
+
+struct phy_reg {
+       void __iomem *reg_wrap_vstatus;
+       void __iomem *reg_gusb2phyacc0;
+       int vstatus_index;
+};
+
+struct phy_data {
+       u8 addr;
+       u8 data;
+};
+
+struct phy_cfg {
+       int page0_size;
+       struct phy_data page0[MAX_USB_PHY_PAGE0_DATA_SIZE];
+       int page1_size;
+       struct phy_data page1[MAX_USB_PHY_PAGE1_DATA_SIZE];
+       int page2_size;
+       struct phy_data page2[MAX_USB_PHY_PAGE2_DATA_SIZE];
+
+       int num_phy;
+
+       bool check_efuse;
+       int check_efuse_version;
+#define CHECK_EFUSE_V1 1
+#define CHECK_EFUSE_V2 2
+       int efuse_dc_driving_rate;
+       int efuse_dc_disconnect_rate;
+       int dc_driving_mask;
+       int dc_disconnect_mask;
+       bool usb_dc_disconnect_at_page0;
+       int driving_updated_for_dev_dis;
+
+       bool do_toggle;
+       bool do_toggle_driving;
+       bool use_default_parameter;
+       bool is_double_sensitivity_mode;
+};
+
+struct phy_parameter {
+       struct phy_reg phy_reg;
+
+       /* Get from efuse */
+       s8 efuse_usb_dc_cal;
+       s8 efuse_usb_dc_dis;
+
+       /* Get from dts */
+       bool inverse_hstx_sync_clock;
+       u32 driving_level;
+       s32 driving_level_compensate;
+       s32 disconnection_compensate;
+};
+
+struct rtk_phy {
+       struct device *dev;
+
+       struct phy_cfg *phy_cfg;
+       int num_phy;
+       struct phy_parameter *phy_parameter;
+
+       struct dentry *debug_dir;
+};
+
+/* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */
+static inline int page_addr_to_array_index(u8 addr)
+{
+       return (int)((((addr) - PAGE_START) & 0x7) +
+               ((((addr) - PAGE_START) & 0x10) >> 1));
+}
+
+static inline u8 array_index_to_page_addr(int index)
+{
+       return ((((index) + PAGE_START) & 0x7) +
+               ((((index) & 0x8) << 1) + PAGE_START));
+}
+
+#define PHY_IO_TIMEOUT_USEC            (50000)
+#define PHY_IO_DELAY_US                        (100)
+
+static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+{
+       int ret;
+       unsigned int val;
+
+       ret = read_poll_timeout(readl, val, ((val & mask) == result),
+                               PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
+       if (ret) {
+               pr_err("%s can't program USB phy\n", __func__);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static char rtk_phy_read(struct phy_reg *phy_reg, char addr)
+{
+       void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0;
+       unsigned int val;
+       int ret = 0;
+
+       addr -= OFFEST_PHY_READ;
+
+       /* polling until VBusy == 0 */
+       ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+       if (ret)
+               return (char)ret;
+
+       /* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */
+       val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+       writel(val, reg_gusb2phyacc0);
+       ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+       if (ret)
+               return (char)ret;
+
+       /* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */
+       val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+       writel(val, reg_gusb2phyacc0);
+       ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+       if (ret)
+               return (char)ret;
+
+       val = readl(reg_gusb2phyacc0);
+
+       return (char)(val & PHY_REG_DATA_MASK);
+}
+
+static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data)
+{
+       unsigned int val;
+       void __iomem *reg_wrap_vstatus = phy_reg->reg_wrap_vstatus;
+       void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0;
+       int shift_bits = phy_reg->vstatus_index * 8;
+       int ret = 0;
+
+       /* write data to VStatusOut2 (data output to phy) */
+       writel((u32)data << shift_bits, reg_wrap_vstatus);
+
+       ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+       if (ret)
+               return ret;
+
+       /* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */
+       val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+
+       writel(val, reg_gusb2phyacc0);
+       ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+       if (ret)
+               return ret;
+
+       /* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */
+       val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+
+       writel(val, reg_gusb2phyacc0);
+       ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int rtk_phy_set_page(struct phy_reg *phy_reg, int page)
+{
+       switch (page) {
+       case 0:
+               return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_0);
+       case 1:
+               return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_1);
+       case 2:
+               return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_2);
+       default:
+               pr_err("%s error page=%d\n", __func__, page);
+       }
+
+       return -EINVAL;
+}
+
+static u8 __updated_dc_disconnect_level_page0_0xe4(struct phy_cfg *phy_cfg,
+                                                  struct phy_parameter *phy_parameter, u8 data)
+{
+       u8 ret;
+       s32 val;
+       s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+       int offset = 4;
+
+       val = (s32)((data >> offset) & dc_disconnect_mask)
+                    + phy_parameter->efuse_usb_dc_dis
+                    + phy_parameter->disconnection_compensate;
+
+       if (val > dc_disconnect_mask)
+               val = dc_disconnect_mask;
+       else if (val < 0)
+               val = 0;
+
+       ret = (data & (~(dc_disconnect_mask << offset))) |
+                   (val & dc_disconnect_mask) << offset;
+
+       return ret;
+}
+
+/* updated disconnect level at page0 */
+static void update_dc_disconnect_level_at_page0(struct rtk_phy *rtk_phy,
+                                               struct phy_parameter *phy_parameter, bool update)
+{
+       struct phy_cfg *phy_cfg;
+       struct phy_reg *phy_reg;
+       struct phy_data *phy_data_page;
+       struct phy_data *phy_data;
+       u8 addr, data;
+       int offset = 4;
+       s32 dc_disconnect_mask;
+       int i;
+
+       phy_cfg = rtk_phy->phy_cfg;
+       phy_reg = &phy_parameter->phy_reg;
+
+       /* Set page 0 */
+       phy_data_page = phy_cfg->page0;
+       rtk_phy_set_page(phy_reg, 0);
+
+       i = page_addr_to_array_index(PAGE0_0XE4);
+       phy_data = phy_data_page + i;
+       if (!phy_data->addr) {
+               phy_data->addr = PAGE0_0XE4;
+               phy_data->data = rtk_phy_read(phy_reg, PAGE0_0XE4);
+       }
+
+       addr = phy_data->addr;
+       data = phy_data->data;
+       dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+
+       if (update)
+               data = __updated_dc_disconnect_level_page0_0xe4(phy_cfg, phy_parameter, data);
+       else
+               data = (data & ~(dc_disconnect_mask << offset)) |
+                       (DEFAULT_DC_DISCONNECTION_VALUE << offset);
+
+       if (rtk_phy_write(phy_reg, addr, data))
+               dev_err(rtk_phy->dev,
+                       "%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
+                       __func__, addr, data);
+}
+
+static u8 __updated_dc_disconnect_level_page1_0xe2(struct phy_cfg *phy_cfg,
+                                                  struct phy_parameter *phy_parameter, u8 data)
+{
+       u8 ret;
+       s32 val;
+       s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+
+       if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+               val = (s32)(data & dc_disconnect_mask)
+                           + phy_parameter->efuse_usb_dc_dis
+                           + phy_parameter->disconnection_compensate;
+       } else { /* for CHECK_EFUSE_V2 or no efuse */
+               if (phy_parameter->efuse_usb_dc_dis)
+                       val = (s32)(phy_parameter->efuse_usb_dc_dis +
+                                   phy_parameter->disconnection_compensate);
+               else
+                       val = (s32)((data & dc_disconnect_mask) +
+                                   phy_parameter->disconnection_compensate);
+       }
+
+       if (val > dc_disconnect_mask)
+               val = dc_disconnect_mask;
+       else if (val < 0)
+               val = 0;
+
+       ret = (data & (~dc_disconnect_mask)) | (val & dc_disconnect_mask);
+
+       return ret;
+}
+
+/* updated disconnect level at page1 */
+static void update_dc_disconnect_level_at_page1(struct rtk_phy *rtk_phy,
+                                               struct phy_parameter *phy_parameter, bool update)
+{
+       struct phy_cfg *phy_cfg;
+       struct phy_data *phy_data_page;
+       struct phy_data *phy_data;
+       struct phy_reg *phy_reg;
+       u8 addr, data;
+       s32 dc_disconnect_mask;
+       int i;
+
+       phy_cfg = rtk_phy->phy_cfg;
+       phy_reg = &phy_parameter->phy_reg;
+
+       /* Set page 1 */
+       phy_data_page = phy_cfg->page1;
+       rtk_phy_set_page(phy_reg, 1);
+
+       i = page_addr_to_array_index(PAGE1_0XE2);
+       phy_data = phy_data_page + i;
+       if (!phy_data->addr) {
+               phy_data->addr = PAGE1_0XE2;
+               phy_data->data = rtk_phy_read(phy_reg, PAGE1_0XE2);
+       }
+
+       addr = phy_data->addr;
+       data = phy_data->data;
+       dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+
+       if (update)
+               data = __updated_dc_disconnect_level_page1_0xe2(phy_cfg, phy_parameter, data);
+       else
+               data = (data & ~dc_disconnect_mask) | DEFAULT_DC_DISCONNECTION_VALUE;
+
+       if (rtk_phy_write(phy_reg, addr, data))
+               dev_err(rtk_phy->dev,
+                       "%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
+                       __func__, addr, data);
+}
+
+static void update_dc_disconnect_level(struct rtk_phy *rtk_phy,
+                                      struct phy_parameter *phy_parameter, bool update)
+{
+       struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+
+       if (phy_cfg->usb_dc_disconnect_at_page0)
+               update_dc_disconnect_level_at_page0(rtk_phy, phy_parameter, update);
+       else
+               update_dc_disconnect_level_at_page1(rtk_phy, phy_parameter, update);
+}
+
+static u8 __update_dc_driving_page0_0xe4(struct phy_cfg *phy_cfg,
+                                        struct phy_parameter *phy_parameter, u8 data)
+{
+       s32 driving_level_compensate = phy_parameter->driving_level_compensate;
+       s32 dc_driving_mask = phy_cfg->dc_driving_mask;
+       s32 val;
+       u8 ret;
+
+       if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+               val = (s32)(data & dc_driving_mask) + driving_level_compensate
+                           + phy_parameter->efuse_usb_dc_cal;
+       } else { /* for CHECK_EFUSE_V2 or no efuse */
+               if (phy_parameter->efuse_usb_dc_cal)
+                       val = (s32)((phy_parameter->efuse_usb_dc_cal & dc_driving_mask)
+                                   + driving_level_compensate);
+               else
+                       val = (s32)(data & dc_driving_mask);
+       }
+
+       if (val > dc_driving_mask)
+               val = dc_driving_mask;
+       else if (val < 0)
+               val = 0;
+
+       ret = (data & (~dc_driving_mask)) | (val & dc_driving_mask);
+
+       return ret;
+}
+
+static void update_dc_driving_level(struct rtk_phy *rtk_phy,
+                                   struct phy_parameter *phy_parameter)
+{
+       struct phy_cfg *phy_cfg;
+       struct phy_reg *phy_reg;
+
+       phy_reg = &phy_parameter->phy_reg;
+       phy_cfg = rtk_phy->phy_cfg;
+       if (!phy_cfg->page0[4].addr) {
+               rtk_phy_set_page(phy_reg, 0);
+               phy_cfg->page0[4].addr = PAGE0_0XE4;
+               phy_cfg->page0[4].data = rtk_phy_read(phy_reg, PAGE0_0XE4);
+       }
+
+       if (phy_parameter->driving_level != DEFAULT_DC_DRIVING_VALUE) {
+               u32 dc_driving_mask;
+               u8 driving_level;
+               u8 data;
+
+               data = phy_cfg->page0[4].data;
+               dc_driving_mask = phy_cfg->dc_driving_mask;
+               driving_level = data & dc_driving_mask;
+
+               dev_dbg(rtk_phy->dev, "%s driving_level=%d => dts driving_level=%d\n",
+                       __func__, driving_level, phy_parameter->driving_level);
+
+               phy_cfg->page0[4].data = (data & (~dc_driving_mask)) |
+                           (phy_parameter->driving_level & dc_driving_mask);
+       }
+
+       phy_cfg->page0[4].data = __update_dc_driving_page0_0xe4(phy_cfg,
+                                                               phy_parameter,
+                                                               phy_cfg->page0[4].data);
+}
+
+static void update_hs_clk_select(struct rtk_phy *rtk_phy,
+                                struct phy_parameter *phy_parameter)
+{
+       struct phy_cfg *phy_cfg;
+       struct phy_reg *phy_reg;
+
+       phy_cfg = rtk_phy->phy_cfg;
+       phy_reg = &phy_parameter->phy_reg;
+
+       if (phy_parameter->inverse_hstx_sync_clock) {
+               if (!phy_cfg->page0[6].addr) {
+                       rtk_phy_set_page(phy_reg, 0);
+                       phy_cfg->page0[6].addr = PAGE0_0XE6;
+                       phy_cfg->page0[6].data = rtk_phy_read(phy_reg, PAGE0_0XE6);
+               }
+
+               phy_cfg->page0[6].data = phy_cfg->page0[6].data | HS_CLK_SELECT;
+       }
+}
+
+static void do_rtk_phy_toggle(struct rtk_phy *rtk_phy,
+                             int index, bool connect)
+{
+       struct phy_parameter *phy_parameter;
+       struct phy_cfg *phy_cfg;
+       struct phy_reg *phy_reg;
+       struct phy_data *phy_data_page;
+       u8 addr, data;
+       int i;
+
+       phy_cfg = rtk_phy->phy_cfg;
+       phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+       phy_reg = &phy_parameter->phy_reg;
+
+       if (!phy_cfg->do_toggle)
+               goto out;
+
+       if (phy_cfg->is_double_sensitivity_mode)
+               goto do_toggle_driving;
+
+       /* Set page 0 */
+       rtk_phy_set_page(phy_reg, 0);
+
+       addr = PAGE0_0XE7;
+       data = rtk_phy_read(phy_reg, addr);
+
+       if (connect)
+               rtk_phy_write(phy_reg, addr, data & (~SENSITIVITY_CTRL));
+       else
+               rtk_phy_write(phy_reg, addr, data | (SENSITIVITY_CTRL));
+
+do_toggle_driving:
+
+       if (!phy_cfg->do_toggle_driving)
+               goto do_toggle;
+
+       /* Page 0 addr 0xE4 driving capability */
+
+       /* Set page 0 */
+       phy_data_page = phy_cfg->page0;
+       rtk_phy_set_page(phy_reg, 0);
+
+       i = page_addr_to_array_index(PAGE0_0XE4);
+       addr = phy_data_page[i].addr;
+       data = phy_data_page[i].data;
+
+       if (connect) {
+               rtk_phy_write(phy_reg, addr, data);
+       } else {
+               u8 value;
+               s32 tmp;
+               s32 driving_updated =
+                           phy_cfg->driving_updated_for_dev_dis;
+               s32 dc_driving_mask = phy_cfg->dc_driving_mask;
+
+               tmp = (s32)(data & dc_driving_mask) + driving_updated;
+
+               if (tmp > dc_driving_mask)
+                       tmp = dc_driving_mask;
+               else if (tmp < 0)
+                       tmp = 0;
+
+               value = (data & (~dc_driving_mask)) | (tmp & dc_driving_mask);
+
+               rtk_phy_write(phy_reg, addr, value);
+       }
+
+do_toggle:
+       /* restore dc disconnect level before toggle */
+       update_dc_disconnect_level(rtk_phy, phy_parameter, false);
+
+       /* Set page 1 */
+       rtk_phy_set_page(phy_reg, 1);
+
+       addr = PAGE1_0XE0;
+       data = rtk_phy_read(phy_reg, addr);
+
+       rtk_phy_write(phy_reg, addr, data &
+                     (~ENABLE_AUTO_SENSITIVITY_CALIBRATION));
+       mdelay(1);
+       rtk_phy_write(phy_reg, addr, data |
+                     (ENABLE_AUTO_SENSITIVITY_CALIBRATION));
+
+       /* update dc disconnect level after toggle */
+       update_dc_disconnect_level(rtk_phy, phy_parameter, true);
+
+out:
+       return;
+}
+
+static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
+{
+       struct phy_parameter *phy_parameter;
+       struct phy_cfg *phy_cfg;
+       struct phy_data *phy_data_page;
+       struct phy_reg *phy_reg;
+       int i;
+
+       phy_cfg = rtk_phy->phy_cfg;
+       phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+       phy_reg = &phy_parameter->phy_reg;
+
+       if (phy_cfg->use_default_parameter) {
+               dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n",
+                       __func__, index);
+               goto do_toggle;
+       }
+
+       /* Set page 0 */
+       phy_data_page = phy_cfg->page0;
+       rtk_phy_set_page(phy_reg, 0);
+
+       for (i = 0; i < phy_cfg->page0_size; i++) {
+               struct phy_data *phy_data = phy_data_page + i;
+               u8 addr = phy_data->addr;
+               u8 data = phy_data->data;
+
+               if (!addr)
+                       continue;
+
+               if (rtk_phy_write(phy_reg, addr, data)) {
+                       dev_err(rtk_phy->dev,
+                               "%s: Error to set page0 parameter addr=0x%x value=0x%x\n",
+                               __func__, addr, data);
+                       return -EINVAL;
+               }
+       }
+
+       /* Set page 1 */
+       phy_data_page = phy_cfg->page1;
+       rtk_phy_set_page(phy_reg, 1);
+
+       for (i = 0; i < phy_cfg->page1_size; i++) {
+               struct phy_data *phy_data = phy_data_page + i;
+               u8 addr = phy_data->addr;
+               u8 data = phy_data->data;
+
+               if (!addr)
+                       continue;
+
+               if (rtk_phy_write(phy_reg, addr, data)) {
+                       dev_err(rtk_phy->dev,
+                               "%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
+                               __func__, addr, data);
+                       return -EINVAL;
+               }
+       }
+
+       if (phy_cfg->page2_size == 0)
+               goto do_toggle;
+
+       /* Set page 2 */
+       phy_data_page = phy_cfg->page2;
+       rtk_phy_set_page(phy_reg, 2);
+
+       for (i = 0; i < phy_cfg->page2_size; i++) {
+               struct phy_data *phy_data = phy_data_page + i;
+               u8 addr = phy_data->addr;
+               u8 data = phy_data->data;
+
+               if (!addr)
+                       continue;
+
+               if (rtk_phy_write(phy_reg, addr, data)) {
+                       dev_err(rtk_phy->dev,
+                               "%s: Error to set page2 parameter addr=0x%x value=0x%x\n",
+                               __func__, addr, data);
+                       return -EINVAL;
+               }
+       }
+
+do_toggle:
+       do_rtk_phy_toggle(rtk_phy, index, false);
+
+       return 0;
+}
+
+static int rtk_phy_init(struct phy *phy)
+{
+       struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+       unsigned long phy_init_time = jiffies;
+       int i, ret = 0;
+
+       if (!rtk_phy)
+               return -EINVAL;
+
+       for (i = 0; i < rtk_phy->num_phy; i++)
+               ret = do_rtk_phy_init(rtk_phy, i);
+
+       dev_dbg(rtk_phy->dev, "Initialized RTK USB 2.0 PHY (take %dms)\n",
+               jiffies_to_msecs(jiffies - phy_init_time));
+       return ret;
+}
+
+static int rtk_phy_exit(struct phy *phy)
+{
+       return 0;
+}
+
+static void rtk_phy_toggle(struct rtk_phy *rtk_phy, bool connect, int port)
+{
+       int index = port;
+
+       if (index > rtk_phy->num_phy) {
+               dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n",
+                       __func__, index, rtk_phy->num_phy);
+               return;
+       }
+
+       do_rtk_phy_toggle(rtk_phy, index, connect);
+}
+
+static int rtk_phy_connect(struct phy *phy, int port)
+{
+       struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+
+       dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port);
+       rtk_phy_toggle(rtk_phy, true, port);
+
+       return 0;
+}
+
+static int rtk_phy_disconnect(struct phy *phy, int port)
+{
+       struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+
+       dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port);
+       rtk_phy_toggle(rtk_phy, false, port);
+
+       return 0;
+}
+
+static const struct phy_ops ops = {
+       .init           = rtk_phy_init,
+       .exit           = rtk_phy_exit,
+       .connect        = rtk_phy_connect,
+       .disconnect     = rtk_phy_disconnect,
+       .owner          = THIS_MODULE,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *create_phy_debug_root(void)
+{
+       struct dentry *phy_debug_root;
+
+       phy_debug_root = debugfs_lookup("phy", usb_debug_root);
+       if (!phy_debug_root)
+               phy_debug_root = debugfs_create_dir("phy", usb_debug_root);
+
+       return phy_debug_root;
+}
+
+static int rtk_usb2_parameter_show(struct seq_file *s, void *unused)
+{
+       struct rtk_phy *rtk_phy = s->private;
+       struct phy_cfg *phy_cfg;
+       int i, index;
+
+       phy_cfg = rtk_phy->phy_cfg;
+
+       seq_puts(s, "Property:\n");
+       seq_printf(s, "  check_efuse: %s\n",
+                  phy_cfg->check_efuse ? "Enable" : "Disable");
+       seq_printf(s, "  check_efuse_version: %d\n",
+                  phy_cfg->check_efuse_version);
+       seq_printf(s, "  efuse_dc_driving_rate: %d\n",
+                  phy_cfg->efuse_dc_driving_rate);
+       seq_printf(s, "  dc_driving_mask: 0x%x\n",
+                  phy_cfg->dc_driving_mask);
+       seq_printf(s, "  efuse_dc_disconnect_rate: %d\n",
+                  phy_cfg->efuse_dc_disconnect_rate);
+       seq_printf(s, "  dc_disconnect_mask: 0x%x\n",
+                  phy_cfg->dc_disconnect_mask);
+       seq_printf(s, "  usb_dc_disconnect_at_page0: %s\n",
+                  phy_cfg->usb_dc_disconnect_at_page0 ? "true" : "false");
+       seq_printf(s, "  do_toggle: %s\n",
+                  phy_cfg->do_toggle ? "Enable" : "Disable");
+       seq_printf(s, "  do_toggle_driving: %s\n",
+                  phy_cfg->do_toggle_driving ? "Enable" : "Disable");
+       seq_printf(s, "  driving_updated_for_dev_dis: 0x%x\n",
+                  phy_cfg->driving_updated_for_dev_dis);
+       seq_printf(s, "  use_default_parameter: %s\n",
+                  phy_cfg->use_default_parameter ? "Enable" : "Disable");
+       seq_printf(s, "  is_double_sensitivity_mode: %s\n",
+                  phy_cfg->is_double_sensitivity_mode ? "Enable" : "Disable");
+
+       for (index = 0; index < rtk_phy->num_phy; index++) {
+               struct phy_parameter *phy_parameter;
+               struct phy_reg *phy_reg;
+               struct phy_data *phy_data_page;
+
+               phy_parameter =  &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+               phy_reg = &phy_parameter->phy_reg;
+
+               seq_printf(s, "PHY %d:\n", index);
+
+               seq_puts(s, "Page 0:\n");
+               /* Set page 0 */
+               phy_data_page = phy_cfg->page0;
+               rtk_phy_set_page(phy_reg, 0);
+
+               for (i = 0; i < phy_cfg->page0_size; i++) {
+                       struct phy_data *phy_data = phy_data_page + i;
+                       u8 addr = array_index_to_page_addr(i);
+                       u8 data = phy_data->data;
+                       u8 value = rtk_phy_read(phy_reg, addr);
+
+                       if (phy_data->addr)
+                               seq_printf(s, "  Page 0: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
+                                          addr, data, value);
+                       else
+                               seq_printf(s, "  Page 0: addr=0x%x data=none ==> read value=0x%02x\n",
+                                          addr, value);
+               }
+
+               seq_puts(s, "Page 1:\n");
+               /* Set page 1 */
+               phy_data_page = phy_cfg->page1;
+               rtk_phy_set_page(phy_reg, 1);
+
+               for (i = 0; i < phy_cfg->page1_size; i++) {
+                       struct phy_data *phy_data = phy_data_page + i;
+                       u8 addr = array_index_to_page_addr(i);
+                       u8 data = phy_data->data;
+                       u8 value = rtk_phy_read(phy_reg, addr);
+
+                       if (phy_data->addr)
+                               seq_printf(s, "  Page 1: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
+                                          addr, data, value);
+                       else
+                               seq_printf(s, "  Page 1: addr=0x%x data=none ==> read value=0x%02x\n",
+                                          addr, value);
+               }
+
+               if (phy_cfg->page2_size == 0)
+                       goto out;
+
+               seq_puts(s, "Page 2:\n");
+               /* Set page 2 */
+               phy_data_page = phy_cfg->page2;
+               rtk_phy_set_page(phy_reg, 2);
+
+               for (i = 0; i < phy_cfg->page2_size; i++) {
+                       struct phy_data *phy_data = phy_data_page + i;
+                       u8 addr = array_index_to_page_addr(i);
+                       u8 data = phy_data->data;
+                       u8 value = rtk_phy_read(phy_reg, addr);
+
+                       if (phy_data->addr)
+                               seq_printf(s, "  Page 2: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
+                                          addr, data, value);
+                       else
+                               seq_printf(s, "  Page 2: addr=0x%x data=none ==> read value=0x%02x\n",
+                                          addr, value);
+               }
+
+out:
+               seq_puts(s, "PHY Property:\n");
+               seq_printf(s, "  efuse_usb_dc_cal: %d\n",
+                          (int)phy_parameter->efuse_usb_dc_cal);
+               seq_printf(s, "  efuse_usb_dc_dis: %d\n",
+                          (int)phy_parameter->efuse_usb_dc_dis);
+               seq_printf(s, "  inverse_hstx_sync_clock: %s\n",
+                          phy_parameter->inverse_hstx_sync_clock ? "Enable" : "Disable");
+               seq_printf(s, "  driving_level: %d\n",
+                          phy_parameter->driving_level);
+               seq_printf(s, "  driving_level_compensate: %d\n",
+                          phy_parameter->driving_level_compensate);
+               seq_printf(s, "  disconnection_compensate: %d\n",
+                          phy_parameter->disconnection_compensate);
+       }
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(rtk_usb2_parameter);
+
+static inline void create_debug_files(struct rtk_phy *rtk_phy)
+{
+       struct dentry *phy_debug_root = NULL;
+
+       phy_debug_root = create_phy_debug_root();
+       if (!phy_debug_root)
+               return;
+
+       rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev),
+                                               phy_debug_root);
+
+       debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
+                           &rtk_usb2_parameter_fops);
+}
+
+static inline void remove_debug_files(struct rtk_phy *rtk_phy)
+{
+       debugfs_remove_recursive(rtk_phy->debug_dir);
+}
+#else
+static inline void create_debug_files(struct rtk_phy *rtk_phy) { }
+static inline void remove_debug_files(struct rtk_phy *rtk_phy) { }
+#endif /* CONFIG_DEBUG_FS */
+
+static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
+                                struct phy_parameter *phy_parameter, int index)
+{
+       struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+       u8 value = 0;
+       struct nvmem_cell *cell;
+       struct soc_device_attribute rtk_soc_groot[] = {
+                   { .family = "Realtek Groot",},
+                   { /* empty */ } };
+
+       if (!phy_cfg->check_efuse)
+               goto out;
+
+       /* Read efuse for usb dc cal */
+       cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-cal");
+       if (IS_ERR(cell)) {
+               dev_dbg(rtk_phy->dev, "%s no usb-dc-cal: %ld\n",
+                       __func__, PTR_ERR(cell));
+       } else {
+               unsigned char *buf;
+               size_t buf_size;
+
+               buf = nvmem_cell_read(cell, &buf_size);
+               if (!IS_ERR(buf)) {
+                       value = buf[0] & phy_cfg->dc_driving_mask;
+                       kfree(buf);
+               }
+               nvmem_cell_put(cell);
+       }
+
+       if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+               int rate = phy_cfg->efuse_dc_driving_rate;
+
+               if (value <= EFUS_USB_DC_CAL_MAX)
+                       phy_parameter->efuse_usb_dc_cal = (int8_t)(value * rate);
+               else
+                       phy_parameter->efuse_usb_dc_cal = -(int8_t)
+                                   ((EFUS_USB_DC_CAL_MAX & value) * rate);
+
+               if (soc_device_match(rtk_soc_groot)) {
+                       dev_dbg(rtk_phy->dev, "For groot IC we need a workaround to adjust efuse_usb_dc_cal\n");
+
+                       /* We don't multiple dc_cal_rate=2 for positive dc cal compensate */
+                       if (value <= EFUS_USB_DC_CAL_MAX)
+                               phy_parameter->efuse_usb_dc_cal = (int8_t)(value);
+
+                       /* We set max dc cal compensate is 0x8 if otp is 0x7 */
+                       if (value == 0x7)
+                               phy_parameter->efuse_usb_dc_cal = (int8_t)(value + 1);
+               }
+       } else { /* for CHECK_EFUSE_V2 */
+               phy_parameter->efuse_usb_dc_cal = value & phy_cfg->dc_driving_mask;
+       }
+
+       /* Read efuse for usb dc disconnect level */
+       value = 0;
+       cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-dis");
+       if (IS_ERR(cell)) {
+               dev_dbg(rtk_phy->dev, "%s no usb-dc-dis: %ld\n",
+                       __func__, PTR_ERR(cell));
+       } else {
+               unsigned char *buf;
+               size_t buf_size;
+
+               buf = nvmem_cell_read(cell, &buf_size);
+               if (!IS_ERR(buf)) {
+                       value = buf[0] & phy_cfg->dc_disconnect_mask;
+                       kfree(buf);
+               }
+               nvmem_cell_put(cell);
+       }
+
+       if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+               int rate = phy_cfg->efuse_dc_disconnect_rate;
+
+               if (value <= EFUS_USB_DC_DIS_MAX)
+                       phy_parameter->efuse_usb_dc_dis = (int8_t)(value * rate);
+               else
+                       phy_parameter->efuse_usb_dc_dis = -(int8_t)
+                                   ((EFUS_USB_DC_DIS_MAX & value) * rate);
+       } else { /* for CHECK_EFUSE_V2 */
+               phy_parameter->efuse_usb_dc_dis = value & phy_cfg->dc_disconnect_mask;
+       }
+
+out:
+       return 0;
+}
+
+static int parse_phy_data(struct rtk_phy *rtk_phy)
+{
+       struct device *dev = rtk_phy->dev;
+       struct device_node *np = dev->of_node;
+       struct phy_parameter *phy_parameter;
+       int ret = 0;
+       int index;
+
+       rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) *
+                                               rtk_phy->num_phy, GFP_KERNEL);
+       if (!rtk_phy->phy_parameter)
+               return -ENOMEM;
+
+       for (index = 0; index < rtk_phy->num_phy; index++) {
+               phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+
+               phy_parameter->phy_reg.reg_wrap_vstatus = of_iomap(np, 0);
+               phy_parameter->phy_reg.reg_gusb2phyacc0 = of_iomap(np, 1) + index;
+               phy_parameter->phy_reg.vstatus_index = index;
+
+               if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock"))
+                       phy_parameter->inverse_hstx_sync_clock = true;
+               else
+                       phy_parameter->inverse_hstx_sync_clock = false;
+
+               if (of_property_read_u32_index(np, "realtek,driving-level",
+                                              index, &phy_parameter->driving_level))
+                       phy_parameter->driving_level = DEFAULT_DC_DRIVING_VALUE;
+
+               if (of_property_read_u32_index(np, "realtek,driving-level-compensate",
+                                              index, &phy_parameter->driving_level_compensate))
+                       phy_parameter->driving_level_compensate = 0;
+
+               if (of_property_read_u32_index(np, "realtek,disconnection-compensate",
+                                              index, &phy_parameter->disconnection_compensate))
+                       phy_parameter->disconnection_compensate = 0;
+
+               get_phy_data_by_efuse(rtk_phy, phy_parameter, index);
+
+               update_dc_driving_level(rtk_phy, phy_parameter);
+
+               update_hs_clk_select(rtk_phy, phy_parameter);
+       }
+
+       return ret;
+}
+
+static int rtk_usb2phy_probe(struct platform_device *pdev)
+{
+       struct rtk_phy *rtk_phy;
+       struct device *dev = &pdev->dev;
+       struct phy *generic_phy;
+       struct phy_provider *phy_provider;
+       const struct phy_cfg *phy_cfg;
+       int ret = 0;
+
+       phy_cfg = of_device_get_match_data(dev);
+       if (!phy_cfg) {
+               dev_err(dev, "phy config are not assigned!\n");
+               return -EINVAL;
+       }
+
+       rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL);
+       if (!rtk_phy)
+               return -ENOMEM;
+
+       rtk_phy->dev                    = &pdev->dev;
+       rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
+
+       memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
+
+       rtk_phy->num_phy = phy_cfg->num_phy;
+
+       ret = parse_phy_data(rtk_phy);
+       if (ret)
+               goto err;
+
+       platform_set_drvdata(pdev, rtk_phy);
+
+       generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops);
+       if (IS_ERR(generic_phy))
+               return PTR_ERR(generic_phy);
+
+       phy_set_drvdata(generic_phy, rtk_phy);
+
+       phy_provider = devm_of_phy_provider_register(rtk_phy->dev,
+                                                    of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
+       create_debug_files(rtk_phy);
+
+err:
+       return ret;
+}
+
+static void rtk_usb2phy_remove(struct platform_device *pdev)
+{
+       struct rtk_phy *rtk_phy = platform_get_drvdata(pdev);
+
+       remove_debug_files(rtk_phy);
+}
+
+static const struct phy_cfg rtd1295_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [0] = {0xe0, 0x90},
+                  [3] = {0xe3, 0x3a},
+                  [4] = {0xe4, 0x68},
+                  [6] = {0xe6, 0x91},
+                 [13] = {0xf5, 0x81},
+                 [15] = {0xf7, 0x02}, },
+       .page1_size = 8,
+       .page1 = { /* default parameter */ },
+       .page2_size = 0,
+       .page2 = { /* no parameter */ },
+       .num_phy = 1,
+       .check_efuse = false,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = 1,
+       .dc_driving_mask = 0xf,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = true,
+       .do_toggle = true,
+       .do_toggle_driving = false,
+       .driving_updated_for_dev_dis = 0xf,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = false,
+};
+
+static const struct phy_cfg rtd1395_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [4] = {0xe4, 0xac},
+                 [13] = {0xf5, 0x00},
+                 [15] = {0xf7, 0x02}, },
+       .page1_size = 8,
+       .page1 = { /* default parameter */ },
+       .page2_size = 0,
+       .page2 = { /* no parameter */ },
+       .num_phy = 1,
+       .check_efuse = false,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = 1,
+       .dc_driving_mask = 0xf,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = true,
+       .do_toggle = true,
+       .do_toggle_driving = false,
+       .driving_updated_for_dev_dis = 0xf,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = false,
+};
+
+static const struct phy_cfg rtd1395_phy_cfg_2port = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [4] = {0xe4, 0xac},
+                 [13] = {0xf5, 0x00},
+                 [15] = {0xf7, 0x02}, },
+       .page1_size = 8,
+       .page1 = { /* default parameter */ },
+       .page2_size = 0,
+       .page2 = { /* no parameter */ },
+       .num_phy = 2,
+       .check_efuse = false,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = 1,
+       .dc_driving_mask = 0xf,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = true,
+       .do_toggle = true,
+       .do_toggle_driving = false,
+       .driving_updated_for_dev_dis = 0xf,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = false,
+};
+
+static const struct phy_cfg rtd1619_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [4] = {0xe4, 0x68}, },
+       .page1_size = 8,
+       .page1 = { /* default parameter */ },
+       .page2_size = 0,
+       .page2 = { /* no parameter */ },
+       .num_phy = 1,
+       .check_efuse = true,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = 1,
+       .dc_driving_mask = 0xf,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = true,
+       .do_toggle = true,
+       .do_toggle_driving = false,
+       .driving_updated_for_dev_dis = 0xf,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = false,
+};
+
+static const struct phy_cfg rtd1319_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [0] = {0xe0, 0x18},
+                  [4] = {0xe4, 0x6a},
+                  [7] = {0xe7, 0x71},
+                 [13] = {0xf5, 0x15},
+                 [15] = {0xf7, 0x32}, },
+       .page1_size = 8,
+       .page1 = { [3] = {0xe3, 0x44}, },
+       .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+       .page2 = { [0] = {0xe0, 0x01}, },
+       .num_phy = 1,
+       .check_efuse = true,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = 1,
+       .dc_driving_mask = 0xf,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = true,
+       .do_toggle = true,
+       .do_toggle_driving = true,
+       .driving_updated_for_dev_dis = 0xf,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = true,
+};
+
+static const struct phy_cfg rtd1312c_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [0] = {0xe0, 0x14},
+                  [4] = {0xe4, 0x67},
+                  [5] = {0xe5, 0x55}, },
+       .page1_size = 8,
+       .page1 = { [3] = {0xe3, 0x23},
+                  [6] = {0xe6, 0x58}, },
+       .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+       .page2 = { /* default parameter */ },
+       .num_phy = 1,
+       .check_efuse = true,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = 1,
+       .dc_driving_mask = 0xf,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = true,
+       .do_toggle = true,
+       .do_toggle_driving = true,
+       .driving_updated_for_dev_dis = 0xf,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = true,
+};
+
+static const struct phy_cfg rtd1619b_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [0] = {0xe0, 0xa3},
+                  [4] = {0xe4, 0xa8},
+                  [5] = {0xe5, 0x4f},
+                  [6] = {0xe6, 0x02}, },
+       .page1_size = 8,
+       .page1 = { [3] = {0xe3, 0x64}, },
+       .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+       .page2 = { [7] = {0xe7, 0x45}, },
+       .num_phy = 1,
+       .check_efuse = true,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+       .dc_driving_mask = 0x1f,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = false,
+       .do_toggle = true,
+       .do_toggle_driving = true,
+       .driving_updated_for_dev_dis = 0x8,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = true,
+};
+
+static const struct phy_cfg rtd1319d_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [0] = {0xe0, 0xa3},
+                  [4] = {0xe4, 0x8e},
+                  [5] = {0xe5, 0x4f},
+                  [6] = {0xe6, 0x02}, },
+       .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
+       .page1 = { [14] = {0xf5, 0x1}, },
+       .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+       .page2 = { [7] = {0xe7, 0x44}, },
+       .check_efuse = true,
+       .num_phy = 1,
+       .check_efuse_version = CHECK_EFUSE_V1,
+       .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+       .dc_driving_mask = 0x1f,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = false,
+       .do_toggle = true,
+       .do_toggle_driving = false,
+       .driving_updated_for_dev_dis = 0x8,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = true,
+};
+
+static const struct phy_cfg rtd1315e_phy_cfg = {
+       .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+       .page0 = { [0] = {0xe0, 0xa3},
+                  [4] = {0xe4, 0x8c},
+                  [5] = {0xe5, 0x4f},
+                  [6] = {0xe6, 0x02}, },
+       .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
+       .page1 = { [3] = {0xe3, 0x7f},
+                 [14] = {0xf5, 0x01}, },
+       .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+       .page2 = { [7] = {0xe7, 0x44}, },
+       .num_phy = 1,
+       .check_efuse = true,
+       .check_efuse_version = CHECK_EFUSE_V2,
+       .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+       .dc_driving_mask = 0x1f,
+       .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+       .dc_disconnect_mask = 0xf,
+       .usb_dc_disconnect_at_page0 = false,
+       .do_toggle = true,
+       .do_toggle_driving = false,
+       .driving_updated_for_dev_dis = 0x8,
+       .use_default_parameter = false,
+       .is_double_sensitivity_mode = true,
+};
+
+static const struct of_device_id usbphy_rtk_dt_match[] = {
+       { .compatible = "realtek,rtd1295-usb2phy", .data = &rtd1295_phy_cfg },
+       { .compatible = "realtek,rtd1312c-usb2phy", .data = &rtd1312c_phy_cfg },
+       { .compatible = "realtek,rtd1315e-usb2phy", .data = &rtd1315e_phy_cfg },
+       { .compatible = "realtek,rtd1319-usb2phy", .data = &rtd1319_phy_cfg },
+       { .compatible = "realtek,rtd1319d-usb2phy", .data = &rtd1319d_phy_cfg },
+       { .compatible = "realtek,rtd1395-usb2phy", .data = &rtd1395_phy_cfg },
+       { .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port },
+       { .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg },
+       { .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg },
+       {},
+};
+MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
+
+static struct platform_driver rtk_usb2phy_driver = {
+       .probe          = rtk_usb2phy_probe,
+       .remove_new     = rtk_usb2phy_remove,
+       .driver         = {
+               .name   = "rtk-usb2phy",
+               .of_match_table = usbphy_rtk_dt_match,
+       },
+};
+
+module_platform_driver(rtk_usb2phy_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
+MODULE_DESCRIPTION("Realtek usb 2.0 phy driver");
diff --git a/drivers/phy/realtek/phy-rtk-usb3.c b/drivers/phy/realtek/phy-rtk-usb3.c
new file mode 100644 (file)
index 0000000..dfcf4b9
--- /dev/null
@@ -0,0 +1,748 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  phy-rtk-usb3.c RTK usb3.0 phy driver
+ *
+ * copyright (c) 2023 realtek semiconductor corporation
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/regmap.h>
+#include <linux/sys_soc.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phy/phy.h>
+#include <linux/usb.h>
+
+#define USB_MDIO_CTRL_PHY_BUSY BIT(7)
+#define USB_MDIO_CTRL_PHY_WRITE BIT(0)
+#define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8
+#define USB_MDIO_CTRL_PHY_DATA_SHIFT 16
+
+#define MAX_USB_PHY_DATA_SIZE 0x30
+#define PHY_ADDR_0X09 0x09
+#define PHY_ADDR_0X0B 0x0b
+#define PHY_ADDR_0X0D 0x0d
+#define PHY_ADDR_0X10 0x10
+#define PHY_ADDR_0X1F 0x1f
+#define PHY_ADDR_0X20 0x20
+#define PHY_ADDR_0X21 0x21
+#define PHY_ADDR_0X30 0x30
+
+#define REG_0X09_FORCE_CALIBRATION BIT(9)
+#define REG_0X0B_RX_OFFSET_RANGE_MASK 0xc
+#define REG_0X0D_RX_DEBUG_TEST_EN BIT(6)
+#define REG_0X10_DEBUG_MODE_SETTING 0x3c0
+#define REG_0X10_DEBUG_MODE_SETTING_MASK 0x3f8
+#define REG_0X1F_RX_OFFSET_CODE_MASK 0x1e
+
+#define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4
+#define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xf
+#define AMPLITUDE_CONTROL_COARSE_MASK 0xff
+#define AMPLITUDE_CONTROL_FINE_MASK 0xffff
+#define AMPLITUDE_CONTROL_COARSE_DEFAULT 0xff
+#define AMPLITUDE_CONTROL_FINE_DEFAULT 0xffff
+
+#define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr)
+#define ARRAY_INDEX_MAP_PHY_ADDR(index) (index)
+
+struct phy_reg {
+       void __iomem *reg_mdio_ctl;
+};
+
+struct phy_data {
+       u8 addr;
+       u16 data;
+};
+
+struct phy_cfg {
+       int param_size;
+       struct phy_data param[MAX_USB_PHY_DATA_SIZE];
+
+       bool check_efuse;
+       bool do_toggle;
+       bool do_toggle_once;
+       bool use_default_parameter;
+       bool check_rx_front_end_offset;
+};
+
+struct phy_parameter {
+       struct phy_reg phy_reg;
+
+       /* Get from efuse */
+       u8 efuse_usb_u3_tx_lfps_swing_trim;
+
+       /* Get from dts */
+       u32 amplitude_control_coarse;
+       u32 amplitude_control_fine;
+};
+
+struct rtk_phy {
+       struct device *dev;
+
+       struct phy_cfg *phy_cfg;
+       int num_phy;
+       struct phy_parameter *phy_parameter;
+
+       struct dentry *debug_dir;
+};
+
+#define PHY_IO_TIMEOUT_USEC            (50000)
+#define PHY_IO_DELAY_US                        (100)
+
+static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+{
+       int ret;
+       unsigned int val;
+
+       ret = read_poll_timeout(readl, val, ((val & mask) == result),
+                               PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
+       if (ret) {
+               pr_err("%s can't program USB phy\n", __func__);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int rtk_phy3_wait_vbusy(struct phy_reg *phy_reg)
+{
+       return utmi_wait_register(phy_reg->reg_mdio_ctl, USB_MDIO_CTRL_PHY_BUSY, 0);
+}
+
+static u16 rtk_phy_read(struct phy_reg *phy_reg, char addr)
+{
+       unsigned int tmp;
+       u32 value;
+
+       tmp = (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT);
+
+       writel(tmp, phy_reg->reg_mdio_ctl);
+
+       rtk_phy3_wait_vbusy(phy_reg);
+
+       value = readl(phy_reg->reg_mdio_ctl);
+       value = value >> USB_MDIO_CTRL_PHY_DATA_SHIFT;
+
+       return (u16)value;
+}
+
+static int rtk_phy_write(struct phy_reg *phy_reg, char addr, u16 data)
+{
+       unsigned int val;
+
+       val = USB_MDIO_CTRL_PHY_WRITE |
+                   (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT) |
+                   (data << USB_MDIO_CTRL_PHY_DATA_SHIFT);
+
+       writel(val, phy_reg->reg_mdio_ctl);
+
+       rtk_phy3_wait_vbusy(phy_reg);
+
+       return 0;
+}
+
+static void do_rtk_usb3_phy_toggle(struct rtk_phy *rtk_phy, int index, bool connect)
+{
+       struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+       struct phy_reg *phy_reg;
+       struct phy_parameter *phy_parameter;
+       struct phy_data *phy_data;
+       u8 addr;
+       u16 data;
+       int i;
+
+       phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+       phy_reg = &phy_parameter->phy_reg;
+
+       if (!phy_cfg->do_toggle)
+               return;
+
+       i = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0X09);
+       phy_data = phy_cfg->param + i;
+       addr = phy_data->addr;
+       data = phy_data->data;
+
+       if (!addr && !data) {
+               addr = PHY_ADDR_0X09;
+               data = rtk_phy_read(phy_reg, addr);
+               phy_data->addr = addr;
+               phy_data->data = data;
+       }
+
+       rtk_phy_write(phy_reg, addr, data & (~REG_0X09_FORCE_CALIBRATION));
+       mdelay(1);
+       rtk_phy_write(phy_reg, addr, data | REG_0X09_FORCE_CALIBRATION);
+}
+
+static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
+{
+       struct phy_cfg *phy_cfg;
+       struct phy_reg *phy_reg;
+       struct phy_parameter *phy_parameter;
+       int i = 0;
+
+       phy_cfg = rtk_phy->phy_cfg;
+       phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+       phy_reg = &phy_parameter->phy_reg;
+
+       if (phy_cfg->use_default_parameter)
+               goto do_toggle;
+
+       for (i = 0; i < phy_cfg->param_size; i++) {
+               struct phy_data *phy_data = phy_cfg->param + i;
+               u8 addr = phy_data->addr;
+               u16 data = phy_data->data;
+
+               if (!addr && !data)
+                       continue;
+
+               rtk_phy_write(phy_reg, addr, data);
+       }
+
+do_toggle:
+       if (phy_cfg->do_toggle_once)
+               phy_cfg->do_toggle = true;
+
+       do_rtk_usb3_phy_toggle(rtk_phy, index, false);
+
+       if (phy_cfg->do_toggle_once) {
+               u16 check_value = 0;
+               int count = 10;
+               u16 value_0x0d, value_0x10;
+
+               /* Enable Debug mode by set 0x0D and 0x10 */
+               value_0x0d = rtk_phy_read(phy_reg, PHY_ADDR_0X0D);
+               value_0x10 = rtk_phy_read(phy_reg, PHY_ADDR_0X10);
+
+               rtk_phy_write(phy_reg, PHY_ADDR_0X0D,
+                             value_0x0d | REG_0X0D_RX_DEBUG_TEST_EN);
+               rtk_phy_write(phy_reg, PHY_ADDR_0X10,
+                             (value_0x10 & ~REG_0X10_DEBUG_MODE_SETTING_MASK) |
+                             REG_0X10_DEBUG_MODE_SETTING);
+
+               check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30);
+
+               while (!(check_value & BIT(15))) {
+                       check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30);
+                       mdelay(1);
+                       if (count-- < 0)
+                               break;
+               }
+
+               if (!(check_value & BIT(15)))
+                       dev_info(rtk_phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n",
+                                PHY_ADDR_0X30, check_value);
+
+               /* Disable Debug mode by set 0x0D and 0x10 to default*/
+               rtk_phy_write(phy_reg, PHY_ADDR_0X0D, value_0x0d);
+               rtk_phy_write(phy_reg, PHY_ADDR_0X10, value_0x10);
+
+               phy_cfg->do_toggle = false;
+       }
+
+       if (phy_cfg->check_rx_front_end_offset) {
+               u16 rx_offset_code, rx_offset_range;
+               u16 code_mask = REG_0X1F_RX_OFFSET_CODE_MASK;
+               u16 range_mask = REG_0X0B_RX_OFFSET_RANGE_MASK;
+               bool do_update = false;
+
+               rx_offset_code = rtk_phy_read(phy_reg, PHY_ADDR_0X1F);
+               if (((rx_offset_code & code_mask) == 0x0) ||
+                   ((rx_offset_code & code_mask) == code_mask))
+                       do_update = true;
+
+               rx_offset_range = rtk_phy_read(phy_reg, PHY_ADDR_0X0B);
+               if (((rx_offset_range & range_mask) == range_mask) && do_update) {
+                       dev_warn(rtk_phy->dev, "Don't update rx_offset_range (rx_offset_code=0x%x, rx_offset_range=0x%x)\n",
+                                rx_offset_code, rx_offset_range);
+                       do_update = false;
+               }
+
+               if (do_update) {
+                       u16 tmp1, tmp2;
+
+                       tmp1 = rx_offset_range & (~range_mask);
+                       tmp2 = rx_offset_range & range_mask;
+                       tmp2 += (1 << 2);
+                       rx_offset_range = tmp1 | (tmp2 & range_mask);
+                       rtk_phy_write(phy_reg, PHY_ADDR_0X0B, rx_offset_range);
+                       goto do_toggle;
+               }
+       }
+
+       return 0;
+}
+
+static int rtk_phy_init(struct phy *phy)
+{
+       struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+       int ret = 0;
+       int i;
+       unsigned long phy_init_time = jiffies;
+
+       for (i = 0; i < rtk_phy->num_phy; i++)
+               ret = do_rtk_phy_init(rtk_phy, i);
+
+       dev_dbg(rtk_phy->dev, "Initialized RTK USB 3.0 PHY (take %dms)\n",
+               jiffies_to_msecs(jiffies - phy_init_time));
+
+       return ret;
+}
+
+static int rtk_phy_exit(struct phy *phy)
+{
+       return 0;
+}
+
+static void rtk_phy_toggle(struct rtk_phy *rtk_phy, bool connect, int port)
+{
+       int index = port;
+
+       if (index > rtk_phy->num_phy) {
+               dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n",
+                       __func__, index, rtk_phy->num_phy);
+               return;
+       }
+
+       do_rtk_usb3_phy_toggle(rtk_phy, index, connect);
+}
+
+static int rtk_phy_connect(struct phy *phy, int port)
+{
+       struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+
+       dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port);
+       rtk_phy_toggle(rtk_phy, true, port);
+
+       return 0;
+}
+
+static int rtk_phy_disconnect(struct phy *phy, int port)
+{
+       struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+
+       dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port);
+       rtk_phy_toggle(rtk_phy, false, port);
+
+       return 0;
+}
+
+static const struct phy_ops ops = {
+       .init           = rtk_phy_init,
+       .exit           = rtk_phy_exit,
+       .connect        = rtk_phy_connect,
+       .disconnect     = rtk_phy_disconnect,
+       .owner          = THIS_MODULE,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *create_phy_debug_root(void)
+{
+       struct dentry *phy_debug_root;
+
+       phy_debug_root = debugfs_lookup("phy", usb_debug_root);
+       if (!phy_debug_root)
+               phy_debug_root = debugfs_create_dir("phy", usb_debug_root);
+
+       return phy_debug_root;
+}
+
+static int rtk_usb3_parameter_show(struct seq_file *s, void *unused)
+{
+       struct rtk_phy *rtk_phy = s->private;
+       struct phy_cfg *phy_cfg;
+       int i, index;
+
+       phy_cfg = rtk_phy->phy_cfg;
+
+       seq_puts(s, "Property:\n");
+       seq_printf(s, "  check_efuse: %s\n",
+                  phy_cfg->check_efuse ? "Enable" : "Disable");
+       seq_printf(s, "  do_toggle: %s\n",
+                  phy_cfg->do_toggle ? "Enable" : "Disable");
+       seq_printf(s, "  do_toggle_once: %s\n",
+                  phy_cfg->do_toggle_once ? "Enable" : "Disable");
+       seq_printf(s, "  use_default_parameter: %s\n",
+                  phy_cfg->use_default_parameter ? "Enable" : "Disable");
+
+       for (index = 0; index < rtk_phy->num_phy; index++) {
+               struct phy_reg *phy_reg;
+               struct phy_parameter *phy_parameter;
+
+               phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+               phy_reg = &phy_parameter->phy_reg;
+
+               seq_printf(s, "PHY %d:\n", index);
+
+               for (i = 0; i < phy_cfg->param_size; i++) {
+                       struct phy_data *phy_data = phy_cfg->param + i;
+                       u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(i);
+                       u16 data = phy_data->data;
+
+                       if (!phy_data->addr && !data)
+                               seq_printf(s, "  addr = 0x%02x, data = none   ==> read value = 0x%04x\n",
+                                          addr, rtk_phy_read(phy_reg, addr));
+                       else
+                               seq_printf(s, "  addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n",
+                                          addr, data, rtk_phy_read(phy_reg, addr));
+               }
+
+               seq_puts(s, "PHY Property:\n");
+               seq_printf(s, "  efuse_usb_u3_tx_lfps_swing_trim: 0x%x\n",
+                          (int)phy_parameter->efuse_usb_u3_tx_lfps_swing_trim);
+               seq_printf(s, "  amplitude_control_coarse: 0x%x\n",
+                          (int)phy_parameter->amplitude_control_coarse);
+               seq_printf(s, "  amplitude_control_fine: 0x%x\n",
+                          (int)phy_parameter->amplitude_control_fine);
+       }
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(rtk_usb3_parameter);
+
+static inline void create_debug_files(struct rtk_phy *rtk_phy)
+{
+       struct dentry *phy_debug_root = NULL;
+
+       phy_debug_root = create_phy_debug_root();
+
+       if (!phy_debug_root)
+               return;
+
+       rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), phy_debug_root);
+
+       debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
+                           &rtk_usb3_parameter_fops);
+}
+
+static inline void remove_debug_files(struct rtk_phy *rtk_phy)
+{
+       debugfs_remove_recursive(rtk_phy->debug_dir);
+}
+#else
+static inline void create_debug_files(struct rtk_phy *rtk_phy) { }
+static inline void remove_debug_files(struct rtk_phy *rtk_phy) { }
+#endif /* CONFIG_DEBUG_FS */
+
+static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
+                                struct phy_parameter *phy_parameter, int index)
+{
+       struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+       u8 value = 0;
+       struct nvmem_cell *cell;
+
+       if (!phy_cfg->check_efuse)
+               goto out;
+
+       cell = nvmem_cell_get(rtk_phy->dev, "usb_u3_tx_lfps_swing_trim");
+       if (IS_ERR(cell)) {
+               dev_dbg(rtk_phy->dev, "%s no usb_u3_tx_lfps_swing_trim: %ld\n",
+                       __func__, PTR_ERR(cell));
+       } else {
+               unsigned char *buf;
+               size_t buf_size;
+
+               buf = nvmem_cell_read(cell, &buf_size);
+               if (!IS_ERR(buf)) {
+                       value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK;
+                       kfree(buf);
+               }
+               nvmem_cell_put(cell);
+       }
+
+       if (value > 0 && value < 0x8)
+               phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = 0x8;
+       else
+               phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = (u8)value;
+
+out:
+       return 0;
+}
+
+static void update_amplitude_control_value(struct rtk_phy *rtk_phy,
+                                          struct phy_parameter *phy_parameter)
+{
+       struct phy_cfg *phy_cfg;
+       struct phy_reg *phy_reg;
+
+       phy_reg = &phy_parameter->phy_reg;
+       phy_cfg = rtk_phy->phy_cfg;
+
+       if (phy_parameter->amplitude_control_coarse != AMPLITUDE_CONTROL_COARSE_DEFAULT) {
+               u16 val_mask = AMPLITUDE_CONTROL_COARSE_MASK;
+               u16 data;
+
+               if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) {
+                       phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20;
+                       data = rtk_phy_read(phy_reg, PHY_ADDR_0X20);
+               } else {
+                       data = phy_cfg->param[PHY_ADDR_0X20].data;
+               }
+
+               data &= (~val_mask);
+               data |= (phy_parameter->amplitude_control_coarse & val_mask);
+
+               phy_cfg->param[PHY_ADDR_0X20].data = data;
+       }
+
+       if (phy_parameter->efuse_usb_u3_tx_lfps_swing_trim) {
+               u8 efuse_val = phy_parameter->efuse_usb_u3_tx_lfps_swing_trim;
+               u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK;
+               int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT;
+               u16 data;
+
+               if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) {
+                       phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20;
+                       data = rtk_phy_read(phy_reg, PHY_ADDR_0X20);
+               } else {
+                       data = phy_cfg->param[PHY_ADDR_0X20].data;
+               }
+
+               data &= ~(val_mask << val_shift);
+               data |= ((efuse_val & val_mask) << val_shift);
+
+               phy_cfg->param[PHY_ADDR_0X20].data = data;
+       }
+
+       if (phy_parameter->amplitude_control_fine != AMPLITUDE_CONTROL_FINE_DEFAULT) {
+               u16 val_mask = AMPLITUDE_CONTROL_FINE_MASK;
+
+               if (!phy_cfg->param[PHY_ADDR_0X21].addr && !phy_cfg->param[PHY_ADDR_0X21].data)
+                       phy_cfg->param[PHY_ADDR_0X21].addr = PHY_ADDR_0X21;
+
+               phy_cfg->param[PHY_ADDR_0X21].data =
+                           phy_parameter->amplitude_control_fine & val_mask;
+       }
+}
+
+static int parse_phy_data(struct rtk_phy *rtk_phy)
+{
+       struct device *dev = rtk_phy->dev;
+       struct phy_parameter *phy_parameter;
+       int ret = 0;
+       int index;
+
+       rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) *
+                                             rtk_phy->num_phy, GFP_KERNEL);
+       if (!rtk_phy->phy_parameter)
+               return -ENOMEM;
+
+       for (index = 0; index < rtk_phy->num_phy; index++) {
+               phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+
+               phy_parameter->phy_reg.reg_mdio_ctl = of_iomap(dev->of_node, 0) + index;
+
+               /* Amplitude control address 0x20 bit 0 to bit 7 */
+               if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-coarse-tuning",
+                                        &phy_parameter->amplitude_control_coarse))
+                       phy_parameter->amplitude_control_coarse = AMPLITUDE_CONTROL_COARSE_DEFAULT;
+
+               /* Amplitude control address 0x21 bit 0 to bit 16 */
+               if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-fine-tuning",
+                                        &phy_parameter->amplitude_control_fine))
+                       phy_parameter->amplitude_control_fine = AMPLITUDE_CONTROL_FINE_DEFAULT;
+
+               get_phy_data_by_efuse(rtk_phy, phy_parameter, index);
+
+               update_amplitude_control_value(rtk_phy, phy_parameter);
+       }
+
+       return ret;
+}
+
+static int rtk_usb3phy_probe(struct platform_device *pdev)
+{
+       struct rtk_phy *rtk_phy;
+       struct device *dev = &pdev->dev;
+       struct phy *generic_phy;
+       struct phy_provider *phy_provider;
+       const struct phy_cfg *phy_cfg;
+       int ret;
+
+       phy_cfg = of_device_get_match_data(dev);
+       if (!phy_cfg) {
+               dev_err(dev, "phy config are not assigned!\n");
+               return -EINVAL;
+       }
+
+       rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL);
+       if (!rtk_phy)
+               return -ENOMEM;
+
+       rtk_phy->dev                    = &pdev->dev;
+       rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
+
+       memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
+
+       rtk_phy->num_phy = 1;
+
+       ret = parse_phy_data(rtk_phy);
+       if (ret)
+               goto err;
+
+       platform_set_drvdata(pdev, rtk_phy);
+
+       generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops);
+       if (IS_ERR(generic_phy))
+               return PTR_ERR(generic_phy);
+
+       phy_set_drvdata(generic_phy, rtk_phy);
+
+       phy_provider = devm_of_phy_provider_register(rtk_phy->dev, of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
+       create_debug_files(rtk_phy);
+
+err:
+       return ret;
+}
+
+static void rtk_usb3phy_remove(struct platform_device *pdev)
+{
+       struct rtk_phy *rtk_phy = platform_get_drvdata(pdev);
+
+       remove_debug_files(rtk_phy);
+}
+
+static const struct phy_cfg rtd1295_phy_cfg = {
+       .param_size = MAX_USB_PHY_DATA_SIZE,
+       .param = {  [0] = {0x01, 0x4008},  [1] = {0x01, 0xe046},
+                   [2] = {0x02, 0x6046},  [3] = {0x03, 0x2779},
+                   [4] = {0x04, 0x72f5},  [5] = {0x05, 0x2ad3},
+                   [6] = {0x06, 0x000e},  [7] = {0x07, 0x2e00},
+                   [8] = {0x08, 0x3591},  [9] = {0x09, 0x525c},
+                  [10] = {0x0a, 0xa600}, [11] = {0x0b, 0xa904},
+                  [12] = {0x0c, 0xc000}, [13] = {0x0d, 0xef1c},
+                  [14] = {0x0e, 0x2000}, [15] = {0x0f, 0x0000},
+                  [16] = {0x10, 0x000c}, [17] = {0x11, 0x4c00},
+                  [18] = {0x12, 0xfc00}, [19] = {0x13, 0x0c81},
+                  [20] = {0x14, 0xde01}, [21] = {0x15, 0x0000},
+                  [22] = {0x16, 0x0000}, [23] = {0x17, 0x0000},
+                  [24] = {0x18, 0x0000}, [25] = {0x19, 0x4004},
+                  [26] = {0x1a, 0x1260}, [27] = {0x1b, 0xff00},
+                  [28] = {0x1c, 0xcb00}, [29] = {0x1d, 0xa03f},
+                  [30] = {0x1e, 0xc2e0}, [31] = {0x1f, 0x2807},
+                  [32] = {0x20, 0x947a}, [33] = {0x21, 0x88aa},
+                  [34] = {0x22, 0x0057}, [35] = {0x23, 0xab66},
+                  [36] = {0x24, 0x0800}, [37] = {0x25, 0x0000},
+                  [38] = {0x26, 0x040a}, [39] = {0x27, 0x01d6},
+                  [40] = {0x28, 0xf8c2}, [41] = {0x29, 0x3080},
+                  [42] = {0x2a, 0x3082}, [43] = {0x2b, 0x2078},
+                  [44] = {0x2c, 0xffff}, [45] = {0x2d, 0xffff},
+                  [46] = {0x2e, 0x0000}, [47] = {0x2f, 0x0040}, },
+       .check_efuse = false,
+       .do_toggle = true,
+       .do_toggle_once = false,
+       .use_default_parameter = false,
+       .check_rx_front_end_offset = false,
+};
+
+static const struct phy_cfg rtd1619_phy_cfg = {
+       .param_size = MAX_USB_PHY_DATA_SIZE,
+       .param = {  [8] = {0x08, 0x3591},
+                  [38] = {0x26, 0x840b},
+                  [40] = {0x28, 0xf842}, },
+       .check_efuse = false,
+       .do_toggle = true,
+       .do_toggle_once = false,
+       .use_default_parameter = false,
+       .check_rx_front_end_offset = false,
+};
+
+static const struct phy_cfg rtd1319_phy_cfg = {
+       .param_size = MAX_USB_PHY_DATA_SIZE,
+       .param = {  [1] = {0x01, 0xac86},
+                   [6] = {0x06, 0x0003},
+                   [9] = {0x09, 0x924c},
+                  [10] = {0x0a, 0xa608},
+                  [11] = {0x0b, 0xb905},
+                  [14] = {0x0e, 0x2010},
+                  [32] = {0x20, 0x705a},
+                  [33] = {0x21, 0xf645},
+                  [34] = {0x22, 0x0013},
+                  [35] = {0x23, 0xcb66},
+                  [41] = {0x29, 0xff00}, },
+       .check_efuse = true,
+       .do_toggle = true,
+       .do_toggle_once = false,
+       .use_default_parameter = false,
+       .check_rx_front_end_offset = false,
+};
+
+static const struct phy_cfg rtd1619b_phy_cfg = {
+       .param_size = MAX_USB_PHY_DATA_SIZE,
+       .param = {  [1] = {0x01, 0xac8c},
+                   [6] = {0x06, 0x0017},
+                   [9] = {0x09, 0x724c},
+                  [10] = {0x0a, 0xb610},
+                  [11] = {0x0b, 0xb90d},
+                  [13] = {0x0d, 0xef2a},
+                  [15] = {0x0f, 0x9050},
+                  [16] = {0x10, 0x000c},
+                  [32] = {0x20, 0x70ff},
+                  [34] = {0x22, 0x0013},
+                  [35] = {0x23, 0xdb66},
+                  [38] = {0x26, 0x8609},
+                  [41] = {0x29, 0xff13},
+                  [42] = {0x2a, 0x3070}, },
+       .check_efuse = true,
+       .do_toggle = false,
+       .do_toggle_once = true,
+       .use_default_parameter = false,
+       .check_rx_front_end_offset = false,
+};
+
+static const  struct phy_cfg rtd1319d_phy_cfg = {
+       .param_size = MAX_USB_PHY_DATA_SIZE,
+       .param = {  [1] = {0x01, 0xac89},
+                   [4] = {0x04, 0xf2f5},
+                   [6] = {0x06, 0x0017},
+                   [9] = {0x09, 0x424c},
+                  [10] = {0x0a, 0x9610},
+                  [11] = {0x0b, 0x9901},
+                  [12] = {0x0c, 0xf000},
+                  [13] = {0x0d, 0xef2a},
+                  [14] = {0x0e, 0x1000},
+                  [15] = {0x0f, 0x9050},
+                  [32] = {0x20, 0x7077},
+                  [35] = {0x23, 0x0b62},
+                  [37] = {0x25, 0x10ec},
+                  [42] = {0x2a, 0x3070}, },
+       .check_efuse = true,
+       .do_toggle = false,
+       .do_toggle_once = true,
+       .use_default_parameter = false,
+       .check_rx_front_end_offset = true,
+};
+
+static const struct of_device_id usbphy_rtk_dt_match[] = {
+       { .compatible = "realtek,rtd1295-usb3phy", .data = &rtd1295_phy_cfg },
+       { .compatible = "realtek,rtd1319-usb3phy", .data = &rtd1319_phy_cfg },
+       { .compatible = "realtek,rtd1319d-usb3phy", .data = &rtd1319d_phy_cfg },
+       { .compatible = "realtek,rtd1619-usb3phy", .data = &rtd1619_phy_cfg },
+       { .compatible = "realtek,rtd1619b-usb3phy", .data = &rtd1619b_phy_cfg },
+       {},
+};
+MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
+
+static struct platform_driver rtk_usb3phy_driver = {
+       .probe          = rtk_usb3phy_probe,
+       .remove_new     = rtk_usb3phy_remove,
+       .driver         = {
+               .name   = "rtk-usb3phy",
+               .of_match_table = usbphy_rtk_dt_match,
+       },
+};
+
+module_platform_driver(rtk_usb3phy_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
+MODULE_DESCRIPTION("Realtek usb 3.0 phy driver");
index 0dc86a7740e382f2dada87af3d1964bc92ddb52e..cfdb54b6070a45cb4609d945775d06cc9406aff0 100644 (file)
@@ -1531,6 +1531,19 @@ int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
 }
 EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion);
 
+int tegra_xusb_padctl_get_port_number(struct phy *phy)
+{
+       struct tegra_xusb_lane *lane;
+
+       if (!phy)
+               return -ENODEV;
+
+       lane = phy_get_drvdata(phy);
+
+       return lane->index;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_port_number);
+
 MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
 MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver");
 MODULE_LICENSE("GPL v2");
index 2b2f14a1b71193ca62319a24a5384aa541835eec..4d305876ec08f6d87e7f2d6c3bb5478d26e1db36 100644 (file)
 #define DP_PORT_VDO    (DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D)) | \
                                DP_CAP_DFP_D | DP_CAP_RECEPTACLE)
 
+static void cros_typec_role_switch_quirk(struct fwnode_handle *fwnode)
+{
+#ifdef CONFIG_ACPI
+       struct fwnode_handle *switch_fwnode;
+
+       /* Supply the USB role switch with the correct pld_crc if it's missing. */
+       switch_fwnode = fwnode_find_reference(fwnode, "usb-role-switch", 0);
+       if (!IS_ERR_OR_NULL(switch_fwnode)) {
+               struct acpi_device *adev = to_acpi_device_node(switch_fwnode);
+
+               if (adev && !adev->pld_crc)
+                       adev->pld_crc = to_acpi_device_node(fwnode)->pld_crc;
+               fwnode_handle_put(switch_fwnode);
+       }
+#endif
+}
+
 static int cros_typec_parse_port_props(struct typec_capability *cap,
                                       struct fwnode_handle *fwnode,
                                       struct device *dev)
@@ -66,6 +83,8 @@ static int cros_typec_parse_port_props(struct typec_capability *cap,
                cap->prefer_role = ret;
        }
 
+       cros_typec_role_switch_quirk(fwnode);
+
        cap->fwnode = fwnode;
 
        return 0;
index 68d80559fddc25b076648aa6c69f99951c15f262..8ea867c2a01a371a64e1eb10327931861d306dc8 100644 (file)
@@ -81,8 +81,8 @@ struct cros_ec_uart {
        struct response_info response;
 };
 
-static ssize_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
-                                    const u8 *data, size_t count)
+static size_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
+                                   const u8 *data, size_t count)
 {
        struct ec_host_response *host_response;
        struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev);
index f3d09b1631e3e9856f92bbe0bd708d63e0e270d0..03ca5bf19f985024f2928aa00d8b54eb98de0b19 100644 (file)
@@ -2,6 +2,7 @@
 menuconfig GOLDFISH
        bool "Platform support for Goldfish virtual devices"
        depends on HAS_IOMEM && HAS_DMA
+       default X86_GOLDFISH
        help
          Say Y here to get to see options for the Goldfish virtual platform.
          This option alone does not add any kernel code.
index 9591a28bc38a9f40da8f9c53fb49c11a6396a968..ba550eaa06fcf594e2b6d3c0d8128b38813daf25 100644 (file)
@@ -227,8 +227,8 @@ EXPORT_SYMBOL_GPL(ssam_client_bind);
 
 /* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
 
-static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
-                               size_t n)
+static size_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
+                              size_t n)
 {
        struct ssam_controller *ctrl;
        int ret;
index b4b6930cacb0b11b016c771b2301a4c8f416f707..35cb152fa9aa7aa703a6c9138966e1aaf31364ac 100644 (file)
@@ -197,11 +197,10 @@ out:
        return ret;
 }
 
-static int rapl_msr_remove(struct platform_device *pdev)
+static void rapl_msr_remove(struct platform_device *pdev)
 {
        cpuhp_remove_state(rapl_msr_priv->pcap_rapl_online);
        powercap_unregister_control_type(rapl_msr_priv->control_type);
-       return 0;
 }
 
 static const struct platform_device_id rapl_msr_ids[] = {
@@ -212,7 +211,7 @@ MODULE_DEVICE_TABLE(platform, rapl_msr_ids);
 
 static struct platform_driver intel_rapl_msr_driver = {
        .probe = rapl_msr_probe,
-       .remove = rapl_msr_remove,
+       .remove_new = rapl_msr_remove,
        .id_table = rapl_msr_ids,
        .driver = {
                .name = "intel_rapl_msr",
index 2d56dd0495d590a13213ea89fe1a8af18c95d323..2589fd0f2481e5727d5080addc64fd2962b5758f 100644 (file)
@@ -5,6 +5,4 @@
 
 obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o
 
-ifeq ($(CONFIG_PPS_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
index d019ca6dee9bff61de2fd2be68d8434f24b1a298..dabac9772741fa64c241ee7f2c6d2d173fc18c7b 100644 (file)
@@ -2274,6 +2274,17 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
                if (ret > 0) {
                        rdev->use_count = 1;
                        regulator->enable_count = 1;
+
+                       /* Propagate the regulator state to its supply */
+                       if (rdev->supply) {
+                               ret = regulator_enable(rdev->supply);
+                               if (ret < 0) {
+                                       destroy_regulator(regulator);
+                                       module_put(rdev->owner);
+                                       put_device(&rdev->dev);
+                                       return ERR_PTR(ret);
+                               }
+                       }
                } else {
                        rdev->use_count = 0;
                        regulator->enable_count = 0;
index d73727a5828a4fa37d00b5b0f70cf4c2b186cc8b..087506e2150805d268ba669e307302828f0a331d 100644 (file)
@@ -1040,8 +1040,8 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       rproc = rproc_alloc(dev, "imx-dsp-rproc", &imx_dsp_rproc_ops, fw_name,
-                           sizeof(*priv));
+       rproc = devm_rproc_alloc(dev, "imx-dsp-rproc", &imx_dsp_rproc_ops,
+                                fw_name, sizeof(*priv));
        if (!rproc)
                return -ENOMEM;
 
@@ -1061,14 +1061,14 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
        ret = imx_dsp_rproc_detect_mode(priv);
        if (ret) {
                dev_err(dev, "failed on imx_dsp_rproc_detect_mode\n");
-               goto err_put_rproc;
+               return ret;
        }
 
        /* There are multiple power domains required by DSP on some platform */
        ret = imx_dsp_attach_pm_domains(priv);
        if (ret) {
                dev_err(dev, "failed on imx_dsp_attach_pm_domains\n");
-               goto err_put_rproc;
+               return ret;
        }
        /* Get clocks */
        ret = imx_dsp_rproc_clk_get(priv);
@@ -1091,8 +1091,6 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev)
 
 err_detach_domains:
        dev_pm_domain_detach_list(priv->pd_list);
-err_put_rproc:
-       rproc_free(rproc);
 
        return ret;
 }
@@ -1105,7 +1103,6 @@ static void imx_dsp_rproc_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        rproc_del(rproc);
        dev_pm_domain_detach_list(priv->pd_list);
-       rproc_free(rproc);
 }
 
 /* pm runtime functions */
index 3161f14442bc210eb8175e2922127e27d2bf875b..5a3fb902acc9f8e9aa6bca7b8c949b297a915a0a 100644 (file)
@@ -1049,16 +1049,14 @@ static int imx_rproc_probe(struct platform_device *pdev)
        int ret;
 
        /* set some other name then imx */
-       rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
-                           NULL, sizeof(*priv));
+       rproc = devm_rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
+                                NULL, sizeof(*priv));
        if (!rproc)
                return -ENOMEM;
 
        dcfg = of_device_get_match_data(dev);
-       if (!dcfg) {
-               ret = -EINVAL;
-               goto err_put_rproc;
-       }
+       if (!dcfg)
+               return -EINVAL;
 
        priv = rproc->priv;
        priv->rproc = rproc;
@@ -1069,8 +1067,7 @@ static int imx_rproc_probe(struct platform_device *pdev)
        priv->workqueue = create_workqueue(dev_name(dev));
        if (!priv->workqueue) {
                dev_err(dev, "cannot create workqueue\n");
-               ret = -ENOMEM;
-               goto err_put_rproc;
+               return -ENOMEM;
        }
 
        ret = imx_rproc_xtr_mbox_init(rproc);
@@ -1112,8 +1109,6 @@ err_put_mbox:
        imx_rproc_free_mbox(rproc);
 err_put_wkq:
        destroy_workqueue(priv->workqueue);
-err_put_rproc:
-       rproc_free(rproc);
 
        return ret;
 }
@@ -1128,7 +1123,6 @@ static void imx_rproc_remove(struct platform_device *pdev)
        imx_rproc_put_scu(rproc);
        imx_rproc_free_mbox(rproc);
        destroy_workqueue(priv->workqueue);
-       rproc_free(rproc);
 }
 
 static const struct of_device_id imx_rproc_of_match[] = {
index 93f9a1537ec60406ff826715453c02436ca2f65b..1d24c9b656a8299cd46e382a541df60a329cff11 100644 (file)
@@ -674,8 +674,8 @@ static int adsp_probe(struct platform_device *pdev)
                return ret;
        }
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
-                           firmware_name, sizeof(*adsp));
+       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, &adsp_ops,
+                                firmware_name, sizeof(*adsp));
        if (!rproc) {
                dev_err(&pdev->dev, "unable to allocate remoteproc\n");
                return -ENOMEM;
@@ -700,16 +700,16 @@ static int adsp_probe(struct platform_device *pdev)
 
        ret = adsp_alloc_memory_region(adsp);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        ret = adsp_init_clock(adsp, desc->clk_ids);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        ret = qcom_rproc_pds_attach(adsp, desc->pd_names, desc->num_pds);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to attach proxy power domains\n");
-               goto free_rproc;
+               return ret;
        }
 
        ret = adsp_init_reset(adsp);
@@ -744,9 +744,6 @@ static int adsp_probe(struct platform_device *pdev)
 disable_pm:
        qcom_rproc_pds_detach(adsp);
 
-free_rproc:
-       rproc_free(rproc);
-
        return ret;
 }
 
@@ -761,7 +758,6 @@ static void adsp_remove(struct platform_device *pdev)
        qcom_remove_sysmon_subdev(adsp->sysmon);
        qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
        qcom_rproc_pds_detach(adsp);
-       rproc_free(adsp->rproc);
 }
 
 static const struct adsp_pil_data adsp_resource_init = {
index 394b2c1cb5e218bad7a11c0dfbc0c25de4bebf99..1779fc890e10243742ff17b06a75d8785338b2b7 100644 (file)
@@ -1990,8 +1990,8 @@ static int q6v5_probe(struct platform_device *pdev)
                return ret;
        }
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
-                           mba_image, sizeof(*qproc));
+       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
+                                mba_image, sizeof(*qproc));
        if (!rproc) {
                dev_err(&pdev->dev, "failed to allocate rproc\n");
                return -ENOMEM;
@@ -2008,7 +2008,7 @@ static int q6v5_probe(struct platform_device *pdev)
                                            1, &qproc->hexagon_mdt_image);
        if (ret < 0 && ret != -EINVAL) {
                dev_err(&pdev->dev, "unable to read mpss firmware-name\n");
-               goto free_rproc;
+               return ret;
        }
 
        platform_set_drvdata(pdev, qproc);
@@ -2019,17 +2019,17 @@ static int q6v5_probe(struct platform_device *pdev)
        qproc->has_spare_reg = desc->has_spare_reg;
        ret = q6v5_init_mem(qproc, pdev);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        ret = q6v5_alloc_memory_region(qproc);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        ret = q6v5_init_clocks(&pdev->dev, qproc->proxy_clks,
                               desc->proxy_clk_names);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to get proxy clocks.\n");
-               goto free_rproc;
+               return ret;
        }
        qproc->proxy_clk_count = ret;
 
@@ -2037,7 +2037,7 @@ static int q6v5_probe(struct platform_device *pdev)
                               desc->reset_clk_names);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to get reset clocks.\n");
-               goto free_rproc;
+               return ret;
        }
        qproc->reset_clk_count = ret;
 
@@ -2045,7 +2045,7 @@ static int q6v5_probe(struct platform_device *pdev)
                               desc->active_clk_names);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to get active clocks.\n");
-               goto free_rproc;
+               return ret;
        }
        qproc->active_clk_count = ret;
 
@@ -2053,7 +2053,7 @@ static int q6v5_probe(struct platform_device *pdev)
                                  desc->proxy_supply);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to get proxy regulators.\n");
-               goto free_rproc;
+               return ret;
        }
        qproc->proxy_reg_count = ret;
 
@@ -2061,7 +2061,7 @@ static int q6v5_probe(struct platform_device *pdev)
                                  desc->active_supply);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to get active regulators.\n");
-               goto free_rproc;
+               return ret;
        }
        qproc->active_reg_count = ret;
 
@@ -2074,12 +2074,12 @@ static int q6v5_probe(struct platform_device *pdev)
                                          desc->fallback_proxy_supply);
                if (ret < 0) {
                        dev_err(&pdev->dev, "Failed to get fallback proxy regulators.\n");
-                       goto free_rproc;
+                       return ret;
                }
                qproc->fallback_proxy_reg_count = ret;
        } else if (ret < 0) {
                dev_err(&pdev->dev, "Failed to init power domains\n");
-               goto free_rproc;
+               return ret;
        } else {
                qproc->proxy_pd_count = ret;
        }
@@ -2127,8 +2127,6 @@ remove_subdevs:
        qcom_remove_glink_subdev(rproc, &qproc->glink_subdev);
 detach_proxy_pds:
        q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count);
-free_rproc:
-       rproc_free(rproc);
 
        return ret;
 }
@@ -2149,8 +2147,6 @@ static void q6v5_remove(struct platform_device *pdev)
        qcom_remove_glink_subdev(rproc, &qproc->glink_subdev);
 
        q6v5_pds_detach(qproc, qproc->proxy_pds, qproc->proxy_pd_count);
-
-       rproc_free(rproc);
 }
 
 static const struct rproc_hexagon_res sc7180_mss = {
index a9dd58608052c285aa87010b1ead045162970d63..54d8005d40a3435cf1207780de7fe6d99c8e92f4 100644 (file)
 
 #define ADSP_DECRYPT_SHUTDOWN_DELAY_MS 100
 
+#define MAX_ASSIGN_COUNT 3
+
 struct adsp_data {
        int crash_reason_smem;
        const char *firmware_name;
        const char *dtb_firmware_name;
        int pas_id;
        int dtb_pas_id;
+       int lite_pas_id;
        unsigned int minidump_id;
        bool auto_boot;
        bool decrypt_shutdown;
@@ -51,6 +54,9 @@ struct adsp_data {
        int ssctl_id;
 
        int region_assign_idx;
+       int region_assign_count;
+       bool region_assign_shared;
+       int region_assign_vmid;
 };
 
 struct qcom_adsp {
@@ -72,6 +78,7 @@ struct qcom_adsp {
        const char *dtb_firmware_name;
        int pas_id;
        int dtb_pas_id;
+       int lite_pas_id;
        unsigned int minidump_id;
        int crash_reason_smem;
        bool decrypt_shutdown;
@@ -87,15 +94,18 @@ struct qcom_adsp {
        phys_addr_t dtb_mem_phys;
        phys_addr_t mem_reloc;
        phys_addr_t dtb_mem_reloc;
-       phys_addr_t region_assign_phys;
+       phys_addr_t region_assign_phys[MAX_ASSIGN_COUNT];
        void *mem_region;
        void *dtb_mem_region;
        size_t mem_size;
        size_t dtb_mem_size;
-       size_t region_assign_size;
+       size_t region_assign_size[MAX_ASSIGN_COUNT];
 
        int region_assign_idx;
-       u64 region_assign_perms;
+       int region_assign_count;
+       bool region_assign_shared;
+       int region_assign_vmid;
+       u64 region_assign_owners[MAX_ASSIGN_COUNT];
 
        struct qcom_rproc_glink glink_subdev;
        struct qcom_rproc_subdev smd_subdev;
@@ -210,6 +220,9 @@ static int adsp_load(struct rproc *rproc, const struct firmware *fw)
        /* Store firmware handle to be used in adsp_start() */
        adsp->firmware = fw;
 
+       if (adsp->lite_pas_id)
+               ret = qcom_scm_pas_shutdown(adsp->lite_pas_id);
+
        if (adsp->dtb_pas_id) {
                ret = request_firmware(&adsp->dtb_firmware, adsp->dtb_firmware_name, adsp->dev);
                if (ret) {
@@ -590,37 +603,53 @@ static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
 
 static int adsp_assign_memory_region(struct qcom_adsp *adsp)
 {
-       struct reserved_mem *rmem = NULL;
-       struct qcom_scm_vmperm perm;
+       struct qcom_scm_vmperm perm[MAX_ASSIGN_COUNT];
        struct device_node *node;
+       unsigned int perm_size;
+       int offset;
        int ret;
 
        if (!adsp->region_assign_idx)
                return 0;
 
-       node = of_parse_phandle(adsp->dev->of_node, "memory-region", adsp->region_assign_idx);
-       if (node)
-               rmem = of_reserved_mem_lookup(node);
-       of_node_put(node);
-       if (!rmem) {
-               dev_err(adsp->dev, "unable to resolve shareable memory-region\n");
-               return -EINVAL;
-       }
+       for (offset = 0; offset < adsp->region_assign_count; ++offset) {
+               struct reserved_mem *rmem = NULL;
+
+               node = of_parse_phandle(adsp->dev->of_node, "memory-region",
+                                       adsp->region_assign_idx + offset);
+               if (node)
+                       rmem = of_reserved_mem_lookup(node);
+               of_node_put(node);
+               if (!rmem) {
+                       dev_err(adsp->dev, "unable to resolve shareable memory-region index %d\n",
+                               offset);
+                       return -EINVAL;
+               }
 
-       perm.vmid = QCOM_SCM_VMID_MSS_MSA;
-       perm.perm = QCOM_SCM_PERM_RW;
+               if (adsp->region_assign_shared)  {
+                       perm[0].vmid = QCOM_SCM_VMID_HLOS;
+                       perm[0].perm = QCOM_SCM_PERM_RW;
+                       perm[1].vmid = adsp->region_assign_vmid;
+                       perm[1].perm = QCOM_SCM_PERM_RW;
+                       perm_size = 2;
+               } else {
+                       perm[0].vmid = adsp->region_assign_vmid;
+                       perm[0].perm = QCOM_SCM_PERM_RW;
+                       perm_size = 1;
+               }
 
-       adsp->region_assign_phys = rmem->base;
-       adsp->region_assign_size = rmem->size;
-       adsp->region_assign_perms = BIT(QCOM_SCM_VMID_HLOS);
+               adsp->region_assign_phys[offset] = rmem->base;
+               adsp->region_assign_size[offset] = rmem->size;
+               adsp->region_assign_owners[offset] = BIT(QCOM_SCM_VMID_HLOS);
 
-       ret = qcom_scm_assign_mem(adsp->region_assign_phys,
-                                 adsp->region_assign_size,
-                                 &adsp->region_assign_perms,
-                                 &perm, 1);
-       if (ret < 0) {
-               dev_err(adsp->dev, "assign memory failed\n");
-               return ret;
+               ret = qcom_scm_assign_mem(adsp->region_assign_phys[offset],
+                                         adsp->region_assign_size[offset],
+                                         &adsp->region_assign_owners[offset],
+                                         perm, perm_size);
+               if (ret < 0) {
+                       dev_err(adsp->dev, "assign memory %d failed\n", offset);
+                       return ret;
+               }
        }
 
        return 0;
@@ -629,20 +658,23 @@ static int adsp_assign_memory_region(struct qcom_adsp *adsp)
 static void adsp_unassign_memory_region(struct qcom_adsp *adsp)
 {
        struct qcom_scm_vmperm perm;
+       int offset;
        int ret;
 
-       if (!adsp->region_assign_idx)
+       if (!adsp->region_assign_idx || adsp->region_assign_shared)
                return;
 
-       perm.vmid = QCOM_SCM_VMID_HLOS;
-       perm.perm = QCOM_SCM_PERM_RW;
+       for (offset = 0; offset < adsp->region_assign_count; ++offset) {
+               perm.vmid = QCOM_SCM_VMID_HLOS;
+               perm.perm = QCOM_SCM_PERM_RW;
 
-       ret = qcom_scm_assign_mem(adsp->region_assign_phys,
-                                 adsp->region_assign_size,
-                                 &adsp->region_assign_perms,
-                                 &perm, 1);
-       if (ret < 0)
-               dev_err(adsp->dev, "unassign memory failed\n");
+               ret = qcom_scm_assign_mem(adsp->region_assign_phys[offset],
+                                         adsp->region_assign_size[offset],
+                                         &adsp->region_assign_owners[offset],
+                                         &perm, 1);
+               if (ret < 0)
+                       dev_err(adsp->dev, "unassign memory %d failed\n", offset);
+       }
 }
 
 static int adsp_probe(struct platform_device *pdev)
@@ -678,7 +710,7 @@ static int adsp_probe(struct platform_device *pdev)
        if (desc->minidump_id)
                ops = &adsp_minidump_ops;
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, ops, fw_name, sizeof(*adsp));
+       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, ops, fw_name, sizeof(*adsp));
 
        if (!rproc) {
                dev_err(&pdev->dev, "unable to allocate remoteproc\n");
@@ -693,9 +725,13 @@ static int adsp_probe(struct platform_device *pdev)
        adsp->rproc = rproc;
        adsp->minidump_id = desc->minidump_id;
        adsp->pas_id = desc->pas_id;
+       adsp->lite_pas_id = desc->lite_pas_id;
        adsp->info_name = desc->sysmon_name;
        adsp->decrypt_shutdown = desc->decrypt_shutdown;
        adsp->region_assign_idx = desc->region_assign_idx;
+       adsp->region_assign_count = min_t(int, MAX_ASSIGN_COUNT, desc->region_assign_count);
+       adsp->region_assign_vmid = desc->region_assign_vmid;
+       adsp->region_assign_shared = desc->region_assign_shared;
        if (dtb_fw_name) {
                adsp->dtb_firmware_name = dtb_fw_name;
                adsp->dtb_pas_id = desc->dtb_pas_id;
@@ -754,7 +790,6 @@ detach_proxy_pds:
        adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
 free_rproc:
        device_init_wakeup(adsp->dev, false);
-       rproc_free(rproc);
 
        return ret;
 }
@@ -773,28 +808,27 @@ static void adsp_remove(struct platform_device *pdev)
        qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev);
        adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count);
        device_init_wakeup(adsp->dev, false);
-       rproc_free(adsp->rproc);
 }
 
 static const struct adsp_data adsp_resource_init = {
-               .crash_reason_smem = 423,
-               .firmware_name = "adsp.mdt",
-               .pas_id = 1,
-               .auto_boot = true,
-               .ssr_name = "lpass",
-               .sysmon_name = "adsp",
-               .ssctl_id = 0x14,
+       .crash_reason_smem = 423,
+       .firmware_name = "adsp.mdt",
+       .pas_id = 1,
+       .auto_boot = true,
+       .ssr_name = "lpass",
+       .sysmon_name = "adsp",
+       .ssctl_id = 0x14,
 };
 
 static const struct adsp_data sdm845_adsp_resource_init = {
-               .crash_reason_smem = 423,
-               .firmware_name = "adsp.mdt",
-               .pas_id = 1,
-               .auto_boot = true,
-               .load_state = "adsp",
-               .ssr_name = "lpass",
-               .sysmon_name = "adsp",
-               .ssctl_id = 0x14,
+       .crash_reason_smem = 423,
+       .firmware_name = "adsp.mdt",
+       .pas_id = 1,
+       .auto_boot = true,
+       .load_state = "adsp",
+       .ssr_name = "lpass",
+       .sysmon_name = "adsp",
+       .ssctl_id = 0x14,
 };
 
 static const struct adsp_data sm6350_adsp_resource = {
@@ -829,18 +863,18 @@ static const struct adsp_data sm6375_mpss_resource = {
 };
 
 static const struct adsp_data sm8150_adsp_resource = {
-               .crash_reason_smem = 423,
-               .firmware_name = "adsp.mdt",
-               .pas_id = 1,
-               .auto_boot = true,
-               .proxy_pd_names = (char*[]){
-                       "cx",
-                       NULL
-               },
-               .load_state = "adsp",
-               .ssr_name = "lpass",
-               .sysmon_name = "adsp",
-               .ssctl_id = 0x14,
+       .crash_reason_smem = 423,
+       .firmware_name = "adsp.mdt",
+       .pas_id = 1,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "cx",
+               NULL
+       },
+       .load_state = "adsp",
+       .ssr_name = "lpass",
+       .sysmon_name = "adsp",
+       .ssctl_id = 0x14,
 };
 
 static const struct adsp_data sm8250_adsp_resource = {
@@ -876,17 +910,17 @@ static const struct adsp_data sm8350_adsp_resource = {
 };
 
 static const struct adsp_data msm8996_adsp_resource = {
-               .crash_reason_smem = 423,
-               .firmware_name = "adsp.mdt",
-               .pas_id = 1,
-               .auto_boot = true,
-               .proxy_pd_names = (char*[]){
-                       "cx",
-                       NULL
-               },
-               .ssr_name = "lpass",
-               .sysmon_name = "adsp",
-               .ssctl_id = 0x14,
+       .crash_reason_smem = 423,
+       .firmware_name = "adsp.mdt",
+       .pas_id = 1,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "cx",
+               NULL
+       },
+       .ssr_name = "lpass",
+       .sysmon_name = "adsp",
+       .ssctl_id = 0x14,
 };
 
 static const struct adsp_data cdsp_resource_init = {
@@ -984,6 +1018,46 @@ static const struct adsp_data sc8280xp_nsp1_resource = {
        .ssctl_id = 0x20,
 };
 
+static const struct adsp_data x1e80100_adsp_resource = {
+       .crash_reason_smem = 423,
+       .firmware_name = "adsp.mdt",
+       .dtb_firmware_name = "adsp_dtb.mdt",
+       .pas_id = 1,
+       .dtb_pas_id = 0x24,
+       .lite_pas_id = 0x1f,
+       .minidump_id = 5,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "lcx",
+               "lmx",
+               NULL
+       },
+       .load_state = "adsp",
+       .ssr_name = "lpass",
+       .sysmon_name = "adsp",
+       .ssctl_id = 0x14,
+};
+
+static const struct adsp_data x1e80100_cdsp_resource = {
+       .crash_reason_smem = 601,
+       .firmware_name = "cdsp.mdt",
+       .dtb_firmware_name = "cdsp_dtb.mdt",
+       .pas_id = 18,
+       .dtb_pas_id = 0x25,
+       .minidump_id = 7,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "cx",
+               "mxc",
+               "nsp",
+               NULL
+       },
+       .load_state = "cdsp",
+       .ssr_name = "cdsp",
+       .sysmon_name = "cdsp",
+       .ssctl_id = 0x17,
+};
+
 static const struct adsp_data sm8350_cdsp_resource = {
        .crash_reason_smem = 601,
        .firmware_name = "cdsp.mdt",
@@ -1033,33 +1107,33 @@ static const struct adsp_data sc8180x_mpss_resource = {
 };
 
 static const struct adsp_data msm8996_slpi_resource_init = {
-               .crash_reason_smem = 424,
-               .firmware_name = "slpi.mdt",
-               .pas_id = 12,
-               .auto_boot = true,
-               .proxy_pd_names = (char*[]){
-                       "ssc_cx",
-                       NULL
-               },
-               .ssr_name = "dsps",
-               .sysmon_name = "slpi",
-               .ssctl_id = 0x16,
+       .crash_reason_smem = 424,
+       .firmware_name = "slpi.mdt",
+       .pas_id = 12,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "ssc_cx",
+               NULL
+       },
+       .ssr_name = "dsps",
+       .sysmon_name = "slpi",
+       .ssctl_id = 0x16,
 };
 
 static const struct adsp_data sdm845_slpi_resource_init = {
-               .crash_reason_smem = 424,
-               .firmware_name = "slpi.mdt",
-               .pas_id = 12,
-               .auto_boot = true,
-               .proxy_pd_names = (char*[]){
-                       "lcx",
-                       "lmx",
-                       NULL
-               },
-               .load_state = "slpi",
-               .ssr_name = "dsps",
-               .sysmon_name = "slpi",
-               .ssctl_id = 0x16,
+       .crash_reason_smem = 424,
+       .firmware_name = "slpi.mdt",
+       .pas_id = 12,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "lcx",
+               "lmx",
+               NULL
+       },
+       .load_state = "slpi",
+       .ssr_name = "dsps",
+       .sysmon_name = "slpi",
+       .ssctl_id = 0x16,
 };
 
 static const struct adsp_data wcss_resource_init = {
@@ -1163,6 +1237,8 @@ static const struct adsp_data sm8550_mpss_resource = {
        .sysmon_name = "modem",
        .ssctl_id = 0x12,
        .region_assign_idx = 2,
+       .region_assign_count = 1,
+       .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
 };
 
 static const struct adsp_data sc7280_wpss_resource = {
@@ -1181,6 +1257,53 @@ static const struct adsp_data sc7280_wpss_resource = {
        .ssctl_id = 0x19,
 };
 
+static const struct adsp_data sm8650_cdsp_resource = {
+       .crash_reason_smem = 601,
+       .firmware_name = "cdsp.mdt",
+       .dtb_firmware_name = "cdsp_dtb.mdt",
+       .pas_id = 18,
+       .dtb_pas_id = 0x25,
+       .minidump_id = 7,
+       .auto_boot = true,
+       .proxy_pd_names = (char*[]){
+               "cx",
+               "mxc",
+               "nsp",
+               NULL
+       },
+       .load_state = "cdsp",
+       .ssr_name = "cdsp",
+       .sysmon_name = "cdsp",
+       .ssctl_id = 0x17,
+       .region_assign_idx = 2,
+       .region_assign_count = 1,
+       .region_assign_shared = true,
+       .region_assign_vmid = QCOM_SCM_VMID_CDSP,
+};
+
+static const struct adsp_data sm8650_mpss_resource = {
+       .crash_reason_smem = 421,
+       .firmware_name = "modem.mdt",
+       .dtb_firmware_name = "modem_dtb.mdt",
+       .pas_id = 4,
+       .dtb_pas_id = 0x26,
+       .minidump_id = 3,
+       .auto_boot = false,
+       .decrypt_shutdown = true,
+       .proxy_pd_names = (char*[]){
+               "cx",
+               "mss",
+               NULL
+       },
+       .load_state = "modem",
+       .ssr_name = "mpss",
+       .sysmon_name = "modem",
+       .ssctl_id = 0x12,
+       .region_assign_idx = 2,
+       .region_assign_count = 3,
+       .region_assign_vmid = QCOM_SCM_VMID_MSS_MSA,
+};
+
 static const struct of_device_id adsp_of_match[] = {
        { .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
        { .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
@@ -1236,6 +1359,11 @@ static const struct of_device_id adsp_of_match[] = {
        { .compatible = "qcom,sm8550-adsp-pas", .data = &sm8550_adsp_resource},
        { .compatible = "qcom,sm8550-cdsp-pas", .data = &sm8550_cdsp_resource},
        { .compatible = "qcom,sm8550-mpss-pas", .data = &sm8550_mpss_resource},
+       { .compatible = "qcom,sm8650-adsp-pas", .data = &sm8550_adsp_resource},
+       { .compatible = "qcom,sm8650-cdsp-pas", .data = &sm8650_cdsp_resource},
+       { .compatible = "qcom,sm8650-mpss-pas", .data = &sm8650_mpss_resource},
+       { .compatible = "qcom,x1e80100-adsp-pas", .data = &x1e80100_adsp_resource},
+       { .compatible = "qcom,x1e80100-cdsp-pas", .data = &x1e80100_cdsp_resource},
        { },
 };
 MODULE_DEVICE_TABLE(of, adsp_of_match);
index cff1fa07d1def7fb0ad462d162e68248888cdfde..94f68c919ee622d2cad0845f56d3cc4aa4e30b63 100644 (file)
@@ -1011,8 +1011,8 @@ static int q6v5_wcss_probe(struct platform_device *pdev)
        if (!desc)
                return -EINVAL;
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, desc->ops,
-                           desc->firmware_name, sizeof(*wcss));
+       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, desc->ops,
+                                desc->firmware_name, sizeof(*wcss));
        if (!rproc) {
                dev_err(&pdev->dev, "failed to allocate rproc\n");
                return -ENOMEM;
@@ -1027,29 +1027,29 @@ static int q6v5_wcss_probe(struct platform_device *pdev)
 
        ret = q6v5_wcss_init_mmio(wcss, pdev);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        ret = q6v5_alloc_memory_region(wcss);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        if (wcss->version == WCSS_QCS404) {
                ret = q6v5_wcss_init_clock(wcss);
                if (ret)
-                       goto free_rproc;
+                       return ret;
 
                ret = q6v5_wcss_init_regulator(wcss);
                if (ret)
-                       goto free_rproc;
+                       return ret;
        }
 
        ret = q6v5_wcss_init_reset(wcss, desc);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, desc->crash_reason_smem, NULL, NULL);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        qcom_add_glink_subdev(rproc, &wcss->glink_subdev, "q6wcss");
        qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss");
@@ -1061,16 +1061,11 @@ static int q6v5_wcss_probe(struct platform_device *pdev)
 
        ret = rproc_add(rproc);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        platform_set_drvdata(pdev, rproc);
 
        return 0;
-
-free_rproc:
-       rproc_free(rproc);
-
-       return ret;
 }
 
 static void q6v5_wcss_remove(struct platform_device *pdev)
@@ -1080,7 +1075,6 @@ static void q6v5_wcss_remove(struct platform_device *pdev)
 
        qcom_q6v5_deinit(&wcss->q6v5);
        rproc_del(rproc);
-       rproc_free(rproc);
 }
 
 static const struct wcss_data wcss_ipq8074_res_init = {
index 90de22c81da9761ec560f198c13d9d1b8d639ffe..a7bb9da27029db23f3759b19e423fab11b8430e4 100644 (file)
@@ -555,8 +555,8 @@ static int wcnss_probe(struct platform_device *pdev)
        if (ret < 0 && ret != -EINVAL)
                return ret;
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,
-                           fw_name, sizeof(*wcnss));
+       rproc = devm_rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,
+                                fw_name, sizeof(*wcnss));
        if (!rproc) {
                dev_err(&pdev->dev, "unable to allocate remoteproc\n");
                return -ENOMEM;
@@ -574,14 +574,12 @@ static int wcnss_probe(struct platform_device *pdev)
        mutex_init(&wcnss->iris_lock);
 
        mmio = devm_platform_ioremap_resource_byname(pdev, "pmu");
-       if (IS_ERR(mmio)) {
-               ret = PTR_ERR(mmio);
-               goto free_rproc;
-       }
+       if (IS_ERR(mmio))
+               return PTR_ERR(mmio);
 
        ret = wcnss_alloc_memory_region(wcnss);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        wcnss->pmu_cfg = mmio + data->pmu_offset;
        wcnss->spare_out = mmio + data->spare_offset;
@@ -592,7 +590,7 @@ static int wcnss_probe(struct platform_device *pdev)
         */
        ret = wcnss_init_pds(wcnss, data->pd_names);
        if (ret && (ret != -ENODATA || !data->num_pd_vregs))
-               goto free_rproc;
+               return ret;
 
        ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs,
                                    data->num_pd_vregs);
@@ -656,8 +654,6 @@ remove_iris:
        qcom_iris_remove(wcnss->iris);
 detach_pds:
        wcnss_release_pds(wcnss);
-free_rproc:
-       rproc_free(rproc);
 
        return ret;
 }
@@ -673,7 +669,6 @@ static void wcnss_remove(struct platform_device *pdev)
        qcom_remove_sysmon_subdev(wcnss->sysmon);
        qcom_remove_smd_subdev(wcnss->rproc, &wcnss->smd_subdev);
        wcnss_release_pds(wcnss);
-       rproc_free(wcnss->rproc);
 }
 
 static const struct of_device_id wcnss_of_match[] = {
index 695cce218e8c6423c67658b5e9be49d0ff1920cc..f276956f2c5cec3b0e0f9809d54f3b75c08a15f7 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/idr.h>
 #include <linux/elf.h>
 #include <linux/crc32.h>
+#include <linux/of_platform.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_ring.h>
@@ -2112,6 +2113,7 @@ EXPORT_SYMBOL(rproc_detach);
 struct rproc *rproc_get_by_phandle(phandle phandle)
 {
        struct rproc *rproc = NULL, *r;
+       struct device_driver *driver;
        struct device_node *np;
 
        np = of_find_node_by_phandle(phandle);
@@ -2122,7 +2124,26 @@ struct rproc *rproc_get_by_phandle(phandle phandle)
        list_for_each_entry_rcu(r, &rproc_list, node) {
                if (r->dev.parent && device_match_of_node(r->dev.parent, np)) {
                        /* prevent underlying implementation from being removed */
-                       if (!try_module_get(r->dev.parent->driver->owner)) {
+
+                       /*
+                        * If the remoteproc's parent has a driver, the
+                        * remoteproc is not part of a cluster and we can use
+                        * that driver.
+                        */
+                       driver = r->dev.parent->driver;
+
+                       /*
+                        * If the remoteproc's parent does not have a driver,
+                        * look for the driver associated with the cluster.
+                        */
+                       if (!driver) {
+                               if (r->dev.parent->parent)
+                                       driver = r->dev.parent->parent->driver;
+                               if (!driver)
+                                       break;
+                       }
+
+                       if (!try_module_get(driver->owner)) {
                                dev_err(&r->dev, "can't get owner\n");
                                break;
                        }
@@ -2533,7 +2554,11 @@ EXPORT_SYMBOL(rproc_free);
  */
 void rproc_put(struct rproc *rproc)
 {
-       module_put(rproc->dev.parent->driver->owner);
+       if (rproc->dev.parent->driver)
+               module_put(rproc->dev.parent->driver->owner);
+       else
+               module_put(rproc->dev.parent->parent->driver->owner);
+
        put_device(&rproc->dev);
 }
 EXPORT_SYMBOL(rproc_put);
index 83d76915a6ad6f28f930b705c274dc82897b36de..25b66b113b69594b7edf01caff62bda8435c9bbb 100644 (file)
@@ -351,6 +351,9 @@ static void rproc_virtio_dev_release(struct device *dev)
 
        kfree(vdev);
 
+       of_reserved_mem_device_release(&rvdev->pdev->dev);
+       dma_release_coherent_memory(&rvdev->pdev->dev);
+
        put_device(&rvdev->pdev->dev);
 }
 
@@ -584,9 +587,6 @@ static void rproc_virtio_remove(struct platform_device *pdev)
        rproc_remove_subdev(rproc, &rvdev->subdev);
        rproc_remove_rvdev(rvdev);
 
-       of_reserved_mem_device_release(&pdev->dev);
-       dma_release_coherent_memory(&pdev->dev);
-
        put_device(&rproc->dev);
 }
 
index cb163766c56d526333dabbdc5a42b09a1fe65546..1340be9d0110175c41318208ece611d882da2399 100644 (file)
@@ -347,23 +347,21 @@ static int st_rproc_probe(struct platform_device *pdev)
        int enabled;
        int ret, i;
 
-       rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
+       rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
        if (!rproc)
                return -ENOMEM;
 
        rproc->has_iommu = false;
        ddata = rproc->priv;
        ddata->config = (struct st_rproc_config *)device_get_match_data(dev);
-       if (!ddata->config) {
-               ret = -ENODEV;
-               goto free_rproc;
-       }
+       if (!ddata->config)
+               return -ENODEV;
 
        platform_set_drvdata(pdev, rproc);
 
        ret = st_rproc_parse_dt(pdev);
        if (ret)
-               goto free_rproc;
+               return ret;
 
        enabled = st_rproc_state(pdev);
        if (enabled < 0) {
@@ -439,8 +437,7 @@ free_mbox:
                mbox_free_channel(ddata->mbox_chan[i]);
 free_clk:
        clk_unprepare(ddata->clk);
-free_rproc:
-       rproc_free(rproc);
+
        return ret;
 }
 
@@ -456,8 +453,6 @@ static void st_rproc_remove(struct platform_device *pdev)
 
        for (i = 0; i < ST_RPROC_MAX_VRING * MBOX_MAX; i++)
                mbox_free_channel(ddata->mbox_chan[i]);
-
-       rproc_free(rproc);
 }
 
 static struct platform_driver st_rproc_driver = {
index 4f469f0bcf8b29d5cecbfa3acab4e83c0dd5c695..88623df7d0c35a0ab1971befbe076721f2316822 100644 (file)
@@ -120,7 +120,7 @@ static int stm32_rproc_mem_alloc(struct rproc *rproc,
        void *va;
 
        dev_dbg(dev, "map memory: %pad+%zx\n", &mem->dma, mem->len);
-       va = ioremap_wc(mem->dma, mem->len);
+       va = (__force void *)ioremap_wc(mem->dma, mem->len);
        if (IS_ERR_OR_NULL(va)) {
                dev_err(dev, "Unable to map memory region: %pad+0x%zx\n",
                        &mem->dma, mem->len);
@@ -137,7 +137,7 @@ static int stm32_rproc_mem_release(struct rproc *rproc,
                                   struct rproc_mem_entry *mem)
 {
        dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
-       iounmap(mem->va);
+       iounmap((__force __iomem void *)mem->va);
 
        return 0;
 }
@@ -657,7 +657,7 @@ done:
         * entire area by overwriting it with the initial values stored in rproc->clean_table.
         */
        *table_sz = RSC_TBL_SIZE;
-       return (struct resource_table *)ddata->rsc_va;
+       return (__force struct resource_table *)ddata->rsc_va;
 }
 
 static const struct rproc_ops st_rproc_ops = {
@@ -843,7 +843,7 @@ static int stm32_rproc_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
+       rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata));
        if (!rproc)
                return -ENOMEM;
 
@@ -897,7 +897,6 @@ free_rproc:
                dev_pm_clear_wake_irq(dev);
                device_init_wakeup(dev, false);
        }
-       rproc_free(rproc);
        return ret;
 }
 
@@ -918,7 +917,6 @@ static void stm32_rproc_remove(struct platform_device *pdev)
                dev_pm_clear_wake_irq(dev);
                device_init_wakeup(dev, false);
        }
-       rproc_free(rproc);
 }
 
 static int stm32_rproc_suspend(struct device *dev)
index ab882e3b7130bcb50df0840207b112280e3f80b9..3555b535b16838bf7a7c9125c2f6c5619051f497 100644 (file)
@@ -550,6 +550,13 @@ static int k3_dsp_rproc_of_get_memories(struct platform_device *pdev,
        return 0;
 }
 
+static void k3_dsp_mem_release(void *data)
+{
+       struct device *dev = data;
+
+       of_reserved_mem_device_release(dev);
+}
+
 static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
 {
        struct device *dev = kproc->dev;
@@ -579,27 +586,25 @@ static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
                        ERR_PTR(ret));
                return ret;
        }
+       ret = devm_add_action_or_reset(dev, k3_dsp_mem_release, dev);
+       if (ret)
+               return ret;
 
        num_rmems--;
-       kproc->rmem = kcalloc(num_rmems, sizeof(*kproc->rmem), GFP_KERNEL);
-       if (!kproc->rmem) {
-               ret = -ENOMEM;
-               goto release_rmem;
-       }
+       kproc->rmem = devm_kcalloc(dev, num_rmems, sizeof(*kproc->rmem), GFP_KERNEL);
+       if (!kproc->rmem)
+               return -ENOMEM;
 
        /* use remaining reserved memory regions for static carveouts */
        for (i = 0; i < num_rmems; i++) {
                rmem_np = of_parse_phandle(np, "memory-region", i + 1);
-               if (!rmem_np) {
-                       ret = -EINVAL;
-                       goto unmap_rmem;
-               }
+               if (!rmem_np)
+                       return -EINVAL;
 
                rmem = of_reserved_mem_lookup(rmem_np);
                if (!rmem) {
                        of_node_put(rmem_np);
-                       ret = -EINVAL;
-                       goto unmap_rmem;
+                       return -EINVAL;
                }
                of_node_put(rmem_np);
 
@@ -607,12 +612,11 @@ static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
                /* 64-bit address regions currently not supported */
                kproc->rmem[i].dev_addr = (u32)rmem->base;
                kproc->rmem[i].size = rmem->size;
-               kproc->rmem[i].cpu_addr = ioremap_wc(rmem->base, rmem->size);
+               kproc->rmem[i].cpu_addr = devm_ioremap_wc(dev, rmem->base, rmem->size);
                if (!kproc->rmem[i].cpu_addr) {
                        dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n",
                                i + 1, &rmem->base, &rmem->size);
-                       ret = -ENOMEM;
-                       goto unmap_rmem;
+                       return -ENOMEM;
                }
 
                dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n",
@@ -623,25 +627,13 @@ static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
        kproc->num_rmems = num_rmems;
 
        return 0;
-
-unmap_rmem:
-       for (i--; i >= 0; i--)
-               iounmap(kproc->rmem[i].cpu_addr);
-       kfree(kproc->rmem);
-release_rmem:
-       of_reserved_mem_device_release(kproc->dev);
-       return ret;
 }
 
-static void k3_dsp_reserved_mem_exit(struct k3_dsp_rproc *kproc)
+static void k3_dsp_release_tsp(void *data)
 {
-       int i;
+       struct ti_sci_proc *tsp = data;
 
-       for (i = 0; i < kproc->num_rmems; i++)
-               iounmap(kproc->rmem[i].cpu_addr);
-       kfree(kproc->rmem);
-
-       of_reserved_mem_device_release(kproc->dev);
+       ti_sci_proc_release(tsp);
 }
 
 static
@@ -657,7 +649,7 @@ struct ti_sci_proc *k3_dsp_rproc_of_get_tsp(struct device *dev,
        if (ret < 0)
                return ERR_PTR(ret);
 
-       tsp = kzalloc(sizeof(*tsp), GFP_KERNEL);
+       tsp = devm_kzalloc(dev, sizeof(*tsp), GFP_KERNEL);
        if (!tsp)
                return ERR_PTR(-ENOMEM);
 
@@ -680,7 +672,6 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
        const char *fw_name;
        bool p_state = false;
        int ret = 0;
-       int ret1;
 
        data = of_device_get_match_data(dev);
        if (!data)
@@ -690,8 +681,8 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
        if (ret)
                return dev_err_probe(dev, ret, "failed to parse firmware-name property\n");
 
-       rproc = rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, fw_name,
-                           sizeof(*kproc));
+       rproc = devm_rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops,
+                                fw_name, sizeof(*kproc));
        if (!rproc)
                return -ENOMEM;
 
@@ -706,56 +697,46 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
        kproc->dev = dev;
        kproc->data = data;
 
-       kproc->ti_sci = ti_sci_get_by_phandle(np, "ti,sci");
-       if (IS_ERR(kproc->ti_sci)) {
-               ret = dev_err_probe(dev, PTR_ERR(kproc->ti_sci),
-                                   "failed to get ti-sci handle\n");
-               kproc->ti_sci = NULL;
-               goto free_rproc;
-       }
+       kproc->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
+       if (IS_ERR(kproc->ti_sci))
+               return dev_err_probe(dev, PTR_ERR(kproc->ti_sci),
+                                    "failed to get ti-sci handle\n");
 
        ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id);
-       if (ret) {
-               dev_err_probe(dev, ret, "missing 'ti,sci-dev-id' property\n");
-               goto put_sci;
-       }
+       if (ret)
+               return dev_err_probe(dev, ret, "missing 'ti,sci-dev-id' property\n");
 
        kproc->reset = devm_reset_control_get_exclusive(dev, NULL);
-       if (IS_ERR(kproc->reset)) {
-               ret = dev_err_probe(dev, PTR_ERR(kproc->reset),
-                                   "failed to get reset\n");
-               goto put_sci;
-       }
+       if (IS_ERR(kproc->reset))
+               return dev_err_probe(dev, PTR_ERR(kproc->reset),
+                                    "failed to get reset\n");
 
        kproc->tsp = k3_dsp_rproc_of_get_tsp(dev, kproc->ti_sci);
-       if (IS_ERR(kproc->tsp)) {
-               ret = dev_err_probe(dev, PTR_ERR(kproc->tsp),
-                                   "failed to construct ti-sci proc control\n");
-               goto put_sci;
-       }
+       if (IS_ERR(kproc->tsp))
+               return dev_err_probe(dev, PTR_ERR(kproc->tsp),
+                                    "failed to construct ti-sci proc control\n");
 
        ret = ti_sci_proc_request(kproc->tsp);
        if (ret < 0) {
                dev_err_probe(dev, ret, "ti_sci_proc_request failed\n");
-               goto free_tsp;
+               return ret;
        }
+       ret = devm_add_action_or_reset(dev, k3_dsp_release_tsp, kproc->tsp);
+       if (ret)
+               return ret;
 
        ret = k3_dsp_rproc_of_get_memories(pdev, kproc);
        if (ret)
-               goto release_tsp;
+               return ret;
 
        ret = k3_dsp_reserved_mem_init(kproc);
-       if (ret) {
-               dev_err_probe(dev, ret, "reserved memory init failed\n");
-               goto release_tsp;
-       }
+       if (ret)
+               return dev_err_probe(dev, ret, "reserved memory init failed\n");
 
        ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id,
                                               NULL, &p_state);
-       if (ret) {
-               dev_err_probe(dev, ret, "failed to get initial state, mode cannot be determined\n");
-               goto release_mem;
-       }
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to get initial state, mode cannot be determined\n");
 
        /* configure J721E devices for either remoteproc or IPC-only mode */
        if (p_state) {
@@ -779,8 +760,7 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
                if (data->uses_lreset) {
                        ret = reset_control_status(kproc->reset);
                        if (ret < 0) {
-                               dev_err_probe(dev, ret, "failed to get reset status\n");
-                               goto release_mem;
+                               return dev_err_probe(dev, ret, "failed to get reset status\n");
                        } else if (ret == 0) {
                                dev_warn(dev, "local reset is deasserted for device\n");
                                k3_dsp_rproc_reset(kproc);
@@ -788,31 +768,13 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
                }
        }
 
-       ret = rproc_add(rproc);
-       if (ret) {
-               dev_err_probe(dev, ret, "failed to add register device with remoteproc core\n");
-               goto release_mem;
-       }
+       ret = devm_rproc_add(dev, rproc);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to add register device with remoteproc core\n");
 
        platform_set_drvdata(pdev, kproc);
 
        return 0;
-
-release_mem:
-       k3_dsp_reserved_mem_exit(kproc);
-release_tsp:
-       ret1 = ti_sci_proc_release(kproc->tsp);
-       if (ret1)
-               dev_err(dev, "failed to release proc (%pe)\n", ERR_PTR(ret1));
-free_tsp:
-       kfree(kproc->tsp);
-put_sci:
-       ret1 = ti_sci_put_handle(kproc->ti_sci);
-       if (ret1)
-               dev_err(dev, "failed to put ti_sci handle (%pe)\n", ERR_PTR(ret1));
-free_rproc:
-       rproc_free(rproc);
-       return ret;
 }
 
 static void k3_dsp_rproc_remove(struct platform_device *pdev)
@@ -824,27 +786,9 @@ static void k3_dsp_rproc_remove(struct platform_device *pdev)
 
        if (rproc->state == RPROC_ATTACHED) {
                ret = rproc_detach(rproc);
-               if (ret) {
-                       /* Note this error path leaks resources */
+               if (ret)
                        dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret));
-                       return;
-               }
        }
-
-       rproc_del(kproc->rproc);
-
-       ret = ti_sci_proc_release(kproc->tsp);
-       if (ret)
-               dev_err(dev, "failed to release proc (%pe)\n", ERR_PTR(ret));
-
-       kfree(kproc->tsp);
-
-       ret = ti_sci_put_handle(kproc->ti_sci);
-       if (ret)
-               dev_err(dev, "failed to put ti_sci handle (%pe)\n", ERR_PTR(ret));
-
-       k3_dsp_reserved_mem_exit(kproc);
-       rproc_free(kproc->rproc);
 }
 
 static const struct k3_dsp_mem_data c66_mems[] = {
index ccd59ddd76100a51d56beec797d00bfa8156440b..85b27c42cf65ba8c21c105a129391d8322cc00f0 100644 (file)
@@ -66,6 +66,15 @@ config RESET_BRCMSTB_RESCAL
          This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on
          BCM7216.
 
+config RESET_GPIO
+       tristate "GPIO reset controller"
+       help
+         This enables a generic reset controller for resets attached via
+         GPIOs.  Typically for OF platforms this driver expects "reset-gpios"
+         property.
+
+         If compiled as module, it will be called reset-gpio.
+
 config RESET_HSDK
        bool "Synopsys HSDK Reset Driver"
        depends on HAS_IOMEM
@@ -213,7 +222,7 @@ config RESET_SCMI
 
 config RESET_SIMPLE
        bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
-       default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
+       default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_SOPHGO || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
        depends on HAS_IOMEM
        help
          This enables a simple reset controller driver for reset lines that
@@ -228,6 +237,7 @@ config RESET_SIMPLE
           - RCC reset controller in STM32 MCUs
           - Allwinner SoCs
           - SiFive FU740 SoCs
+          - Sophgo SoCs
 
 config RESET_SOCFPGA
        bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
index 8270da8a4baa62a3677eaf50cbd32ffa4c9450f2..fd8b49fa46fc89a2d5f2e71ccb4e65898fab9a9b 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
 obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
 obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o
 obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
+obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
 obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
 obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
 obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o
index 4d5a78d3c085bc76cda872cc80379b2fa6135ff2..dba74e857be621b9e0b2c5ab575219191e1bf792 100644 (file)
@@ -5,14 +5,19 @@
  * Copyright 2013 Philipp Zabel, Pengutronix
  */
 #include <linux/atomic.h>
+#include <linux/cleanup.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/kref.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/idr.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/acpi.h>
+#include <linux/platform_device.h>
 #include <linux/reset.h>
 #include <linux/reset-controller.h>
 #include <linux/slab.h>
@@ -23,6 +28,11 @@ static LIST_HEAD(reset_controller_list);
 static DEFINE_MUTEX(reset_lookup_mutex);
 static LIST_HEAD(reset_lookup_list);
 
+/* Protects reset_gpio_lookup_list */
+static DEFINE_MUTEX(reset_gpio_lookup_mutex);
+static LIST_HEAD(reset_gpio_lookup_list);
+static DEFINE_IDA(reset_gpio_ida);
+
 /**
  * struct reset_control - a reset control
  * @rcdev: a pointer to the reset controller device
@@ -63,6 +73,16 @@ struct reset_control_array {
        struct reset_control *rstc[] __counted_by(num_rstcs);
 };
 
+/**
+ * struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices
+ * @of_args: phandle to the reset controller with all the args like GPIO number
+ * @list: list entry for the reset_gpio_lookup_list
+ */
+struct reset_gpio_lookup {
+       struct of_phandle_args of_args;
+       struct list_head list;
+};
+
 static const char *rcdev_name(struct reset_controller_dev *rcdev)
 {
        if (rcdev->dev)
@@ -71,6 +91,9 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
        if (rcdev->of_node)
                return rcdev->of_node->full_name;
 
+       if (rcdev->of_args)
+               return rcdev->of_args->np->full_name;
+
        return NULL;
 }
 
@@ -99,6 +122,9 @@ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
  */
 int reset_controller_register(struct reset_controller_dev *rcdev)
 {
+       if (rcdev->of_node && rcdev->of_args)
+               return -EINVAL;
+
        if (!rcdev->of_xlate) {
                rcdev->of_reset_n_cells = 1;
                rcdev->of_xlate = of_reset_simple_xlate;
@@ -813,12 +839,171 @@ static void __reset_control_put_internal(struct reset_control *rstc)
        kref_put(&rstc->refcnt, __reset_control_release);
 }
 
+static int __reset_add_reset_gpio_lookup(int id, struct device_node *np,
+                                        unsigned int gpio,
+                                        unsigned int of_flags)
+{
+       const struct fwnode_handle *fwnode = of_fwnode_handle(np);
+       unsigned int lookup_flags;
+       const char *label_tmp;
+
+       /*
+        * Later we map GPIO flags between OF and Linux, however not all
+        * constants from include/dt-bindings/gpio/gpio.h and
+        * include/linux/gpio/machine.h match each other.
+        */
+       if (of_flags > GPIO_ACTIVE_LOW) {
+               pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
+                      of_flags, gpio);
+               return -EINVAL;
+       }
+
+       struct gpio_device *gdev __free(gpio_device_put) = gpio_device_find_by_fwnode(fwnode);
+       if (!gdev)
+               return -EPROBE_DEFER;
+
+       label_tmp = gpio_device_get_label(gdev);
+       if (!label_tmp)
+               return -EINVAL;
+
+       char *label __free(kfree) = kstrdup(label_tmp, GFP_KERNEL);
+       if (!label)
+               return -ENOMEM;
+
+       /* Size: one lookup entry plus sentinel */
+       struct gpiod_lookup_table *lookup __free(kfree) = kzalloc(struct_size(lookup, table, 2),
+                                                                 GFP_KERNEL);
+       if (!lookup)
+               return -ENOMEM;
+
+       lookup->dev_id = kasprintf(GFP_KERNEL, "reset-gpio.%d", id);
+       if (!lookup->dev_id)
+               return -ENOMEM;
+
+       lookup_flags = GPIO_PERSISTENT;
+       lookup_flags |= of_flags & GPIO_ACTIVE_LOW;
+       lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset",
+                                      lookup_flags);
+
+       /* Not freed on success, because it is persisent subsystem data. */
+       gpiod_add_lookup_table(no_free_ptr(lookup));
+
+       return 0;
+}
+
+/*
+ * @args:      phandle to the GPIO provider with all the args like GPIO number
+ */
+static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
+{
+       struct reset_gpio_lookup *rgpio_dev;
+       struct platform_device *pdev;
+       int id, ret;
+
+       /*
+        * Currently only #gpio-cells=2 is supported with the meaning of:
+        * args[0]: GPIO number
+        * args[1]: GPIO flags
+        * TODO: Handle other cases.
+        */
+       if (args->args_count != 2)
+               return -ENOENT;
+
+       /*
+        * Registering reset-gpio device might cause immediate
+        * bind, resulting in its probe() registering new reset controller thus
+        * taking reset_list_mutex lock via reset_controller_register().
+        */
+       lockdep_assert_not_held(&reset_list_mutex);
+
+       mutex_lock(&reset_gpio_lookup_mutex);
+
+       list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) {
+               if (args->np == rgpio_dev->of_args.np) {
+                       if (of_phandle_args_equal(args, &rgpio_dev->of_args))
+                               goto out; /* Already on the list, done */
+               }
+       }
+
+       id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
+       if (id < 0) {
+               ret = id;
+               goto err_unlock;
+       }
+
+       /* Not freed on success, because it is persisent subsystem data. */
+       rgpio_dev = kzalloc(sizeof(*rgpio_dev), GFP_KERNEL);
+       if (!rgpio_dev) {
+               ret = -ENOMEM;
+               goto err_ida_free;
+       }
+
+       ret = __reset_add_reset_gpio_lookup(id, args->np, args->args[0],
+                                           args->args[1]);
+       if (ret < 0)
+               goto err_kfree;
+
+       rgpio_dev->of_args = *args;
+       /*
+        * We keep the device_node reference, but of_args.np is put at the end
+        * of __of_reset_control_get(), so get it one more time.
+        * Hold reference as long as rgpio_dev memory is valid.
+        */
+       of_node_get(rgpio_dev->of_args.np);
+       pdev = platform_device_register_data(NULL, "reset-gpio", id,
+                                            &rgpio_dev->of_args,
+                                            sizeof(rgpio_dev->of_args));
+       ret = PTR_ERR_OR_ZERO(pdev);
+       if (ret)
+               goto err_put;
+
+       list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
+
+out:
+       mutex_unlock(&reset_gpio_lookup_mutex);
+
+       return 0;
+
+err_put:
+       of_node_put(rgpio_dev->of_args.np);
+err_kfree:
+       kfree(rgpio_dev);
+err_ida_free:
+       ida_free(&reset_gpio_ida, id);
+err_unlock:
+       mutex_unlock(&reset_gpio_lookup_mutex);
+
+       return ret;
+}
+
+static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args,
+                                                      bool gpio_fallback)
+{
+       struct reset_controller_dev *rcdev;
+
+       lockdep_assert_held(&reset_list_mutex);
+
+       list_for_each_entry(rcdev, &reset_controller_list, list) {
+               if (gpio_fallback) {
+                       if (rcdev->of_args && of_phandle_args_equal(args,
+                                                                   rcdev->of_args))
+                               return rcdev;
+               } else {
+                       if (args->np == rcdev->of_node)
+                               return rcdev;
+               }
+       }
+
+       return NULL;
+}
+
 struct reset_control *
 __of_reset_control_get(struct device_node *node, const char *id, int index,
                       bool shared, bool optional, bool acquired)
 {
+       bool gpio_fallback = false;
        struct reset_control *rstc;
-       struct reset_controller_dev *r, *rcdev;
+       struct reset_controller_dev *rcdev;
        struct of_phandle_args args;
        int rstc_id;
        int ret;
@@ -839,39 +1024,52 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
                                         index, &args);
        if (ret == -EINVAL)
                return ERR_PTR(ret);
-       if (ret)
-               return optional ? NULL : ERR_PTR(ret);
+       if (ret) {
+               if (!IS_ENABLED(CONFIG_RESET_GPIO))
+                       return optional ? NULL : ERR_PTR(ret);
 
-       mutex_lock(&reset_list_mutex);
-       rcdev = NULL;
-       list_for_each_entry(r, &reset_controller_list, list) {
-               if (args.np == r->of_node) {
-                       rcdev = r;
-                       break;
+               /*
+                * There can be only one reset-gpio for regular devices, so
+                * don't bother with the "reset-gpios" phandle index.
+                */
+               ret = of_parse_phandle_with_args(node, "reset-gpios", "#gpio-cells",
+                                                0, &args);
+               if (ret)
+                       return optional ? NULL : ERR_PTR(ret);
+
+               gpio_fallback = true;
+
+               ret = __reset_add_reset_gpio_device(&args);
+               if (ret) {
+                       rstc = ERR_PTR(ret);
+                       goto out_put;
                }
        }
 
+       mutex_lock(&reset_list_mutex);
+       rcdev = __reset_find_rcdev(&args, gpio_fallback);
        if (!rcdev) {
                rstc = ERR_PTR(-EPROBE_DEFER);
-               goto out;
+               goto out_unlock;
        }
 
        if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
                rstc = ERR_PTR(-EINVAL);
-               goto out;
+               goto out_unlock;
        }
 
        rstc_id = rcdev->of_xlate(rcdev, &args);
        if (rstc_id < 0) {
                rstc = ERR_PTR(rstc_id);
-               goto out;
+               goto out_unlock;
        }
 
        /* reset_list_mutex also protects the rcdev's reset_control list */
        rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired);
 
-out:
+out_unlock:
        mutex_unlock(&reset_list_mutex);
+out_put:
        of_node_put(args.np);
 
        return rstc;
diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c
new file mode 100644 (file)
index 0000000..2290b25
--- /dev/null
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+struct reset_gpio_priv {
+       struct reset_controller_dev rc;
+       struct gpio_desc *reset;
+};
+
+static inline struct reset_gpio_priv
+*rc_to_reset_gpio(struct reset_controller_dev *rc)
+{
+       return container_of(rc, struct reset_gpio_priv, rc);
+}
+
+static int reset_gpio_assert(struct reset_controller_dev *rc, unsigned long id)
+{
+       struct reset_gpio_priv *priv = rc_to_reset_gpio(rc);
+
+       gpiod_set_value_cansleep(priv->reset, 1);
+
+       return 0;
+}
+
+static int reset_gpio_deassert(struct reset_controller_dev *rc,
+                              unsigned long id)
+{
+       struct reset_gpio_priv *priv = rc_to_reset_gpio(rc);
+
+       gpiod_set_value_cansleep(priv->reset, 0);
+
+       return 0;
+}
+
+static int reset_gpio_status(struct reset_controller_dev *rc, unsigned long id)
+{
+       struct reset_gpio_priv *priv = rc_to_reset_gpio(rc);
+
+       return gpiod_get_value_cansleep(priv->reset);
+}
+
+static const struct reset_control_ops reset_gpio_ops = {
+       .assert = reset_gpio_assert,
+       .deassert = reset_gpio_deassert,
+       .status = reset_gpio_status,
+};
+
+static int reset_gpio_of_xlate(struct reset_controller_dev *rcdev,
+                              const struct of_phandle_args *reset_spec)
+{
+       return reset_spec->args[0];
+}
+
+static void reset_gpio_of_node_put(void *data)
+{
+       of_node_put(data);
+}
+
+static int reset_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct of_phandle_args *platdata = dev_get_platdata(dev);
+       struct reset_gpio_priv *priv;
+       int ret;
+
+       if (!platdata)
+               return -EINVAL;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, &priv->rc);
+
+       priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(priv->reset))
+               return dev_err_probe(dev, PTR_ERR(priv->reset),
+                                    "Could not get reset gpios\n");
+
+       priv->rc.ops = &reset_gpio_ops;
+       priv->rc.owner = THIS_MODULE;
+       priv->rc.dev = dev;
+       priv->rc.of_args = platdata;
+       ret = devm_add_action_or_reset(dev, reset_gpio_of_node_put,
+                                      priv->rc.of_node);
+       if (ret)
+               return ret;
+
+       /* Cells to match GPIO specifier, but it's not really used */
+       priv->rc.of_reset_n_cells = 2;
+       priv->rc.of_xlate = reset_gpio_of_xlate;
+       priv->rc.nr_resets = 1;
+
+       return devm_reset_controller_register(dev, &priv->rc);
+}
+
+static const struct platform_device_id reset_gpio_ids[] = {
+       { .name = "reset-gpio", },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, reset_gpio_ids);
+
+static struct platform_driver reset_gpio_driver = {
+       .probe          = reset_gpio_probe,
+       .id_table       = reset_gpio_ids,
+       .driver = {
+               .name = "reset-gpio",
+       },
+};
+module_platform_driver(reset_gpio_driver);
+
+MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
+MODULE_DESCRIPTION("Generic GPIO reset driver");
+MODULE_LICENSE("GPL");
index 818cabcc9fb7527d5f1d4fe5ca9f99af85e19485..27606783983086ec7cd63852642137a6107adb8e 100644 (file)
@@ -151,6 +151,8 @@ static const struct of_device_id reset_simple_dt_ids[] = {
        { .compatible = "snps,dw-high-reset" },
        { .compatible = "snps,dw-low-reset",
                .data = &reset_simple_active_low },
+       { .compatible = "sophgo,sg2042-reset",
+               .data = &reset_simple_active_low },
        { /* sentinel */ },
 };
 
index 09833ad05da75cb6ca91f53e4e425cac7fad6fc9..1cb8d7474428afabc65071c2f543bb483736229c 100644 (file)
@@ -399,8 +399,8 @@ static void rpmsg_eptdev_release_device(struct device *dev)
 {
        struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
 
-       ida_simple_remove(&rpmsg_ept_ida, dev->id);
-       ida_simple_remove(&rpmsg_minor_ida, MINOR(eptdev->dev.devt));
+       ida_free(&rpmsg_ept_ida, dev->id);
+       ida_free(&rpmsg_minor_ida, MINOR(eptdev->dev.devt));
        kfree(eptdev);
 }
 
@@ -441,12 +441,12 @@ static int rpmsg_chrdev_eptdev_add(struct rpmsg_eptdev *eptdev, struct rpmsg_cha
 
        eptdev->chinfo = chinfo;
 
-       ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
+       ret = ida_alloc_max(&rpmsg_minor_ida, RPMSG_DEV_MAX - 1, GFP_KERNEL);
        if (ret < 0)
                goto free_eptdev;
        dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
 
-       ret = ida_simple_get(&rpmsg_ept_ida, 0, 0, GFP_KERNEL);
+       ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL);
        if (ret < 0)
                goto free_minor_ida;
        dev->id = ret;
@@ -462,9 +462,9 @@ static int rpmsg_chrdev_eptdev_add(struct rpmsg_eptdev *eptdev, struct rpmsg_cha
        return ret;
 
 free_ept_ida:
-       ida_simple_remove(&rpmsg_ept_ida, dev->id);
+       ida_free(&rpmsg_ept_ida, dev->id);
 free_minor_ida:
-       ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+       ida_free(&rpmsg_minor_ida, MINOR(dev->devt));
 free_eptdev:
        put_device(dev);
        kfree(eptdev);
index 8abc7d022ff71ab7ea6f54eff5c712b89382cf38..4295c01a2861bc04a817aeaa7de857930db9b08a 100644 (file)
@@ -605,7 +605,7 @@ static void rpmsg_dev_remove(struct device *dev)
                rpmsg_destroy_ept(rpdev->ept);
 }
 
-static struct bus_type rpmsg_bus = {
+static const struct bus_type rpmsg_bus = {
        .name           = "rpmsg",
        .match          = rpmsg_dev_match,
        .dev_groups     = rpmsg_dev_groups,
index 433253835690806a8f75749a2e2d6e79e33ab8e2..c312794ba4b3f094295bc758812b90859132fa8c 100644 (file)
@@ -130,8 +130,8 @@ static void rpmsg_ctrldev_release_device(struct device *dev)
 {
        struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
 
-       ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
-       ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+       ida_free(&rpmsg_ctrl_ida, dev->id);
+       ida_free(&rpmsg_minor_ida, MINOR(dev->devt));
        kfree(ctrldev);
 }
 
@@ -156,12 +156,12 @@ static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev)
        cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
        ctrldev->cdev.owner = THIS_MODULE;
 
-       ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
+       ret = ida_alloc_max(&rpmsg_minor_ida, RPMSG_DEV_MAX - 1, GFP_KERNEL);
        if (ret < 0)
                goto free_ctrldev;
        dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
 
-       ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
+       ret = ida_alloc(&rpmsg_ctrl_ida, GFP_KERNEL);
        if (ret < 0)
                goto free_minor_ida;
        dev->id = ret;
@@ -179,9 +179,9 @@ static int rpmsg_ctrldev_probe(struct rpmsg_device *rpdev)
        return ret;
 
 free_ctrl_ida:
-       ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+       ida_free(&rpmsg_ctrl_ida, dev->id);
 free_minor_ida:
-       ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+       ida_free(&rpmsg_minor_ida, MINOR(dev->devt));
 free_ctrldev:
        put_device(dev);
        kfree(ctrldev);
index e37a4341f442d8ca2fcd80e82bd2adf6c2ca9ea5..c63e32d012f23cb33687b783b7c50fc32bfcce17 100644 (file)
@@ -1858,7 +1858,8 @@ config RTC_DRV_MT2712
 
 config RTC_DRV_MT6397
        tristate "MediaTek PMIC based RTC"
-       depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
+       depends on MFD_MT6397 || COMPILE_TEST
+       select IRQ_DOMAIN
        help
          This selects the MediaTek(R) RTC driver. RTC is part of MediaTek
          MT6397 PMIC. You should enable MT6397 PMIC MFD before select
index 921ee182797439b1496239c93b5d9e8ed76a0b45..e31fa0ad127e9545afac745a621d4ccbcd5fca28 100644 (file)
@@ -21,7 +21,6 @@
 #include "rtc-core.h"
 
 static DEFINE_IDA(rtc_ida);
-struct class *rtc_class;
 
 static void rtc_device_release(struct device *dev)
 {
@@ -199,6 +198,11 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
 #define RTC_CLASS_DEV_PM_OPS   NULL
 #endif
 
+const struct class rtc_class = {
+       .name = "rtc",
+       .pm = RTC_CLASS_DEV_PM_OPS,
+};
+
 /* Ensure the caller will set the id before releasing the device */
 static struct rtc_device *rtc_allocate_device(void)
 {
@@ -220,7 +224,7 @@ static struct rtc_device *rtc_allocate_device(void)
 
        rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
-       rtc->dev.class = rtc_class;
+       rtc->dev.class = &rtc_class;
        rtc->dev.groups = rtc_get_dev_attribute_groups();
        rtc->dev.release = rtc_device_release;
 
@@ -475,13 +479,14 @@ EXPORT_SYMBOL_GPL(devm_rtc_device_register);
 
 static int __init rtc_init(void)
 {
-       rtc_class = class_create("rtc");
-       if (IS_ERR(rtc_class)) {
-               pr_err("couldn't create class\n");
-               return PTR_ERR(rtc_class);
-       }
-       rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
+       int err;
+
+       err = class_register(&rtc_class);
+       if (err)
+               return err;
+
        rtc_dev_init();
+
        return 0;
 }
 subsys_initcall(rtc_init);
index 1b63111cdda2e91b880c5270dbde42c79f1a3b92..5faafb4aa55cc3c1bdc104df389e7ceb5f3063a3 100644 (file)
@@ -696,7 +696,7 @@ struct rtc_device *rtc_class_open(const char *name)
        struct device *dev;
        struct rtc_device *rtc = NULL;
 
-       dev = class_find_device_by_name(rtc_class, name);
+       dev = class_find_device_by_name(&rtc_class, name);
        if (dev)
                rtc = to_rtc_device(dev);
 
index 1109cad83838496d92cd328bc14213f50f2c4413..8b087d9556bee8b837e16a16e6220de8fa381693 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 
-enum ds1511reg {
-       DS1511_SEC = 0x0,
-       DS1511_MIN = 0x1,
-       DS1511_HOUR = 0x2,
-       DS1511_DOW = 0x3,
-       DS1511_DOM = 0x4,
-       DS1511_MONTH = 0x5,
-       DS1511_YEAR = 0x6,
-       DS1511_CENTURY = 0x7,
-       DS1511_AM1_SEC = 0x8,
-       DS1511_AM2_MIN = 0x9,
-       DS1511_AM3_HOUR = 0xa,
-       DS1511_AM4_DATE = 0xb,
-       DS1511_WD_MSEC = 0xc,
-       DS1511_WD_SEC = 0xd,
-       DS1511_CONTROL_A = 0xe,
-       DS1511_CONTROL_B = 0xf,
-       DS1511_RAMADDR_LSB = 0x10,
-       DS1511_RAMDATA = 0x13
-};
+#define DS1511_SEC             0x0
+#define DS1511_MIN             0x1
+#define DS1511_HOUR            0x2
+#define DS1511_DOW             0x3
+#define DS1511_DOM             0x4
+#define DS1511_MONTH           0x5
+#define DS1511_YEAR            0x6
+#define DS1511_CENTURY         0x7
+#define DS1511_AM1_SEC         0x8
+#define DS1511_AM2_MIN         0x9
+#define DS1511_AM3_HOUR                0xa
+#define DS1511_AM4_DATE                0xb
+#define DS1511_WD_MSEC         0xc
+#define DS1511_WD_SEC          0xd
+#define DS1511_CONTROL_A       0xe
+#define DS1511_CONTROL_B       0xf
+#define DS1511_RAMADDR_LSB     0x10
+#define DS1511_RAMDATA         0x13
 
 #define DS1511_BLF1    0x80
 #define DS1511_BLF2    0x40
@@ -61,35 +59,10 @@ enum ds1511reg {
 #define DS1511_WDS     0x01
 #define DS1511_RAM_MAX 0x100
 
-#define RTC_CMD                DS1511_CONTROL_B
-#define RTC_CMD1       DS1511_CONTROL_A
-
-#define RTC_ALARM_SEC  DS1511_AM1_SEC
-#define RTC_ALARM_MIN  DS1511_AM2_MIN
-#define RTC_ALARM_HOUR DS1511_AM3_HOUR
-#define RTC_ALARM_DATE DS1511_AM4_DATE
-
-#define RTC_SEC                DS1511_SEC
-#define RTC_MIN                DS1511_MIN
-#define RTC_HOUR       DS1511_HOUR
-#define RTC_DOW                DS1511_DOW
-#define RTC_DOM                DS1511_DOM
-#define RTC_MON                DS1511_MONTH
-#define RTC_YEAR       DS1511_YEAR
-#define RTC_CENTURY    DS1511_CENTURY
-
-#define RTC_TIE        DS1511_TIE
-#define RTC_TE DS1511_TE
-
-struct rtc_plat_data {
+struct ds1511_data {
        struct rtc_device *rtc;
        void __iomem *ioaddr;           /* virtual base address */
        int irq;
-       unsigned int irqen;
-       int alrm_sec;
-       int alrm_min;
-       int alrm_hour;
-       int alrm_mday;
        spinlock_t lock;
 };
 
@@ -98,95 +71,33 @@ static DEFINE_SPINLOCK(ds1511_lock);
 static __iomem char *ds1511_base;
 static u32 reg_spacing = 1;
 
-static noinline void
-rtc_write(uint8_t val, uint32_t reg)
+static void rtc_write(uint8_t val, uint32_t reg)
 {
        writeb(val, ds1511_base + (reg * reg_spacing));
 }
 
-static noinline uint8_t
-rtc_read(enum ds1511reg reg)
+static uint8_t rtc_read(uint32_t reg)
 {
        return readb(ds1511_base + (reg * reg_spacing));
 }
 
-static inline void
-rtc_disable_update(void)
+static void rtc_disable_update(void)
 {
-       rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
+       rtc_write((rtc_read(DS1511_CONTROL_B) & ~DS1511_TE), DS1511_CONTROL_B);
 }
 
-static void
-rtc_enable_update(void)
+static void rtc_enable_update(void)
 {
-       rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
-}
-
-/*
- * #define DS1511_WDOG_RESET_SUPPORT
- *
- * Uncomment this if you want to use these routines in
- * some platform code.
- */
-#ifdef DS1511_WDOG_RESET_SUPPORT
-/*
- * just enough code to set the watchdog timer so that it
- * will reboot the system
- */
-void
-ds1511_wdog_set(unsigned long deciseconds)
-{
-       /*
-        * the wdog timer can take 99.99 seconds
-        */
-       deciseconds %= 10000;
-       /*
-        * set the wdog values in the wdog registers
-        */
-       rtc_write(bin2bcd(deciseconds % 100), DS1511_WD_MSEC);
-       rtc_write(bin2bcd(deciseconds / 100), DS1511_WD_SEC);
-       /*
-        * set wdog enable and wdog 'steering' bit to issue a reset
-        */
-       rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD);
-}
-
-void
-ds1511_wdog_disable(void)
-{
-       /*
-        * clear wdog enable and wdog 'steering' bits
-        */
-       rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
-       /*
-        * clear the wdog counter
-        */
-       rtc_write(0, DS1511_WD_MSEC);
-       rtc_write(0, DS1511_WD_SEC);
+       rtc_write((rtc_read(DS1511_CONTROL_B) | DS1511_TE), DS1511_CONTROL_B);
 }
-#endif
 
-/*
- * set the rtc chip's idea of the time.
- * stupidly, some callers call with year unmolested;
- * and some call with  year = year - 1900.  thanks.
- */
 static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
 {
        u8 mon, day, dow, hrs, min, sec, yrs, cen;
        unsigned long flags;
 
-       /*
-        * won't have to change this for a while
-        */
-       if (rtc_tm->tm_year < 1900)
-               rtc_tm->tm_year += 1900;
-
-       if (rtc_tm->tm_year < 1970)
-               return -EINVAL;
-
        yrs = rtc_tm->tm_year % 100;
-       cen = rtc_tm->tm_year / 100;
+       cen = 19 + rtc_tm->tm_year / 100;
        mon = rtc_tm->tm_mon + 1;   /* tm_mon starts at zero */
        day = rtc_tm->tm_mday;
        dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
@@ -194,15 +105,6 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
        min = rtc_tm->tm_min;
        sec = rtc_tm->tm_sec;
 
-       if ((mon > 12) || (day == 0))
-               return -EINVAL;
-
-       if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year))
-               return -EINVAL;
-
-       if ((hrs >= 24) || (min >= 60) || (sec >= 60))
-               return -EINVAL;
-
        /*
         * each register is a different number of valid bits
         */
@@ -216,14 +118,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
 
        spin_lock_irqsave(&ds1511_lock, flags);
        rtc_disable_update();
-       rtc_write(cen, RTC_CENTURY);
-       rtc_write(yrs, RTC_YEAR);
-       rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
-       rtc_write(day, RTC_DOM);
-       rtc_write(hrs, RTC_HOUR);
-       rtc_write(min, RTC_MIN);
-       rtc_write(sec, RTC_SEC);
-       rtc_write(dow, RTC_DOW);
+       rtc_write(cen, DS1511_CENTURY);
+       rtc_write(yrs, DS1511_YEAR);
+       rtc_write((rtc_read(DS1511_MONTH) & 0xe0) | mon, DS1511_MONTH);
+       rtc_write(day, DS1511_DOM);
+       rtc_write(hrs, DS1511_HOUR);
+       rtc_write(min, DS1511_MIN);
+       rtc_write(sec, DS1511_SEC);
+       rtc_write(dow, DS1511_DOW);
        rtc_enable_update();
        spin_unlock_irqrestore(&ds1511_lock, flags);
 
@@ -238,14 +140,14 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
        spin_lock_irqsave(&ds1511_lock, flags);
        rtc_disable_update();
 
-       rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
-       rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
-       rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
-       rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
-       rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
-       rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
-       rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
-       century = rtc_read(RTC_CENTURY);
+       rtc_tm->tm_sec = rtc_read(DS1511_SEC) & 0x7f;
+       rtc_tm->tm_min = rtc_read(DS1511_MIN) & 0x7f;
+       rtc_tm->tm_hour = rtc_read(DS1511_HOUR) & 0x3f;
+       rtc_tm->tm_mday = rtc_read(DS1511_DOM) & 0x3f;
+       rtc_tm->tm_wday = rtc_read(DS1511_DOW) & 0x7;
+       rtc_tm->tm_mon = rtc_read(DS1511_MONTH) & 0x1f;
+       rtc_tm->tm_year = rtc_read(DS1511_YEAR) & 0x7f;
+       century = rtc_read(DS1511_CENTURY);
 
        rtc_enable_update();
        spin_unlock_irqrestore(&ds1511_lock, flags);
@@ -271,106 +173,67 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
        return 0;
 }
 
-/*
- * write the alarm register settings
- *
- * we only have the use to interrupt every second, otherwise
- * known as the update interrupt, or the interrupt if the whole
- * date/hours/mins/secs matches.  the ds1511 has many more
- * permutations, but the kernel doesn't.
- */
-static void
-ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+static void ds1511_rtc_alarm_enable(unsigned int enabled)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->lock, flags);
-       rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
-              0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,
-              RTC_ALARM_DATE);
-       rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
-              0x80 : bin2bcd(pdata->alrm_hour) & 0x3f,
-              RTC_ALARM_HOUR);
-       rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
-              0x80 : bin2bcd(pdata->alrm_min) & 0x7f,
-              RTC_ALARM_MIN);
-       rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
-              0x80 : bin2bcd(pdata->alrm_sec) & 0x7f,
-              RTC_ALARM_SEC);
-       rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
-       rtc_read(RTC_CMD1);     /* clear interrupts */
-       spin_unlock_irqrestore(&pdata->lock, flags);
+       rtc_write(rtc_read(DS1511_CONTROL_B) | (enabled ? DS1511_TIE : 0), DS1511_CONTROL_B);
 }
 
-static int
-ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+static int ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
-       struct rtc_plat_data *pdata = dev_get_drvdata(dev);
+       struct ds1511_data *ds1511 = dev_get_drvdata(dev);
+       unsigned long flags;
 
-       if (pdata->irq <= 0)
-               return -EINVAL;
+       spin_lock_irqsave(&ds1511->lock, flags);
+       rtc_write(bin2bcd(alrm->time.tm_mday) & 0x3f, DS1511_AM4_DATE);
+       rtc_write(bin2bcd(alrm->time.tm_hour) & 0x3f, DS1511_AM3_HOUR);
+       rtc_write(bin2bcd(alrm->time.tm_min) & 0x7f, DS1511_AM2_MIN);
+       rtc_write(bin2bcd(alrm->time.tm_sec) & 0x7f, DS1511_AM1_SEC);
+       ds1511_rtc_alarm_enable(alrm->enabled);
 
-       pdata->alrm_mday = alrm->time.tm_mday;
-       pdata->alrm_hour = alrm->time.tm_hour;
-       pdata->alrm_min = alrm->time.tm_min;
-       pdata->alrm_sec = alrm->time.tm_sec;
-       if (alrm->enabled)
-               pdata->irqen |= RTC_AF;
+       rtc_read(DS1511_CONTROL_A);     /* clear interrupts */
+       spin_unlock_irqrestore(&ds1511->lock, flags);
 
-       ds1511_rtc_update_alarm(pdata);
        return 0;
 }
 
-static int
-ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+static int ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
-       struct rtc_plat_data *pdata = dev_get_drvdata(dev);
-
-       if (pdata->irq <= 0)
-               return -EINVAL;
+       alrm->time.tm_mday = bcd2bin(rtc_read(DS1511_AM4_DATE) & 0x3f);
+       alrm->time.tm_hour = bcd2bin(rtc_read(DS1511_AM3_HOUR) & 0x3f);
+       alrm->time.tm_min = bcd2bin(rtc_read(DS1511_AM2_MIN) & 0x7f);
+       alrm->time.tm_sec = bcd2bin(rtc_read(DS1511_AM1_SEC) & 0x7f);
+       alrm->enabled = !!(rtc_read(DS1511_CONTROL_B) & DS1511_TIE);
 
-       alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
-       alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
-       alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
-       alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
-       alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
        return 0;
 }
 
-static irqreturn_t
-ds1511_interrupt(int irq, void *dev_id)
+static irqreturn_t ds1511_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+       struct ds1511_data *ds1511 = platform_get_drvdata(pdev);
        unsigned long events = 0;
 
-       spin_lock(&pdata->lock);
+       spin_lock(&ds1511->lock);
        /*
         * read and clear interrupt
         */
-       if (rtc_read(RTC_CMD1) & DS1511_IRQF) {
-               events = RTC_IRQF;
-               if (rtc_read(RTC_ALARM_SEC) & 0x80)
-                       events |= RTC_UF;
-               else
-                       events |= RTC_AF;
-               rtc_update_irq(pdata->rtc, 1, events);
+       if (rtc_read(DS1511_CONTROL_A) & DS1511_IRQF) {
+               events = RTC_IRQF | RTC_AF;
+               rtc_update_irq(ds1511->rtc, 1, events);
        }
-       spin_unlock(&pdata->lock);
+       spin_unlock(&ds1511->lock);
        return events ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       struct rtc_plat_data *pdata = dev_get_drvdata(dev);
-
-       if (pdata->irq <= 0)
-               return -EINVAL;
-       if (enabled)
-               pdata->irqen |= RTC_AF;
-       else
-               pdata->irqen &= ~RTC_AF;
-       ds1511_rtc_update_alarm(pdata);
+       struct ds1511_data *ds1511 = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ds1511->lock, flags);
+       ds1511_rtc_alarm_enable(enabled);
+       spin_unlock_irqrestore(&ds1511->lock, flags);
+
        return 0;
 }
 
@@ -408,7 +271,7 @@ static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
 
 static int ds1511_rtc_probe(struct platform_device *pdev)
 {
-       struct rtc_plat_data *pdata;
+       struct ds1511_data *ds1511;
        int ret = 0;
        struct nvmem_config ds1511_nvmem_cfg = {
                .name = "ds1511_nvram",
@@ -420,21 +283,21 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
                .priv = &pdev->dev,
        };
 
-       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-       if (!pdata)
+       ds1511 = devm_kzalloc(&pdev->dev, sizeof(*ds1511), GFP_KERNEL);
+       if (!ds1511)
                return -ENOMEM;
 
        ds1511_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(ds1511_base))
                return PTR_ERR(ds1511_base);
-       pdata->ioaddr = ds1511_base;
-       pdata->irq = platform_get_irq(pdev, 0);
+       ds1511->ioaddr = ds1511_base;
+       ds1511->irq = platform_get_irq(pdev, 0);
 
        /*
         * turn on the clock and the crystal, etc.
         */
-       rtc_write(DS1511_BME, RTC_CMD);
-       rtc_write(0, RTC_CMD1);
+       rtc_write(DS1511_BME, DS1511_CONTROL_B);
+       rtc_write(0, DS1511_CONTROL_A);
        /*
         * clear the wdog counter
         */
@@ -448,38 +311,43 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
        /*
         * check for a dying bat-tree
         */
-       if (rtc_read(RTC_CMD1) & DS1511_BLF1)
+       if (rtc_read(DS1511_CONTROL_A) & DS1511_BLF1)
                dev_warn(&pdev->dev, "voltage-low detected.\n");
 
-       spin_lock_init(&pdata->lock);
-       platform_set_drvdata(pdev, pdata);
-
-       pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
-       if (IS_ERR(pdata->rtc))
-               return PTR_ERR(pdata->rtc);
-
-       pdata->rtc->ops = &ds1511_rtc_ops;
+       spin_lock_init(&ds1511->lock);
+       platform_set_drvdata(pdev, ds1511);
 
-       ret = devm_rtc_register_device(pdata->rtc);
-       if (ret)
-               return ret;
+       ds1511->rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(ds1511->rtc))
+               return PTR_ERR(ds1511->rtc);
 
-       devm_rtc_nvmem_register(pdata->rtc, &ds1511_nvmem_cfg);
+       ds1511->rtc->ops = &ds1511_rtc_ops;
+       ds1511->rtc->range_max = RTC_TIMESTAMP_END_2099;
+       ds1511->rtc->alarm_offset_max = 28 * 24 * 60 * 60 - 1;
 
        /*
         * if the platform has an interrupt in mind for this device,
         * then by all means, set it
         */
-       if (pdata->irq > 0) {
-               rtc_read(RTC_CMD1);
-               if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
+       if (ds1511->irq > 0) {
+               rtc_read(DS1511_CONTROL_A);
+               if (devm_request_irq(&pdev->dev, ds1511->irq, ds1511_interrupt,
                        IRQF_SHARED, pdev->name, pdev) < 0) {
 
                        dev_warn(&pdev->dev, "interrupt not available.\n");
-                       pdata->irq = 0;
+                       ds1511->irq = 0;
                }
        }
 
+       if (ds1511->irq == 0)
+               clear_bit(RTC_FEATURE_ALARM, ds1511->rtc->features);
+
+       ret = devm_rtc_register_device(ds1511->rtc);
+       if (ret)
+               return ret;
+
+       devm_rtc_nvmem_register(ds1511->rtc, &ds1511_nvmem_cfg);
+
        return 0;
 }
 
index 866489ad56d67db1b5a69c4b9e7bc294b864c7f4..0013bff0447d5b8df1e5a801a69414184d0f84d8 100644 (file)
@@ -909,10 +909,7 @@ static int m41t80_probe(struct i2c_client *client)
        if (IS_ERR(m41t80_data->rtc))
                return PTR_ERR(m41t80_data->rtc);
 
-#ifdef CONFIG_OF
-       wakeup_source = of_property_read_bool(client->dev.of_node,
-                                             "wakeup-source");
-#endif
+       wakeup_source = device_property_read_bool(&client->dev, "wakeup-source");
        if (client->irq > 0) {
                unsigned long irqflags = IRQF_TRIGGER_LOW;
 
index 402fda8fd54884eb8d1485ab456de696049dc510..a2441e5c2c74d6f452646b68f6df706447bd486d 100644 (file)
@@ -204,7 +204,7 @@ static bool max31335_volatile_reg(struct device *dev, unsigned int reg)
                return true;
 
        /* interrupt status register */
-       if (reg == MAX31335_INT_EN1_A1IE)
+       if (reg == MAX31335_STATUS1)
                return true;
 
        /* temperature registers */
index f488a189a4651ffead1bbcc1e4e9d3a5cd01d5df..076d8b99f91314ca221ee7c7477403bd94987a98 100644 (file)
@@ -102,6 +102,8 @@ static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *ala
                if (flags < 0)
                        return flags;
                *alarm_enable = flags & NCT3018Y_BIT_AIE;
+               dev_dbg(&client->dev, "%s:alarm_enable:%x\n", __func__, *alarm_enable);
+
        }
 
        if (alarm_flag) {
@@ -110,11 +112,9 @@ static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *ala
                if (flags < 0)
                        return flags;
                *alarm_flag = flags & NCT3018Y_BIT_AF;
+               dev_dbg(&client->dev, "%s:alarm_flag:%x\n", __func__, *alarm_flag);
        }
 
-       dev_dbg(&client->dev, "%s:alarm_enable:%x alarm_flag:%x\n",
-               __func__, *alarm_enable, *alarm_flag);
-
        return 0;
 }
 
index d1efde3e7a8094e01b4f34b66f2f5990258ca3cb..98b77f790b0c5a63595caacd6a17ba6ba4e3b222 100644 (file)
@@ -370,6 +370,30 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset)
        return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value);
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pcf8523_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (client->irq > 0 && device_may_wakeup(dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int pcf8523_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (client->irq > 0 && device_may_wakeup(dev))
+               disable_irq_wake(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pcf8523_pm, pcf8523_suspend, pcf8523_resume);
+
 static const struct rtc_class_ops pcf8523_rtc_ops = {
        .read_time = pcf8523_rtc_read_time,
        .set_time = pcf8523_rtc_set_time,
@@ -487,6 +511,7 @@ static struct i2c_driver pcf8523_driver = {
        .driver = {
                .name = "rtc-pcf8523",
                .of_match_table = pcf8523_of_match,
+               .pm = &pcf8523_pm,
        },
        .probe = pcf8523_probe,
        .id_table = pcf8523_id,
index cead018c3f06a5917396561321ef354b8db6acc3..0a97cfedd7060ace133224fe718d401cb4a7fda7 100644 (file)
@@ -3976,7 +3976,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
 
        ccw = cqr->cpaddr;
        ccw->cmd_code = CCW_CMD_RDC;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        ccw->flags = 0;
        ccw->count = rdc_buffer_size;
        cqr->startdev = device;
@@ -4020,7 +4020,7 @@ char *dasd_get_sense(struct irb *irb)
 
        if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) {
                if (irb->scsw.tm.tcw)
-                       tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw));
+                       tsb = tcw_get_tsb(dma32_to_virt(irb->scsw.tm.tcw));
                if (tsb && tsb->length == 64 && tsb->flags)
                        switch (tsb->flags & 0x07) {
                        case 1: /* tsa_iostat */
index 459b7f8ac8837283fc07e6257bd871f407008d08..bbbacfc386f28d92ae2ab9e2091d8178328d6d55 100644 (file)
@@ -216,7 +216,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
        memset(ccw, 0, sizeof(struct ccw1));
        ccw->cmd_code = CCW_CMD_DCTL;
        ccw->count = 4;
-       ccw->cda = (__u32)virt_to_phys(DCTL_data);
+       ccw->cda = virt_to_dma32(DCTL_data);
        dctl_cqr->flags = erp->flags;
        dctl_cqr->function = dasd_3990_erp_DCTL;
        dctl_cqr->refers = erp;
@@ -1589,7 +1589,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 {
 
        struct dasd_device *device = default_erp->startdev;
-       __u32 cpa = 0;
+       dma32_t cpa = 0;
        struct dasd_ccw_req *cqr;
        struct dasd_ccw_req *erp;
        struct DE_eckd_data *DE_data;
@@ -1693,7 +1693,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
        ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 16;
-       ccw->cda = (__u32)virt_to_phys(DE_data);
+       ccw->cda = virt_to_dma32(DE_data);
 
        /* create LO ccw */
        ccw++;
@@ -1701,7 +1701,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
        ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 16;
-       ccw->cda = (__u32)virt_to_phys(LO_data);
+       ccw->cda = virt_to_dma32(LO_data);
 
        /* TIC to the failed ccw */
        ccw++;
@@ -1747,7 +1747,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 {
 
        struct dasd_device *device = previous_erp->startdev;
-       __u32 cpa = 0;
+       dma32_t cpa = 0;
        struct dasd_ccw_req *cqr;
        struct dasd_ccw_req *erp;
        char *LO_data;          /* struct LO_eckd_data */
@@ -2386,7 +2386,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
                tcw = erp->cpaddr;
                tsb = (struct tsb *) &tcw[1];
                *tcw = *((struct tcw *)cqr->cpaddr);
-               tcw->tsb = virt_to_phys(tsb);
+               tcw->tsb = virt_to_dma64(tsb);
        } else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) {
                /* PSF cannot be chained from NOOP/TIC */
                erp->cpaddr = cqr->cpaddr;
@@ -2397,7 +2397,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
                ccw->flags = CCW_FLAG_CC;
                ccw++;
                ccw->cmd_code = CCW_CMD_TIC;
-               ccw->cda      = (__u32)virt_to_phys(cqr->cpaddr);
+               ccw->cda      = virt_to_dma32(cqr->cpaddr);
        }
 
        erp->flags = cqr->flags;
index e84cd5436556392de9c63d78470cc3c48f578d16..f7e768d8ca76643e506abd30b4c6835687f18cb9 100644 (file)
@@ -435,7 +435,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
        ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - feature codes */
        memset(lcu->uac, 0, sizeof(*(lcu->uac)));
@@ -443,7 +443,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
        ccw++;
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(*(lcu->uac));
-       ccw->cda = (__u32)virt_to_phys(lcu->uac);
+       ccw->cda = virt_to_dma32(lcu->uac);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -739,7 +739,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,
        ccw->cmd_code = DASD_ECKD_CCW_RSCK;
        ccw->flags = CCW_FLAG_SLI;
        ccw->count = 16;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        ((char *)cqr->data)[0] = reason;
 
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
index 373c1a86c33ed5d7b760087a6669315bfa35182d..180a008d38eaaffbea289e26540d4a38f6f0fb0e 100644 (file)
@@ -283,7 +283,7 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
                ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
                ccw->flags = 0;
                ccw->count = 16;
-               ccw->cda = (__u32)virt_to_phys(data);
+               ccw->cda = virt_to_dma32(data);
        }
 
        memset(data, 0, sizeof(struct DE_eckd_data));
@@ -393,7 +393,7 @@ static void locate_record_ext(struct ccw1 *ccw, struct LRE_eckd_data *data,
                        ccw->count = 22;
                else
                        ccw->count = 20;
-               ccw->cda = (__u32)virt_to_phys(data);
+               ccw->cda = virt_to_dma32(data);
        }
 
        memset(data, 0, sizeof(*data));
@@ -539,11 +539,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
        ccw->flags = 0;
        if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) {
                ccw->count = sizeof(*pfxdata) + 2;
-               ccw->cda = (__u32)virt_to_phys(pfxdata);
+               ccw->cda = virt_to_dma32(pfxdata);
                memset(pfxdata, 0, sizeof(*pfxdata) + 2);
        } else {
                ccw->count = sizeof(*pfxdata);
-               ccw->cda = (__u32)virt_to_phys(pfxdata);
+               ccw->cda = virt_to_dma32(pfxdata);
                memset(pfxdata, 0, sizeof(*pfxdata));
        }
 
@@ -610,7 +610,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk,
        ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
        ccw->flags = 0;
        ccw->count = 16;
-       ccw->cda = (__u32)virt_to_phys(data);
+       ccw->cda = virt_to_dma32(data);
 
        memset(data, 0, sizeof(struct LO_eckd_data));
        sector = 0;
@@ -825,7 +825,7 @@ static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device,
        ccw = cqr->cpaddr;
        ccw->cmd_code = DASD_ECKD_CCW_RCD;
        ccw->flags = 0;
-       ccw->cda = (__u32)virt_to_phys(rcd_buffer);
+       ccw->cda = virt_to_dma32(rcd_buffer);
        ccw->count = DASD_ECKD_RCD_DATA_SIZE;
        cqr->magic = DASD_ECKD_MAGIC;
 
@@ -853,7 +853,7 @@ static void read_conf_cb(struct dasd_ccw_req *cqr, void *data)
 
        if (cqr->status !=  DASD_CQR_DONE) {
                ccw = cqr->cpaddr;
-               rcd_buffer = phys_to_virt(ccw->cda);
+               rcd_buffer = dma32_to_virt(ccw->cda);
                memset(rcd_buffer, 0, sizeof(*rcd_buffer));
 
                rcd_buffer[0] = 0xE5;
@@ -1534,7 +1534,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
        ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - feature codes */
        features = (struct dasd_rssd_features *) (prssdp + 1);
@@ -1543,7 +1543,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
        ccw++;
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(struct dasd_rssd_features);
-       ccw->cda = (__u32)virt_to_phys(features);
+       ccw->cda = virt_to_dma32(features);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -1603,7 +1603,7 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
        ccw->count = sizeof(*prssdp);
        ccw->flags |= CCW_FLAG_CC;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - Volume Storage Query */
        vsq = (struct dasd_rssd_vsq *)(prssdp + 1);
@@ -1613,7 +1613,7 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(*vsq);
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)virt_to_phys(vsq);
+       ccw->cda = virt_to_dma32(vsq);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -1788,7 +1788,7 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
        ccw->count = sizeof(*prssdp);
        ccw->flags |= CCW_FLAG_CC;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        lcq = (struct dasd_rssd_lcq *)(prssdp + 1);
        memset(lcq, 0, sizeof(*lcq));
@@ -1797,7 +1797,7 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(*lcq);
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)virt_to_phys(lcq);
+       ccw->cda = virt_to_dma32(lcq);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -1894,7 +1894,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
        }
        ccw = cqr->cpaddr;
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->cda = (__u32)virt_to_phys(psf_ssc_data);
+       ccw->cda = virt_to_dma32(psf_ssc_data);
        ccw->count = 66;
 
        cqr->startdev = device;
@@ -2250,7 +2250,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
                ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
                ccw->flags = 0;
                ccw->count = 8;
-               ccw->cda = (__u32)virt_to_phys(count_data);
+               ccw->cda = virt_to_dma32(count_data);
                ccw++;
                count_data++;
        }
@@ -2264,7 +2264,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
        ccw->flags = 0;
        ccw->count = 8;
-       ccw->cda = (__u32)virt_to_phys(count_data);
+       ccw->cda = virt_to_dma32(count_data);
 
        cqr->block = NULL;
        cqr->startdev = device;
@@ -2635,7 +2635,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
                ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
                ccw->flags = CCW_FLAG_SLI;
                ccw->count = 8;
-               ccw->cda = (__u32)virt_to_phys(fmt_buffer);
+               ccw->cda = virt_to_dma32(fmt_buffer);
                ccw++;
                fmt_buffer++;
        }
@@ -2845,7 +2845,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
                        ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
                        ccw->flags = CCW_FLAG_SLI;
                        ccw->count = 8;
-                       ccw->cda = (__u32)virt_to_phys(ect);
+                       ccw->cda = virt_to_dma32(ect);
                        ccw++;
                }
                if ((intensity & ~0x08) & 0x04) {       /* erase track */
@@ -2860,7 +2860,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
                        ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
                        ccw->flags = CCW_FLAG_SLI;
                        ccw->count = 8;
-                       ccw->cda = (__u32)virt_to_phys(ect);
+                       ccw->cda = virt_to_dma32(ect);
                } else {                /* write remaining records */
                        for (i = 0; i < rpt; i++) {
                                ect = (struct eckd_count *) data;
@@ -2895,7 +2895,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
                                                DASD_ECKD_CCW_WRITE_CKD_MT;
                                ccw->flags = CCW_FLAG_SLI;
                                ccw->count = 8;
-                               ccw->cda = (__u32)virt_to_phys(ect);
+                               ccw->cda = virt_to_dma32(ect);
                                ccw++;
                        }
                }
@@ -3836,7 +3836,7 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block,
        }
 
        ccw = cqr->cpaddr;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        ccw->cmd_code = DASD_ECKD_CCW_DSO;
        ccw->count = size;
 
@@ -3961,7 +3961,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                                               unsigned int blksize)
 {
        struct dasd_eckd_private *private;
-       unsigned long *idaws;
+       dma64_t *idaws;
        struct LO_eckd_data *LO_data;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
@@ -4039,8 +4039,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                        dasd_sfree_request(cqr, startdev);
                        return ERR_PTR(-EAGAIN);
                }
-               idaws = (unsigned long *) (cqr->data +
-                                          sizeof(struct PFX_eckd_data));
+               idaws = (dma64_t *)(cqr->data + sizeof(struct PFX_eckd_data));
        } else {
                if (define_extent(ccw++, cqr->data, first_trk,
                                  last_trk, cmd, basedev, 0) == -EAGAIN) {
@@ -4050,8 +4049,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                        dasd_sfree_request(cqr, startdev);
                        return ERR_PTR(-EAGAIN);
                }
-               idaws = (unsigned long *) (cqr->data +
-                                          sizeof(struct DE_eckd_data));
+               idaws = (dma64_t *)(cqr->data + sizeof(struct DE_eckd_data));
        }
        /* Build locate_record+read/write/ccws. */
        LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -4105,11 +4103,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                        ccw->cmd_code = rcmd;
                        ccw->count = count;
                        if (idal_is_needed(dst, blksize)) {
-                               ccw->cda = (__u32)virt_to_phys(idaws);
+                               ccw->cda = virt_to_dma32(idaws);
                                ccw->flags = CCW_FLAG_IDA;
                                idaws = idal_create_words(idaws, dst, blksize);
                        } else {
-                               ccw->cda = (__u32)virt_to_phys(dst);
+                               ccw->cda = virt_to_dma32(dst);
                                ccw->flags = 0;
                        }
                        ccw++;
@@ -4152,7 +4150,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
                                               unsigned int blk_per_trk,
                                               unsigned int blksize)
 {
-       unsigned long *idaws;
+       dma64_t *idaws;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
        struct req_iterator iter;
@@ -4222,7 +4220,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
         *   (or 2K blocks on 31-bit)
         * - the scope of a ccw and it's idal ends with the track boundaries
         */
-       idaws = (unsigned long *) (cqr->data + sizeof(struct PFX_eckd_data));
+       idaws = (dma64_t *)(cqr->data + sizeof(struct PFX_eckd_data));
        recid = first_rec;
        new_track = 1;
        end_idaw = 0;
@@ -4243,7 +4241,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
                                ccw[-1].flags |= CCW_FLAG_CC;
                                ccw->cmd_code = cmd;
                                ccw->count = len_to_track_end;
-                               ccw->cda = (__u32)virt_to_phys(idaws);
+                               ccw->cda = virt_to_dma32(idaws);
                                ccw->flags = CCW_FLAG_IDA;
                                ccw++;
                                recid += count;
@@ -4259,7 +4257,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
                         * idaw ends
                         */
                        if (!idaw_dst) {
-                               if ((__u32)virt_to_phys(dst) & (IDA_BLOCK_SIZE - 1)) {
+                               if ((unsigned long)(dst) & (IDA_BLOCK_SIZE - 1)) {
                                        dasd_sfree_request(cqr, startdev);
                                        return ERR_PTR(-ERANGE);
                                } else
@@ -4279,7 +4277,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
                         * idal_create_words will handle cases where idaw_len
                         * is larger then IDA_BLOCK_SIZE
                         */
-                       if (!((__u32)virt_to_phys(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE - 1)))
+                       if (!((unsigned long)(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE - 1)))
                                end_idaw = 1;
                        /* We also need to end the idaw at track end */
                        if (!len_to_track_end) {
@@ -4738,11 +4736,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
        struct req_iterator iter;
        struct dasd_ccw_req *cqr;
        unsigned int trkcount;
-       unsigned long *idaws;
        unsigned int size;
        unsigned char cmd;
        struct bio_vec bv;
        struct ccw1 *ccw;
+       dma64_t *idaws;
        int use_prefix;
        void *data;
        char *dst;
@@ -4823,7 +4821,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
                                  trkcount, cmd, basedev, 0, 0);
        }
 
-       idaws = (unsigned long *)(cqr->data + size);
+       idaws = (dma64_t *)(cqr->data + size);
        len_to_track_end = 0;
        if (start_padding_sectors) {
                ccw[-1].flags |= CCW_FLAG_CC;
@@ -4832,7 +4830,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
                ccw->count = 57326;
                /* 64k map to one track */
                len_to_track_end = 65536 - start_padding_sectors * 512;
-               ccw->cda = (__u32)virt_to_phys(idaws);
+               ccw->cda = virt_to_dma32(idaws);
                ccw->flags |= CCW_FLAG_IDA;
                ccw->flags |= CCW_FLAG_SLI;
                ccw++;
@@ -4851,7 +4849,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
                        ccw->count = 57326;
                        /* 64k map to one track */
                        len_to_track_end = 65536;
-                       ccw->cda = (__u32)virt_to_phys(idaws);
+                       ccw->cda = virt_to_dma32(idaws);
                        ccw->flags |= CCW_FLAG_IDA;
                        ccw->flags |= CCW_FLAG_SLI;
                        ccw++;
@@ -4908,9 +4906,9 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
                                ccw++;
                        if (dst) {
                                if (ccw->flags & CCW_FLAG_IDA)
-                                       cda = *((char **)phys_to_virt(ccw->cda));
+                                       cda = *((char **)dma32_to_virt(ccw->cda));
                                else
-                                       cda = phys_to_virt(ccw->cda);
+                                       cda = dma32_to_virt(ccw->cda);
                                if (dst != cda) {
                                        if (rq_data_dir(req) == READ)
                                                memcpy(dst, cda, bv.bv_len);
@@ -5060,7 +5058,7 @@ dasd_eckd_release(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_RELEASE;
        ccw->flags |= CCW_FLAG_SLI;
        ccw->count = 32;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        cqr->startdev = device;
        cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5115,7 +5113,7 @@ dasd_eckd_reserve(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_RESERVE;
        ccw->flags |= CCW_FLAG_SLI;
        ccw->count = 32;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        cqr->startdev = device;
        cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5169,7 +5167,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_SLCK;
        ccw->flags |= CCW_FLAG_SLI;
        ccw->count = 32;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        cqr->startdev = device;
        cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5230,7 +5228,7 @@ static int dasd_eckd_snid(struct dasd_device *device,
        ccw->cmd_code = DASD_ECKD_CCW_SNID;
        ccw->flags |= CCW_FLAG_SLI;
        ccw->count = 12;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
        cqr->startdev = device;
        cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5297,7 +5295,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
        ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - Performance Statistics */
        stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
@@ -5306,7 +5304,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
        ccw++;
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
-       ccw->cda = (__u32)virt_to_phys(stats);
+       ccw->cda = virt_to_dma32(stats);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -5450,7 +5448,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
        ccw->count = usrparm.psf_data_len;
        ccw->flags |= CCW_FLAG_CC;
-       ccw->cda = (__u32)virt_to_phys(psf_data);
+       ccw->cda = virt_to_dma32(psf_data);
 
        ccw++;
 
@@ -5458,7 +5456,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = usrparm.rssd_result_len;
        ccw->flags = CCW_FLAG_SLI ;
-       ccw->cda = (__u32)virt_to_phys(rssd_result);
+       ccw->cda = virt_to_dma32(rssd_result);
 
        rc = dasd_sleep_on(cqr);
        if (rc)
@@ -5527,9 +5525,9 @@ dasd_eckd_dump_ccw_range(struct dasd_device *device, struct ccw1 *from,
 
                /* get pointer to data (consider IDALs) */
                if (from->flags & CCW_FLAG_IDA)
-                       datap = (char *)*((addr_t *)phys_to_virt(from->cda));
+                       datap = (char *)*((addr_t *)dma32_to_virt(from->cda));
                else
-                       datap = phys_to_virt(from->cda);
+                       datap = dma32_to_virt(from->cda);
 
                /* dump data (max 128 bytes) */
                for (count = 0; count < from->count && count < 128; count++) {
@@ -5598,7 +5596,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                       scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw),
                       req ? req->intrc : 0);
        len += sprintf(page + len, "Failing CCW: %px\n",
-                      phys_to_virt(irb->scsw.cmd.cpa));
+                      dma32_to_virt(irb->scsw.cmd.cpa));
        if (irb->esw.esw0.erw.cons) {
                for (sl = 0; sl < 4; sl++) {
                        len += sprintf(page + len, "Sense(hex) %2d-%2d:",
@@ -5641,7 +5639,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
                /* print failing CCW area (maximum 4) */
                /* scsw->cda is either valid or zero  */
                from = ++to;
-               fail = phys_to_virt(irb->scsw.cmd.cpa); /* failing CCW */
+               fail = dma32_to_virt(irb->scsw.cmd.cpa); /* failing CCW */
                if (from <  fail - 2) {
                        from = fail - 2;     /* there is a gap - print header */
                        dev_err(dev, "......\n");
@@ -5691,12 +5689,12 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
                       (irb->scsw.tm.ifob << 7) | irb->scsw.tm.sesq,
                       req ? req->intrc : 0);
        len += sprintf(page + len, "Failing TCW: %px\n",
-                      phys_to_virt(irb->scsw.tm.tcw));
+                      dma32_to_virt(irb->scsw.tm.tcw));
 
        tsb = NULL;
        sense = NULL;
        if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01))
-               tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw));
+               tsb = tcw_get_tsb(dma32_to_virt(irb->scsw.tm.tcw));
 
        if (tsb) {
                len += sprintf(page + len, "tsb->length %d\n", tsb->length);
@@ -5906,7 +5904,7 @@ retry:
        ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - message buffer */
        message_buf = (struct dasd_rssd_messages *) (prssdp + 1);
@@ -5916,7 +5914,7 @@ retry:
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(struct dasd_rssd_messages);
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)virt_to_phys(message_buf);
+       ccw->cda = virt_to_dma32(message_buf);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -5997,14 +5995,14 @@ static int dasd_eckd_query_host_access(struct dasd_device *device,
        ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)virt_to_phys(prssdp);
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - query host access */
        ccw++;
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(struct dasd_psf_query_host_access);
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)virt_to_phys(host_access);
+       ccw->cda = virt_to_dma32(host_access);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -6239,14 +6237,14 @@ static int dasd_eckd_query_pprc_status(struct dasd_device *device,
        ccw->count = sizeof(struct dasd_psf_prssd_data);
        ccw->flags |= CCW_FLAG_CC;
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)(addr_t)prssdp;
+       ccw->cda = virt_to_dma32(prssdp);
 
        /* Read Subsystem Data - query host access */
        ccw++;
        ccw->cmd_code = DASD_ECKD_CCW_RSSD;
        ccw->count = sizeof(*pprc_data);
        ccw->flags |= CCW_FLAG_SLI;
-       ccw->cda = (__u32)(addr_t)pprc_data;
+       ccw->cda = virt_to_dma32(pprc_data);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -6340,7 +6338,7 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
        psf_cuir->ssid = device->path[pos].ssid;
        ccw = cqr->cpaddr;
        ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->cda = (__u32)virt_to_phys(psf_cuir);
+       ccw->cda = virt_to_dma32(psf_cuir);
        ccw->flags = CCW_FLAG_SLI;
        ccw->count = sizeof(struct dasd_psf_cuir_response);
 
index 5064a616e041a310c1db35c0cbeacdd7980f0b86..194e9e2d9cb899bc9d9ee08c92a61e7f5c490802 100644 (file)
@@ -485,7 +485,7 @@ int dasd_eer_enable(struct dasd_device *device)
        ccw->cmd_code = DASD_ECKD_CCW_SNSS;
        ccw->count = SNSS_DATA_SIZE;
        ccw->flags = 0;
-       ccw->cda = (__u32)virt_to_phys(cqr->data);
+       ccw->cda = virt_to_dma32(cqr->data);
 
        cqr->buildclk = get_tod_clock();
        cqr->status = DASD_CQR_FILLED;
index bcbb2f8e91feb6ca1a674742188083d5a0cdb49d..361e9bd752570523372792d915187d8374bce9aa 100644 (file)
@@ -78,7 +78,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
        ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
        ccw->flags = 0;
        ccw->count = 16;
-       ccw->cda = (__u32)virt_to_phys(data);
+       ccw->cda = virt_to_dma32(data);
        memset(data, 0, sizeof (struct DE_fba_data));
        if (rw == WRITE)
                (data->mask).perm = 0x0;
@@ -98,7 +98,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
        ccw->cmd_code = DASD_FBA_CCW_LOCATE;
        ccw->flags = 0;
        ccw->count = 8;
-       ccw->cda = (__u32)virt_to_phys(data);
+       ccw->cda = virt_to_dma32(data);
        memset(data, 0, sizeof (struct LO_fba_data));
        if (rw == WRITE)
                data->operation.cmd = 0x5;
@@ -257,7 +257,7 @@ static void ccw_write_zero(struct ccw1 *ccw, int count)
        ccw->cmd_code = DASD_FBA_CCW_WRITE;
        ccw->flags |= CCW_FLAG_SLI;
        ccw->count = count;
-       ccw->cda = (__u32)virt_to_phys(dasd_fba_zero_page);
+       ccw->cda = virt_to_dma32(dasd_fba_zero_page);
 }
 
 /*
@@ -427,7 +427,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp_regular(
                                                struct request *req)
 {
        struct dasd_fba_private *private = block->base->private;
-       unsigned long *idaws;
+       dma64_t *idaws;
        struct LO_fba_data *LO_data;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
@@ -487,7 +487,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp_regular(
        define_extent(ccw++, cqr->data, rq_data_dir(req),
                      block->bp_block, blk_rq_pos(req), blk_rq_sectors(req));
        /* Build locate_record + read/write ccws. */
-       idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
+       idaws = (dma64_t *)(cqr->data + sizeof(struct DE_fba_data));
        LO_data = (struct LO_fba_data *) (idaws + cidaw);
        /* Locate record for all blocks for smart devices. */
        if (private->rdc_data.mode.bits.data_chain != 0) {
@@ -523,11 +523,11 @@ static struct dasd_ccw_req *dasd_fba_build_cp_regular(
                        ccw->cmd_code = cmd;
                        ccw->count = block->bp_block;
                        if (idal_is_needed(dst, blksize)) {
-                               ccw->cda = (__u32)virt_to_phys(idaws);
+                               ccw->cda = virt_to_dma32(idaws);
                                ccw->flags = CCW_FLAG_IDA;
                                idaws = idal_create_words(idaws, dst, blksize);
                        } else {
-                               ccw->cda = (__u32)virt_to_phys(dst);
+                               ccw->cda = virt_to_dma32(dst);
                                ccw->flags = 0;
                        }
                        ccw++;
@@ -585,9 +585,9 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
                                ccw++;
                        if (dst) {
                                if (ccw->flags & CCW_FLAG_IDA)
-                                       cda = *((char **)phys_to_virt(ccw->cda));
+                                       cda = *((char **)dma32_to_virt(ccw->cda));
                                else
-                                       cda = phys_to_virt(ccw->cda);
+                                       cda = dma32_to_virt(ccw->cda);
                                if (dst != cda) {
                                        if (rq_data_dir(req) == READ)
                                                memcpy(dst, cda, bv.bv_len);
@@ -672,7 +672,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
        len += sprintf(page + len, "in req: %px CS: 0x%02X DS: 0x%02X\n",
                       req, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
        len += sprintf(page + len, "Failing CCW: %px\n",
-                      (void *) (addr_t) irb->scsw.cmd.cpa);
+                      (void *)(u64)dma32_to_u32(irb->scsw.cmd.cpa));
        if (irb->esw.esw0.erw.cons) {
                for (sl = 0; sl < 4; sl++) {
                        len += sprintf(page + len, "Sense(hex) %2d-%2d:",
@@ -701,7 +701,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                for (count = 0; count < 32 && count < act->count;
                     count += sizeof(int))
                        len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
+                                      ((int *)dma32_to_virt(act->cda))
                                       [(count>>2)]);
                len += sprintf(page + len, "\n");
                act++;
@@ -710,18 +710,18 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 
        /* print failing CCW area */
        len = 0;
-       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2) {
-               act = ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2;
+       if (act < ((struct ccw1 *)dma32_to_virt(irb->scsw.cmd.cpa)) - 2) {
+               act = ((struct ccw1 *)dma32_to_virt(irb->scsw.cmd.cpa)) - 2;
                len += sprintf(page + len, "......\n");
        }
-       end = min((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa + 2, last);
+       end = min((struct ccw1 *)dma32_to_virt(irb->scsw.cmd.cpa) + 2, last);
        while (act <= end) {
                len += sprintf(page + len, "CCW %px: %08X %08X DAT:",
                               act, ((int *) act)[0], ((int *) act)[1]);
                for (count = 0; count < 32 && count < act->count;
                     count += sizeof(int))
                        len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
+                                      ((int *)dma32_to_virt(act->cda))
                                       [(count>>2)]);
                len += sprintf(page + len, "\n");
                act++;
@@ -738,7 +738,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                for (count = 0; count < 32 && count < act->count;
                     count += sizeof(int))
                        len += sprintf(page + len, " %08X",
-                                      ((int *) (addr_t) act->cda)
+                                      ((int *)dma32_to_virt(act->cda))
                                       [(count>>2)]);
                len += sprintf(page + len, "\n");
                act++;
index ba66aa6a83c6c1f9605a26a4341211c96f7ba2bb..6d1689a2717e5fa433d7575d16eaa7ead66810f5 100644 (file)
@@ -920,7 +920,7 @@ __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff,
 
        dev_sz = dev_info->end - dev_info->start + 1;
        if (kaddr)
-               *kaddr = (void *) dev_info->start + offset;
+               *kaddr = __va(dev_info->start + offset);
        if (pfn)
                *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset),
                                PFN_DEV|PFN_SPECIAL);
index 9f6fdd0daa74eb33bbf4fd7f570df7ce192d8b4b..1d456a5a3bfb8ec1cae92b24c00013dd418c0bd3 100644 (file)
@@ -131,7 +131,7 @@ static void scm_request_done(struct scm_request *scmrq)
 
        for (i = 0; i < nr_requests_per_io && scmrq->request[i]; i++) {
                msb = &scmrq->aob->msb[i];
-               aidaw = (u64)phys_to_virt(msb->data_addr);
+               aidaw = (u64)dma64_to_virt(msb->data_addr);
 
                if ((msb->flags & MSB_FLAG_IDA) && aidaw &&
                    IS_ALIGNED(aidaw, PAGE_SIZE))
@@ -196,12 +196,12 @@ static int scm_request_prepare(struct scm_request *scmrq)
        msb->scm_addr = scmdev->address + ((u64) blk_rq_pos(req) << 9);
        msb->oc = (rq_data_dir(req) == READ) ? MSB_OC_READ : MSB_OC_WRITE;
        msb->flags |= MSB_FLAG_IDA;
-       msb->data_addr = (u64)virt_to_phys(aidaw);
+       msb->data_addr = virt_to_dma64(aidaw);
 
        rq_for_each_segment(bv, req, iter) {
                WARN_ON(bv.bv_offset);
                msb->blk_count += bv.bv_len >> 12;
-               aidaw->data_addr = virt_to_phys(page_address(bv.bv_page));
+               aidaw->data_addr = virt_to_dma64(page_address(bv.bv_page));
                aidaw++;
        }
 
index 0b0324fe4aff302bf8c7c4575df585c5ce60df28..dcb3c32f027af6748448600bad51864f6ba5d9a1 100644 (file)
@@ -159,7 +159,7 @@ static void raw3215_mk_read_req(struct raw3215_info *raw)
        ccw->cmd_code = 0x0A; /* read inquiry */
        ccw->flags = 0x20;    /* ignore incorrect length */
        ccw->count = 160;
-       ccw->cda = (__u32)__pa(raw->inbuf);
+       ccw->cda = virt_to_dma32(raw->inbuf);
 }
 
 /*
@@ -218,7 +218,7 @@ static void raw3215_mk_write_req(struct raw3215_info *raw)
                        ccw[-1].flags |= 0x40; /* use command chaining */
                ccw->cmd_code = 0x01; /* write, auto carrier return */
                ccw->flags = 0x20;    /* ignore incorrect length ind.  */
-               ccw->cda = (__u32)__pa(raw->buffer + ix);
+               ccw->cda = virt_to_dma32(raw->buffer + ix);
                count = len;
                if (ix + count > RAW3215_BUFFER_SIZE)
                        count = RAW3215_BUFFER_SIZE - ix;
index 4f26b0a55620fcd7b6fdb89075d9235e41c78f5b..4d824f86bbbbb466a897d1ff5806651788a6d2e8 100644 (file)
@@ -126,7 +126,7 @@ static int fs3270_activate(struct raw3270_view *view)
        raw3270_request_set_cmd(fp->init, TC_EWRITEA);
        raw3270_request_set_idal(fp->init, fp->rdbuf);
        fp->init->rescnt = 0;
-       cp = fp->rdbuf->data[0];
+       cp = dma64_to_virt(fp->rdbuf->data[0]);
        if (fp->rdbuf_size == 0) {
                /* No saved buffer. Just clear the screen. */
                fp->init->ccw.count = 1;
@@ -164,7 +164,7 @@ static void fs3270_save_callback(struct raw3270_request *rq, void *data)
        fp = (struct fs3270 *)rq->view;
 
        /* Correct idal buffer element 0 address. */
-       fp->rdbuf->data[0] -= 5;
+       fp->rdbuf->data[0] = dma64_add(fp->rdbuf->data[0], -5);
        fp->rdbuf->size += 5;
 
        /*
@@ -202,7 +202,7 @@ static void fs3270_deactivate(struct raw3270_view *view)
         * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence
         * in the activation command.
         */
-       fp->rdbuf->data[0] += 5;
+       fp->rdbuf->data[0] = dma64_add(fp->rdbuf->data[0], 5);
        fp->rdbuf->size -= 5;
        raw3270_request_set_idal(fp->init, fp->rdbuf);
        fp->init->rescnt = 0;
@@ -521,13 +521,13 @@ static const struct file_operations fs3270_fops = {
 static void fs3270_create_cb(int minor)
 {
        __register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops);
-       device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
+       device_create(&class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
                      NULL, "3270/tub%d", minor);
 }
 
 static void fs3270_destroy_cb(int minor)
 {
-       device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor));
+       device_destroy(&class3270, MKDEV(IBM_FS3270_MAJOR, minor));
        __unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
 }
 
@@ -546,7 +546,7 @@ static int __init fs3270_init(void)
        rc = __register_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270", &fs3270_fops);
        if (rc)
                return rc;
-       device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0),
+       device_create(&class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0),
                      NULL, "3270/tub");
        raw3270_register_notifier(&fs3270_notifier);
        return 0;
@@ -555,7 +555,7 @@ static int __init fs3270_init(void)
 static void __exit fs3270_exit(void)
 {
        raw3270_unregister_notifier(&fs3270_notifier);
-       device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, 0));
+       device_destroy(&class3270, MKDEV(IBM_FS3270_MAJOR, 0));
        __unregister_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270");
 }
 
index 7115c0f85650767204470aeb4f1fa8af238d8b5e..37173cb0f5f5a222b936029b8ff8e7997c401d4d 100644 (file)
@@ -29,7 +29,9 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 
-struct class *class3270;
+const struct class class3270 = {
+       .name = "3270",
+};
 EXPORT_SYMBOL(class3270);
 
 /* The main 3270 data structure. */
@@ -160,7 +162,7 @@ struct raw3270_request *raw3270_request_alloc(size_t size)
        /*
         * Setup ccw.
         */
-       rq->ccw.cda = __pa(rq->buffer);
+       rq->ccw.cda = virt_to_dma32(rq->buffer);
        rq->ccw.flags = CCW_FLAG_SLI;
 
        return rq;
@@ -186,7 +188,7 @@ int raw3270_request_reset(struct raw3270_request *rq)
                return -EBUSY;
        rq->ccw.cmd_code = 0;
        rq->ccw.count = 0;
-       rq->ccw.cda = __pa(rq->buffer);
+       rq->ccw.cda = virt_to_dma32(rq->buffer);
        rq->ccw.flags = CCW_FLAG_SLI;
        rq->rescnt = 0;
        rq->rc = 0;
@@ -221,7 +223,7 @@ EXPORT_SYMBOL(raw3270_request_add_data);
  */
 void raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
 {
-       rq->ccw.cda = __pa(data);
+       rq->ccw.cda = virt_to_dma32(data);
        rq->ccw.count = size;
 }
 EXPORT_SYMBOL(raw3270_request_set_data);
@@ -231,7 +233,7 @@ EXPORT_SYMBOL(raw3270_request_set_data);
  */
 void raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
 {
-       rq->ccw.cda = __pa(ib->data);
+       rq->ccw.cda = virt_to_dma32(ib->data);
        rq->ccw.count = ib->size;
        rq->ccw.flags |= CCW_FLAG_IDA;
 }
@@ -577,7 +579,7 @@ static void raw3270_read_modified(struct raw3270 *rp)
        rp->init_readmod.ccw.cmd_code = TC_READMOD;
        rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
        rp->init_readmod.ccw.count = sizeof(rp->init_data);
-       rp->init_readmod.ccw.cda = (__u32)__pa(rp->init_data);
+       rp->init_readmod.ccw.cda = virt_to_dma32(rp->init_data);
        rp->init_readmod.callback = raw3270_read_modified_cb;
        rp->init_readmod.callback_data = rp->init_data;
        rp->state = RAW3270_STATE_READMOD;
@@ -597,7 +599,7 @@ static void raw3270_writesf_readpart(struct raw3270 *rp)
        rp->init_readpart.ccw.cmd_code = TC_WRITESF;
        rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
        rp->init_readpart.ccw.count = sizeof(wbuf);
-       rp->init_readpart.ccw.cda = (__u32)__pa(&rp->init_data);
+       rp->init_readpart.ccw.cda = virt_to_dma32(&rp->init_data);
        rp->state = RAW3270_STATE_W4ATTN;
        raw3270_start_irq(&rp->init_view, &rp->init_readpart);
 }
@@ -635,7 +637,7 @@ static int __raw3270_reset_device(struct raw3270 *rp)
        rp->init_reset.ccw.cmd_code = TC_EWRITEA;
        rp->init_reset.ccw.flags = CCW_FLAG_SLI;
        rp->init_reset.ccw.count = 1;
-       rp->init_reset.ccw.cda = (__u32)__pa(rp->init_data);
+       rp->init_reset.ccw.cda = virt_to_dma32(rp->init_data);
        rp->init_reset.callback = raw3270_reset_device_cb;
        rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
        if (rc == 0 && rp->state == RAW3270_STATE_INIT)
@@ -1316,23 +1318,25 @@ static int raw3270_init(void)
                return 0;
        raw3270_registered = 1;
        rc = ccw_driver_register(&raw3270_ccw_driver);
-       if (rc == 0) {
-               /* Create attributes for early (= console) device. */
-               mutex_lock(&raw3270_mutex);
-               class3270 = class_create("3270");
-               list_for_each_entry(rp, &raw3270_devices, list) {
-                       get_device(&rp->cdev->dev);
-                       raw3270_create_attributes(rp);
-               }
-               mutex_unlock(&raw3270_mutex);
+       if (rc)
+               return rc;
+       rc = class_register(&class3270);
+       if (rc)
+               return rc;
+       /* Create attributes for early (= console) device. */
+       mutex_lock(&raw3270_mutex);
+       list_for_each_entry(rp, &raw3270_devices, list) {
+               get_device(&rp->cdev->dev);
+               raw3270_create_attributes(rp);
        }
-       return rc;
+       mutex_unlock(&raw3270_mutex);
+       return 0;
 }
 
 static void raw3270_exit(void)
 {
        ccw_driver_unregister(&raw3270_ccw_driver);
-       class_destroy(class3270);
+       class_unregister(&class3270);
 }
 
 MODULE_LICENSE("GPL");
index b1beecc7a0a94acbd30f86dd9983a21f730144ce..5040c7e0e051b68ccbccb39bd7db5732fdb1dda9 100644 (file)
@@ -14,7 +14,7 @@
 
 struct raw3270;
 struct raw3270_view;
-extern struct class *class3270;
+extern const struct class class3270;
 
 /* 3270 CCW request */
 struct raw3270_request {
index 4e5d5efa978f26f014c2913c02506576b00512c1..0aba30efb483d7fce64bf2c216c058077d065fe2 100644 (file)
@@ -305,7 +305,9 @@ tape_ccw_cc(struct ccw1 *ccw, __u8 cmd_code, __u16 memsize, void *cda)
        ccw->cmd_code = cmd_code;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = memsize;
-       ccw->cda = (__u32)(addr_t) cda;
+       ccw->cda = 0;
+       if (cda)
+               ccw->cda = virt_to_dma32(cda);
        return ccw + 1;
 }
 
@@ -315,7 +317,9 @@ tape_ccw_end(struct ccw1 *ccw, __u8 cmd_code, __u16 memsize, void *cda)
        ccw->cmd_code = cmd_code;
        ccw->flags = 0;
        ccw->count = memsize;
-       ccw->cda = (__u32)(addr_t) cda;
+       ccw->cda = 0;
+       if (cda)
+               ccw->cda = virt_to_dma32(cda);
        return ccw + 1;
 }
 
@@ -325,7 +329,7 @@ tape_ccw_cmd(struct ccw1 *ccw, __u8 cmd_code)
        ccw->cmd_code = cmd_code;
        ccw->flags = 0;
        ccw->count = 0;
-       ccw->cda = (__u32)(addr_t) &ccw->cmd_code;
+       ccw->cda = virt_to_dma32(&ccw->cmd_code);
        return ccw + 1;
 }
 
@@ -336,7 +340,7 @@ tape_ccw_repeat(struct ccw1 *ccw, __u8 cmd_code, int count)
                ccw->cmd_code = cmd_code;
                ccw->flags = CCW_FLAG_CC;
                ccw->count = 0;
-               ccw->cda = (__u32)(addr_t) &ccw->cmd_code;
+               ccw->cda = virt_to_dma32(&ccw->cmd_code);
                ccw++;
        }
        return ccw;
index 277a0f903d11bfdb50e2c545286358dac3c8a86a..eae362bbfbb55dab640e28869188e1960befe4af 100644 (file)
@@ -22,7 +22,9 @@ MODULE_DESCRIPTION(
 );
 MODULE_LICENSE("GPL");
 
-static struct class *tape_class;
+static const struct class tape_class = {
+       .name = "tape390",
+};
 
 /*
  * Register a tape device and return a pointer to the cdev structure.
@@ -74,7 +76,7 @@ struct tape_class_device *register_tape_dev(
        if (rc)
                goto fail_with_cdev;
 
-       tcd->class_device = device_create(tape_class, device,
+       tcd->class_device = device_create(&tape_class, device,
                                          tcd->char_device->dev, NULL,
                                          "%s", tcd->device_name);
        rc = PTR_ERR_OR_ZERO(tcd->class_device);
@@ -91,7 +93,7 @@ struct tape_class_device *register_tape_dev(
        return tcd;
 
 fail_with_class_device:
-       device_destroy(tape_class, tcd->char_device->dev);
+       device_destroy(&tape_class, tcd->char_device->dev);
 
 fail_with_cdev:
        cdev_del(tcd->char_device);
@@ -107,7 +109,7 @@ void unregister_tape_dev(struct device *device, struct tape_class_device *tcd)
 {
        if (tcd != NULL && !IS_ERR(tcd)) {
                sysfs_remove_link(&device->kobj, tcd->mode_name);
-               device_destroy(tape_class, tcd->char_device->dev);
+               device_destroy(&tape_class, tcd->char_device->dev);
                cdev_del(tcd->char_device);
                kfree(tcd);
        }
@@ -117,15 +119,12 @@ EXPORT_SYMBOL(unregister_tape_dev);
 
 static int __init tape_init(void)
 {
-       tape_class = class_create("tape390");
-
-       return 0;
+       return class_register(&tape_class);
 }
 
 static void __exit tape_exit(void)
 {
-       class_destroy(tape_class);
-       tape_class = NULL;
+       class_unregister(&tape_class);
 }
 
 postcore_initcall(tape_init);
index 6946ba9a9de2c592f3e4172e76407f0b2ec95e48..d7e408c8d0b84a067383ab697ebf4305013679a8 100644 (file)
@@ -679,7 +679,9 @@ static const struct attribute_group *vmlogrdr_attr_groups[] = {
        NULL,
 };
 
-static struct class *vmlogrdr_class;
+static const struct class vmlogrdr_class = {
+       .name = "vmlogrdr_class",
+};
 static struct device_driver vmlogrdr_driver = {
        .name = "vmlogrdr",
        .bus  = &iucv_bus,
@@ -699,12 +701,9 @@ static int vmlogrdr_register_driver(void)
        if (ret)
                goto out_iucv;
 
-       vmlogrdr_class = class_create("vmlogrdr");
-       if (IS_ERR(vmlogrdr_class)) {
-               ret = PTR_ERR(vmlogrdr_class);
-               vmlogrdr_class = NULL;
+       ret = class_register(&vmlogrdr_class);
+       if (ret)
                goto out_driver;
-       }
        return 0;
 
 out_driver:
@@ -718,8 +717,7 @@ out:
 
 static void vmlogrdr_unregister_driver(void)
 {
-       class_destroy(vmlogrdr_class);
-       vmlogrdr_class = NULL;
+       class_unregister(&vmlogrdr_class);
        driver_unregister(&vmlogrdr_driver);
        iucv_unregister(&vmlogrdr_iucv_handler, 1);
 }
@@ -754,7 +752,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
                return ret;
        }
 
-       priv->class_device = device_create(vmlogrdr_class, dev,
+       priv->class_device = device_create(&vmlogrdr_class, dev,
                                           MKDEV(vmlogrdr_major,
                                                 priv->minor_num),
                                           priv, "%s", dev_name(dev));
@@ -771,7 +769,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
 
 static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
 {
-       device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
+       device_destroy(&vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
        if (priv->device != NULL) {
                device_unregister(priv->device);
                priv->device=NULL;
index 1d17a83569ce436ca37718dad31150cbd41df47a..fe94dec427b6972bdfeeffb529ffabbc1b0091f3 100644 (file)
@@ -48,7 +48,9 @@ MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver");
 MODULE_LICENSE("GPL");
 
 static dev_t ur_first_dev_maj_min;
-static struct class *vmur_class;
+static const struct class vmur_class = {
+       .name = "vmur",
+};
 static struct debug_info *vmur_dbf;
 
 /* We put the device's record length (for writes) in the driver_info field */
@@ -195,7 +197,7 @@ static void free_chan_prog(struct ccw1 *cpa)
        struct ccw1 *ptr = cpa;
 
        while (ptr->cda) {
-               kfree(phys_to_virt(ptr->cda));
+               kfree(dma32_to_virt(ptr->cda));
                ptr++;
        }
        kfree(cpa);
@@ -237,7 +239,7 @@ static struct ccw1 *alloc_chan_prog(const char __user *ubuf, int rec_count,
                        free_chan_prog(cpa);
                        return ERR_PTR(-ENOMEM);
                }
-               cpa[i].cda = (u32)virt_to_phys(kbuf);
+               cpa[i].cda = virt_to_dma32(kbuf);
                if (copy_from_user(kbuf, ubuf, reclen)) {
                        free_chan_prog(cpa);
                        return ERR_PTR(-EFAULT);
@@ -912,7 +914,7 @@ static int ur_set_online(struct ccw_device *cdev)
                goto fail_free_cdev;
        }
 
-       urd->device = device_create(vmur_class, &cdev->dev,
+       urd->device = device_create(&vmur_class, &cdev->dev,
                                    urd->char_device->dev, NULL, "%s", node_id);
        if (IS_ERR(urd->device)) {
                rc = PTR_ERR(urd->device);
@@ -958,7 +960,7 @@ static int ur_set_offline_force(struct ccw_device *cdev, int force)
                /* Work not run yet - need to release reference here */
                urdev_put(urd);
        }
-       device_destroy(vmur_class, urd->char_device->dev);
+       device_destroy(&vmur_class, urd->char_device->dev);
        cdev_del(urd->char_device);
        urd->char_device = NULL;
        rc = 0;
@@ -1022,11 +1024,9 @@ static int __init ur_init(void)
 
        debug_set_level(vmur_dbf, 6);
 
-       vmur_class = class_create("vmur");
-       if (IS_ERR(vmur_class)) {
-               rc = PTR_ERR(vmur_class);
+       rc = class_register(&vmur_class);
+       if (rc)
                goto fail_free_dbf;
-       }
 
        rc = ccw_driver_register(&ur_driver);
        if (rc)
@@ -1046,7 +1046,7 @@ static int __init ur_init(void)
 fail_unregister_driver:
        ccw_driver_unregister(&ur_driver);
 fail_class_destroy:
-       class_destroy(vmur_class);
+       class_unregister(&vmur_class);
 fail_free_dbf:
        debug_unregister(vmur_dbf);
        return rc;
@@ -1056,7 +1056,7 @@ static void __exit ur_exit(void)
 {
        unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);
        ccw_driver_unregister(&ur_driver);
-       class_destroy(vmur_class);
+       class_unregister(&vmur_class);
        debug_unregister(vmur_dbf);
        pr_info("%s unloaded.\n", ur_banner);
 }
index 6eb8bcd948dc45db60c0c4d22bb2c3de2805172d..b72f672a7720a61885c3540231fe0da56b00ef7b 100644 (file)
@@ -240,7 +240,7 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
                rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj,
                                       &gdev->dev.kobj, "group_device");
                if (rc) {
-                       for (--i; i >= 0; i--)
+                       while (i--)
                                sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
                                                  "group_device");
                        return rc;
@@ -251,7 +251,7 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
                rc = sysfs_create_link(&gdev->dev.kobj,
                                       &gdev->cdev[i]->dev.kobj, str);
                if (rc) {
-                       for (--i; i >= 0; i--) {
+                       while (i--) {
                                sprintf(str, "cdev%d", i);
                                sysfs_remove_link(&gdev->dev.kobj, str);
                        }
index 3d88899dff7cfcf4da1d68c939fc73bd3937ba1f..44ea76f9e1decf7b51338da1363643fd9bdd6475 100644 (file)
@@ -191,7 +191,7 @@ EXPORT_SYMBOL_GPL(chsc_ssqd);
  * Returns 0 on success.
  */
 int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc,
-             u64 summary_indicator_addr, u64 subchannel_indicator_addr, u8 isc)
+             dma64_t summary_indicator_addr, dma64_t subchannel_indicator_addr, u8 isc)
 {
        memset(scssc, 0, sizeof(*scssc));
        scssc->request.length = 0x0fe0;
@@ -844,7 +844,7 @@ chsc_add_cmg_attr(struct channel_subsystem *css)
        }
        return ret;
 cleanup:
-       for (--i; i >= 0; i--) {
+       while (i--) {
                if (!css->chps[i])
                        continue;
                chp_remove_cmg_attr(css->chps[i]);
@@ -861,9 +861,9 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
                u32 key : 4;
                u32 : 28;
                u32 zeroes1;
-               u32 cub_addr1;
+               dma32_t cub_addr1;
                u32 zeroes2;
-               u32 cub_addr2;
+               dma32_t cub_addr2;
                u32 reserved[13];
                struct chsc_header response;
                u32 status : 8;
@@ -881,8 +881,8 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable)
        secm_area->request.code = 0x0016;
 
        secm_area->key = PAGE_DEFAULT_KEY >> 4;
-       secm_area->cub_addr1 = virt_to_phys(css->cub_addr1);
-       secm_area->cub_addr2 = virt_to_phys(css->cub_addr2);
+       secm_area->cub_addr1 = virt_to_dma32(css->cub_addr1);
+       secm_area->cub_addr2 = virt_to_dma32(css->cub_addr2);
 
        secm_area->operation_code = enable ? 0 : 1;
 
index d1caacb08e674226197e462918a60eff236f6123..03602295f33503ed20a8dc521053be2e51d33d8d 100644 (file)
@@ -91,8 +91,8 @@ struct chsc_scssc_area {
        u16:16;
        u32:32;
        u32:32;
-       u64 summary_indicator_addr;
-       u64 subchannel_indicator_addr;
+       dma64_t summary_indicator_addr;
+       dma64_t subchannel_indicator_addr;
        u32 ks:4;
        u32 kc:4;
        u32:21;
@@ -164,7 +164,7 @@ void chsc_chp_offline(struct chp_id chpid);
 int chsc_get_channel_measurement_chars(struct channel_path *chp);
 int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd);
 int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc,
-             u64 summary_indicator_addr, u64 subchannel_indicator_addr,
+             dma64_t summary_indicator_addr, dma64_t subchannel_indicator_addr,
              u8 isc);
 int chsc_sgib(u32 origin);
 int chsc_error_from_response(int response);
index a5736b7357b2825fa90acfc58d7f397553e23ec7..7e759c21480e73031f468635f404d002ec463305 100644 (file)
@@ -148,7 +148,7 @@ cio_start_key (struct subchannel *sch,      /* subchannel structure */
        orb->cmd.i2k = 0;
        orb->cmd.key = key >> 4;
        /* issue "Start Subchannel" */
-       orb->cmd.cpa = (u32)virt_to_phys(cpa);
+       orb->cmd.cpa = virt_to_dma32(cpa);
        ccode = ssch(sch->schid, orb);
 
        /* process condition code */
@@ -717,7 +717,7 @@ int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
        orb->tm.key = key >> 4;
        orb->tm.b = 1;
        orb->tm.lpm = lpm ? lpm : sch->lpm;
-       orb->tm.tcw = (u32)virt_to_phys(tcw);
+       orb->tm.tcw = virt_to_dma32(tcw);
        cc = ssch(sch->schid, orb);
        switch (cc) {
        case 0:
index 094431a62ad542beff160eca325a6b75b5778f15..1d68db1a3d4e473e3628afa519cf4735b8c1398f 100644 (file)
@@ -1114,26 +1114,33 @@ static int cio_dma_pool_init(void)
        return 0;
 }
 
-void *cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
-                       size_t size)
+void *__cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
+                         size_t size, dma32_t *dma_handle)
 {
        dma_addr_t dma_addr;
-       unsigned long addr;
        size_t chunk_size;
+       void *addr;
 
        if (!gp_dma)
                return NULL;
-       addr = gen_pool_alloc(gp_dma, size);
+       addr = gen_pool_dma_alloc(gp_dma, size, &dma_addr);
        while (!addr) {
                chunk_size = round_up(size, PAGE_SIZE);
-               addr = (unsigned long) dma_alloc_coherent(dma_dev,
-                                        chunk_size, &dma_addr, CIO_DMA_GFP);
+               addr = dma_alloc_coherent(dma_dev, chunk_size, &dma_addr, CIO_DMA_GFP);
                if (!addr)
                        return NULL;
-               gen_pool_add_virt(gp_dma, addr, dma_addr, chunk_size, -1);
-               addr = gen_pool_alloc(gp_dma, size);
+               gen_pool_add_virt(gp_dma, (unsigned long)addr, dma_addr, chunk_size, -1);
+               addr = gen_pool_dma_alloc(gp_dma, size, dma_handle ? &dma_addr : NULL);
        }
-       return (void *) addr;
+       if (dma_handle)
+               *dma_handle = (__force dma32_t)dma_addr;
+       return addr;
+}
+
+void *cio_gp_dma_zalloc(struct gen_pool *gp_dma, struct device *dma_dev,
+                       size_t size)
+{
+       return __cio_gp_dma_zalloc(gp_dma, dma_dev, size, NULL);
 }
 
 void cio_gp_dma_free(struct gen_pool *gp_dma, void *cpu_addr, size_t size)
index c396ac3e3a3272571132e859dbe21666de0c7b0e..65d8b2cfd6262d53a03bf10295d5d6c59f518c5d 100644 (file)
@@ -64,13 +64,13 @@ static void ccw_timeout_log(struct ccw_device *cdev)
                printk(KERN_WARNING "cio: orb indicates transport mode\n");
                printk(KERN_WARNING "cio: last tcw:\n");
                print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-                              phys_to_virt(orb->tm.tcw),
+                              dma32_to_virt(orb->tm.tcw),
                               sizeof(struct tcw), 0);
        } else {
                printk(KERN_WARNING "cio: orb indicates command mode\n");
-               if ((void *)(addr_t)orb->cmd.cpa ==
+               if (dma32_to_virt(orb->cmd.cpa) ==
                    &private->dma_area->sense_ccw ||
-                   (void *)(addr_t)orb->cmd.cpa ==
+                   dma32_to_virt(orb->cmd.cpa) ==
                    cdev->private->dma_area->iccws)
                        printk(KERN_WARNING "cio: last channel program "
                               "(intern):\n");
@@ -78,7 +78,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
                        printk(KERN_WARNING "cio: last channel program:\n");
 
                print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
-                              phys_to_virt(orb->cmd.cpa),
+                              dma32_to_virt(orb->cmd.cpa),
                               sizeof(struct ccw1), 0);
        }
        printk(KERN_WARNING "cio: ccw device state: %d\n",
index ce99ee2457e6e8669346fdee588cd05e0783b93f..a512eac8348529edcc033bdf9f977e1bbe3eae7f 100644 (file)
@@ -210,7 +210,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev)
        snsid_init(cdev);
        /* Channel program setup. */
        cp->cmd_code    = CCW_CMD_SENSE_ID;
-       cp->cda         = (u32)virt_to_phys(&cdev->private->dma_area->senseid);
+       cp->cda         = virt_to_dma32(&cdev->private->dma_area->senseid);
        cp->count       = sizeof(struct senseid);
        cp->flags       = CCW_FLAG_SLI;
        /* Request setup. */
index a5dba3829769c7954ed2d3ba38800bc768fb0019..40c97f8730751f2afa862ace30b16f1ade38ea80 100644 (file)
@@ -823,13 +823,14 @@ EXPORT_SYMBOL_GPL(ccw_device_get_chid);
  * the subchannels dma pool. Maximal size of allocation supported
  * is PAGE_SIZE.
  */
-void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size)
+void *ccw_device_dma_zalloc(struct ccw_device *cdev, size_t size,
+                           dma32_t *dma_handle)
 {
        void *addr;
 
        if (!get_device(&cdev->dev))
                return NULL;
-       addr = cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size);
+       addr = __cio_gp_dma_zalloc(cdev->private->dma_pool, &cdev->dev, size, dma_handle);
        if (IS_ERR_OR_NULL(addr))
                put_device(&cdev->dev);
        return addr;
index ad90045873e25a3e4e8f26c6baa566841d902af3..b3afe283cc1033f678e6729c164c485b4ecbce32 100644 (file)
@@ -141,7 +141,7 @@ static void spid_build_cp(struct ccw_device *cdev, u8 fn)
 
        pgid->inf.fc    = fn;
        cp->cmd_code    = CCW_CMD_SET_PGID;
-       cp->cda         = (u32)virt_to_phys(pgid);
+       cp->cda         = virt_to_dma32(pgid);
        cp->count       = sizeof(*pgid);
        cp->flags       = CCW_FLAG_SLI;
        req->cp         = cp;
@@ -442,7 +442,7 @@ static void snid_build_cp(struct ccw_device *cdev)
 
        /* Channel program setup. */
        cp->cmd_code    = CCW_CMD_SENSE_PGID;
-       cp->cda         = (u32)virt_to_phys(&cdev->private->dma_area->pgid[i]);
+       cp->cda         = virt_to_dma32(&cdev->private->dma_area->pgid[i]);
        cp->count       = sizeof(struct pgid);
        cp->flags       = CCW_FLAG_SLI;
        req->cp         = cp;
@@ -632,11 +632,11 @@ static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2)
        struct ccw1 *cp = cdev->private->dma_area->iccws;
 
        cp[0].cmd_code = CCW_CMD_STLCK;
-       cp[0].cda = (u32)virt_to_phys(buf1);
+       cp[0].cda = virt_to_dma32(buf1);
        cp[0].count = 32;
        cp[0].flags = CCW_FLAG_CC;
        cp[1].cmd_code = CCW_CMD_RELEASE;
-       cp[1].cda = (u32)virt_to_phys(buf2);
+       cp[1].cda = virt_to_dma32(buf2);
        cp[1].count = 32;
        cp[1].flags = 0;
        req->cp = cp;
index 6c2e35065fec3e9376a08e5375cd583420321b09..0ff8482a7b155ef878e44b5dcd7bd995f86be740 100644 (file)
@@ -332,7 +332,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
         */
        sense_ccw = &to_io_private(sch)->dma_area->sense_ccw;
        sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-       sense_ccw->cda = virt_to_phys(cdev->private->dma_area->irb.ecw);
+       sense_ccw->cda = virt_to_dma32(cdev->private->dma_area->irb.ecw);
        sense_ccw->count = SENSE_MAX_COUNT;
        sense_ccw->flags = CCW_FLAG_SLI;
 
index 1caedf931a5f00e89966bd2189ea26511e92d9d6..165de15523016c758ba8972b0c0d59b4d2aca5b4 100644 (file)
@@ -63,7 +63,7 @@ static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob)
        int cc;
 
        orb_init(orb);
-       orb->eadm.aob = (u32)virt_to_phys(aob);
+       orb->eadm.aob = virt_to_dma32(aob);
        orb->eadm.intparm = (u32)virt_to_phys(sch);
        orb->eadm.key = PAGE_DEFAULT_KEY >> 4;
 
@@ -147,7 +147,7 @@ static void eadm_subchannel_irq(struct subchannel *sch)
                css_sched_sch_todo(sch, SCH_TODO_EVAL);
                return;
        }
-       scm_irq_handler(phys_to_virt(scsw->aob), error);
+       scm_irq_handler(dma32_to_virt(scsw->aob), error);
        private->state = EADM_IDLE;
 
        if (private->completion)
index 84f24a2f46e4a0ae48f34ac8ddbe664c5f396a8b..ba35b64949d3a35a8d4e28488227c615072e90c4 100644 (file)
@@ -25,7 +25,7 @@
  */
 struct tcw *tcw_get_intrg(struct tcw *tcw)
 {
-       return phys_to_virt(tcw->intrg);
+       return dma32_to_virt(tcw->intrg);
 }
 EXPORT_SYMBOL(tcw_get_intrg);
 
@@ -40,9 +40,9 @@ EXPORT_SYMBOL(tcw_get_intrg);
 void *tcw_get_data(struct tcw *tcw)
 {
        if (tcw->r)
-               return phys_to_virt(tcw->input);
+               return dma64_to_virt(tcw->input);
        if (tcw->w)
-               return phys_to_virt(tcw->output);
+               return dma64_to_virt(tcw->output);
        return NULL;
 }
 EXPORT_SYMBOL(tcw_get_data);
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(tcw_get_data);
  */
 struct tccb *tcw_get_tccb(struct tcw *tcw)
 {
-       return phys_to_virt(tcw->tccb);
+       return dma64_to_virt(tcw->tccb);
 }
 EXPORT_SYMBOL(tcw_get_tccb);
 
@@ -67,7 +67,7 @@ EXPORT_SYMBOL(tcw_get_tccb);
  */
 struct tsb *tcw_get_tsb(struct tcw *tcw)
 {
-       return phys_to_virt(tcw->tsb);
+       return dma64_to_virt(tcw->tsb);
 }
 EXPORT_SYMBOL(tcw_get_tsb);
 
@@ -190,7 +190,7 @@ EXPORT_SYMBOL(tcw_finalize);
  */
 void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
 {
-       tcw->intrg = (u32)virt_to_phys(intrg_tcw);
+       tcw->intrg = virt_to_dma32(intrg_tcw);
 }
 EXPORT_SYMBOL(tcw_set_intrg);
 
@@ -208,11 +208,11 @@ EXPORT_SYMBOL(tcw_set_intrg);
 void tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
 {
        if (tcw->r) {
-               tcw->input = virt_to_phys(data);
+               tcw->input = virt_to_dma64(data);
                if (use_tidal)
                        tcw->flags |= TCW_FLAGS_INPUT_TIDA;
        } else if (tcw->w) {
-               tcw->output = virt_to_phys(data);
+               tcw->output = virt_to_dma64(data);
                if (use_tidal)
                        tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
        }
@@ -228,7 +228,7 @@ EXPORT_SYMBOL(tcw_set_data);
  */
 void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
 {
-       tcw->tccb = virt_to_phys(tccb);
+       tcw->tccb = virt_to_dma64(tccb);
 }
 EXPORT_SYMBOL(tcw_set_tccb);
 
@@ -241,7 +241,7 @@ EXPORT_SYMBOL(tcw_set_tccb);
  */
 void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
 {
-       tcw->tsb = virt_to_phys(tsb);
+       tcw->tsb = virt_to_dma64(tsb);
 }
 EXPORT_SYMBOL(tcw_set_tsb);
 
@@ -346,7 +346,7 @@ struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
        memset(tidaw, 0, sizeof(struct tidaw));
        tidaw->flags = flags;
        tidaw->count = count;
-       tidaw->addr = virt_to_phys(addr);
+       tidaw->addr = virt_to_dma64(addr);
        return tidaw;
 }
 EXPORT_SYMBOL(tcw_add_tidaw);
index a2d3778b2c95928d0fd9c7ecf67573d313cb01d3..14d2a1822b50600396193f02426ab87e36135b0c 100644 (file)
@@ -12,6 +12,9 @@
 #ifndef S390_ORB_H
 #define S390_ORB_H
 
+#include <linux/types.h>
+#include <asm/dma-types.h>
+
 /*
  * Command-mode operation request block
  */
@@ -34,7 +37,7 @@ struct cmd_orb {
        u32 ils:1;      /* incorrect length */
        u32 zero:6;     /* reserved zeros */
        u32 orbx:1;     /* ORB extension control */
-       u32 cpa;        /* channel program address */
+       dma32_t cpa;    /* channel program address */
 }  __packed __aligned(4);
 
 /*
@@ -49,7 +52,7 @@ struct tm_orb {
        u32 lpm:8;
        u32:7;
        u32 x:1;
-       u32 tcw;
+       dma32_t tcw;
        u32 prio:8;
        u32:8;
        u32 rsvpgm:8;
@@ -71,7 +74,7 @@ struct eadm_orb {
        u32 compat2:1;
        u32:21;
        u32 x:1;
-       u32 aob;
+       dma32_t aob;
        u32 css_prio:8;
        u32:8;
        u32 scm_prio:8;
index 9cde55730b65a733b5d1cb9977c83750392e6312..3d9f0834c78bf1e6a55c17a21218b29bacbd1dce 100644 (file)
@@ -82,7 +82,7 @@ static inline int do_siga_input(unsigned long schid, unsigned long mask,
  */
 static inline int do_siga_output(unsigned long schid, unsigned long mask,
                                 unsigned int *bb, unsigned long fc,
-                                unsigned long aob)
+                                dma64_t aob)
 {
        int cc;
 
@@ -321,7 +321,7 @@ static inline int qdio_siga_sync_q(struct qdio_q *q)
 }
 
 static int qdio_siga_output(struct qdio_q *q, unsigned int count,
-                           unsigned int *busy_bit, unsigned long aob)
+                           unsigned int *busy_bit, dma64_t aob)
 {
        unsigned long schid = *((u32 *) &q->irq_ptr->schid);
        unsigned int fc = QDIO_SIGA_WRITE;
@@ -628,7 +628,7 @@ int qdio_inspect_output_queue(struct ccw_device *cdev, unsigned int nr,
 EXPORT_SYMBOL_GPL(qdio_inspect_output_queue);
 
 static int qdio_kick_outbound_q(struct qdio_q *q, unsigned int count,
-                               unsigned long aob)
+                               dma64_t aob)
 {
        int retries = 0, cc;
        unsigned int busy_bit;
@@ -1070,7 +1070,7 @@ int qdio_establish(struct ccw_device *cdev,
        irq_ptr->ccw->cmd_code = ciw->cmd;
        irq_ptr->ccw->flags = CCW_FLAG_SLI;
        irq_ptr->ccw->count = ciw->count;
-       irq_ptr->ccw->cda = (u32) virt_to_phys(irq_ptr->qdr);
+       irq_ptr->ccw->cda = virt_to_dma32(irq_ptr->qdr);
 
        spin_lock_irq(get_ccwdev_lock(cdev));
        ccw_device_set_options_mask(cdev, 0);
@@ -1263,9 +1263,9 @@ static int handle_outbound(struct qdio_q *q, unsigned int bufnr, unsigned int co
                qperf_inc(q, outbound_queue_full);
 
        if (queue_type(q) == QDIO_IQDIO_QFMT) {
-               unsigned long phys_aob = aob ? virt_to_phys(aob) : 0;
+               dma64_t phys_aob = aob ? virt_to_dma64(aob) : 0;
 
-               WARN_ON_ONCE(!IS_ALIGNED(phys_aob, 256));
+               WARN_ON_ONCE(!IS_ALIGNED(dma64_to_u64(phys_aob), 256));
                rc = qdio_kick_outbound_q(q, count, phys_aob);
        } else if (qdio_need_siga_sync(q->irq_ptr)) {
                rc = qdio_sync_output_queue(q);
index 714878e2acc4d907f94a7f4c1f2384e1a131413e..99c0fd23022de3f2c8d97366ab705a07ad2d846d 100644 (file)
@@ -179,7 +179,7 @@ static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
 
        /* fill in sl */
        for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
-               q->sl->element[j].sbal = virt_to_phys(q->sbal[j]);
+               q->sl->element[j].sbal = virt_to_dma64(q->sbal[j]);
 }
 
 static void setup_queues(struct qdio_irq *irq_ptr,
@@ -291,9 +291,9 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr)
 
 static void qdio_fill_qdr_desc(struct qdesfmt0 *desc, struct qdio_q *queue)
 {
-       desc->sliba = virt_to_phys(queue->slib);
-       desc->sla = virt_to_phys(queue->sl);
-       desc->slsba = virt_to_phys(&queue->slsb);
+       desc->sliba = virt_to_dma64(queue->slib);
+       desc->sla = virt_to_dma64(queue->sl);
+       desc->slsba = virt_to_dma64(&queue->slsb);
 
        desc->akey = PAGE_DEFAULT_KEY >> 4;
        desc->bkey = PAGE_DEFAULT_KEY >> 4;
@@ -315,7 +315,7 @@ static void setup_qdr(struct qdio_irq *irq_ptr,
        irq_ptr->qdr->oqdcnt = qdio_init->no_output_qs;
        irq_ptr->qdr->iqdsz = sizeof(struct qdesfmt0) / 4; /* size in words */
        irq_ptr->qdr->oqdsz = sizeof(struct qdesfmt0) / 4;
-       irq_ptr->qdr->qiba = virt_to_phys(&irq_ptr->qib);
+       irq_ptr->qdr->qiba = virt_to_dma64(&irq_ptr->qib);
        irq_ptr->qdr->qkey = PAGE_DEFAULT_KEY >> 4;
 
        for (i = 0; i < qdio_init->no_input_qs; i++)
index 9b9335dd06db6cbe149b8897d6e9d5a645d512f6..ccd4ed93bd92ddacdafc4f28393fde530ad88fbe 100644 (file)
@@ -137,15 +137,15 @@ static struct airq_struct tiqdio_airq = {
 static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
 {
        struct chsc_scssc_area *scssc = (void *)irq_ptr->chsc_page;
-       u64 summary_indicator_addr, subchannel_indicator_addr;
+       dma64_t summary_indicator_addr, subchannel_indicator_addr;
        int rc;
 
        if (reset) {
                summary_indicator_addr = 0;
                subchannel_indicator_addr = 0;
        } else {
-               summary_indicator_addr = virt_to_phys(tiqdio_airq.lsi_ptr);
-               subchannel_indicator_addr = virt_to_phys(irq_ptr->dsci);
+               summary_indicator_addr = virt_to_dma64(tiqdio_airq.lsi_ptr);
+               subchannel_indicator_addr = virt_to_dma64(irq_ptr->dsci);
        }
 
        rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr,
index aafd66305eadebf66170bc6d7049002e9e31b1f2..6e5c508b1e07c626b43c73ffcbafb7853a264e61 100644 (file)
@@ -190,7 +190,7 @@ static bool page_array_iova_pinned(struct page_array *pa, u64 iova, u64 length)
 }
 /* Create the list of IDAL words for a page_array. */
 static inline void page_array_idal_create_words(struct page_array *pa,
-                                               unsigned long *idaws)
+                                               dma64_t *idaws)
 {
        int i;
 
@@ -203,10 +203,10 @@ static inline void page_array_idal_create_words(struct page_array *pa,
         */
 
        for (i = 0; i < pa->pa_nr; i++) {
-               idaws[i] = page_to_phys(pa->pa_page[i]);
+               idaws[i] = virt_to_dma64(page_to_virt(pa->pa_page[i]));
 
                /* Incorporate any offset from each starting address */
-               idaws[i] += pa->pa_iova[i] & (PAGE_SIZE - 1);
+               idaws[i] = dma64_add(idaws[i], pa->pa_iova[i] & ~PAGE_MASK);
        }
 }
 
@@ -227,7 +227,7 @@ static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
                        pccw1->flags = ccw0.flags;
                        pccw1->count = ccw0.count;
                }
-               pccw1->cda = ccw0.cda;
+               pccw1->cda = u32_to_dma32(ccw0.cda);
                pccw1++;
        }
 }
@@ -299,11 +299,12 @@ static inline int ccw_does_data_transfer(struct ccw1 *ccw)
  *
  * Returns 1 if yes, 0 if no.
  */
-static inline int is_cpa_within_range(u32 cpa, u32 head, int len)
+static inline int is_cpa_within_range(dma32_t cpa, u32 head, int len)
 {
        u32 tail = head + (len - 1) * sizeof(struct ccw1);
+       u32 gcpa = dma32_to_u32(cpa);
 
-       return (head <= cpa && cpa <= tail);
+       return head <= gcpa && gcpa <= tail;
 }
 
 static inline int is_tic_within_range(struct ccw1 *ccw, u32 head, int len)
@@ -356,7 +357,7 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
        if (ccw_is_tic(ccw))
                return;
 
-       kfree(phys_to_virt(ccw->cda));
+       kfree(dma32_to_virt(ccw->cda));
 }
 
 /**
@@ -417,15 +418,17 @@ static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp)
 static int ccwchain_loop_tic(struct ccwchain *chain,
                             struct channel_program *cp);
 
-static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
+static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
 {
        struct vfio_device *vdev =
                &container_of(cp, struct vfio_ccw_private, cp)->vdev;
        struct ccwchain *chain;
        int len, ret;
+       u32 gcda;
 
+       gcda = dma32_to_u32(cda);
        /* Copy 2K (the most we support today) of possible CCWs */
-       ret = vfio_dma_rw(vdev, cda, cp->guest_cp, CCWCHAIN_LEN_MAX * sizeof(struct ccw1), false);
+       ret = vfio_dma_rw(vdev, gcda, cp->guest_cp, CCWCHAIN_LEN_MAX * sizeof(struct ccw1), false);
        if (ret)
                return ret;
 
@@ -434,7 +437,7 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
                convert_ccw0_to_ccw1(cp->guest_cp, CCWCHAIN_LEN_MAX);
 
        /* Count the CCWs in the current chain */
-       len = ccwchain_calc_length(cda, cp);
+       len = ccwchain_calc_length(gcda, cp);
        if (len < 0)
                return len;
 
@@ -444,7 +447,7 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
                return -ENOMEM;
 
        chain->ch_len = len;
-       chain->ch_iova = cda;
+       chain->ch_iova = gcda;
 
        /* Copy the actual CCWs into the new chain */
        memcpy(chain->ch_ccw, cp->guest_cp, len * sizeof(struct ccw1));
@@ -487,13 +490,13 @@ static int ccwchain_fetch_tic(struct ccw1 *ccw,
                              struct channel_program *cp)
 {
        struct ccwchain *iter;
-       u32 ccw_head;
+       u32 cda, ccw_head;
 
        list_for_each_entry(iter, &cp->ccwchain_list, next) {
                ccw_head = iter->ch_iova;
                if (is_cpa_within_range(ccw->cda, ccw_head, iter->ch_len)) {
-                       ccw->cda = (__u32) (addr_t) (((char *)iter->ch_ccw) +
-                                                    (ccw->cda - ccw_head));
+                       cda = (u64)iter->ch_ccw + dma32_to_u32(ccw->cda) - ccw_head;
+                       ccw->cda = u32_to_dma32(cda);
                        return 0;
                }
        }
@@ -501,14 +504,12 @@ static int ccwchain_fetch_tic(struct ccw1 *ccw,
        return -EFAULT;
 }
 
-static unsigned long *get_guest_idal(struct ccw1 *ccw,
-                                    struct channel_program *cp,
-                                    int idaw_nr)
+static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int idaw_nr)
 {
        struct vfio_device *vdev =
                &container_of(cp, struct vfio_ccw_private, cp)->vdev;
-       unsigned long *idaws;
-       unsigned int *idaws_f1;
+       dma64_t *idaws;
+       dma32_t *idaws_f1;
        int idal_len = idaw_nr * sizeof(*idaws);
        int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
        int idaw_mask = ~(idaw_size - 1);
@@ -520,7 +521,7 @@ static unsigned long *get_guest_idal(struct ccw1 *ccw,
 
        if (ccw_is_idal(ccw)) {
                /* Copy IDAL from guest */
-               ret = vfio_dma_rw(vdev, ccw->cda, idaws, idal_len, false);
+               ret = vfio_dma_rw(vdev, dma32_to_u32(ccw->cda), idaws, idal_len, false);
                if (ret) {
                        kfree(idaws);
                        return ERR_PTR(ret);
@@ -528,14 +529,18 @@ static unsigned long *get_guest_idal(struct ccw1 *ccw,
        } else {
                /* Fabricate an IDAL based off CCW data address */
                if (cp->orb.cmd.c64) {
-                       idaws[0] = ccw->cda;
-                       for (i = 1; i < idaw_nr; i++)
-                               idaws[i] = (idaws[i - 1] + idaw_size) & idaw_mask;
+                       idaws[0] = u64_to_dma64(dma32_to_u32(ccw->cda));
+                       for (i = 1; i < idaw_nr; i++) {
+                               idaws[i] = dma64_add(idaws[i - 1], idaw_size);
+                               idaws[i] = dma64_and(idaws[i], idaw_mask);
+                       }
                } else {
-                       idaws_f1 = (unsigned int *)idaws;
+                       idaws_f1 = (dma32_t *)idaws;
                        idaws_f1[0] = ccw->cda;
-                       for (i = 1; i < idaw_nr; i++)
-                               idaws_f1[i] = (idaws_f1[i - 1] + idaw_size) & idaw_mask;
+                       for (i = 1; i < idaw_nr; i++) {
+                               idaws_f1[i] = dma32_add(idaws_f1[i - 1], idaw_size);
+                               idaws_f1[i] = dma32_and(idaws_f1[i], idaw_mask);
+                       }
                }
        }
 
@@ -572,7 +577,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
        if (ccw_is_idal(ccw)) {
                /* Read first IDAW to check its starting address. */
                /* All subsequent IDAWs will be 2K- or 4K-aligned. */
-               ret = vfio_dma_rw(vdev, ccw->cda, &iova, size, false);
+               ret = vfio_dma_rw(vdev, dma32_to_u32(ccw->cda), &iova, size, false);
                if (ret)
                        return ret;
 
@@ -583,7 +588,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
                if (!cp->orb.cmd.c64)
                        iova = iova >> 32;
        } else {
-               iova = ccw->cda;
+               iova = dma32_to_u32(ccw->cda);
        }
 
        /* Format-1 IDAWs operate on 2K each */
@@ -604,8 +609,8 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
 {
        struct vfio_device *vdev =
                &container_of(cp, struct vfio_ccw_private, cp)->vdev;
-       unsigned long *idaws;
-       unsigned int *idaws_f1;
+       dma64_t *idaws;
+       dma32_t *idaws_f1;
        int ret;
        int idaw_nr;
        int i;
@@ -636,12 +641,12 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
         * Copy guest IDAWs into page_array, in case the memory they
         * occupy is not contiguous.
         */
-       idaws_f1 = (unsigned int *)idaws;
+       idaws_f1 = (dma32_t *)idaws;
        for (i = 0; i < idaw_nr; i++) {
                if (cp->orb.cmd.c64)
-                       pa->pa_iova[i] = idaws[i];
+                       pa->pa_iova[i] = dma64_to_u64(idaws[i]);
                else
-                       pa->pa_iova[i] = idaws_f1[i];
+                       pa->pa_iova[i] = dma32_to_u32(idaws_f1[i]);
        }
 
        if (ccw_does_data_transfer(ccw)) {
@@ -652,7 +657,7 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
                pa->pa_nr = 0;
        }
 
-       ccw->cda = (__u32) virt_to_phys(idaws);
+       ccw->cda = virt_to_dma32(idaws);
        ccw->flags |= CCW_FLAG_IDA;
 
        /* Populate the IDAL with pinned/translated addresses from page */
@@ -874,7 +879,7 @@ union orb *cp_get_orb(struct channel_program *cp, struct subchannel *sch)
 
        chain = list_first_entry(&cp->ccwchain_list, struct ccwchain, next);
        cpa = chain->ch_ccw;
-       orb->cmd.cpa = (__u32)virt_to_phys(cpa);
+       orb->cmd.cpa = virt_to_dma32(cpa);
 
        return orb;
 }
@@ -896,7 +901,7 @@ union orb *cp_get_orb(struct channel_program *cp, struct subchannel *sch)
 void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
 {
        struct ccwchain *chain;
-       u32 cpa = scsw->cmd.cpa;
+       dma32_t cpa = scsw->cmd.cpa;
        u32 ccw_head;
 
        if (!cp->initialized)
@@ -919,9 +924,10 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
                         * (cpa - ccw_head) is the offset value of the host
                         * physical ccw to its chain head.
                         * Adding this value to the guest physical ccw chain
-                        * head gets us the guest cpa.
+                        * head gets us the guest cpa:
+                        * cpa = chain->ch_iova + (cpa - ccw_head)
                         */
-                       cpa = chain->ch_iova + (cpa - ccw_head);
+                       cpa = dma32_add(cpa, chain->ch_iova - ccw_head);
                        break;
                }
        }
index 09877b46181d469a1fead1b7cbc0aff1b56e4fa9..4d7988ea47ef0f3e23304a5b1547c2bb29ce50ee 100644 (file)
@@ -378,7 +378,7 @@ static void fsm_open(struct vfio_ccw_private *private,
 
        spin_lock_irq(&sch->lock);
        sch->isc = VFIO_CCW_ISC;
-       ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+       ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
        if (ret)
                goto err_unlock;
 
index 02c503f16bc2dbd28828910db992fc1f5e6a9cbc..eba07f8ef3087190e6a0af4be9d278c4cff0643c 100644 (file)
@@ -107,7 +107,11 @@ EXPORT_SYMBOL(zcrypt_msgtype);
 
 struct zcdn_device;
 
-static struct class *zcrypt_class;
+static void zcdn_device_release(struct device *dev);
+static const struct class zcrypt_class = {
+       .name = ZCRYPT_NAME,
+       .dev_release = zcdn_device_release,
+};
 static dev_t zcrypt_devt;
 static struct cdev zcrypt_cdev;
 
@@ -130,7 +134,7 @@ static int zcdn_destroy(const char *name);
  */
 static inline struct zcdn_device *find_zcdndev_by_name(const char *name)
 {
-       struct device *dev = class_find_device_by_name(zcrypt_class, name);
+       struct device *dev = class_find_device_by_name(&zcrypt_class, name);
 
        return dev ? to_zcdn_dev(dev) : NULL;
 }
@@ -142,7 +146,7 @@ static inline struct zcdn_device *find_zcdndev_by_name(const char *name)
  */
 static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt)
 {
-       struct device *dev = class_find_device_by_devt(zcrypt_class, devt);
+       struct device *dev = class_find_device_by_devt(&zcrypt_class, devt);
 
        return dev ? to_zcdn_dev(dev) : NULL;
 }
@@ -396,7 +400,7 @@ static int zcdn_create(const char *name)
                goto unlockout;
        }
        zcdndev->device.release = zcdn_device_release;
-       zcdndev->device.class = zcrypt_class;
+       zcdndev->device.class = &zcrypt_class;
        zcdndev->device.devt = devt;
        zcdndev->device.groups = zcdn_dev_attr_groups;
        if (name[0])
@@ -573,6 +577,7 @@ static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
 {
        if (!zq || !try_module_get(zq->queue->ap_dev.device.driver->owner))
                return NULL;
+       zcrypt_card_get(zc);
        zcrypt_queue_get(zq);
        get_device(&zq->queue->ap_dev.device);
        atomic_add(weight, &zc->load);
@@ -592,6 +597,7 @@ static inline void zcrypt_drop_queue(struct zcrypt_card *zc,
        atomic_sub(weight, &zq->load);
        put_device(&zq->queue->ap_dev.device);
        zcrypt_queue_put(zq);
+       zcrypt_card_put(zc);
        module_put(mod);
 }
 
@@ -2075,12 +2081,9 @@ static int __init zcdn_init(void)
        int rc;
 
        /* create a new class 'zcrypt' */
-       zcrypt_class = class_create(ZCRYPT_NAME);
-       if (IS_ERR(zcrypt_class)) {
-               rc = PTR_ERR(zcrypt_class);
-               goto out_class_create_failed;
-       }
-       zcrypt_class->dev_release = zcdn_device_release;
+       rc = class_register(&zcrypt_class);
+       if (rc)
+               goto out_class_register_failed;
 
        /* alloc device minor range */
        rc = alloc_chrdev_region(&zcrypt_devt,
@@ -2096,35 +2099,35 @@ static int __init zcdn_init(void)
                goto out_cdev_add_failed;
 
        /* need some class specific sysfs attributes */
-       rc = class_create_file(zcrypt_class, &class_attr_zcdn_create);
+       rc = class_create_file(&zcrypt_class, &class_attr_zcdn_create);
        if (rc)
                goto out_class_create_file_1_failed;
-       rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy);
+       rc = class_create_file(&zcrypt_class, &class_attr_zcdn_destroy);
        if (rc)
                goto out_class_create_file_2_failed;
 
        return 0;
 
 out_class_create_file_2_failed:
-       class_remove_file(zcrypt_class, &class_attr_zcdn_create);
+       class_remove_file(&zcrypt_class, &class_attr_zcdn_create);
 out_class_create_file_1_failed:
        cdev_del(&zcrypt_cdev);
 out_cdev_add_failed:
        unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
 out_alloc_chrdev_failed:
-       class_destroy(zcrypt_class);
-out_class_create_failed:
+       class_unregister(&zcrypt_class);
+out_class_register_failed:
        return rc;
 }
 
 static void zcdn_exit(void)
 {
-       class_remove_file(zcrypt_class, &class_attr_zcdn_create);
-       class_remove_file(zcrypt_class, &class_attr_zcdn_destroy);
+       class_remove_file(&zcrypt_class, &class_attr_zcdn_create);
+       class_remove_file(&zcrypt_class, &class_attr_zcdn_destroy);
        zcdn_destroy_all();
        cdev_del(&zcrypt_cdev);
        unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
-       class_destroy(zcrypt_class);
+       class_unregister(&zcrypt_class);
 }
 
 /*
index 90ec477386a86cd7d1abb396a1f176d0e8caf820..9678c6a2cda727cb9a9a1a35efc6b94d476dfb84 100644 (file)
@@ -1325,7 +1325,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
        clear_normalized_cda(&ch->ccw[1]);
 
        CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
-                       (void *)(unsigned long)ch->ccw[1].cda,
+                       (void *)(u64)dma32_to_u32(ch->ccw[1].cda),
                        ch->trans_skb->data);
        ch->ccw[1].count = ch->max_bufsize;
 
@@ -1340,7 +1340,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
        }
 
        CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
-                       (void *)(unsigned long)ch->ccw[1].cda,
+                       (void *)(u64)dma32_to_u32(ch->ccw[1].cda),
                        ch->trans_skb->data);
 
        ch->ccw[1].count = ch->trans_skb->len;
index ac15d7c2b200bf005c56ac8707bbfb907823caed..878fe3ce53ada11f1a70e2ec6be74eb84d0cef5e 100644 (file)
@@ -1389,7 +1389,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type,
                ch->ccw[15].cmd_code = CCW_CMD_WRITE;
                ch->ccw[15].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[15].count    = TH_HEADER_LENGTH;
-               ch->ccw[15].cda      = virt_to_phys(ch->discontact_th);
+               ch->ccw[15].cda      = virt_to_dma32(ch->discontact_th);
 
                ch->ccw[16].cmd_code = CCW_CMD_NOOP;
                ch->ccw[16].flags    = CCW_FLAG_SLI;
index 7a2f34a5e0e09ff95bfd2f5b9248f1bdbf68b771..9e580ef69bdaabe69128399baba45f8e957691b3 100644 (file)
@@ -1708,57 +1708,57 @@ static void mpc_action_side_xid(fsm_instance *fsm, void *arg, int side)
                ch->ccw[9].cmd_code     = CCW_CMD_WRITE;
                ch->ccw[9].flags        = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[9].count        = TH_HEADER_LENGTH;
-               ch->ccw[9].cda          = virt_to_phys(ch->xid_th);
+               ch->ccw[9].cda          = virt_to_dma32(ch->xid_th);
 
                if (ch->xid == NULL)
                                goto done;
                ch->ccw[10].cmd_code    = CCW_CMD_WRITE;
                ch->ccw[10].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[10].count       = XID2_LENGTH;
-               ch->ccw[10].cda         = virt_to_phys(ch->xid);
+               ch->ccw[10].cda         = virt_to_dma32(ch->xid);
 
                ch->ccw[11].cmd_code    = CCW_CMD_READ;
                ch->ccw[11].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[11].count       = TH_HEADER_LENGTH;
-               ch->ccw[11].cda         = virt_to_phys(ch->rcvd_xid_th);
+               ch->ccw[11].cda         = virt_to_dma32(ch->rcvd_xid_th);
 
                ch->ccw[12].cmd_code    = CCW_CMD_READ;
                ch->ccw[12].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[12].count       = XID2_LENGTH;
-               ch->ccw[12].cda         = virt_to_phys(ch->rcvd_xid);
+               ch->ccw[12].cda         = virt_to_dma32(ch->rcvd_xid);
 
                ch->ccw[13].cmd_code    = CCW_CMD_READ;
-               ch->ccw[13].cda         = virt_to_phys(ch->rcvd_xid_id);
+               ch->ccw[13].cda         = virt_to_dma32(ch->rcvd_xid_id);
 
        } else { /* side == YSIDE : mpc_action_yside_xid */
                ch->ccw[9].cmd_code     = CCW_CMD_READ;
                ch->ccw[9].flags        = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[9].count        = TH_HEADER_LENGTH;
-               ch->ccw[9].cda          = virt_to_phys(ch->rcvd_xid_th);
+               ch->ccw[9].cda          = virt_to_dma32(ch->rcvd_xid_th);
 
                ch->ccw[10].cmd_code    = CCW_CMD_READ;
                ch->ccw[10].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[10].count       = XID2_LENGTH;
-               ch->ccw[10].cda         = virt_to_phys(ch->rcvd_xid);
+               ch->ccw[10].cda         = virt_to_dma32(ch->rcvd_xid);
 
                if (ch->xid_th == NULL)
                                goto done;
                ch->ccw[11].cmd_code    = CCW_CMD_WRITE;
                ch->ccw[11].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[11].count       = TH_HEADER_LENGTH;
-               ch->ccw[11].cda         = virt_to_phys(ch->xid_th);
+               ch->ccw[11].cda         = virt_to_dma32(ch->xid_th);
 
                if (ch->xid == NULL)
                                goto done;
                ch->ccw[12].cmd_code    = CCW_CMD_WRITE;
                ch->ccw[12].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[12].count       = XID2_LENGTH;
-               ch->ccw[12].cda         = virt_to_phys(ch->xid);
+               ch->ccw[12].cda         = virt_to_dma32(ch->xid);
 
                if (ch->xid_id == NULL)
                                goto done;
                ch->ccw[13].cmd_code    = CCW_CMD_WRITE;
-               ch->ccw[13].cda         = virt_to_phys(ch->xid_id);
+               ch->ccw[13].cda         = virt_to_dma32(ch->xid_id);
 
        }
        ch->ccw[13].flags       = CCW_FLAG_SLI | CCW_FLAG_CC;
index a1f2acd6fb8f66a91650bdc4ced82a35c728d96c..25d4e6376591e657461d5524309373e681d9c4ad 100644 (file)
@@ -218,7 +218,7 @@ lcs_setup_read_ccws(struct lcs_card *card)
                 * we do not need to do set_normalized_cda.
                 */
                card->read.ccws[cnt].cda =
-                       (__u32)virt_to_phys(card->read.iob[cnt].data);
+                       virt_to_dma32(card->read.iob[cnt].data);
                ((struct lcs_header *)
                 card->read.iob[cnt].data)->offset = LCS_ILLEGAL_OFFSET;
                card->read.iob[cnt].callback = lcs_get_frames_cb;
@@ -230,8 +230,7 @@ lcs_setup_read_ccws(struct lcs_card *card)
        card->read.ccws[LCS_NUM_BUFFS - 1].flags |= CCW_FLAG_SUSPEND;
        /* Last ccw is a tic (transfer in channel). */
        card->read.ccws[LCS_NUM_BUFFS].cmd_code = LCS_CCW_TRANSFER;
-       card->read.ccws[LCS_NUM_BUFFS].cda =
-               (__u32)virt_to_phys(card->read.ccws);
+       card->read.ccws[LCS_NUM_BUFFS].cda = virt_to_dma32(card->read.ccws);
        /* Setg initial state of the read channel. */
        card->read.state = LCS_CH_STATE_INIT;
 
@@ -273,12 +272,11 @@ lcs_setup_write_ccws(struct lcs_card *card)
                 * we do not need to do set_normalized_cda.
                 */
                card->write.ccws[cnt].cda =
-                       (__u32)virt_to_phys(card->write.iob[cnt].data);
+                       virt_to_dma32(card->write.iob[cnt].data);
        }
        /* Last ccw is a tic (transfer in channel). */
        card->write.ccws[LCS_NUM_BUFFS].cmd_code = LCS_CCW_TRANSFER;
-       card->write.ccws[LCS_NUM_BUFFS].cda =
-               (__u32)virt_to_phys(card->write.ccws);
+       card->write.ccws[LCS_NUM_BUFFS].cda = virt_to_dma32(card->write.ccws);
        /* Set initial state of the write channel. */
        card->read.state = LCS_CH_STATE_INIT;
 
@@ -1399,7 +1397,7 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        if ((channel->state != LCS_CH_STATE_INIT) &&
            (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
            (irb->scsw.cmd.cpa != 0)) {
-               index = (struct ccw1 *) __va((addr_t) irb->scsw.cmd.cpa)
+               index = (struct ccw1 *)dma32_to_virt(irb->scsw.cmd.cpa)
                        - channel->ccws;
                if ((irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED) ||
                    (irb->scsw.cmd.cstat & SCHN_STAT_PCI))
index cf8506d0f185c0bd6b921cbc6ed507c1be38088b..a0cce6872075d4330578065191804db4f6bd747b 100644 (file)
@@ -426,7 +426,7 @@ static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,
        ccw->cmd_code = cmd_code;
        ccw->flags = flags | CCW_FLAG_SLI;
        ccw->count = len;
-       ccw->cda = (__u32)virt_to_phys(data);
+       ccw->cda = virt_to_dma32(data);
 }
 
 static int __qeth_issue_next_read(struct qeth_card *card)
@@ -1359,7 +1359,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        qeth_tx_complete_buf(queue, buf, error, budget);
 
        for (i = 0; i < queue->max_elements; ++i) {
-               void *data = phys_to_virt(buf->buffer->element[i].addr);
+               void *data = dma64_to_virt(buf->buffer->element[i].addr);
 
                if (__test_and_clear_bit(i, buf->from_kmem_cache) && data)
                        kmem_cache_free(qeth_core_header_cache, data);
@@ -1404,7 +1404,7 @@ static void qeth_tx_complete_pending_bufs(struct qeth_card *card,
                        for (i = 0;
                             i < aob->sb_count && i < queue->max_elements;
                             i++) {
-                               void *data = phys_to_virt(aob->sba[i]);
+                               void *data = dma64_to_virt(aob->sba[i]);
 
                                if (test_bit(i, buf->from_kmem_cache) && data)
                                        kmem_cache_free(qeth_core_header_cache,
@@ -2918,8 +2918,8 @@ 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 =
-                       page_to_phys(pool_entry->elements[i]);
+               buf->buffer->element[i].addr = u64_to_dma64(
+                       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
@@ -3765,9 +3765,9 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err,
 
                while ((e < QDIO_MAX_ELEMENTS_PER_BUFFER) &&
                       buffer->element[e].addr) {
-                       unsigned long phys_aob_addr = buffer->element[e].addr;
+                       dma64_t phys_aob_addr = buffer->element[e].addr;
 
-                       qeth_qdio_handle_aob(card, phys_to_virt(phys_aob_addr));
+                       qeth_qdio_handle_aob(card, dma64_to_virt(phys_aob_addr));
                        ++e;
                }
                qeth_scrub_qdio_buffer(buffer, QDIO_MAX_ELEMENTS_PER_BUFFER);
@@ -4042,7 +4042,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
        if (hd_len) {
                is_first_elem = false;
 
-               buffer->element[element].addr = virt_to_phys(hdr);
+               buffer->element[element].addr = virt_to_dma64(hdr);
                buffer->element[element].length = hd_len;
                buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG;
 
@@ -4063,7 +4063,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
                elem_length = min_t(unsigned int, length,
                                    PAGE_SIZE - offset_in_page(data));
 
-               buffer->element[element].addr = virt_to_phys(data);
+               buffer->element[element].addr = virt_to_dma64(data);
                buffer->element[element].length = elem_length;
                length -= elem_length;
                if (is_first_elem) {
@@ -4093,7 +4093,7 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
                        elem_length = min_t(unsigned int, length,
                                            PAGE_SIZE - offset_in_page(data));
 
-                       buffer->element[element].addr = virt_to_phys(data);
+                       buffer->element[element].addr = virt_to_dma64(data);
                        buffer->element[element].length = elem_length;
                        buffer->element[element].eflags =
                                SBAL_EFLAGS_MIDDLE_FRAG;
@@ -5569,7 +5569,7 @@ next_packet:
                offset = 0;
        }
 
-       hdr = phys_to_virt(element->addr) + offset;
+       hdr = dma64_to_virt(element->addr) + offset;
        offset += sizeof(*hdr);
        skb = NULL;
 
@@ -5661,7 +5661,7 @@ use_skb:
 walk_packet:
        while (skb_len) {
                int data_len = min(skb_len, (int)(element->length - offset));
-               char *data = phys_to_virt(element->addr) + offset;
+               char *data = dma64_to_virt(element->addr) + offset;
 
                skb_len -= data_len;
                offset += data_len;
index ceed1b6f7cb6114a50d241b522aafccf61a295b7..22e82000334ab46255b610708683b6e904a94952 100644 (file)
@@ -2742,7 +2742,7 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
        for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) {
 
                sbale = &sbal->element[idx];
-               req_id = sbale->addr;
+               req_id = dma64_to_u64(sbale->addr);
                fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
 
                if (!fsf_req) {
index f54f506b02d66f709a002216ef2301ff7b343fe0..8cbc5e1711af055ebf7f66ac3e6a2383a3c2be71 100644 (file)
@@ -125,7 +125,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
                        memset(pl, 0,
                               ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *));
                        sbale = qdio->res_q[idx]->element;
-                       req_id = sbale->addr;
+                       req_id = dma64_to_u64(sbale->addr);
                        scount = min(sbale->scount + 1,
                                     ZFCP_QDIO_MAX_SBALS_PER_REQ + 1);
                                     /* incl. signaling SBAL */
@@ -256,7 +256,7 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
                                             q_req->sbal_number);
                        return -EINVAL;
                }
-               sbale->addr = sg_phys(sg);
+               sbale->addr = u64_to_dma64(sg_phys(sg));
                sbale->length = sg->length;
        }
        return 0;
index 90134d9b69a77adba7044c91042cc08e0135e631..8f7d2ae94441ae9e23da4ce050ede741588badca 100644 (file)
@@ -129,14 +129,14 @@ void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
                                        % QDIO_MAX_BUFFERS_PER_Q;
 
        sbale = zfcp_qdio_sbale_req(qdio, q_req);
-       sbale->addr = req_id;
+       sbale->addr = u64_to_dma64(req_id);
        sbale->eflags = 0;
        sbale->sflags = SBAL_SFLAGS0_COMMAND | sbtype;
 
        if (unlikely(!data))
                return;
        sbale++;
-       sbale->addr = virt_to_phys(data);
+       sbale->addr = virt_to_dma64(data);
        sbale->length = len;
 }
 
@@ -159,7 +159,7 @@ void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
        BUG_ON(q_req->sbale_curr == qdio->max_sbale_per_sbal - 1);
        q_req->sbale_curr++;
        sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-       sbale->addr = virt_to_phys(data);
+       sbale->addr = virt_to_dma64(data);
        sbale->length = len;
 }
 
index ac67576301bf53d20d7194e3ae38cba6a7bae979..d7569f3955591acc43dcb0e5df58c3104e3eea65 100644 (file)
@@ -72,6 +72,7 @@ struct virtio_ccw_device {
        unsigned int config_ready;
        void *airq_info;
        struct vcdev_dma_area *dma_area;
+       dma32_t dma_area_addr;
 };
 
 static inline unsigned long *indicators(struct virtio_ccw_device *vcdev)
@@ -84,20 +85,50 @@ static inline unsigned long *indicators2(struct virtio_ccw_device *vcdev)
        return &vcdev->dma_area->indicators2;
 }
 
+/* Spec stipulates a 64 bit address */
+static inline dma64_t indicators_dma(struct virtio_ccw_device *vcdev)
+{
+       u64 dma_area_addr = dma32_to_u32(vcdev->dma_area_addr);
+
+       return dma64_add(u64_to_dma64(dma_area_addr),
+                        offsetof(struct vcdev_dma_area, indicators));
+}
+
+/* Spec stipulates a 64 bit address */
+static inline dma64_t indicators2_dma(struct virtio_ccw_device *vcdev)
+{
+       u64 dma_area_addr = dma32_to_u32(vcdev->dma_area_addr);
+
+       return dma64_add(u64_to_dma64(dma_area_addr),
+                        offsetof(struct vcdev_dma_area, indicators2));
+}
+
+static inline dma32_t config_block_dma(struct virtio_ccw_device *vcdev)
+{
+       return dma32_add(vcdev->dma_area_addr,
+                        offsetof(struct vcdev_dma_area, config_block));
+}
+
+static inline dma32_t status_dma(struct virtio_ccw_device *vcdev)
+{
+       return dma32_add(vcdev->dma_area_addr,
+                        offsetof(struct vcdev_dma_area, status));
+}
+
 struct vq_info_block_legacy {
-       __u64 queue;
+       dma64_t queue;
        __u32 align;
        __u16 index;
        __u16 num;
 } __packed;
 
 struct vq_info_block {
-       __u64 desc;
+       dma64_t desc;
        __u32 res0;
        __u16 index;
        __u16 num;
-       __u64 avail;
-       __u64 used;
+       dma64_t avail;
+       dma64_t used;
 } __packed;
 
 struct virtio_feature_desc {
@@ -106,8 +137,8 @@ struct virtio_feature_desc {
 } __packed;
 
 struct virtio_thinint_area {
-       unsigned long summary_indicator;
-       unsigned long indicator;
+       dma64_t summary_indicator;
+       dma64_t indicator;
        u64 bit_nr;
        u8 isc;
 } __packed;
@@ -123,6 +154,7 @@ struct virtio_rev_info {
 
 struct virtio_ccw_vq_info {
        struct virtqueue *vq;
+       dma32_t info_block_addr;
        int num;
        union {
                struct vq_info_block s;
@@ -156,6 +188,11 @@ static inline u8 *get_summary_indicator(struct airq_info *info)
        return summary_indicators + info->summary_indicator_idx;
 }
 
+static inline dma64_t get_summary_indicator_dma(struct airq_info *info)
+{
+       return virt_to_dma64(get_summary_indicator(info));
+}
+
 #define CCW_CMD_SET_VQ 0x13
 #define CCW_CMD_VDEV_RESET 0x33
 #define CCW_CMD_SET_IND 0x43
@@ -260,12 +297,12 @@ static struct airq_info *new_airq_info(int index)
        return info;
 }
 
-static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
-                                       u64 *first, void **airq_info)
+static unsigned long *get_airq_indicator(struct virtqueue *vqs[], int nvqs,
+                                        u64 *first, void **airq_info)
 {
        int i, j;
        struct airq_info *info;
-       unsigned long indicator_addr = 0;
+       unsigned long *indicator_addr = NULL;
        unsigned long bit, flags;
 
        for (i = 0; i < MAX_AIRQ_AREAS && !indicator_addr; i++) {
@@ -275,7 +312,7 @@ static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
                info = airq_areas[i];
                mutex_unlock(&airq_areas_lock);
                if (!info)
-                       return 0;
+                       return NULL;
                write_lock_irqsave(&info->lock, flags);
                bit = airq_iv_alloc(info->aiv, nvqs);
                if (bit == -1UL) {
@@ -285,7 +322,7 @@ static unsigned long get_airq_indicator(struct virtqueue *vqs[], int nvqs,
                }
                *first = bit;
                *airq_info = info;
-               indicator_addr = (unsigned long)info->aiv->vector;
+               indicator_addr = info->aiv->vector;
                for (j = 0; j < nvqs; j++) {
                        airq_iv_set_ptr(info->aiv, bit + j,
                                        (unsigned long)vqs[j]);
@@ -348,31 +385,31 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
                                      struct ccw1 *ccw)
 {
        int ret;
-       unsigned long *indicatorp = NULL;
        struct virtio_thinint_area *thinint_area = NULL;
        struct airq_info *airq_info = vcdev->airq_info;
+       dma64_t *indicatorp = NULL;
 
        if (vcdev->is_thinint) {
                thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
-                                                    sizeof(*thinint_area));
+                                                    sizeof(*thinint_area),
+                                                    &ccw->cda);
                if (!thinint_area)
                        return;
                thinint_area->summary_indicator =
-                       (unsigned long) get_summary_indicator(airq_info);
+                       get_summary_indicator_dma(airq_info);
                thinint_area->isc = VIRTIO_AIRQ_ISC;
                ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
                ccw->count = sizeof(*thinint_area);
-               ccw->cda = (__u32)virt_to_phys(thinint_area);
        } else {
                /* payload is the address of the indicators */
                indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
-                                                  sizeof(indicators(vcdev)));
+                                                  sizeof(*indicatorp),
+                                                  &ccw->cda);
                if (!indicatorp)
                        return;
                *indicatorp = 0;
                ccw->cmd_code = CCW_CMD_SET_IND;
-               ccw->count = sizeof(indicators(vcdev));
-               ccw->cda = (__u32)virt_to_phys(indicatorp);
+               ccw->count = sizeof(*indicatorp);
        }
        /* Deregister indicators from host. */
        *indicators(vcdev) = 0;
@@ -386,7 +423,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
                         "Failed to deregister indicators (%d)\n", ret);
        else if (vcdev->is_thinint)
                virtio_ccw_drop_indicators(vcdev);
-       ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(indicators(vcdev)));
+       ccw_device_dma_free(vcdev->cdev, indicatorp, sizeof(*indicatorp));
        ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area));
 }
 
@@ -426,7 +463,7 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
        ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
        ccw->flags = 0;
        ccw->count = sizeof(struct vq_config_block);
-       ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->config_block);
+       ccw->cda = config_block_dma(vcdev);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
        if (ret)
                return ret;
@@ -463,7 +500,7 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
        }
        ccw->cmd_code = CCW_CMD_SET_VQ;
        ccw->flags = 0;
-       ccw->cda = (__u32)virt_to_phys(info->info_block);
+       ccw->cda = info->info_block_addr;
        ret = ccw_io_helper(vcdev, ccw,
                            VIRTIO_CCW_DOING_SET_VQ | index);
        /*
@@ -486,7 +523,7 @@ static void virtio_ccw_del_vqs(struct virtio_device *vdev)
        struct ccw1 *ccw;
        struct virtio_ccw_device *vcdev = to_vc_device(vdev);
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return;
 
@@ -525,7 +562,8 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
                goto out_err;
        }
        info->info_block = ccw_device_dma_zalloc(vcdev->cdev,
-                                                sizeof(*info->info_block));
+                                                sizeof(*info->info_block),
+                                                &info->info_block_addr);
        if (!info->info_block) {
                dev_warn(&vcdev->cdev->dev, "no info block\n");
                err = -ENOMEM;
@@ -556,22 +594,22 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
        /* Register it with the host. */
        queue = virtqueue_get_desc_addr(vq);
        if (vcdev->revision == 0) {
-               info->info_block->l.queue = queue;
+               info->info_block->l.queue = u64_to_dma64(queue);
                info->info_block->l.align = KVM_VIRTIO_CCW_RING_ALIGN;
                info->info_block->l.index = i;
                info->info_block->l.num = info->num;
                ccw->count = sizeof(info->info_block->l);
        } else {
-               info->info_block->s.desc = queue;
+               info->info_block->s.desc = u64_to_dma64(queue);
                info->info_block->s.index = i;
                info->info_block->s.num = info->num;
-               info->info_block->s.avail = (__u64)virtqueue_get_avail_addr(vq);
-               info->info_block->s.used = (__u64)virtqueue_get_used_addr(vq);
+               info->info_block->s.avail = u64_to_dma64(virtqueue_get_avail_addr(vq));
+               info->info_block->s.used = u64_to_dma64(virtqueue_get_used_addr(vq));
                ccw->count = sizeof(info->info_block->s);
        }
        ccw->cmd_code = CCW_CMD_SET_VQ;
        ccw->flags = 0;
-       ccw->cda = (__u32)virt_to_phys(info->info_block);
+       ccw->cda = info->info_block_addr;
        err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
        if (err) {
                dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
@@ -605,11 +643,12 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
 {
        int ret;
        struct virtio_thinint_area *thinint_area = NULL;
-       unsigned long indicator_addr;
+       unsigned long *indicator_addr;
        struct airq_info *info;
 
        thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
-                                            sizeof(*thinint_area));
+                                            sizeof(*thinint_area),
+                                            &ccw->cda);
        if (!thinint_area) {
                ret = -ENOMEM;
                goto out;
@@ -622,15 +661,13 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
                ret = -ENOSPC;
                goto out;
        }
-       thinint_area->indicator = virt_to_phys((void *)indicator_addr);
+       thinint_area->indicator = virt_to_dma64(indicator_addr);
        info = vcdev->airq_info;
-       thinint_area->summary_indicator =
-               virt_to_phys(get_summary_indicator(info));
+       thinint_area->summary_indicator = get_summary_indicator_dma(info);
        thinint_area->isc = VIRTIO_AIRQ_ISC;
        ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
        ccw->flags = CCW_FLAG_SLI;
        ccw->count = sizeof(*thinint_area);
-       ccw->cda = (__u32)virt_to_phys(thinint_area);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
        if (ret) {
                if (ret == -EOPNOTSUPP) {
@@ -658,11 +695,11 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                               struct irq_affinity *desc)
 {
        struct virtio_ccw_device *vcdev = to_vc_device(vdev);
-       unsigned long *indicatorp = NULL;
+       dma64_t *indicatorp = NULL;
        int ret, i, queue_idx = 0;
        struct ccw1 *ccw;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return -ENOMEM;
 
@@ -687,10 +724,11 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
         * the address of the indicators.
        */
        indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
-                                          sizeof(indicators(vcdev)));
+                                          sizeof(*indicatorp),
+                                          &ccw->cda);
        if (!indicatorp)
                goto out;
-       *indicatorp = (unsigned long) indicators(vcdev);
+       *indicatorp = indicators_dma(vcdev);
        if (vcdev->is_thinint) {
                ret = virtio_ccw_register_adapter_ind(vcdev, vqs, nvqs, ccw);
                if (ret)
@@ -702,32 +740,30 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                *indicators(vcdev) = 0;
                ccw->cmd_code = CCW_CMD_SET_IND;
                ccw->flags = 0;
-               ccw->count = sizeof(indicators(vcdev));
-               ccw->cda = (__u32)virt_to_phys(indicatorp);
+               ccw->count = sizeof(*indicatorp);
                ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
                if (ret)
                        goto out;
        }
        /* Register indicators2 with host for config changes */
-       *indicatorp = (unsigned long) indicators2(vcdev);
+       *indicatorp = indicators2_dma(vcdev);
        *indicators2(vcdev) = 0;
        ccw->cmd_code = CCW_CMD_SET_CONF_IND;
        ccw->flags = 0;
-       ccw->count = sizeof(indicators2(vcdev));
-       ccw->cda = (__u32)virt_to_phys(indicatorp);
+       ccw->count = sizeof(*indicatorp);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
        if (ret)
                goto out;
 
        if (indicatorp)
                ccw_device_dma_free(vcdev->cdev, indicatorp,
-                                   sizeof(indicators(vcdev)));
+                                   sizeof(*indicatorp));
        ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
        return 0;
 out:
        if (indicatorp)
                ccw_device_dma_free(vcdev->cdev, indicatorp,
-                                   sizeof(indicators(vcdev)));
+                                   sizeof(*indicatorp));
        ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
        virtio_ccw_del_vqs(vdev);
        return ret;
@@ -738,7 +774,7 @@ static void virtio_ccw_reset(struct virtio_device *vdev)
        struct virtio_ccw_device *vcdev = to_vc_device(vdev);
        struct ccw1 *ccw;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return;
 
@@ -762,11 +798,12 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
        u64 rc;
        struct ccw1 *ccw;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return 0;
 
-       features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features));
+       features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features),
+                                        &ccw->cda);
        if (!features) {
                rc = 0;
                goto out_free;
@@ -776,7 +813,6 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
        ccw->cmd_code = CCW_CMD_READ_FEAT;
        ccw->flags = 0;
        ccw->count = sizeof(*features);
-       ccw->cda = (__u32)virt_to_phys(features);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
        if (ret) {
                rc = 0;
@@ -793,7 +829,6 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
        ccw->cmd_code = CCW_CMD_READ_FEAT;
        ccw->flags = 0;
        ccw->count = sizeof(*features);
-       ccw->cda = (__u32)virt_to_phys(features);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
        if (ret == 0)
                rc |= (u64)le32_to_cpu(features->features) << 32;
@@ -825,11 +860,12 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
                return -EINVAL;
        }
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return -ENOMEM;
 
-       features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features));
+       features = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*features),
+                                        &ccw->cda);
        if (!features) {
                ret = -ENOMEM;
                goto out_free;
@@ -846,7 +882,6 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
        ccw->cmd_code = CCW_CMD_WRITE_FEAT;
        ccw->flags = 0;
        ccw->count = sizeof(*features);
-       ccw->cda = (__u32)virt_to_phys(features);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
        if (ret)
                goto out_free;
@@ -860,7 +895,6 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
        ccw->cmd_code = CCW_CMD_WRITE_FEAT;
        ccw->flags = 0;
        ccw->count = sizeof(*features);
-       ccw->cda = (__u32)virt_to_phys(features);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
 
 out_free:
@@ -879,12 +913,13 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
        void *config_area;
        unsigned long flags;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return;
 
        config_area = ccw_device_dma_zalloc(vcdev->cdev,
-                                           VIRTIO_CCW_CONFIG_SIZE);
+                                           VIRTIO_CCW_CONFIG_SIZE,
+                                           &ccw->cda);
        if (!config_area)
                goto out_free;
 
@@ -892,7 +927,6 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
        ccw->cmd_code = CCW_CMD_READ_CONF;
        ccw->flags = 0;
        ccw->count = offset + len;
-       ccw->cda = (__u32)virt_to_phys(config_area);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG);
        if (ret)
                goto out_free;
@@ -919,12 +953,13 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
        void *config_area;
        unsigned long flags;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return;
 
        config_area = ccw_device_dma_zalloc(vcdev->cdev,
-                                           VIRTIO_CCW_CONFIG_SIZE);
+                                           VIRTIO_CCW_CONFIG_SIZE,
+                                           &ccw->cda);
        if (!config_area)
                goto out_free;
 
@@ -939,7 +974,6 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
        ccw->cmd_code = CCW_CMD_WRITE_CONF;
        ccw->flags = 0;
        ccw->count = offset + len;
-       ccw->cda = (__u32)virt_to_phys(config_area);
        ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
 
 out_free:
@@ -956,14 +990,14 @@ static u8 virtio_ccw_get_status(struct virtio_device *vdev)
        if (vcdev->revision < 2)
                return vcdev->dma_area->status;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return old_status;
 
        ccw->cmd_code = CCW_CMD_READ_STATUS;
        ccw->flags = 0;
        ccw->count = sizeof(vcdev->dma_area->status);
-       ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status);
+       ccw->cda = status_dma(vcdev);
        ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
 /*
  * If the channel program failed (should only happen if the device
@@ -983,7 +1017,7 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
        struct ccw1 *ccw;
        int ret;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return;
 
@@ -992,11 +1026,11 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
        ccw->cmd_code = CCW_CMD_WRITE_STATUS;
        ccw->flags = 0;
        ccw->count = sizeof(status);
-       ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status);
        /* We use ssch for setting the status which is a serializing
         * instruction that guarantees the memory writes have
         * completed before ssch.
         */
+       ccw->cda = status_dma(vcdev);
        ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
        /* Write failed? We assume status is unchanged. */
        if (ret)
@@ -1278,10 +1312,10 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
        struct ccw1 *ccw;
        int ret;
 
-       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw));
+       ccw = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*ccw), NULL);
        if (!ccw)
                return -ENOMEM;
-       rev = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*rev));
+       rev = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*rev), &ccw->cda);
        if (!rev) {
                ccw_device_dma_free(vcdev->cdev, ccw, sizeof(*ccw));
                return -ENOMEM;
@@ -1291,7 +1325,6 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
        ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV;
        ccw->flags = 0;
        ccw->count = sizeof(*rev);
-       ccw->cda = (__u32)virt_to_phys(rev);
 
        vcdev->revision = VIRTIO_CCW_REV_MAX;
        do {
@@ -1333,7 +1366,8 @@ static int virtio_ccw_online(struct ccw_device *cdev)
        vcdev->vdev.dev.parent = &cdev->dev;
        vcdev->cdev = cdev;
        vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev,
-                                               sizeof(*vcdev->dma_area));
+                                               sizeof(*vcdev->dma_area),
+                                               &vcdev->dma_area_addr);
        if (!vcdev->dma_area) {
                ret = -ENOMEM;
                goto out_free;
index 8b40f75fc9d7c6b20fa9b5a8664aa26cd49027f3..634f2f501c6c6a99952576945f2c743307e3bc48 100644 (file)
@@ -241,6 +241,11 @@ config SCSI_SCAN_ASYNC
          Note that this setting also affects whether resuming from
          system suspend will be performed asynchronously.
 
+config SCSI_PROTO_TEST
+       tristate "scsi_proto.h unit tests" if !KUNIT_ALL_TESTS
+       depends on SCSI && KUNIT
+       default KUNIT_ALL_TESTS
+
 menu "SCSI Transports"
        depends on SCSI
 
index f055bfd54a6832b3da7b08e6c56a129ff320041f..1313ddf2fd1a1eda2e84018a6ea31d0480028075 100644 (file)
@@ -24,6 +24,8 @@ obj-$(CONFIG_SCSI_COMMON)     += scsi_common.o
 
 obj-$(CONFIG_RAID_ATTRS)       += raid_class.o
 
+obj-$(CONFIG_SCSI_PROTO_TEST)  += scsi_proto_test.o
+
 # --- NOTE ORDERING HERE ---
 # For kernel non-modular link, transport attributes need to
 # be initialised before drivers
index 8cad9792a56275b38f70595baf7fb095882a6c1f..3e0c0381277acd7aed4afdbf3fc7433ef2568868 100644 (file)
@@ -517,6 +517,8 @@ void scsi_attach_vpd(struct scsi_device *sdev)
                        scsi_update_vpd_page(sdev, 0xb1, &sdev->vpd_pgb1);
                if (vpd_buf->data[i] == 0xb2)
                        scsi_update_vpd_page(sdev, 0xb2, &sdev->vpd_pgb2);
+               if (vpd_buf->data[i] == 0xb7)
+                       scsi_update_vpd_page(sdev, 0xb7, &sdev->vpd_pgb7);
        }
        kfree(vpd_buf);
 }
index 914d9c12e7412de0123bcb8b04e73ffee33c430a..acf0592d63dae44f13ca9772a3938d08a136ef91 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/prefetch.h>
 #include <linux/debugfs.h>
 #include <linux/async.h>
+#include <linux/cleanup.h>
 
 #include <net/checksum.h>
 
@@ -532,6 +533,8 @@ static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_get_stream_status(struct scsi_cmnd *scp,
+                                 struct sdebug_dev_info *devip);
 static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
@@ -606,6 +609,9 @@ static const struct opcode_info_t sa_in_16_iarr[] = {
        {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
            {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0, 0xc7} },      /* GET LBA STATUS(16) */
+       {0, 0x9e, 0x16, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL,
+           {16, 0x16, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff,
+            0, 0} },   /* GET STREAM STATUS */
 };
 
 static const struct opcode_info_t vl_iarr[] = {        /* VARIABLE LENGTH */
@@ -896,6 +902,8 @@ static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
 static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
 static int poll_queues; /* iouring iopoll interface.*/
 
+static atomic_long_t writes_by_group_number[64];
+
 static char sdebug_proc_name[] = MY_NAME;
 static const char *my_name = MY_NAME;
 
@@ -1867,6 +1875,19 @@ static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
        return 0x3c;
 }
 
+#define SDEBUG_BLE_LEN_AFTER_B4 28     /* thus vpage 32 bytes long */
+
+enum { MAXIMUM_NUMBER_OF_STREAMS = 6, PERMANENT_STREAM_COUNT = 5 };
+
+/* Block limits extension VPD page (SBC-4) */
+static int inquiry_vpd_b7(unsigned char *arrb4)
+{
+       memset(arrb4, 0, SDEBUG_BLE_LEN_AFTER_B4);
+       arrb4[1] = 1; /* Reduced stream control support (RSCS) */
+       put_unaligned_be16(MAXIMUM_NUMBER_OF_STREAMS, &arrb4[2]);
+       return SDEBUG_BLE_LEN_AFTER_B4;
+}
+
 #define SDEBUG_LONG_INQ_SZ 96
 #define SDEBUG_MAX_INQ_ARR_SZ 584
 
@@ -1903,7 +1924,8 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                u32 len;
                char lu_id_str[6];
                int host_no = devip->sdbg_host->shost->host_no;
-               
+
+               arr[1] = cmd[2];
                port_group_id = (((host_no + 1) & 0x7f) << 8) +
                    (devip->channel & 0x7f);
                if (sdebug_vpd_use_hostno == 0)
@@ -1914,7 +1936,6 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                                 (devip->target * 1000) - 3;
                len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
                if (0 == cmd[2]) { /* supported vital product data pages */
-                       arr[1] = cmd[2];        /*sanity */
                        n = 4;
                        arr[n++] = 0x0;   /* this page */
                        arr[n++] = 0x80;  /* unit serial number */
@@ -1932,26 +1953,22 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                                        arr[n++] = 0xb2;  /* LB Provisioning */
                                if (is_zbc)
                                        arr[n++] = 0xb6;  /* ZB dev. char. */
+                               arr[n++] = 0xb7;  /* Block limits extension */
                        }
                        arr[3] = n - 4;   /* number of supported VPD pages */
                } else if (0x80 == cmd[2]) { /* unit serial number */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = len;
                        memcpy(&arr[4], lu_id_str, len);
                } else if (0x83 == cmd[2]) { /* device identification */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
                                                target_dev_id, lu_id_num,
                                                lu_id_str, len,
                                                &devip->lu_name);
                } else if (0x84 == cmd[2]) { /* Software interface ident. */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_84(&arr[4]);
                } else if (0x85 == cmd[2]) { /* Management network addresses */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_85(&arr[4]);
                } else if (0x86 == cmd[2]) { /* extended inquiry */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = 0x3c;  /* number of following entries */
                        if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
                                arr[4] = 0x4;   /* SPT: GRD_CHK:1 */
@@ -1959,33 +1976,32 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                                arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
                        else
                                arr[4] = 0x0;   /* no protection stuff */
-                       arr[5] = 0x7;   /* head of q, ordered + simple q's */
+                       /*
+                        * GROUP_SUP=1; HEADSUP=1 (HEAD OF QUEUE); ORDSUP=1
+                        * (ORDERED queuing); SIMPSUP=1 (SIMPLE queuing).
+                        */
+                       arr[5] = 0x17;
                } else if (0x87 == cmd[2]) { /* mode page policy */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = 0x8;   /* number of following entries */
                        arr[4] = 0x2;   /* disconnect-reconnect mp */
                        arr[6] = 0x80;  /* mlus, shared */
                        arr[8] = 0x18;   /* protocol specific lu */
                        arr[10] = 0x82;  /* mlus, per initiator port */
                } else if (0x88 == cmd[2]) { /* SCSI Ports */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
                } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
-                       arr[1] = cmd[2];        /*sanity */
                        n = inquiry_vpd_89(&arr[4]);
                        put_unaligned_be16(n, arr + 2);
                } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_b0(&arr[4]);
                } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_b1(devip, &arr[4]);
                } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_b2(&arr[4]);
                } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
-                       arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_vpd_b6(devip, &arr[4]);
+               } else if (cmd[2] == 0xb7) { /* block limits extension page */
+                       arr[3] = inquiry_vpd_b7(&arr[4]);
                } else {
                        mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
                        kfree(arr);
@@ -2554,6 +2570,40 @@ static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
        return sizeof(ctrl_m_pg);
 }
 
+/* IO Advice Hints Grouping mode page */
+static int resp_grouping_m_pg(unsigned char *p, int pcontrol, int target)
+{
+       /* IO Advice Hints Grouping mode page */
+       struct grouping_m_pg {
+               u8 page_code;   /* OR 0x40 when subpage_code > 0 */
+               u8 subpage_code;
+               __be16 page_length;
+               u8 reserved[12];
+               struct scsi_io_group_descriptor descr[MAXIMUM_NUMBER_OF_STREAMS];
+       };
+       static const struct grouping_m_pg gr_m_pg = {
+               .page_code = 0xa | 0x40,
+               .subpage_code = 5,
+               .page_length = cpu_to_be16(sizeof(gr_m_pg) - 4),
+               .descr = {
+                       { .st_enble = 1 },
+                       { .st_enble = 1 },
+                       { .st_enble = 1 },
+                       { .st_enble = 1 },
+                       { .st_enble = 1 },
+                       { .st_enble = 0 },
+               }
+       };
+
+       BUILD_BUG_ON(sizeof(struct grouping_m_pg) !=
+                    16 + MAXIMUM_NUMBER_OF_STREAMS * 16);
+       memcpy(p, &gr_m_pg, sizeof(gr_m_pg));
+       if (1 == pcontrol) {
+               /* There are no changeable values so clear from byte 4 on. */
+               memset(p + 4, 0, sizeof(gr_m_pg) - 4);
+       }
+       return sizeof(gr_m_pg);
+}
 
 static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
 {      /* Informational Exceptions control mode page for mode_sense */
@@ -2627,7 +2677,8 @@ static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
        return sizeof(sas_sha_m_pg);
 }
 
-#define SDEBUG_MAX_MSENSE_SZ 256
+/* PAGE_SIZE is more than necessary but provides room for future expansion. */
+#define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE
 
 static int resp_mode_sense(struct scsi_cmnd *scp,
                           struct sdebug_dev_info *devip)
@@ -2638,10 +2689,13 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
        int target_dev_id;
        int target = scp->device->id;
        unsigned char *ap;
-       unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
+       unsigned char *arr __free(kfree);
        unsigned char *cmd = scp->cmnd;
-       bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
+       bool dbd, llbaa, msense_6, is_disk, is_zbc;
 
+       arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC);
+       if (!arr)
+               return -ENOMEM;
        dbd = !!(cmd[1] & 0x8);         /* disable block descriptors */
        pcontrol = (cmd[2] & 0xc0) >> 6;
        pcode = cmd[2] & 0x3f;
@@ -2699,45 +2753,63 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
                ap = arr + offset;
        }
 
-       if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
-               /* TODO: Control Extension page */
-               mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
-               return check_condition_result;
-       }
-       bad_pcode = false;
-
+       /*
+        * N.B. If len>0 before resp_*_pg() call, then form of that call should be:
+        *        len += resp_*_pg(ap + len, pcontrol, target);
+        */
        switch (pcode) {
        case 0x1:       /* Read-Write error recovery page, direct access */
+               if (subpcode > 0x0 && subpcode < 0xff)
+                       goto bad_subpcode;
                len = resp_err_recov_pg(ap, pcontrol, target);
                offset += len;
                break;
        case 0x2:       /* Disconnect-Reconnect page, all devices */
+               if (subpcode > 0x0 && subpcode < 0xff)
+                       goto bad_subpcode;
                len = resp_disconnect_pg(ap, pcontrol, target);
                offset += len;
                break;
        case 0x3:       /* Format device page, direct access */
+               if (subpcode > 0x0 && subpcode < 0xff)
+                       goto bad_subpcode;
                if (is_disk) {
                        len = resp_format_pg(ap, pcontrol, target);
                        offset += len;
-               } else
-                       bad_pcode = true;
+               } else {
+                       goto bad_pcode;
+               }
                break;
        case 0x8:       /* Caching page, direct access */
+               if (subpcode > 0x0 && subpcode < 0xff)
+                       goto bad_subpcode;
                if (is_disk || is_zbc) {
                        len = resp_caching_pg(ap, pcontrol, target);
                        offset += len;
-               } else
-                       bad_pcode = true;
+               } else {
+                       goto bad_pcode;
+               }
                break;
        case 0xa:       /* Control Mode page, all devices */
-               len = resp_ctrl_m_pg(ap, pcontrol, target);
+               switch (subpcode) {
+               case 0:
+                       len = resp_ctrl_m_pg(ap, pcontrol, target);
+                       break;
+               case 0x05:
+                       len = resp_grouping_m_pg(ap, pcontrol, target);
+                       break;
+               case 0xff:
+                       len = resp_ctrl_m_pg(ap, pcontrol, target);
+                       len += resp_grouping_m_pg(ap + len, pcontrol, target);
+                       break;
+               default:
+                       goto bad_subpcode;
+               }
                offset += len;
                break;
        case 0x19:      /* if spc==1 then sas phy, control+discover */
-               if ((subpcode > 0x2) && (subpcode < 0xff)) {
-                       mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
-                       return check_condition_result;
-               }
+               if (subpcode > 0x2 && subpcode < 0xff)
+                       goto bad_subpcode;
                len = 0;
                if ((0x0 == subpcode) || (0xff == subpcode))
                        len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
@@ -2749,49 +2821,50 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
                offset += len;
                break;
        case 0x1c:      /* Informational Exceptions Mode page, all devices */
+               if (subpcode > 0x0 && subpcode < 0xff)
+                       goto bad_subpcode;
                len = resp_iec_m_pg(ap, pcontrol, target);
                offset += len;
                break;
        case 0x3f:      /* Read all Mode pages */
-               if ((0 == subpcode) || (0xff == subpcode)) {
-                       len = resp_err_recov_pg(ap, pcontrol, target);
-                       len += resp_disconnect_pg(ap + len, pcontrol, target);
-                       if (is_disk) {
-                               len += resp_format_pg(ap + len, pcontrol,
-                                                     target);
-                               len += resp_caching_pg(ap + len, pcontrol,
-                                                      target);
-                       } else if (is_zbc) {
-                               len += resp_caching_pg(ap + len, pcontrol,
-                                                      target);
-                       }
-                       len += resp_ctrl_m_pg(ap + len, pcontrol, target);
-                       len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
-                       if (0xff == subpcode) {
-                               len += resp_sas_pcd_m_spg(ap + len, pcontrol,
-                                                 target, target_dev_id);
-                               len += resp_sas_sha_m_spg(ap + len, pcontrol);
-                       }
-                       len += resp_iec_m_pg(ap + len, pcontrol, target);
-                       offset += len;
-               } else {
-                       mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
-                       return check_condition_result;
+               if (subpcode > 0x0 && subpcode < 0xff)
+                       goto bad_subpcode;
+               len = resp_err_recov_pg(ap, pcontrol, target);
+               len += resp_disconnect_pg(ap + len, pcontrol, target);
+               if (is_disk) {
+                       len += resp_format_pg(ap + len, pcontrol, target);
+                       len += resp_caching_pg(ap + len, pcontrol, target);
+               } else if (is_zbc) {
+                       len += resp_caching_pg(ap + len, pcontrol, target);
                }
+               len += resp_ctrl_m_pg(ap + len, pcontrol, target);
+               if (0xff == subpcode)
+                       len += resp_grouping_m_pg(ap + len, pcontrol, target);
+               len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
+               if (0xff == subpcode) {
+                       len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
+                                                 target_dev_id);
+                       len += resp_sas_sha_m_spg(ap + len, pcontrol);
+               }
+               len += resp_iec_m_pg(ap + len, pcontrol, target);
+               offset += len;
                break;
        default:
-               bad_pcode = true;
-               break;
-       }
-       if (bad_pcode) {
-               mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
-               return check_condition_result;
+               goto bad_pcode;
        }
        if (msense_6)
                arr[0] = offset - 1;
        else
                put_unaligned_be16((offset - 2), arr + 0);
        return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
+
+bad_pcode:
+       mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
+       return check_condition_result;
+
+bad_subpcode:
+       mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
+       return check_condition_result;
 }
 
 #define SDEBUG_MAX_MSELECT_SZ 512
@@ -3306,7 +3379,8 @@ static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
 
 /* Returns number of bytes copied or -1 if error. */
 static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
-                           u32 sg_skip, u64 lba, u32 num, bool do_write)
+                           u32 sg_skip, u64 lba, u32 num, bool do_write,
+                           u8 group_number)
 {
        int ret;
        u64 block, rest = 0;
@@ -3325,6 +3399,10 @@ static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
                return 0;
        if (scp->sc_data_direction != dir)
                return -1;
+
+       if (do_write && group_number < ARRAY_SIZE(writes_by_group_number))
+               atomic_long_inc(&writes_by_group_number[group_number]);
+
        fsp = sip->storep;
 
        block = do_div(lba, sdebug_store_sectors);
@@ -3698,7 +3776,7 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                }
        }
 
-       ret = do_device_access(sip, scp, 0, lba, num, false);
+       ret = do_device_access(sip, scp, 0, lba, num, false, 0);
        sdeb_read_unlock(sip);
        if (unlikely(ret == -1))
                return DID_ERROR << 16;
@@ -3883,6 +3961,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
        bool check_prot;
        u32 num;
+       u8 group = 0;
        u32 ei_lba;
        int ret;
        u64 lba;
@@ -3894,11 +3973,13 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                ei_lba = 0;
                lba = get_unaligned_be64(cmd + 2);
                num = get_unaligned_be32(cmd + 10);
+               group = cmd[14] & 0x3f;
                check_prot = true;
                break;
        case WRITE_10:
                ei_lba = 0;
                lba = get_unaligned_be32(cmd + 2);
+               group = cmd[6] & 0x3f;
                num = get_unaligned_be16(cmd + 7);
                check_prot = true;
                break;
@@ -3913,15 +3994,18 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                ei_lba = 0;
                lba = get_unaligned_be32(cmd + 2);
                num = get_unaligned_be32(cmd + 6);
+               group = cmd[6] & 0x3f;
                check_prot = true;
                break;
        case 0x53:      /* XDWRITEREAD(10) */
                ei_lba = 0;
                lba = get_unaligned_be32(cmd + 2);
+               group = cmd[6] & 0x1f;
                num = get_unaligned_be16(cmd + 7);
                check_prot = false;
                break;
        default:        /* assume WRITE(32) */
+               group = cmd[6] & 0x3f;
                lba = get_unaligned_be64(cmd + 12);
                ei_lba = get_unaligned_be32(cmd + 20);
                num = get_unaligned_be32(cmd + 28);
@@ -3976,7 +4060,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                }
        }
 
-       ret = do_device_access(sip, scp, 0, lba, num, true);
+       ret = do_device_access(sip, scp, 0, lba, num, true, group);
        if (unlikely(scsi_debug_lbp()))
                map_region(sip, lba, num);
        /* If ZBC zone then bump its write pointer */
@@ -4028,12 +4112,14 @@ static int resp_write_scat(struct scsi_cmnd *scp,
        u32 lb_size = sdebug_sector_size;
        u32 ei_lba;
        u64 lba;
+       u8 group;
        int ret, res;
        bool is_16;
        static const u32 lrd_size = 32; /* + parameter list header size */
 
        if (cmd[0] == VARIABLE_LENGTH_CMD) {
                is_16 = false;
+               group = cmd[6] & 0x3f;
                wrprotect = (cmd[10] >> 5) & 0x7;
                lbdof = get_unaligned_be16(cmd + 12);
                num_lrd = get_unaligned_be16(cmd + 16);
@@ -4044,6 +4130,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
                lbdof = get_unaligned_be16(cmd + 4);
                num_lrd = get_unaligned_be16(cmd + 8);
                bt_len = get_unaligned_be32(cmd + 10);
+               group = cmd[14] & 0x3f;
                if (unlikely(have_dif_prot)) {
                        if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
                            wrprotect) {
@@ -4132,7 +4219,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
                        }
                }
 
-               ret = do_device_access(sip, scp, sg_off, lba, num, true);
+               ret = do_device_access(sip, scp, sg_off, lba, num, true, group);
                /* If ZBC zone then bump its write pointer */
                if (sdebug_dev_is_zoned(devip))
                        zbc_inc_wp(devip, lba, num);
@@ -4507,6 +4594,51 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
        return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
 }
 
+static int resp_get_stream_status(struct scsi_cmnd *scp,
+                                 struct sdebug_dev_info *devip)
+{
+       u16 starting_stream_id, stream_id;
+       const u8 *cmd = scp->cmnd;
+       u32 alloc_len, offset;
+       u8 arr[256] = {};
+       struct scsi_stream_status_header *h = (void *)arr;
+
+       starting_stream_id = get_unaligned_be16(cmd + 4);
+       alloc_len = get_unaligned_be32(cmd + 10);
+
+       if (alloc_len < 8) {
+               mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
+               return check_condition_result;
+       }
+
+       if (starting_stream_id >= MAXIMUM_NUMBER_OF_STREAMS) {
+               mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
+               return check_condition_result;
+       }
+
+       /*
+        * The GET STREAM STATUS command only reports status information
+        * about open streams. Treat the non-permanent stream as open.
+        */
+       put_unaligned_be16(MAXIMUM_NUMBER_OF_STREAMS,
+                          &h->number_of_open_streams);
+
+       for (offset = 8, stream_id = starting_stream_id;
+            offset + 8 <= min_t(u32, alloc_len, sizeof(arr)) &&
+                    stream_id < MAXIMUM_NUMBER_OF_STREAMS;
+            offset += 8, stream_id++) {
+               struct scsi_stream_status *stream_status = (void *)arr + offset;
+
+               stream_status->perm = stream_id < PERMANENT_STREAM_COUNT;
+               put_unaligned_be16(stream_id,
+                                  &stream_status->stream_identifier);
+               stream_status->rel_lifetime = stream_id + 1;
+       }
+       put_unaligned_be32(offset - 8, &h->len); /* PARAMETER DATA LENGTH */
+
+       return fill_from_dev_buffer(scp, arr, min(offset, alloc_len));
+}
+
 static int resp_sync_cache(struct scsi_cmnd *scp,
                           struct sdebug_dev_info *devip)
 {
@@ -7182,6 +7314,30 @@ static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
 }
 static DRIVER_ATTR_RO(tur_ms_to_ready);
 
+static ssize_t group_number_stats_show(struct device_driver *ddp, char *buf)
+{
+       char *p = buf, *end = buf + PAGE_SIZE;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(writes_by_group_number); i++)
+               p += scnprintf(p, end - p, "%d %ld\n", i,
+                              atomic_long_read(&writes_by_group_number[i]));
+
+       return p - buf;
+}
+
+static ssize_t group_number_stats_store(struct device_driver *ddp,
+                                       const char *buf, size_t count)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(writes_by_group_number); i++)
+               atomic_long_set(&writes_by_group_number[i], 0);
+
+       return count;
+}
+static DRIVER_ATTR_RW(group_number_stats);
+
 /* Note: The following array creates attribute files in the
    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
    files (over those found in the /sys/module/scsi_debug/parameters
@@ -7228,6 +7384,7 @@ static struct attribute *sdebug_drv_attrs[] = {
        &driver_attr_cdb_len.attr,
        &driver_attr_tur_ms_to_ready.attr,
        &driver_attr_zbc.attr,
+       &driver_attr_group_number_stats.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(sdebug_drv);
diff --git a/drivers/scsi/scsi_proto_test.c b/drivers/scsi/scsi_proto_test.c
new file mode 100644 (file)
index 0000000..7fa0a78
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2023 Google LLC
+ */
+#include <kunit/test.h>
+#include <asm-generic/unaligned.h>
+#include <scsi/scsi_proto.h>
+
+static void test_scsi_proto(struct kunit *test)
+{
+       static const union {
+               struct scsi_io_group_descriptor desc;
+               u8 arr[sizeof(struct scsi_io_group_descriptor)];
+       } d = { .arr = { 0x45, 0, 0, 0, 0xb0, 0xe4, 0xe3 } };
+       KUNIT_EXPECT_EQ(test, d.desc.io_advice_hints_mode + 0, 1);
+       KUNIT_EXPECT_EQ(test, d.desc.st_enble + 0, 1);
+       KUNIT_EXPECT_EQ(test, d.desc.cs_enble + 0, 0);
+       KUNIT_EXPECT_EQ(test, d.desc.ic_enable + 0, 1);
+       KUNIT_EXPECT_EQ(test, d.desc.acdlu + 0, 1);
+       KUNIT_EXPECT_EQ(test, d.desc.rlbsr + 0, 3);
+       KUNIT_EXPECT_EQ(test, d.desc.lbm_descriptor_type + 0, 0);
+       KUNIT_EXPECT_EQ(test, d.desc.params[0] + 0, 0xe4);
+       KUNIT_EXPECT_EQ(test, d.desc.params[1] + 0, 0xe3);
+
+       static const union {
+               struct scsi_stream_status s;
+               u8 arr[sizeof(struct scsi_stream_status)];
+       } ss = { .arr = { 0x80, 0, 0x12, 0x34, 0x3f } };
+       KUNIT_EXPECT_EQ(test, ss.s.perm + 0, 1);
+       KUNIT_EXPECT_EQ(test, get_unaligned_be16(&ss.s.stream_identifier),
+                       0x1234);
+       KUNIT_EXPECT_EQ(test, ss.s.rel_lifetime + 0, 0x3f);
+
+       static const union {
+               struct scsi_stream_status_header h;
+               u8 arr[sizeof(struct scsi_stream_status_header)];
+       } sh = { .arr = { 1, 2, 3, 4, 0, 0, 5, 6 } };
+       KUNIT_EXPECT_EQ(test, get_unaligned_be32(&sh.h.len), 0x1020304);
+       KUNIT_EXPECT_EQ(test, get_unaligned_be16(&sh.h.number_of_open_streams),
+                       0x506);
+}
+
+static struct kunit_case scsi_proto_test_cases[] = {
+       KUNIT_CASE(test_scsi_proto),
+       {}
+};
+
+static struct kunit_suite scsi_proto_test_suite = {
+       .name = "scsi_proto",
+       .test_cases = scsi_proto_test_cases,
+};
+kunit_test_suite(scsi_proto_test_suite);
+
+MODULE_DESCRIPTION("<scsi/scsi_proto.h> unit tests");
+MODULE_AUTHOR("Bart Van Assche");
+MODULE_LICENSE("GPL");
index 49dd34426d5e06a20d454aa5ca39c3a05b7b6fa3..775df00021e4d5591044d8e3272bb435a11cfa6a 100644 (file)
@@ -449,6 +449,7 @@ static void scsi_device_dev_release(struct device *dev)
        struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
        struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
        struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL;
+       struct scsi_vpd *vpd_pgb7 = NULL;
        unsigned long flags;
 
        might_sleep();
@@ -494,6 +495,8 @@ static void scsi_device_dev_release(struct device *dev)
                                       lockdep_is_held(&sdev->inquiry_mutex));
        vpd_pgb2 = rcu_replace_pointer(sdev->vpd_pgb2, vpd_pgb2,
                                       lockdep_is_held(&sdev->inquiry_mutex));
+       vpd_pgb7 = rcu_replace_pointer(sdev->vpd_pgb7, vpd_pgb7,
+                                      lockdep_is_held(&sdev->inquiry_mutex));
        mutex_unlock(&sdev->inquiry_mutex);
 
        if (vpd_pg0)
@@ -510,6 +513,8 @@ static void scsi_device_dev_release(struct device *dev)
                kfree_rcu(vpd_pgb1, rcu);
        if (vpd_pgb2)
                kfree_rcu(vpd_pgb2, rcu);
+       if (vpd_pgb7)
+               kfree_rcu(vpd_pgb7, rcu);
        kfree(sdev->inquiry);
        kfree(sdev);
 
@@ -921,6 +926,7 @@ sdev_vpd_pg_attr(pg89);
 sdev_vpd_pg_attr(pgb0);
 sdev_vpd_pg_attr(pgb1);
 sdev_vpd_pg_attr(pgb2);
+sdev_vpd_pg_attr(pgb7);
 sdev_vpd_pg_attr(pg0);
 
 static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
@@ -1295,6 +1301,9 @@ static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
        if (attr == &dev_attr_vpd_pgb2 && !sdev->vpd_pgb2)
                return 0;
 
+       if (attr == &dev_attr_vpd_pgb7 && !sdev->vpd_pgb7)
+               return 0;
+
        return S_IRUGO;
 }
 
@@ -1347,6 +1356,7 @@ static struct bin_attribute *scsi_sdev_bin_attrs[] = {
        &dev_attr_vpd_pgb0,
        &dev_attr_vpd_pgb1,
        &dev_attr_vpd_pgb2,
+       &dev_attr_vpd_pgb7,
        &dev_attr_inquiry,
        NULL
 };
index 2cc73c650ca60a557fb2952dbed8a078ba58745b..ccff8f2e2e75bd4b0286f04c96cb41d588205941 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/blkpg.h>
 #include <linux/blk-pm.h>
 #include <linux/delay.h>
+#include <linux/rw_hint.h>
 #include <linux/major.h>
 #include <linux/mutex.h>
 #include <linux/string_helpers.h>
@@ -1080,12 +1081,38 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd)
        return BLK_STS_OK;
 }
 
+/**
+ * sd_group_number() - Compute the GROUP NUMBER field
+ * @cmd: SCSI command for which to compute the value of the six-bit GROUP NUMBER
+ *     field.
+ *
+ * From SBC-5 r05 (https://www.t10.org/cgi-bin/ac.pl?t=f&f=sbc5r05.pdf):
+ * 0: no relative lifetime.
+ * 1: shortest relative lifetime.
+ * 2: second shortest relative lifetime.
+ * 3 - 0x3d: intermediate relative lifetimes.
+ * 0x3e: second longest relative lifetime.
+ * 0x3f: longest relative lifetime.
+ */
+static u8 sd_group_number(struct scsi_cmnd *cmd)
+{
+       const struct request *rq = scsi_cmd_to_rq(cmd);
+       struct scsi_disk *sdkp = scsi_disk(rq->q->disk);
+
+       if (!sdkp->rscs)
+               return 0;
+
+       return min3((u32)rq->write_hint, (u32)sdkp->permanent_stream_count,
+                   0x3fu);
+}
+
 static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write,
                                       sector_t lba, unsigned int nr_blocks,
                                       unsigned char flags, unsigned int dld)
 {
        cmd->cmd_len = SD_EXT_CDB_SIZE;
        cmd->cmnd[0]  = VARIABLE_LENGTH_CMD;
+       cmd->cmnd[6]  = sd_group_number(cmd);
        cmd->cmnd[7]  = 0x18; /* Additional CDB len */
        cmd->cmnd[9]  = write ? WRITE_32 : READ_32;
        cmd->cmnd[10] = flags;
@@ -1104,7 +1131,7 @@ static blk_status_t sd_setup_rw16_cmnd(struct scsi_cmnd *cmd, bool write,
        cmd->cmd_len  = 16;
        cmd->cmnd[0]  = write ? WRITE_16 : READ_16;
        cmd->cmnd[1]  = flags | ((dld >> 2) & 0x01);
-       cmd->cmnd[14] = (dld & 0x03) << 6;
+       cmd->cmnd[14] = ((dld & 0x03) << 6) | sd_group_number(cmd);
        cmd->cmnd[15] = 0;
        put_unaligned_be64(lba, &cmd->cmnd[2]);
        put_unaligned_be32(nr_blocks, &cmd->cmnd[10]);
@@ -1119,7 +1146,7 @@ static blk_status_t sd_setup_rw10_cmnd(struct scsi_cmnd *cmd, bool write,
        cmd->cmd_len = 10;
        cmd->cmnd[0] = write ? WRITE_10 : READ_10;
        cmd->cmnd[1] = flags;
-       cmd->cmnd[6] = 0;
+       cmd->cmnd[6] = sd_group_number(cmd);
        cmd->cmnd[9] = 0;
        put_unaligned_be32(lba, &cmd->cmnd[2]);
        put_unaligned_be16(nr_blocks, &cmd->cmnd[7]);
@@ -1256,7 +1283,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd)
                ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks,
                                         protect | fua, dld);
        } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) ||
-                  sdp->use_10_for_rw || protect) {
+                  sdp->use_10_for_rw || protect || rq->write_hint) {
                ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks,
                                         protect | fua);
        } else {
@@ -3059,6 +3086,70 @@ defaults:
        sdkp->DPOFUA = 0;
 }
 
+static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned int stream_id)
+{
+       u8 cdb[16] = { SERVICE_ACTION_IN_16, SAI_GET_STREAM_STATUS };
+       struct {
+               struct scsi_stream_status_header h;
+               struct scsi_stream_status s;
+       } buf;
+       struct scsi_device *sdev = sdkp->device;
+       struct scsi_sense_hdr sshdr;
+       const struct scsi_exec_args exec_args = {
+               .sshdr = &sshdr,
+       };
+       int res;
+
+       put_unaligned_be16(stream_id, &cdb[4]);
+       put_unaligned_be32(sizeof(buf), &cdb[10]);
+
+       res = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, &buf, sizeof(buf),
+                              SD_TIMEOUT, sdkp->max_retries, &exec_args);
+       if (res < 0)
+               return false;
+       if (scsi_status_is_check_condition(res) && scsi_sense_valid(&sshdr))
+               sd_print_sense_hdr(sdkp, &sshdr);
+       if (res)
+               return false;
+       if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status))
+               return false;
+       return buf.h.stream_status[0].perm;
+}
+
+static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer)
+{
+       struct scsi_device *sdp = sdkp->device;
+       const struct scsi_io_group_descriptor *desc, *start, *end;
+       struct scsi_sense_hdr sshdr;
+       struct scsi_mode_data data;
+       int res;
+
+       res = scsi_mode_sense(sdp, /*dbd=*/0x8, /*modepage=*/0x0a,
+                             /*subpage=*/0x05, buffer, SD_BUF_SIZE, SD_TIMEOUT,
+                             sdkp->max_retries, &data, &sshdr);
+       if (res < 0)
+               return;
+       start = (void *)buffer + data.header_length + 16;
+       end = (void *)buffer + ALIGN_DOWN(data.header_length + data.length,
+                                         sizeof(*end));
+       /*
+        * From "SBC-5 Constrained Streams with Data Lifetimes": Device severs
+        * should assign the lowest numbered stream identifiers to permanent
+        * streams.
+        */
+       for (desc = start; desc < end; desc++)
+               if (!desc->st_enble || !sd_is_perm_stream(sdkp, desc - start))
+                       break;
+       sdkp->permanent_stream_count = desc - start;
+       if (sdkp->rscs && sdkp->permanent_stream_count < 2)
+               sd_printk(KERN_INFO, sdkp,
+                         "Unexpected: RSCS has been set and the permanent stream count is %u\n",
+                         sdkp->permanent_stream_count);
+       else if (sdkp->permanent_stream_count)
+               sd_printk(KERN_INFO, sdkp, "permanent stream count = %d\n",
+                         sdkp->permanent_stream_count);
+}
+
 /*
  * The ATO bit indicates whether the DIF application tag is available
  * for use by the operating system.
@@ -3166,6 +3257,18 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
        rcu_read_unlock();
 }
 
+/* Parse the Block Limits Extension VPD page (0xb7) */
+static void sd_read_block_limits_ext(struct scsi_disk *sdkp)
+{
+       struct scsi_vpd *vpd;
+
+       rcu_read_lock();
+       vpd = rcu_dereference(sdkp->device->vpd_pgb7);
+       if (vpd && vpd->len >= 2)
+               sdkp->rscs = vpd->data[5] & 1;
+       rcu_read_unlock();
+}
+
 /**
  * sd_read_block_characteristics - Query block dev. characteristics
  * @sdkp: disk to query
@@ -3541,6 +3644,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
                if (scsi_device_supports_vpd(sdp)) {
                        sd_read_block_provisioning(sdkp);
                        sd_read_block_limits(sdkp);
+                       sd_read_block_limits_ext(sdkp);
                        sd_read_block_characteristics(sdkp);
                        sd_zbc_read_zones(sdkp, buffer);
                        sd_read_cpr(sdkp);
@@ -3550,6 +3654,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
 
                sd_read_write_protect_flag(sdkp, buffer);
                sd_read_cache_type(sdkp, buffer);
+               sd_read_io_hints(sdkp, buffer);
                sd_read_app_tag_own(sdkp, buffer);
                sd_read_write_same(sdkp, buffer);
                sd_read_security(sdkp, buffer);
index 409dda5350d10fb898b7bad49889ec165f257511..5c4285a582b220367d9eda5fabc4ca5115cc919d 100644 (file)
@@ -125,6 +125,8 @@ struct scsi_disk {
        unsigned int    physical_block_size;
        unsigned int    max_medium_access_timeouts;
        unsigned int    medium_access_timed_out;
+                       /* number of permanent streams */
+       u16             permanent_stream_count;
        u8              media_present;
        u8              write_prot;
        u8              protection_type;/* Data Integrity Field */
@@ -151,6 +153,7 @@ struct scsi_disk {
        unsigned        urswrz : 1;
        unsigned        security : 1;
        unsigned        ignore_medium_access_errors : 1;
+       unsigned        rscs : 1; /* reduced stream control support */
 };
 #define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev)
 
index ca4f4ca413f11d6b2c0a29ab528da14042f395d2..74350b5871dc8ecf627c6539170872741831436e 100644 (file)
@@ -455,7 +455,7 @@ struct syscore_ops intc_syscore_ops = {
        .resume         = intc_resume,
 };
 
-struct bus_type intc_subsys = {
+const struct bus_type intc_subsys = {
        .name           = "intc",
        .dev_name       = "intc",
 };
index fa73c173b56a60ffc34434c7f7fb54ae46374552..9b6cd1bebb4e305d733983c184677b8ec0fcb369 100644 (file)
@@ -160,7 +160,7 @@ void _intc_enable(struct irq_data *data, unsigned long handle);
 /* core.c */
 extern struct list_head intc_list;
 extern raw_spinlock_t intc_big_lock;
-extern struct bus_type intc_subsys;
+extern const struct bus_type intc_subsys;
 
 unsigned int intc_get_dfl_prio_level(void);
 unsigned int intc_get_prio_level(unsigned int irq);
index aeefeb7255247d139892153271d78f040f7abf2e..9e01642e72de31ad557f0d47bb87f06db66e8875 100644 (file)
@@ -91,63 +91,42 @@ static int siox_gpio_probe(struct platform_device *pdev)
        int ret;
        struct siox_master *smaster;
 
-       smaster = siox_master_alloc(&pdev->dev, sizeof(*ddata));
-       if (!smaster) {
-               dev_err(dev, "failed to allocate siox master\n");
-               return -ENOMEM;
-       }
+       smaster = devm_siox_master_alloc(dev, sizeof(*ddata));
+       if (!smaster)
+               return dev_err_probe(dev, -ENOMEM,
+                                    "failed to allocate siox master\n");
 
        platform_set_drvdata(pdev, smaster);
        ddata = siox_master_get_devdata(smaster);
 
        ddata->din = devm_gpiod_get(dev, "din", GPIOD_IN);
-       if (IS_ERR(ddata->din)) {
-               ret = dev_err_probe(dev, PTR_ERR(ddata->din),
-                                   "Failed to get din GPIO\n");
-               goto err;
-       }
+       if (IS_ERR(ddata->din))
+               return dev_err_probe(dev, PTR_ERR(ddata->din),
+                                    "Failed to get din GPIO\n");
 
        ddata->dout = devm_gpiod_get(dev, "dout", GPIOD_OUT_LOW);
-       if (IS_ERR(ddata->dout)) {
-               ret = dev_err_probe(dev, PTR_ERR(ddata->dout),
-                                   "Failed to get dout GPIO\n");
-               goto err;
-       }
+       if (IS_ERR(ddata->dout))
+               return dev_err_probe(dev, PTR_ERR(ddata->dout),
+                                    "Failed to get dout GPIO\n");
 
        ddata->dclk = devm_gpiod_get(dev, "dclk", GPIOD_OUT_LOW);
-       if (IS_ERR(ddata->dclk)) {
-               ret = dev_err_probe(dev, PTR_ERR(ddata->dclk),
-                                   "Failed to get dclk GPIO\n");
-               goto err;
-       }
+       if (IS_ERR(ddata->dclk))
+               return dev_err_probe(dev, PTR_ERR(ddata->dclk),
+                                    "Failed to get dclk GPIO\n");
 
        ddata->dld = devm_gpiod_get(dev, "dld", GPIOD_OUT_LOW);
-       if (IS_ERR(ddata->dld)) {
-               ret = dev_err_probe(dev, PTR_ERR(ddata->dld),
-                                   "Failed to get dld GPIO\n");
-               goto err;
-       }
+       if (IS_ERR(ddata->dld))
+               return dev_err_probe(dev, PTR_ERR(ddata->dld),
+                                    "Failed to get dld GPIO\n");
 
        smaster->pushpull = siox_gpio_pushpull;
        /* XXX: determine automatically like spi does */
        smaster->busno = 0;
 
-       ret = siox_master_register(smaster);
-       if (ret) {
-               dev_err_probe(dev, ret,
-                             "Failed to register siox master\n");
-err:
-               siox_master_put(smaster);
-       }
-
-       return ret;
-}
-
-static int siox_gpio_remove(struct platform_device *pdev)
-{
-       struct siox_master *master = platform_get_drvdata(pdev);
-
-       siox_master_unregister(master);
+       ret = devm_siox_master_register(dev, smaster);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to register siox master\n");
 
        return 0;
 }
@@ -160,7 +139,6 @@ MODULE_DEVICE_TABLE(of, siox_gpio_dt_ids);
 
 static struct platform_driver siox_gpio_driver = {
        .probe = siox_gpio_probe,
-       .remove = siox_gpio_remove,
 
        .driver = {
                .name = DRIVER_NAME,
index 561408583b2bfe00f6dbff314988aeee733a49ae..24a45920a240ddcc932c77df62e35ecaa1e4d168 100644 (file)
@@ -498,7 +498,7 @@ static void siox_device_release(struct device *dev)
        kfree(sdevice);
 }
 
-static struct device_type siox_device_type = {
+static const struct device_type siox_device_type = {
        .groups = siox_device_groups,
        .release = siox_device_release,
 };
@@ -543,7 +543,7 @@ static void siox_shutdown(struct device *dev)
                sdriver->shutdown(sdevice);
 }
 
-static struct bus_type siox_bus_type = {
+static const struct bus_type siox_bus_type = {
        .name = "siox",
        .match = siox_match,
        .probe = siox_probe,
@@ -676,7 +676,7 @@ static void siox_master_release(struct device *dev)
        kfree(smaster);
 }
 
-static struct device_type siox_master_type = {
+static const struct device_type siox_master_type = {
        .groups = siox_master_groups,
        .release = siox_master_release,
 };
@@ -707,6 +707,31 @@ struct siox_master *siox_master_alloc(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(siox_master_alloc);
 
+static void devm_siox_master_put(void *data)
+{
+       struct siox_master *smaster = data;
+
+       siox_master_put(smaster);
+}
+
+struct siox_master *devm_siox_master_alloc(struct device *dev,
+                                          size_t size)
+{
+       struct siox_master *smaster;
+       int ret;
+
+       smaster = siox_master_alloc(dev, size);
+       if (!smaster)
+               return NULL;
+
+       ret = devm_add_action_or_reset(dev, devm_siox_master_put, smaster);
+       if (ret)
+               return NULL;
+
+       return smaster;
+}
+EXPORT_SYMBOL_GPL(devm_siox_master_alloc);
+
 int siox_master_register(struct siox_master *smaster)
 {
        int ret;
@@ -717,6 +742,8 @@ int siox_master_register(struct siox_master *smaster)
        if (!smaster->pushpull)
                return -EINVAL;
 
+       get_device(&smaster->dev);
+
        dev_set_name(&smaster->dev, "siox-%d", smaster->busno);
 
        mutex_init(&smaster->lock);
@@ -768,6 +795,25 @@ void siox_master_unregister(struct siox_master *smaster)
 }
 EXPORT_SYMBOL_GPL(siox_master_unregister);
 
+static void devm_siox_master_unregister(void *data)
+{
+       struct siox_master *smaster = data;
+
+       siox_master_unregister(smaster);
+}
+
+int devm_siox_master_register(struct device *dev, struct siox_master *smaster)
+{
+       int ret;
+
+       ret = siox_master_register(smaster);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, devm_siox_master_unregister, smaster);
+}
+EXPORT_SYMBOL_GPL(devm_siox_master_register);
+
 static struct siox_device *siox_device_add(struct siox_master *smaster,
                                           const char *type, size_t inbytes,
                                           size_t outbytes, u8 statustype)
index f08b43b713c5cdd2f01904646d7bfc85a81e496c..513f2c8312f7d6db388a84fc792e997143c389bc 100644 (file)
@@ -45,5 +45,9 @@ static inline void siox_master_put(struct siox_master *smaster)
        put_device(&smaster->dev);
 }
 
+struct siox_master *devm_siox_master_alloc(struct device *dev, size_t size);
+
 int siox_master_register(struct siox_master *smaster);
 void siox_master_unregister(struct siox_master *smaster);
+
+int devm_siox_master_register(struct device *dev, struct siox_master *smaster);
index d43873bb5fe6df58d212122abf3fa1d92121914f..41e62de1f91f30dc3dd750a6f8ba175275c4c4ba 100644 (file)
@@ -100,7 +100,7 @@ static int slim_device_uevent(const struct device *dev, struct kobj_uevent_env *
        return add_uevent_var(env, "MODALIAS=slim:%s", dev_name(&sbdev->dev));
 }
 
-struct bus_type slimbus_bus = {
+const struct bus_type slimbus_bus = {
        .name           = "slimbus",
        .match          = slim_device_match,
        .probe          = slim_device_probe,
@@ -436,8 +436,8 @@ static int slim_device_alloc_laddr(struct slim_device *sbdev,
                if (ret < 0)
                        goto err;
        } else if (report_present) {
-               ret = ida_simple_get(&ctrl->laddr_ida,
-                                    0, SLIM_LA_MANAGER - 1, GFP_KERNEL);
+               ret = ida_alloc_max(&ctrl->laddr_ida,
+                                   SLIM_LA_MANAGER - 1, GFP_KERNEL);
                if (ret < 0)
                        goto err;
 
index 77aa6d26476cd24b5eba6a663671d7677055538c..efeba8275a6691e20be511e4dcef6ce15e087b61 100644 (file)
@@ -220,7 +220,7 @@ struct slimbus_power_resp_msg_v01 {
        struct qmi_response_type_v01 resp;
 };
 
-static struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
        {
                .data_type  = QMI_UNSIGNED_4_BYTE,
                .elem_len   = 1,
@@ -262,7 +262,7 @@ static struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
        {
                .data_type  = QMI_STRUCT,
                .elem_len   = 1,
@@ -284,7 +284,7 @@ static struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
        {
                .data_type  = QMI_UNSIGNED_4_BYTE,
                .elem_len   = 1,
@@ -324,7 +324,7 @@ static struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info slimbus_power_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info slimbus_power_resp_msg_v01_ei[] = {
        {
                .data_type  = QMI_STRUCT,
                .elem_len   = 1,
index 1d2b27e3ea63f800c97b76c936940520fc96fa0b..b811446e0fa55febb51e6338c53ec62f183e9955 100644 (file)
@@ -523,7 +523,7 @@ int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d,
        struct qbman_eq_desc *ed;
        int i, ret;
 
-       ed = kcalloc(sizeof(struct qbman_eq_desc), 32, GFP_KERNEL);
+       ed = kcalloc(32, sizeof(struct qbman_eq_desc), GFP_KERNEL);
        if (!ed)
                return -ENOMEM;
 
index 739e4eee6b75ca666abe04004184fc451a09ad21..7e9074519ad22d7d6b26a9148f5f65b4e2e79b4f 100644 (file)
@@ -991,7 +991,7 @@ struct qman_portal {
        /* linked-list of CSCN handlers. */
        struct list_head cgr_cbs;
        /* list lock */
-       spinlock_t cgr_lock;
+       raw_spinlock_t cgr_lock;
        struct work_struct congestion_work;
        struct work_struct mr_work;
        char irqname[MAX_IRQNAME];
@@ -1281,7 +1281,7 @@ static int qman_create_portal(struct qman_portal *portal,
                /* if the given mask is NULL, assume all CGRs can be seen */
                qman_cgrs_fill(&portal->cgrs[0]);
        INIT_LIST_HEAD(&portal->cgr_cbs);
-       spin_lock_init(&portal->cgr_lock);
+       raw_spin_lock_init(&portal->cgr_lock);
        INIT_WORK(&portal->congestion_work, qm_congestion_task);
        INIT_WORK(&portal->mr_work, qm_mr_process_task);
        portal->bits = 0;
@@ -1456,11 +1456,14 @@ static void qm_congestion_task(struct work_struct *work)
        union qm_mc_result *mcr;
        struct qman_cgr *cgr;
 
-       spin_lock(&p->cgr_lock);
+       /*
+        * FIXME: QM_MCR_TIMEOUT is 10ms, which is too long for a raw spinlock!
+        */
+       raw_spin_lock_irq(&p->cgr_lock);
        qm_mc_start(&p->p);
        qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION);
        if (!qm_mc_result_timeout(&p->p, &mcr)) {
-               spin_unlock(&p->cgr_lock);
+               raw_spin_unlock_irq(&p->cgr_lock);
                dev_crit(p->config->dev, "QUERYCONGESTION timeout\n");
                qman_p_irqsource_add(p, QM_PIRQ_CSCI);
                return;
@@ -1476,7 +1479,7 @@ static void qm_congestion_task(struct work_struct *work)
        list_for_each_entry(cgr, &p->cgr_cbs, node)
                if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid))
                        cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid));
-       spin_unlock(&p->cgr_lock);
+       raw_spin_unlock_irq(&p->cgr_lock);
        qman_p_irqsource_add(p, QM_PIRQ_CSCI);
 }
 
@@ -2440,7 +2443,7 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
        preempt_enable();
 
        cgr->chan = p->config->channel;
-       spin_lock(&p->cgr_lock);
+       raw_spin_lock_irq(&p->cgr_lock);
 
        if (opts) {
                struct qm_mcc_initcgr local_opts = *opts;
@@ -2477,7 +2480,7 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
            qman_cgrs_get(&p->cgrs[1], cgr->cgrid))
                cgr->cb(p, cgr, 1);
 out:
-       spin_unlock(&p->cgr_lock);
+       raw_spin_unlock_irq(&p->cgr_lock);
        put_affine_portal();
        return ret;
 }
@@ -2512,7 +2515,7 @@ int qman_delete_cgr(struct qman_cgr *cgr)
                return -EINVAL;
 
        memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
-       spin_lock_irqsave(&p->cgr_lock, irqflags);
+       raw_spin_lock_irqsave(&p->cgr_lock, irqflags);
        list_del(&cgr->node);
        /*
         * If there are no other CGR objects for this CGRID in the list,
@@ -2537,7 +2540,7 @@ int qman_delete_cgr(struct qman_cgr *cgr)
                /* add back to the list */
                list_add(&cgr->node, &p->cgr_cbs);
 release_lock:
-       spin_unlock_irqrestore(&p->cgr_lock, irqflags);
+       raw_spin_unlock_irqrestore(&p->cgr_lock, irqflags);
        put_affine_portal();
        return ret;
 }
@@ -2577,9 +2580,9 @@ static int qman_update_cgr(struct qman_cgr *cgr, struct qm_mcc_initcgr *opts)
        if (!p)
                return -EINVAL;
 
-       spin_lock_irqsave(&p->cgr_lock, irqflags);
+       raw_spin_lock_irqsave(&p->cgr_lock, irqflags);
        ret = qm_modify_cgr(cgr, 0, opts);
-       spin_unlock_irqrestore(&p->cgr_lock, irqflags);
+       raw_spin_unlock_irqrestore(&p->cgr_lock, irqflags);
        put_affine_portal();
        return ret;
 }
index 4458b2e0562b09bda26f063e11e09daa5e67d04f..6eb6cf06278e6684507249d1bf8b586e71055671 100644 (file)
@@ -287,6 +287,7 @@ EXPORT_SYMBOL(sunxi_sram_release);
 struct sunxi_sramc_variant {
        int num_emac_clocks;
        bool has_ldo_ctrl;
+       bool has_ths_offset;
 };
 
 static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = {
@@ -308,8 +309,10 @@ static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = {
 
 static const struct sunxi_sramc_variant sun50i_h616_sramc_variant = {
        .num_emac_clocks = 2,
+       .has_ths_offset = true,
 };
 
+#define SUNXI_SRAM_THS_OFFSET_REG      0x0
 #define SUNXI_SRAM_EMAC_CLOCK_REG      0x30
 #define SUNXI_SYS_LDO_CTRL_REG         0x150
 
@@ -318,6 +321,8 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
 {
        const struct sunxi_sramc_variant *variant = dev_get_drvdata(dev);
 
+       if (reg == SUNXI_SRAM_THS_OFFSET_REG && variant->has_ths_offset)
+               return true;
        if (reg >= SUNXI_SRAM_EMAC_CLOCK_REG &&
            reg <  SUNXI_SRAM_EMAC_CLOCK_REG + variant->num_emac_clocks * 4)
                return true;
@@ -327,6 +332,20 @@ static bool sunxi_sram_regmap_accessible_reg(struct device *dev,
        return false;
 }
 
+static void sunxi_sram_lock(void *_lock)
+{
+       spinlock_t *lock = _lock;
+
+       spin_lock(lock);
+}
+
+static void sunxi_sram_unlock(void *_lock)
+{
+       spinlock_t *lock = _lock;
+
+       spin_unlock(lock);
+}
+
 static struct regmap_config sunxi_sram_regmap_config = {
        .reg_bits       = 32,
        .val_bits       = 32,
@@ -336,6 +355,9 @@ static struct regmap_config sunxi_sram_regmap_config = {
        /* other devices have no business accessing other registers */
        .readable_reg   = sunxi_sram_regmap_accessible_reg,
        .writeable_reg  = sunxi_sram_regmap_accessible_reg,
+       .lock           = sunxi_sram_lock,
+       .unlock         = sunxi_sram_unlock,
+       .lock_arg       = &sram_lock,
 };
 
 static int __init sunxi_sram_probe(struct platform_device *pdev)
index 11991eb12636449be443a0f83915796105f7091f..079035db7dd8592aa62a21d5e88480028c5941bb 100644 (file)
@@ -830,11 +830,11 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
 
        is_target = of_property_read_bool((&pdev->dev)->of_node, "spi-slave");
        if (is_target)
-               controller = spi_alloc_target(&pdev->dev,
-                                             sizeof(struct fsl_lpspi_data));
+               controller = devm_spi_alloc_target(&pdev->dev,
+                                                  sizeof(struct fsl_lpspi_data));
        else
-               controller = spi_alloc_host(&pdev->dev,
-                                           sizeof(struct fsl_lpspi_data));
+               controller = devm_spi_alloc_host(&pdev->dev,
+                                                sizeof(struct fsl_lpspi_data));
 
        if (!controller)
                return -ENOMEM;
index 833a1bb7a91438e02c2d5a176e1afdaba4159552..c3e5cee18bea73b4afbd16e6272860a833985e2b 100644 (file)
@@ -668,8 +668,8 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
                                ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1)
                                                << MX51_ECSPI_CTRL_BL_OFFSET;
                        else
-                               ctrl |= spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word,
-                                               BITS_PER_BYTE) * spi_imx->bits_per_word
+                               ctrl |= (spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word,
+                                               BITS_PER_BYTE) * spi_imx->bits_per_word - 1)
                                                << MX51_ECSPI_CTRL_BL_OFFSET;
                }
        }
index f982bdebd02838a0494d1a6fdcf3f658fcd7dea4..3c0c24ed1f3dbe3de539fcd0297098b41a6efcf7 100644 (file)
  *
  * Datasheet and Schematic:
  * The LM70 is a temperature sensor chip from National Semiconductor; its
- * datasheet is available at http://www.national.com/pf/LM/LM70.html
+ * datasheet is available at https://www.ti.com/lit/gpn/lm70
  * The schematic for this particular board (the LM70EVAL-LLP) is
  * available (on page 4) here:
- *  http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
+ *  https://download.datasheets.com/pdfs/documentation/nat/kit&board/lm70llpevalmanual.pdf
  *
  * Also see Documentation/spi/spi-lm70llp.rst.  The SPI<->parport code here is
  * (heavily) based on spi-butterfly by David Brownell.
index c9d6d42a88f55b4518881eb7cee6d2d8ec8657f7..17b8baf749e6aa2a6263b8b018361469032f7c56 100644 (file)
@@ -382,7 +382,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
                 * read path) and expect the core to use the regular SPI
                 * interface in other cases.
                 */
-               if (!ret || ret != -ENOTSUPP || ret != -EOPNOTSUPP) {
+               if (!ret || (ret != -ENOTSUPP && ret != -EOPNOTSUPP)) {
                        spi_mem_add_op_stats(ctlr->pcpu_statistics, op, ret);
                        spi_mem_add_op_stats(mem->spi->pcpu_statistics, op, ret);
 
index 8d4633b353eef662b224c966f7b9d9ba7527e076..e4cb22fe007523a3e07551fc86c126213330be16 100644 (file)
@@ -788,17 +788,19 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
                mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);
                mtk_spi_setup_packet(host);
 
-               cnt = mdata->xfer_len / 4;
-               iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
-                               trans->tx_buf + mdata->num_xfered, cnt);
+               if (trans->tx_buf) {
+                       cnt = mdata->xfer_len / 4;
+                       iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
+                                       trans->tx_buf + mdata->num_xfered, cnt);
 
-               remainder = mdata->xfer_len % 4;
-               if (remainder > 0) {
-                       reg_val = 0;
-                       memcpy(&reg_val,
-                               trans->tx_buf + (cnt * 4) + mdata->num_xfered,
-                               remainder);
-                       writel(reg_val, mdata->base + SPI_TX_DATA_REG);
+                       remainder = mdata->xfer_len % 4;
+                       if (remainder > 0) {
+                               reg_val = 0;
+                               memcpy(&reg_val,
+                                       trans->tx_buf + (cnt * 4) + mdata->num_xfered,
+                                       remainder);
+                               writel(reg_val, mdata->base + SPI_TX_DATA_REG);
+                       }
                }
 
                mtk_spi_enable_transfer(host);
index f18738ae95f8f9f76779921848470ee40783c130..ff75838c1b5dfa44fccca525c3a8a334051167fb 100644 (file)
@@ -1063,10 +1063,14 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
        if (spi->mode & SPI_CS_HIGH)
                enable = !enable;
 
-       if (spi_is_csgpiod(spi)) {
-               if (!spi->controller->set_cs_timing && !activate)
-                       spi_delay_exec(&spi->cs_hold, NULL);
+       /*
+        * Handle chip select delays for GPIO based CS or controllers without
+        * programmable chip select timing.
+        */
+       if ((spi_is_csgpiod(spi) || !spi->controller->set_cs_timing) && !activate)
+               spi_delay_exec(&spi->cs_hold, NULL);
 
+       if (spi_is_csgpiod(spi)) {
                if (!(spi->mode & SPI_NO_CS)) {
                        /*
                         * Historically ACPI has no means of the GPIO polarity and
@@ -1099,16 +1103,16 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
                if ((spi->controller->flags & SPI_CONTROLLER_GPIO_SS) &&
                    spi->controller->set_cs)
                        spi->controller->set_cs(spi, !enable);
-
-               if (!spi->controller->set_cs_timing) {
-                       if (activate)
-                               spi_delay_exec(&spi->cs_setup, NULL);
-                       else
-                               spi_delay_exec(&spi->cs_inactive, NULL);
-               }
        } else if (spi->controller->set_cs) {
                spi->controller->set_cs(spi, !enable);
        }
+
+       if (spi_is_csgpiod(spi) || !spi->controller->set_cs_timing) {
+               if (activate)
+                       spi_delay_exec(&spi->cs_setup, NULL);
+               else
+                       spi_delay_exec(&spi->cs_inactive, NULL);
+       }
 }
 
 #ifdef CONFIG_HAS_DMA
index 784b9f673ead0c55cf6ce8ecd8ac9ab6ae64c65d..5175b1c4f16198633b9e252797a0b052fe9af0cc 100644 (file)
@@ -46,14 +46,10 @@ source "drivers/staging/iio/Kconfig"
 
 source "drivers/staging/sm750fb/Kconfig"
 
-source "drivers/staging/emxx_udc/Kconfig"
-
 source "drivers/staging/nvec/Kconfig"
 
 source "drivers/staging/media/Kconfig"
 
-source "drivers/staging/board/Kconfig"
-
 source "drivers/staging/gdm724x/Kconfig"
 
 source "drivers/staging/fbtft/Kconfig"
index 2ea99c7b05d978aaf111acc008c5baa9c1a5c27c..67399c0ad8719cb57f4d3a3e44d64d90227c2317 100644 (file)
@@ -14,9 +14,7 @@ obj-$(CONFIG_VT6656)          += vt6656/
 obj-$(CONFIG_VME_BUS)          += vme_user/
 obj-$(CONFIG_IIO)              += iio/
 obj-$(CONFIG_FB_SM750)         += sm750fb/
-obj-$(CONFIG_USB_EMXX)         += emxx_udc/
 obj-$(CONFIG_MFD_NVEC)         += nvec/
-obj-$(CONFIG_STAGING_BOARD)    += board/
 obj-$(CONFIG_LTE_GDM724X)      += gdm724x/
 obj-$(CONFIG_FB_TFT)           += fbtft/
 obj-$(CONFIG_MOST)             += most/
index 727b956aa23172169c05581530edfb1cf3723e26..c51818c56dd21741528a428fc7b6ada44ab26bb0 100644 (file)
@@ -165,14 +165,9 @@ static ssize_t sysfs_read(struct device *dev, char *buf,
 {
        struct axis_fifo *fifo = dev_get_drvdata(dev);
        unsigned int read_val;
-       unsigned int len;
-       char tmp[32];
 
        read_val = ioread32(fifo->base_addr + addr_offset);
-       len =  snprintf(tmp, sizeof(tmp), "0x%x\n", read_val);
-       memcpy(buf, tmp, len);
-
-       return len;
+       return sysfs_emit(buf, "0x%x\n", read_val);
 }
 
 static ssize_t isr_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/staging/board/Kconfig b/drivers/staging/board/Kconfig
deleted file mode 100644 (file)
index b492167..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config STAGING_BOARD
-       bool "Staging Board Support"
-       depends on OF_ADDRESS && OF_IRQ && HAVE_CLK
-       help
-         Staging board base is to support continuous upstream
-         in-tree development and integration of platform devices.
-
-         Helps developers integrate devices as platform devices for
-         device drivers that only provide platform device bindings.
-         This in turn allows for incremental development of both
-         hardware feature support and DT binding work in parallel.
diff --git a/drivers/staging/board/Makefile b/drivers/staging/board/Makefile
deleted file mode 100644 (file)
index ed78397..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-y  := board.o
-obj-$(CONFIG_ARCH_EMEV2)       += kzm9d.o
-obj-$(CONFIG_ARCH_R8A7740)     += armadillo800eva.o
diff --git a/drivers/staging/board/TODO b/drivers/staging/board/TODO
deleted file mode 100644 (file)
index 8db70e1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-* replace platform device code with DT nodes once the driver supports DT
-* remove staging board code when no more platform devices are needed
diff --git a/drivers/staging/board/armadillo800eva.c b/drivers/staging/board/armadillo800eva.c
deleted file mode 100644 (file)
index 0225234..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Staging board support for Armadillo 800 eva.
- * Enable not-yet-DT-capable devices here.
- *
- * Based on board-armadillo800eva.c
- *
- * Copyright (C) 2012 Renesas Solutions Corp.
- * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/fb.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/videodev2.h>
-
-#include <video/sh_mobile_lcdc.h>
-
-#include "board.h"
-
-static struct fb_videomode lcdc0_mode = {
-       .name           = "AMPIER/AM-800480",
-       .xres           = 800,
-       .yres           = 480,
-       .left_margin    = 88,
-       .right_margin   = 40,
-       .hsync_len      = 128,
-       .upper_margin   = 20,
-       .lower_margin   = 5,
-       .vsync_len      = 5,
-       .sync           = 0,
-};
-
-static struct sh_mobile_lcdc_info lcdc0_info = {
-       .clock_source   = LCDC_CLK_BUS,
-       .ch[0] = {
-               .chan           = LCDC_CHAN_MAINLCD,
-               .fourcc         = V4L2_PIX_FMT_RGB565,
-               .interface_type = RGB24,
-               .clock_divider  = 5,
-               .flags          = 0,
-               .lcd_modes      = &lcdc0_mode,
-               .num_modes      = 1,
-               .panel_cfg = {
-                       .width  = 111,
-                       .height = 68,
-               },
-       },
-};
-
-static struct resource lcdc0_resources[] = {
-       DEFINE_RES_MEM_NAMED(0xfe940000, 0x4000, "LCD0"),
-       DEFINE_RES_IRQ(177 + 32),
-};
-
-static struct platform_device lcdc0_device = {
-       .name           = "sh_mobile_lcdc_fb",
-       .num_resources  = ARRAY_SIZE(lcdc0_resources),
-       .resource       = lcdc0_resources,
-       .id             = 0,
-       .dev    = {
-               .platform_data  = &lcdc0_info,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
-       },
-};
-
-static const struct board_staging_clk lcdc0_clocks[] __initconst = {
-       { "lcdc0", NULL, "sh_mobile_lcdc_fb.0" },
-};
-
-static const struct board_staging_dev armadillo800eva_devices[] __initconst = {
-       {
-               .pdev    = &lcdc0_device,
-               .clocks  = lcdc0_clocks,
-               .nclocks = ARRAY_SIZE(lcdc0_clocks),
-               .domain  = "/system-controller@e6180000/pm-domains/c5/a4lc@1"
-       },
-};
-
-static void __init armadillo800eva_init(void)
-{
-       board_staging_gic_setup_xlate("arm,pl390", 32);
-       board_staging_register_devices(armadillo800eva_devices,
-                                      ARRAY_SIZE(armadillo800eva_devices));
-}
-
-board_staging("renesas,armadillo800eva", armadillo800eva_init);
diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c
deleted file mode 100644 (file)
index f980af0..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2014 Magnus Damm
- * Copyright (C) 2015 Glider bvba
- */
-
-#define pr_fmt(fmt)    "board_staging: "  fmt
-
-#include <linux/clkdev.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-#include <linux/pm_domain.h>
-
-#include "board.h"
-
-static struct device_node *irqc_node __initdata;
-static unsigned int irqc_base __initdata;
-
-static bool find_by_address(u64 base_address)
-{
-       struct device_node *dn = of_find_all_nodes(NULL);
-       struct resource res;
-
-       while (dn) {
-               if (!of_address_to_resource(dn, 0, &res)) {
-                       if (res.start == base_address) {
-                               of_node_put(dn);
-                               return true;
-                       }
-               }
-               dn = of_find_all_nodes(dn);
-       }
-
-       return false;
-}
-
-bool __init board_staging_dt_node_available(const struct resource *resource,
-                                           unsigned int num_resources)
-{
-       unsigned int i;
-
-       for (i = 0; i < num_resources; i++) {
-               const struct resource *r = resource + i;
-
-               if (resource_type(r) == IORESOURCE_MEM)
-                       if (find_by_address(r->start))
-                               return true; /* DT node available */
-       }
-
-       return false; /* Nothing found */
-}
-
-int __init board_staging_gic_setup_xlate(const char *gic_match,
-                                        unsigned int base)
-{
-       WARN_ON(irqc_node);
-
-       irqc_node = of_find_compatible_node(NULL, NULL, gic_match);
-
-       WARN_ON(!irqc_node);
-       if (!irqc_node)
-               return -ENOENT;
-
-       irqc_base = base;
-       return 0;
-}
-
-static void __init gic_fixup_resource(struct resource *res)
-{
-       struct of_phandle_args irq_data;
-       unsigned int hwirq = res->start;
-       unsigned int virq;
-
-       if (resource_type(res) != IORESOURCE_IRQ || !irqc_node)
-               return;
-
-       irq_data.np = irqc_node;
-       irq_data.args_count = 3;
-       irq_data.args[0] = 0;
-       irq_data.args[1] = hwirq - irqc_base;
-       switch (res->flags &
-               (IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE |
-                IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL)) {
-       case IORESOURCE_IRQ_LOWEDGE:
-               irq_data.args[2] = IRQ_TYPE_EDGE_FALLING;
-               break;
-       case IORESOURCE_IRQ_HIGHEDGE:
-               irq_data.args[2] = IRQ_TYPE_EDGE_RISING;
-               break;
-       case IORESOURCE_IRQ_LOWLEVEL:
-               irq_data.args[2] = IRQ_TYPE_LEVEL_LOW;
-               break;
-       case IORESOURCE_IRQ_HIGHLEVEL:
-       default:
-               irq_data.args[2] = IRQ_TYPE_LEVEL_HIGH;
-               break;
-       }
-
-       virq = irq_create_of_mapping(&irq_data);
-       if (WARN_ON(!virq))
-               return;
-
-       pr_debug("hwirq %u -> virq %u\n", hwirq, virq);
-       res->start = virq;
-}
-
-void __init board_staging_gic_fixup_resources(struct resource *res,
-                                             unsigned int nres)
-{
-       unsigned int i;
-
-       for (i = 0; i < nres; i++)
-               gic_fixup_resource(&res[i]);
-}
-
-int __init board_staging_register_clock(const struct board_staging_clk *bsc)
-{
-       int error;
-
-       pr_debug("Aliasing clock %s for con_id %s dev_id %s\n", bsc->clk,
-                bsc->con_id, bsc->dev_id);
-       error = clk_add_alias(bsc->con_id, bsc->dev_id, bsc->clk, NULL);
-       if (error)
-               pr_err("Failed to alias clock %s (%d)\n", bsc->clk, error);
-
-       return error;
-}
-
-#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
-static int board_staging_add_dev_domain(struct platform_device *pdev,
-                                       const char *domain)
-{
-       struct device *dev = &pdev->dev;
-       struct of_phandle_args pd_args;
-       struct device_node *np;
-
-       np = of_find_node_by_path(domain);
-       if (!np) {
-               pr_err("Cannot find domain node %s\n", domain);
-               return -ENOENT;
-       }
-
-       pd_args.np = np;
-       pd_args.args_count = 0;
-
-       /* Initialization similar to device_pm_init_common() */
-       spin_lock_init(&dev->power.lock);
-       dev->power.early_init = true;
-
-       return of_genpd_add_device(&pd_args, dev);
-}
-#else
-static inline int board_staging_add_dev_domain(struct platform_device *pdev,
-                                              const char *domain)
-{
-       return 0;
-}
-#endif
-
-int __init board_staging_register_device(const struct board_staging_dev *dev)
-{
-       struct platform_device *pdev = dev->pdev;
-       unsigned int i;
-       int error;
-
-       pr_debug("Trying to register device %s\n", pdev->name);
-       if (board_staging_dt_node_available(pdev->resource,
-                                           pdev->num_resources)) {
-               pr_warn("Skipping %s, already in DT\n", pdev->name);
-               return -EEXIST;
-       }
-
-       board_staging_gic_fixup_resources(pdev->resource, pdev->num_resources);
-
-       for (i = 0; i < dev->nclocks; i++)
-               board_staging_register_clock(&dev->clocks[i]);
-
-       if (dev->domain)
-               board_staging_add_dev_domain(pdev, dev->domain);
-
-       error = platform_device_register(pdev);
-       if (error) {
-               pr_err("Failed to register device %s (%d)\n", pdev->name,
-                      error);
-               return error;
-       }
-
-       return error;
-}
-
-void __init board_staging_register_devices(const struct board_staging_dev *devs,
-                                          unsigned int ndevs)
-{
-       unsigned int i;
-
-       for (i = 0; i < ndevs; i++)
-               board_staging_register_device(&devs[i]);
-}
diff --git a/drivers/staging/board/board.h b/drivers/staging/board/board.h
deleted file mode 100644 (file)
index 5609daf..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __BOARD_H__
-#define __BOARD_H__
-
-#include <linux/init.h>
-#include <linux/of.h>
-
-struct board_staging_clk {
-       const char *clk;
-       const char *con_id;
-       const char *dev_id;
-};
-
-struct board_staging_dev {
-       /* Platform Device */
-       struct platform_device *pdev;
-       /* Clocks (optional) */
-       const struct board_staging_clk *clocks;
-       unsigned int nclocks;
-       /* Generic PM Domain (optional) */
-       const char *domain;
-};
-
-struct resource;
-
-bool board_staging_dt_node_available(const struct resource *resource,
-                                    unsigned int num_resources);
-int board_staging_gic_setup_xlate(const char *gic_match, unsigned int base);
-void board_staging_gic_fixup_resources(struct resource *res, unsigned int nres);
-int board_staging_register_clock(const struct board_staging_clk *bsc);
-int board_staging_register_device(const struct board_staging_dev *dev);
-void board_staging_register_devices(const struct board_staging_dev *devs,
-                                   unsigned int ndevs);
-
-#define board_staging(str, fn)                 \
-static int __init runtime_board_check(void)    \
-{                                              \
-       if (of_machine_is_compatible(str))      \
-               fn();                           \
-                                               \
-       return 0;                               \
-}                                              \
-                                               \
-device_initcall(runtime_board_check)
-
-#endif /* __BOARD_H__ */
diff --git a/drivers/staging/board/kzm9d.c b/drivers/staging/board/kzm9d.c
deleted file mode 100644 (file)
index d449a83..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Staging board support for KZM9D. Enable not-yet-DT-capable devices here. */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include "board.h"
-
-static struct resource usbs1_res[] __initdata = {
-       DEFINE_RES_MEM(0xe2800000, 0x2000),
-       DEFINE_RES_IRQ(159),
-};
-
-static void __init kzm9d_init(void)
-{
-       board_staging_gic_setup_xlate("arm,pl390", 32);
-
-       if (!board_staging_dt_node_available(usbs1_res,
-                                            ARRAY_SIZE(usbs1_res))) {
-               board_staging_gic_fixup_resources(usbs1_res,
-                                                 ARRAY_SIZE(usbs1_res));
-               platform_device_register_simple("emxx_udc", -1, usbs1_res,
-                                               ARRAY_SIZE(usbs1_res));
-       }
-}
-
-board_staging("renesas,kzm9d", kzm9d_init);
diff --git a/drivers/staging/emxx_udc/Kconfig b/drivers/staging/emxx_udc/Kconfig
deleted file mode 100644 (file)
index e7a95b3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config USB_EMXX
-       tristate "EMXX USB Function Device Controller"
-       depends on USB_GADGET && (ARCH_RENESAS || COMPILE_TEST)
-       help
-          The Emma Mobile series of SoCs from Renesas Electronics and
-          former NEC Electronics include USB Function hardware.
-
-          Say "y" to link the driver statically, or "m" to build a
-          dynamically linked module called "emxx_udc" and force all
-          gadget drivers to also be dynamically linked.
diff --git a/drivers/staging/emxx_udc/Makefile b/drivers/staging/emxx_udc/Makefile
deleted file mode 100644 (file)
index 569c5e9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_USB_EMXX) := emxx_udc.o
diff --git a/drivers/staging/emxx_udc/TODO b/drivers/staging/emxx_udc/TODO
deleted file mode 100644 (file)
index 471529a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-* add clock framework support (platform device with CCF needs special care)
-* break out board-specific VBUS GPIO to work with multiplatform
-* convert VBUS GPIO to use GPIO descriptors from <linux/gpio/consumer.h>
-  and stop using the old GPIO API
-* DT bindings
-* move driver into drivers/usb/gadget/
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
deleted file mode 100644 (file)
index eb63daa..0000000
+++ /dev/null
@@ -1,3223 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- *  drivers/usb/gadget/emxx_udc.c
- *     EMXX FCD (Function Controller Driver) for USB.
- *
- *  Copyright (C) 2010 Renesas Electronics Corporation
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/clk.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/dma-mapping.h>
-#include <linux/workqueue.h>
-#include <linux/device.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include <linux/irq.h>
-#include <linux/gpio/consumer.h>
-
-#include "emxx_udc.h"
-
-#define        DRIVER_DESC     "EMXX UDC driver"
-#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
-
-static struct gpio_desc *vbus_gpio;
-static int vbus_irq;
-
-static const char      driver_name[] = "emxx_udc";
-
-/*===========================================================================*/
-/* Prototype */
-static void _nbu2ss_ep_dma_abort(struct nbu2ss_udc *, struct nbu2ss_ep *);
-static void _nbu2ss_ep0_enable(struct nbu2ss_udc *);
-/*static void _nbu2ss_ep0_disable(struct nbu2ss_udc *);*/
-static void _nbu2ss_ep_done(struct nbu2ss_ep *, struct nbu2ss_req *, int);
-static void _nbu2ss_set_test_mode(struct nbu2ss_udc *, u32 mode);
-static void _nbu2ss_endpoint_toggle_reset(struct nbu2ss_udc *udc, u8 ep_adrs);
-
-static int _nbu2ss_pullup(struct nbu2ss_udc *, int);
-static void _nbu2ss_fifo_flush(struct nbu2ss_udc *, struct nbu2ss_ep *);
-
-/*===========================================================================*/
-/* Macro */
-#define        _nbu2ss_zero_len_pkt(udc, epnum)        \
-       _nbu2ss_ep_in_end(udc, epnum, 0, 0)
-
-/*===========================================================================*/
-/* Global */
-static struct nbu2ss_udc udc_controller;
-
-/*-------------------------------------------------------------------------*/
-/* Read */
-static inline u32 _nbu2ss_readl(void __iomem *address)
-{
-       return __raw_readl(address);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Write */
-static inline void _nbu2ss_writel(void __iomem *address, u32 udata)
-{
-       __raw_writel(udata, address);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Set Bit */
-static inline void _nbu2ss_bitset(void __iomem *address, u32 udata)
-{
-       u32     reg_dt = __raw_readl(address) | (udata);
-
-       __raw_writel(reg_dt, address);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Clear Bit */
-static inline void _nbu2ss_bitclr(void __iomem *address, u32 udata)
-{
-       u32     reg_dt = __raw_readl(address) & ~(udata);
-
-       __raw_writel(reg_dt, address);
-}
-
-#ifdef UDC_DEBUG_DUMP
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_dump_register(struct nbu2ss_udc *udc)
-{
-       int             i;
-       u32 reg_data;
-
-       pr_info("=== %s()\n", __func__);
-
-       if (!udc) {
-               pr_err("%s udc == NULL\n", __func__);
-               return;
-       }
-
-       spin_unlock(&udc->lock);
-
-       dev_dbg(&udc->dev, "\n-USB REG-\n");
-       for (i = 0x0 ; i < USB_BASE_SIZE ; i += 16) {
-               reg_data = _nbu2ss_readl(IO_ADDRESS(USB_BASE_ADDRESS + i));
-               dev_dbg(&udc->dev, "USB%04x =%08x", i, (int)reg_data);
-
-               reg_data = _nbu2ss_readl(IO_ADDRESS(USB_BASE_ADDRESS + i + 4));
-               dev_dbg(&udc->dev, " %08x", (int)reg_data);
-
-               reg_data = _nbu2ss_readl(IO_ADDRESS(USB_BASE_ADDRESS + i + 8));
-               dev_dbg(&udc->dev, " %08x", (int)reg_data);
-
-               reg_data = _nbu2ss_readl(IO_ADDRESS(USB_BASE_ADDRESS + i + 12));
-               dev_dbg(&udc->dev, " %08x\n", (int)reg_data);
-       }
-
-       spin_lock(&udc->lock);
-}
-#endif /* UDC_DEBUG_DUMP */
-
-/*-------------------------------------------------------------------------*/
-/* Endpoint 0 Callback (Complete) */
-static void _nbu2ss_ep0_complete(struct usb_ep *_ep, struct usb_request *_req)
-{
-       u8              recipient;
-       u16             selector;
-       u16             wIndex;
-       u32             test_mode;
-       struct usb_ctrlrequest  *p_ctrl;
-       struct nbu2ss_udc *udc;
-
-       if (!_ep || !_req)
-               return;
-
-       udc = (struct nbu2ss_udc *)_req->context;
-       p_ctrl = &udc->ctrl;
-       if ((p_ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
-               if (p_ctrl->bRequest == USB_REQ_SET_FEATURE) {
-                       /*-------------------------------------------------*/
-                       /* SET_FEATURE */
-                       recipient = (u8)(p_ctrl->bRequestType & USB_RECIP_MASK);
-                       selector  = le16_to_cpu(p_ctrl->wValue);
-                       if ((recipient == USB_RECIP_DEVICE) &&
-                           (selector == USB_DEVICE_TEST_MODE)) {
-                               wIndex = le16_to_cpu(p_ctrl->wIndex);
-                               test_mode = (u32)(wIndex >> 8);
-                               _nbu2ss_set_test_mode(udc, test_mode);
-                       }
-               }
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-/* Initialization usb_request */
-static void _nbu2ss_create_ep0_packet(struct nbu2ss_udc *udc,
-                                     void *p_buf, unsigned int length)
-{
-       udc->ep0_req.req.buf            = p_buf;
-       udc->ep0_req.req.length         = length;
-       udc->ep0_req.req.dma            = 0;
-       udc->ep0_req.req.zero           = true;
-       udc->ep0_req.req.complete       = _nbu2ss_ep0_complete;
-       udc->ep0_req.req.status         = -EINPROGRESS;
-       udc->ep0_req.req.context        = udc;
-       udc->ep0_req.req.actual         = 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Acquisition of the first address of RAM(FIFO) */
-static u32 _nbu2ss_get_begin_ram_address(struct nbu2ss_udc *udc)
-{
-       u32             num, buf_type;
-       u32             data, last_ram_adr, use_ram_size;
-
-       struct ep_regs __iomem *p_ep_regs;
-
-       last_ram_adr = (D_RAM_SIZE_CTRL / sizeof(u32)) * 2;
-       use_ram_size = 0;
-
-       for (num = 0; num < NUM_ENDPOINTS - 1; num++) {
-               p_ep_regs = &udc->p_regs->EP_REGS[num];
-               data = _nbu2ss_readl(&p_ep_regs->EP_PCKT_ADRS);
-               buf_type = _nbu2ss_readl(&p_ep_regs->EP_CONTROL) & EPN_BUF_TYPE;
-               if (buf_type == 0) {
-                       /* Single Buffer */
-                       use_ram_size += (data & EPN_MPKT) / sizeof(u32);
-               } else {
-                       /* Double Buffer */
-                       use_ram_size += ((data & EPN_MPKT) / sizeof(u32)) * 2;
-               }
-
-               if ((data >> 16) > last_ram_adr)
-                       last_ram_adr = data >> 16;
-       }
-
-       return last_ram_adr + use_ram_size;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Construction of Endpoint */
-static int _nbu2ss_ep_init(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep)
-{
-       u32             num;
-       u32             data;
-       u32             begin_adrs;
-
-       if (ep->epnum == 0)
-               return  -EINVAL;
-
-       num = ep->epnum - 1;
-
-       /*-------------------------------------------------------------*/
-       /* RAM Transfer Address */
-       begin_adrs = _nbu2ss_get_begin_ram_address(udc);
-       data = (begin_adrs << 16) | ep->ep.maxpacket;
-       _nbu2ss_writel(&udc->p_regs->EP_REGS[num].EP_PCKT_ADRS, data);
-
-       /*-------------------------------------------------------------*/
-       /* Interrupt Enable */
-       data = 1 << (ep->epnum + 8);
-       _nbu2ss_bitset(&udc->p_regs->USB_INT_ENA, data);
-
-       /*-------------------------------------------------------------*/
-       /* Endpoint Type(Mode) */
-       /*   Bulk, Interrupt, ISO */
-       switch (ep->ep_type) {
-       case USB_ENDPOINT_XFER_BULK:
-               data = EPN_BULK;
-               break;
-
-       case USB_ENDPOINT_XFER_INT:
-               data = EPN_BUF_SINGLE | EPN_INTERRUPT;
-               break;
-
-       case USB_ENDPOINT_XFER_ISOC:
-               data = EPN_ISO;
-               break;
-
-       default:
-               data = 0;
-               break;
-       }
-
-       _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-       _nbu2ss_endpoint_toggle_reset(udc, (ep->epnum | ep->direct));
-
-       if (ep->direct == USB_DIR_OUT) {
-               /*---------------------------------------------------------*/
-               /* OUT */
-               data = EPN_EN | EPN_BCLR | EPN_DIR0;
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_ONAK | EPN_OSTL_EN | EPN_OSTL;
-               _nbu2ss_bitclr(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_OUT_EN | EPN_OUT_END_EN;
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_INT_ENA, data);
-       } else {
-               /*---------------------------------------------------------*/
-               /* IN */
-               data = EPN_EN | EPN_BCLR | EPN_AUTO;
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_ISTL;
-               _nbu2ss_bitclr(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_IN_EN | EPN_IN_END_EN;
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_INT_ENA, data);
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Release of Endpoint */
-static int _nbu2ss_epn_exit(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep)
-{
-       u32             num;
-       u32             data;
-
-       if ((ep->epnum == 0) || (udc->vbus_active == 0))
-               return  -EINVAL;
-
-       num = ep->epnum - 1;
-
-       /*-------------------------------------------------------------*/
-       /* RAM Transfer Address */
-       _nbu2ss_writel(&udc->p_regs->EP_REGS[num].EP_PCKT_ADRS, 0);
-
-       /*-------------------------------------------------------------*/
-       /* Interrupt Disable */
-       data = 1 << (ep->epnum + 8);
-       _nbu2ss_bitclr(&udc->p_regs->USB_INT_ENA, data);
-
-       if (ep->direct == USB_DIR_OUT) {
-               /*---------------------------------------------------------*/
-               /* OUT */
-               data = EPN_ONAK | EPN_BCLR;
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_EN | EPN_DIR0;
-               _nbu2ss_bitclr(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_OUT_EN | EPN_OUT_END_EN;
-               _nbu2ss_bitclr(&udc->p_regs->EP_REGS[num].EP_INT_ENA, data);
-       } else {
-               /*---------------------------------------------------------*/
-               /* IN */
-               data = EPN_BCLR;
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_EN | EPN_AUTO;
-               _nbu2ss_bitclr(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-
-               data = EPN_IN_EN | EPN_IN_END_EN;
-               _nbu2ss_bitclr(&udc->p_regs->EP_REGS[num].EP_INT_ENA, data);
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* DMA setting (without Endpoint 0) */
-static void _nbu2ss_ep_dma_init(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep)
-{
-       u32             num;
-       u32             data;
-
-       data = _nbu2ss_readl(&udc->p_regs->USBSSCONF);
-       if (((ep->epnum == 0) || (data & (1 << ep->epnum)) == 0))
-               return;         /* Not Support DMA */
-
-       num = ep->epnum - 1;
-
-       if (ep->direct == USB_DIR_OUT) {
-               /*---------------------------------------------------------*/
-               /* OUT */
-               data = ep->ep.maxpacket;
-               _nbu2ss_writel(&udc->p_regs->EP_DCR[num].EP_DCR2, data);
-
-               /*---------------------------------------------------------*/
-               /* Transfer Direct */
-               data = DCR1_EPN_DIR0;
-               _nbu2ss_bitset(&udc->p_regs->EP_DCR[num].EP_DCR1, data);
-
-               /*---------------------------------------------------------*/
-               /* DMA Mode etc. */
-               data = EPN_STOP_MODE | EPN_STOP_SET  | EPN_DMAMODE0;
-               _nbu2ss_writel(&udc->p_regs->EP_REGS[num].EP_DMA_CTRL, data);
-       } else {
-               /*---------------------------------------------------------*/
-               /* IN */
-               _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, EPN_AUTO);
-
-               /*---------------------------------------------------------*/
-               /* DMA Mode etc. */
-               data = EPN_BURST_SET | EPN_DMAMODE0;
-               _nbu2ss_writel(&udc->p_regs->EP_REGS[num].EP_DMA_CTRL, data);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-/* DMA setting release */
-static void _nbu2ss_ep_dma_exit(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep)
-{
-       u32             num;
-       u32             data;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (udc->vbus_active == 0)
-               return;         /* VBUS OFF */
-
-       data = _nbu2ss_readl(&preg->USBSSCONF);
-       if ((ep->epnum == 0) || ((data & (1 << ep->epnum)) == 0))
-               return;         /* Not Support DMA */
-
-       num = ep->epnum - 1;
-
-       _nbu2ss_ep_dma_abort(udc, ep);
-
-       if (ep->direct == USB_DIR_OUT) {
-               /*---------------------------------------------------------*/
-               /* OUT */
-               _nbu2ss_writel(&preg->EP_DCR[num].EP_DCR2, 0);
-               _nbu2ss_bitclr(&preg->EP_DCR[num].EP_DCR1, DCR1_EPN_DIR0);
-               _nbu2ss_writel(&preg->EP_REGS[num].EP_DMA_CTRL, 0);
-       } else {
-               /*---------------------------------------------------------*/
-               /* IN */
-               _nbu2ss_bitclr(&preg->EP_REGS[num].EP_CONTROL, EPN_AUTO);
-               _nbu2ss_writel(&preg->EP_REGS[num].EP_DMA_CTRL, 0);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-/* Abort DMA */
-static void _nbu2ss_ep_dma_abort(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep)
-{
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       _nbu2ss_bitclr(&preg->EP_DCR[ep->epnum - 1].EP_DCR1, DCR1_EPN_REQEN);
-       mdelay(DMA_DISABLE_TIME);       /* DCR1_EPN_REQEN Clear */
-       _nbu2ss_bitclr(&preg->EP_REGS[ep->epnum - 1].EP_DMA_CTRL, EPN_DMA_EN);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Start IN Transfer */
-static void _nbu2ss_ep_in_end(struct nbu2ss_udc *udc,
-                             u32 epnum, u32 data32, u32 length)
-{
-       u32             data;
-       u32             num;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (length >= sizeof(u32))
-               return;
-
-       if (epnum == 0) {
-               _nbu2ss_bitclr(&preg->EP0_CONTROL, EP0_AUTO);
-
-               /* Writing of 1-4 bytes */
-               if (length)
-                       _nbu2ss_writel(&preg->EP0_WRITE, data32);
-
-               data = ((length << 5) & EP0_DW) | EP0_DEND;
-               _nbu2ss_writel(&preg->EP0_CONTROL, data);
-
-               _nbu2ss_bitset(&preg->EP0_CONTROL, EP0_AUTO);
-       } else {
-               num = epnum - 1;
-
-               _nbu2ss_bitclr(&preg->EP_REGS[num].EP_CONTROL, EPN_AUTO);
-
-               /* Writing of 1-4 bytes */
-               if (length)
-                       _nbu2ss_writel(&preg->EP_REGS[num].EP_WRITE, data32);
-
-               data = (((length) << 5) & EPN_DW) | EPN_DEND;
-               _nbu2ss_bitset(&preg->EP_REGS[num].EP_CONTROL, data);
-
-               _nbu2ss_bitset(&preg->EP_REGS[num].EP_CONTROL, EPN_AUTO);
-       }
-}
-
-#ifdef USE_DMA
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_dma_map_single(struct nbu2ss_udc *udc,
-                                  struct nbu2ss_ep *ep,
-                                  struct nbu2ss_req *req, u8 direct)
-{
-       if (req->req.dma == DMA_ADDR_INVALID) {
-               if (req->unaligned) {
-                       req->req.dma = ep->phys_buf;
-               } else {
-                       req->req.dma = dma_map_single(udc->gadget.dev.parent,
-                                                     req->req.buf,
-                                                     req->req.length,
-                                                     (direct == USB_DIR_IN)
-                                                     ? DMA_TO_DEVICE
-                                                     : DMA_FROM_DEVICE);
-               }
-               req->mapped = 1;
-       } else {
-               if (!req->unaligned)
-                       dma_sync_single_for_device(udc->gadget.dev.parent,
-                                                  req->req.dma,
-                                                  req->req.length,
-                                                  (direct == USB_DIR_IN)
-                                                  ? DMA_TO_DEVICE
-                                                  : DMA_FROM_DEVICE);
-
-               req->mapped = 0;
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_dma_unmap_single(struct nbu2ss_udc *udc,
-                                    struct nbu2ss_ep *ep,
-                                    struct nbu2ss_req *req, u8 direct)
-{
-       u8              data[4];
-       u8              *p;
-       u32             count = 0;
-
-       if (direct == USB_DIR_OUT) {
-               count = req->req.actual % 4;
-               if (count) {
-                       p = req->req.buf;
-                       p += (req->req.actual - count);
-                       memcpy(data, p, count);
-               }
-       }
-
-       if (req->mapped) {
-               if (req->unaligned) {
-                       if (direct == USB_DIR_OUT)
-                               memcpy(req->req.buf, ep->virt_buf,
-                                      req->req.actual & 0xfffffffc);
-               } else {
-                       dma_unmap_single(udc->gadget.dev.parent,
-                                        req->req.dma, req->req.length,
-                               (direct == USB_DIR_IN)
-                               ? DMA_TO_DEVICE
-                               : DMA_FROM_DEVICE);
-               }
-               req->req.dma = DMA_ADDR_INVALID;
-               req->mapped = 0;
-       } else {
-               if (!req->unaligned)
-                       dma_sync_single_for_cpu(udc->gadget.dev.parent,
-                                               req->req.dma, req->req.length,
-                               (direct == USB_DIR_IN)
-                               ? DMA_TO_DEVICE
-                               : DMA_FROM_DEVICE);
-       }
-
-       if (count) {
-               p = req->req.buf;
-               p += (req->req.actual - count);
-               memcpy(p, data, count);
-       }
-}
-#endif
-
-/*-------------------------------------------------------------------------*/
-/* Endpoint 0 OUT Transfer (PIO) */
-static int ep0_out_pio(struct nbu2ss_udc *udc, u8 *buf, u32 length)
-{
-       u32             i;
-       u32 numreads = length / sizeof(u32);
-       union usb_reg_access *buf32 = (union usb_reg_access *)buf;
-
-       if (!numreads)
-               return 0;
-
-       /* PIO Read */
-       for (i = 0; i < numreads; i++) {
-               buf32->dw = _nbu2ss_readl(&udc->p_regs->EP0_READ);
-               buf32++;
-       }
-
-       return  numreads * sizeof(u32);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Endpoint 0 OUT Transfer (PIO, OverBytes) */
-static int ep0_out_overbytes(struct nbu2ss_udc *udc, u8 *p_buf, u32 length)
-{
-       u32             i;
-       u32             i_read_size = 0;
-       union usb_reg_access  temp_32;
-       union usb_reg_access  *p_buf_32 = (union usb_reg_access *)p_buf;
-
-       if ((length > 0) && (length < sizeof(u32))) {
-               temp_32.dw = _nbu2ss_readl(&udc->p_regs->EP0_READ);
-               for (i = 0 ; i < length ; i++)
-                       p_buf_32->byte.DATA[i] = temp_32.byte.DATA[i];
-               i_read_size += length;
-       }
-
-       return i_read_size;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Endpoint 0 IN Transfer (PIO) */
-static int EP0_in_PIO(struct nbu2ss_udc *udc, u8 *p_buf, u32 length)
-{
-       u32             i;
-       u32             i_max_length   = EP0_PACKETSIZE;
-       u32             i_word_length  = 0;
-       u32             i_write_length = 0;
-       union usb_reg_access  *p_buf_32 = (union usb_reg_access *)p_buf;
-
-       /*------------------------------------------------------------*/
-       /* Transfer Length */
-       if (i_max_length < length)
-               i_word_length = i_max_length / sizeof(u32);
-       else
-               i_word_length = length / sizeof(u32);
-
-       /*------------------------------------------------------------*/
-       /* PIO */
-       for (i = 0; i < i_word_length; i++) {
-               _nbu2ss_writel(&udc->p_regs->EP0_WRITE, p_buf_32->dw);
-               p_buf_32++;
-               i_write_length += sizeof(u32);
-       }
-
-       return i_write_length;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Endpoint 0 IN Transfer (PIO, OverBytes) */
-static int ep0_in_overbytes(struct nbu2ss_udc *udc,
-                           u8 *p_buf,
-                           u32 i_remain_size)
-{
-       u32             i;
-       union usb_reg_access  temp_32;
-       union usb_reg_access  *p_buf_32 = (union usb_reg_access *)p_buf;
-
-       if ((i_remain_size > 0) && (i_remain_size < sizeof(u32))) {
-               for (i = 0 ; i < i_remain_size ; i++)
-                       temp_32.byte.DATA[i] = p_buf_32->byte.DATA[i];
-               _nbu2ss_ep_in_end(udc, 0, temp_32.dw, i_remain_size);
-
-               return i_remain_size;
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Transfer NULL Packet (Epndoint 0) */
-static int EP0_send_NULL(struct nbu2ss_udc *udc, bool pid_flag)
-{
-       u32             data;
-
-       data = _nbu2ss_readl(&udc->p_regs->EP0_CONTROL);
-       data &= ~(u32)EP0_INAK;
-
-       if (pid_flag)
-               data |= (EP0_INAK_EN | EP0_PIDCLR | EP0_DEND);
-       else
-               data |= (EP0_INAK_EN | EP0_DEND);
-
-       _nbu2ss_writel(&udc->p_regs->EP0_CONTROL, data);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Receive NULL Packet (Endpoint 0) */
-static int EP0_receive_NULL(struct nbu2ss_udc *udc, bool pid_flag)
-{
-       u32             data;
-
-       data = _nbu2ss_readl(&udc->p_regs->EP0_CONTROL);
-       data &= ~(u32)EP0_ONAK;
-
-       if (pid_flag)
-               data |= EP0_PIDCLR;
-
-       _nbu2ss_writel(&udc->p_regs->EP0_CONTROL, data);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_ep0_in_transfer(struct nbu2ss_udc *udc,
-                                  struct nbu2ss_req *req)
-{
-       u8              *p_buffer;                      /* IN Data Buffer */
-       u32             data;
-       u32             i_remain_size = 0;
-       int             result = 0;
-
-       /*-------------------------------------------------------------*/
-       /* End confirmation */
-       if (req->req.actual == req->req.length) {
-               if ((req->req.actual % EP0_PACKETSIZE) == 0) {
-                       if (req->zero) {
-                               req->zero = false;
-                               EP0_send_NULL(udc, false);
-                               return 1;
-                       }
-               }
-
-               return 0;               /* Transfer End */
-       }
-
-       /*-------------------------------------------------------------*/
-       /* NAK release */
-       data = _nbu2ss_readl(&udc->p_regs->EP0_CONTROL);
-       data |= EP0_INAK_EN;
-       data &= ~(u32)EP0_INAK;
-       _nbu2ss_writel(&udc->p_regs->EP0_CONTROL, data);
-
-       i_remain_size = req->req.length - req->req.actual;
-       p_buffer = (u8 *)req->req.buf;
-       p_buffer += req->req.actual;
-
-       /*-------------------------------------------------------------*/
-       /* Data transfer */
-       result = EP0_in_PIO(udc, p_buffer, i_remain_size);
-
-       req->div_len = result;
-       i_remain_size -= result;
-
-       if (i_remain_size == 0) {
-               EP0_send_NULL(udc, false);
-               return result;
-       }
-
-       if ((i_remain_size < sizeof(u32)) && (result != EP0_PACKETSIZE)) {
-               p_buffer += result;
-               result += ep0_in_overbytes(udc, p_buffer, i_remain_size);
-               req->div_len = result;
-       }
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_ep0_out_transfer(struct nbu2ss_udc *udc,
-                                   struct nbu2ss_req *req)
-{
-       u8              *p_buffer;
-       u32             i_remain_size;
-       u32             i_recv_length;
-       int             result = 0;
-       int             f_rcv_zero;
-
-       /*-------------------------------------------------------------*/
-       /* Receive data confirmation */
-       i_recv_length = _nbu2ss_readl(&udc->p_regs->EP0_LENGTH) & EP0_LDATA;
-       if (i_recv_length != 0) {
-               f_rcv_zero = 0;
-
-               i_remain_size = req->req.length - req->req.actual;
-               p_buffer = (u8 *)req->req.buf;
-               p_buffer += req->req.actual;
-
-               result = ep0_out_pio(udc, p_buffer
-                                       , min(i_remain_size, i_recv_length));
-               if (result < 0)
-                       return result;
-
-               req->req.actual += result;
-               i_recv_length -= result;
-
-               if ((i_recv_length > 0) && (i_recv_length < sizeof(u32))) {
-                       p_buffer += result;
-                       i_remain_size -= result;
-
-                       result = ep0_out_overbytes(udc, p_buffer
-                                       , min(i_remain_size, i_recv_length));
-                       req->req.actual += result;
-               }
-       } else {
-               f_rcv_zero = 1;
-       }
-
-       /*-------------------------------------------------------------*/
-       /* End confirmation */
-       if (req->req.actual == req->req.length) {
-               if ((req->req.actual % EP0_PACKETSIZE) == 0) {
-                       if (req->zero) {
-                               req->zero = false;
-                               EP0_receive_NULL(udc, false);
-                               return 1;
-                       }
-               }
-
-               return 0;               /* Transfer End */
-       }
-
-       if ((req->req.actual % EP0_PACKETSIZE) != 0)
-               return 0;               /* Short Packet Transfer End */
-
-       if (req->req.actual > req->req.length) {
-               dev_err(udc->dev, " *** Overrun Error\n");
-               return -EOVERFLOW;
-       }
-
-       if (f_rcv_zero != 0) {
-               i_remain_size = _nbu2ss_readl(&udc->p_regs->EP0_CONTROL);
-               if (i_remain_size & EP0_ONAK) {
-                       /*---------------------------------------------------*/
-                       /* NACK release */
-                       _nbu2ss_bitclr(&udc->p_regs->EP0_CONTROL, EP0_ONAK);
-               }
-               result = 1;
-       }
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_out_dma(struct nbu2ss_udc *udc, struct nbu2ss_req *req,
-                          u32 num, u32 length)
-{
-       dma_addr_t      p_buffer;
-       u32             mpkt;
-       u32             lmpkt;
-       u32             dmacnt;
-       u32             burst = 1;
-       u32             data;
-       int             result;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (req->dma_flag)
-               return 1;               /* DMA is forwarded */
-
-       req->dma_flag = true;
-       p_buffer = req->req.dma;
-       p_buffer += req->req.actual;
-
-       /* DMA Address */
-       _nbu2ss_writel(&preg->EP_DCR[num].EP_TADR, (u32)p_buffer);
-
-       /* Number of transfer packets */
-       mpkt = _nbu2ss_readl(&preg->EP_REGS[num].EP_PCKT_ADRS) & EPN_MPKT;
-       dmacnt = length / mpkt;
-       lmpkt = (length % mpkt) & ~(u32)0x03;
-
-       if (dmacnt > DMA_MAX_COUNT) {
-               dmacnt = DMA_MAX_COUNT;
-               lmpkt = 0;
-       } else if (lmpkt != 0) {
-               if (dmacnt == 0)
-                       burst = 0;      /* Burst OFF */
-               dmacnt++;
-       }
-
-       data = mpkt | (lmpkt << 16);
-       _nbu2ss_writel(&preg->EP_DCR[num].EP_DCR2, data);
-
-       data = ((dmacnt & 0xff) << 16) | DCR1_EPN_DIR0 | DCR1_EPN_REQEN;
-       _nbu2ss_writel(&preg->EP_DCR[num].EP_DCR1, data);
-
-       if (burst == 0) {
-               _nbu2ss_writel(&preg->EP_REGS[num].EP_LEN_DCNT, 0);
-               _nbu2ss_bitclr(&preg->EP_REGS[num].EP_DMA_CTRL, EPN_BURST_SET);
-       } else {
-               _nbu2ss_writel(&preg->EP_REGS[num].EP_LEN_DCNT
-                               , (dmacnt << 16));
-               _nbu2ss_bitset(&preg->EP_REGS[num].EP_DMA_CTRL, EPN_BURST_SET);
-       }
-       _nbu2ss_bitset(&preg->EP_REGS[num].EP_DMA_CTRL, EPN_DMA_EN);
-
-       result = length & ~(u32)0x03;
-       req->div_len = result;
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_epn_out_pio(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
-                              struct nbu2ss_req *req, u32 length)
-{
-       u8              *p_buffer;
-       u32             i;
-       u32             data;
-       u32             i_word_length;
-       union usb_reg_access    temp_32;
-       union usb_reg_access    *p_buf_32;
-       int             result = 0;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (req->dma_flag)
-               return 1;               /* DMA is forwarded */
-
-       if (length == 0)
-               return 0;
-
-       p_buffer = (u8 *)req->req.buf;
-       p_buf_32 = (union usb_reg_access *)(p_buffer + req->req.actual);
-
-       i_word_length = length / sizeof(u32);
-       if (i_word_length > 0) {
-               /*---------------------------------------------------------*/
-               /* Copy of every four bytes */
-               for (i = 0; i < i_word_length; i++) {
-                       p_buf_32->dw =
-                       _nbu2ss_readl(&preg->EP_REGS[ep->epnum - 1].EP_READ);
-                       p_buf_32++;
-               }
-               result = i_word_length * sizeof(u32);
-       }
-
-       data = length - result;
-       if (data > 0) {
-               /*---------------------------------------------------------*/
-               /* Copy of fraction byte */
-               temp_32.dw =
-                       _nbu2ss_readl(&preg->EP_REGS[ep->epnum - 1].EP_READ);
-               for (i = 0 ; i < data ; i++)
-                       p_buf_32->byte.DATA[i] = temp_32.byte.DATA[i];
-               result += data;
-       }
-
-       req->req.actual += result;
-
-       if ((req->req.actual == req->req.length) ||
-           ((req->req.actual % ep->ep.maxpacket) != 0)) {
-               result = 0;
-       }
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_epn_out_data(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
-                               struct nbu2ss_req *req, u32 data_size)
-{
-       u32             num;
-       u32             i_buf_size;
-       int             nret = 1;
-
-       if (ep->epnum == 0)
-               return -EINVAL;
-
-       num = ep->epnum - 1;
-
-       i_buf_size = min((req->req.length - req->req.actual), data_size);
-
-       if ((ep->ep_type != USB_ENDPOINT_XFER_INT) && (req->req.dma != 0) &&
-           (i_buf_size  >= sizeof(u32))) {
-               nret = _nbu2ss_out_dma(udc, req, num, i_buf_size);
-       } else {
-               i_buf_size = min_t(u32, i_buf_size, ep->ep.maxpacket);
-               nret = _nbu2ss_epn_out_pio(udc, ep, req, i_buf_size);
-       }
-
-       return nret;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_epn_out_transfer(struct nbu2ss_udc *udc,
-                                   struct nbu2ss_ep *ep,
-                                   struct nbu2ss_req *req)
-{
-       u32             num;
-       u32             i_recv_length;
-       int             result = 1;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (ep->epnum == 0)
-               return -EINVAL;
-
-       num = ep->epnum - 1;
-
-       /*-------------------------------------------------------------*/
-       /* Receive Length */
-       i_recv_length =
-               _nbu2ss_readl(&preg->EP_REGS[num].EP_LEN_DCNT) & EPN_LDATA;
-
-       if (i_recv_length != 0) {
-               result = _nbu2ss_epn_out_data(udc, ep, req, i_recv_length);
-               if (i_recv_length < ep->ep.maxpacket) {
-                       if (i_recv_length == result) {
-                               req->req.actual += result;
-                               result = 0;
-                       }
-               }
-       } else {
-               if ((req->req.actual == req->req.length) ||
-                   ((req->req.actual % ep->ep.maxpacket) != 0)) {
-                       result = 0;
-               }
-       }
-
-       if (result == 0) {
-               if ((req->req.actual % ep->ep.maxpacket) == 0) {
-                       if (req->zero) {
-                               req->zero = false;
-                               return 1;
-                       }
-               }
-       }
-
-       if (req->req.actual > req->req.length) {
-               dev_err(udc->dev, " Overrun Error\n");
-               dev_err(udc->dev, " actual = %d, length = %d\n",
-                       req->req.actual, req->req.length);
-               result = -EOVERFLOW;
-       }
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_in_dma(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
-                         struct nbu2ss_req *req, u32 num, u32 length)
-{
-       dma_addr_t      p_buffer;
-       u32             mpkt;           /* MaxPacketSize */
-       u32             lmpkt;          /* Last Packet Data Size */
-       u32             dmacnt;         /* IN Data Size */
-       u32             i_write_length;
-       u32             data;
-       int             result = -EINVAL;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (req->dma_flag)
-               return 1;               /* DMA is forwarded */
-
-#ifdef USE_DMA
-       if (req->req.actual == 0)
-               _nbu2ss_dma_map_single(udc, ep, req, USB_DIR_IN);
-#endif
-       req->dma_flag = true;
-
-       /* MAX Packet Size */
-       mpkt = _nbu2ss_readl(&preg->EP_REGS[num].EP_PCKT_ADRS) & EPN_MPKT;
-
-       i_write_length = min(DMA_MAX_COUNT * mpkt, length);
-
-       /*------------------------------------------------------------*/
-       /* Number of transmission packets */
-       if (mpkt < i_write_length) {
-               dmacnt = i_write_length / mpkt;
-               lmpkt  = (i_write_length % mpkt) & ~(u32)0x3;
-               if (lmpkt != 0)
-                       dmacnt++;
-               else
-                       lmpkt = mpkt & ~(u32)0x3;
-
-       } else {
-               dmacnt = 1;
-               lmpkt  = i_write_length & ~(u32)0x3;
-       }
-
-       /* Packet setting */
-       data = mpkt | (lmpkt << 16);
-       _nbu2ss_writel(&preg->EP_DCR[num].EP_DCR2, data);
-
-       /* Address setting */
-       p_buffer = req->req.dma;
-       p_buffer += req->req.actual;
-       _nbu2ss_writel(&preg->EP_DCR[num].EP_TADR, (u32)p_buffer);
-
-       /* Packet and DMA setting */
-       data = ((dmacnt & 0xff) << 16) | DCR1_EPN_REQEN;
-       _nbu2ss_writel(&preg->EP_DCR[num].EP_DCR1, data);
-
-       /* Packet setting of EPC */
-       data = dmacnt << 16;
-       _nbu2ss_writel(&preg->EP_REGS[num].EP_LEN_DCNT, data);
-
-       /*DMA setting of EPC */
-       _nbu2ss_bitset(&preg->EP_REGS[num].EP_DMA_CTRL, EPN_DMA_EN);
-
-       result = i_write_length & ~(u32)0x3;
-       req->div_len = result;
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_epn_in_pio(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
-                             struct nbu2ss_req *req, u32 length)
-{
-       u8              *p_buffer;
-       u32             i;
-       u32             data;
-       u32             i_word_length;
-       union usb_reg_access    temp_32;
-       union usb_reg_access    *p_buf_32 = NULL;
-       int             result = 0;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (req->dma_flag)
-               return 1;               /* DMA is forwarded */
-
-       if (length > 0) {
-               p_buffer = (u8 *)req->req.buf;
-               p_buf_32 = (union usb_reg_access *)(p_buffer + req->req.actual);
-
-               i_word_length = length / sizeof(u32);
-               if (i_word_length > 0) {
-                       for (i = 0; i < i_word_length; i++) {
-                               _nbu2ss_writel(&preg->EP_REGS[ep->epnum - 1].EP_WRITE,
-                                              p_buf_32->dw);
-
-                               p_buf_32++;
-                       }
-                       result = i_word_length * sizeof(u32);
-               }
-       }
-
-       if (result != ep->ep.maxpacket) {
-               data = length - result;
-               temp_32.dw = 0;
-               for (i = 0 ; i < data ; i++)
-                       temp_32.byte.DATA[i] = p_buf_32->byte.DATA[i];
-
-               _nbu2ss_ep_in_end(udc, ep->epnum, temp_32.dw, data);
-               result += data;
-       }
-
-       req->div_len = result;
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_epn_in_data(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep,
-                              struct nbu2ss_req *req, u32 data_size)
-{
-       u32             num;
-       int             nret = 1;
-
-       if (ep->epnum == 0)
-               return -EINVAL;
-
-       num = ep->epnum - 1;
-
-       if ((ep->ep_type != USB_ENDPOINT_XFER_INT) && (req->req.dma != 0) &&
-           (data_size >= sizeof(u32))) {
-               nret = _nbu2ss_in_dma(udc, ep, req, num, data_size);
-       } else {
-               data_size = min_t(u32, data_size, ep->ep.maxpacket);
-               nret = _nbu2ss_epn_in_pio(udc, ep, req, data_size);
-       }
-
-       return nret;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_epn_in_transfer(struct nbu2ss_udc *udc,
-                                  struct nbu2ss_ep *ep, struct nbu2ss_req *req)
-{
-       u32             num;
-       u32             i_buf_size;
-       int             result = 0;
-       u32             status;
-
-       if (ep->epnum == 0)
-               return -EINVAL;
-
-       num = ep->epnum - 1;
-
-       status = _nbu2ss_readl(&udc->p_regs->EP_REGS[num].EP_STATUS);
-
-       /*-------------------------------------------------------------*/
-       /* State confirmation of FIFO */
-       if (req->req.actual == 0) {
-               if ((status & EPN_IN_EMPTY) == 0)
-                       return 1;       /* Not Empty */
-
-       } else {
-               if ((status & EPN_IN_FULL) != 0)
-                       return 1;       /* Not Empty */
-       }
-
-       /*-------------------------------------------------------------*/
-       /* Start transfer */
-       i_buf_size = req->req.length - req->req.actual;
-       if (i_buf_size > 0)
-               result = _nbu2ss_epn_in_data(udc, ep, req, i_buf_size);
-       else if (req->req.length == 0)
-               _nbu2ss_zero_len_pkt(udc, ep->epnum);
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_start_transfer(struct nbu2ss_udc *udc,
-                                 struct nbu2ss_ep *ep,
-                                 struct nbu2ss_req *req,
-                                 bool  bflag)
-{
-       int             nret = -EINVAL;
-
-       req->dma_flag = false;
-       req->div_len = 0;
-
-       if (req->req.length == 0) {
-               req->zero = false;
-       } else {
-               if ((req->req.length % ep->ep.maxpacket) == 0)
-                       req->zero = req->req.zero;
-               else
-                       req->zero = false;
-       }
-
-       if (ep->epnum == 0) {
-               /* EP0 */
-               switch (udc->ep0state) {
-               case EP0_IN_DATA_PHASE:
-                       nret = _nbu2ss_ep0_in_transfer(udc, req);
-                       break;
-
-               case EP0_OUT_DATA_PHASE:
-                       nret = _nbu2ss_ep0_out_transfer(udc, req);
-                       break;
-
-               case EP0_IN_STATUS_PHASE:
-                       nret = EP0_send_NULL(udc, true);
-                       break;
-
-               default:
-                       break;
-               }
-
-       } else {
-               /* EPN */
-               if (ep->direct == USB_DIR_OUT) {
-                       /* OUT */
-                       if (!bflag)
-                               nret = _nbu2ss_epn_out_transfer(udc, ep, req);
-               } else {
-                       /* IN */
-                       nret = _nbu2ss_epn_in_transfer(udc, ep, req);
-               }
-       }
-
-       return nret;
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_restert_transfer(struct nbu2ss_ep *ep)
-{
-       u32             length;
-       bool    bflag = false;
-       struct nbu2ss_req *req;
-
-       req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
-       if (!req)
-               return;
-
-       if (ep->epnum > 0) {
-               length = _nbu2ss_readl(&ep->udc->p_regs->EP_REGS[ep->epnum - 1].EP_LEN_DCNT);
-
-               length &= EPN_LDATA;
-               if (length < ep->ep.maxpacket)
-                       bflag = true;
-       }
-
-       _nbu2ss_start_transfer(ep->udc, ep, req, bflag);
-}
-
-/*-------------------------------------------------------------------------*/
-/*     Endpoint Toggle Reset */
-static void _nbu2ss_endpoint_toggle_reset(struct nbu2ss_udc *udc, u8 ep_adrs)
-{
-       u8              num;
-       u32             data;
-
-       if ((ep_adrs == 0) || (ep_adrs == 0x80))
-               return;
-
-       num = (ep_adrs & 0x7F) - 1;
-
-       if (ep_adrs & USB_DIR_IN)
-               data = EPN_IPIDCLR;
-       else
-               data = EPN_BCLR | EPN_OPIDCLR;
-
-       _nbu2ss_bitset(&udc->p_regs->EP_REGS[num].EP_CONTROL, data);
-}
-
-/*-------------------------------------------------------------------------*/
-/*     Endpoint STALL set */
-static void _nbu2ss_set_endpoint_stall(struct nbu2ss_udc *udc,
-                                      u8 ep_adrs, bool bstall)
-{
-       u8              num, epnum;
-       u32             data;
-       struct nbu2ss_ep *ep;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if ((ep_adrs == 0) || (ep_adrs == 0x80)) {
-               if (bstall) {
-                       /* Set STALL */
-                       _nbu2ss_bitset(&preg->EP0_CONTROL, EP0_STL);
-               } else {
-                       /* Clear STALL */
-                       _nbu2ss_bitclr(&preg->EP0_CONTROL, EP0_STL);
-               }
-       } else {
-               epnum = ep_adrs & USB_ENDPOINT_NUMBER_MASK;
-               num = epnum - 1;
-               ep = &udc->ep[epnum];
-
-               if (bstall) {
-                       /* Set STALL */
-                       ep->halted = true;
-
-                       if (ep_adrs & USB_DIR_IN)
-                               data = EPN_BCLR | EPN_ISTL;
-                       else
-                               data = EPN_OSTL_EN | EPN_OSTL;
-
-                       _nbu2ss_bitset(&preg->EP_REGS[num].EP_CONTROL, data);
-               } else {
-                       if (ep_adrs & USB_DIR_IN) {
-                               _nbu2ss_bitclr(&preg->EP_REGS[num].EP_CONTROL
-                                               , EPN_ISTL);
-                       } else {
-                               data =
-                               _nbu2ss_readl(&preg->EP_REGS[num].EP_CONTROL);
-
-                               data &= ~EPN_OSTL;
-                               data |= EPN_OSTL_EN;
-
-                               _nbu2ss_writel(&preg->EP_REGS[num].EP_CONTROL
-                                               , data);
-                       }
-
-                       /* Clear STALL */
-                       ep->stalled = false;
-                       if (ep->halted) {
-                               ep->halted = false;
-                               _nbu2ss_restert_transfer(ep);
-                       }
-               }
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_set_test_mode(struct nbu2ss_udc *udc, u32 mode)
-{
-       u32             data;
-
-       if (mode > MAX_TEST_MODE_NUM)
-               return;
-
-       dev_info(udc->dev, "SET FEATURE : test mode = %d\n", mode);
-
-       data = _nbu2ss_readl(&udc->p_regs->USB_CONTROL);
-       data &= ~TEST_FORCE_ENABLE;
-       data |= mode << TEST_MODE_SHIFT;
-
-       _nbu2ss_writel(&udc->p_regs->USB_CONTROL, data);
-       _nbu2ss_bitset(&udc->p_regs->TEST_CONTROL, CS_TESTMODEEN);
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_set_feature_device(struct nbu2ss_udc *udc,
-                                     u16 selector, u16 wIndex)
-{
-       int     result = -EOPNOTSUPP;
-
-       switch (selector) {
-       case USB_DEVICE_REMOTE_WAKEUP:
-               if (wIndex == 0x0000) {
-                       udc->remote_wakeup = U2F_ENABLE;
-                       result = 0;
-               }
-               break;
-
-       case USB_DEVICE_TEST_MODE:
-               wIndex >>= 8;
-               if (wIndex <= MAX_TEST_MODE_NUM)
-                       result = 0;
-               break;
-
-       default:
-               break;
-       }
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_get_ep_stall(struct nbu2ss_udc *udc, u8 ep_adrs)
-{
-       u8              epnum;
-       u32             data = 0, bit_data;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       epnum = ep_adrs & ~USB_ENDPOINT_DIR_MASK;
-       if (epnum == 0) {
-               data = _nbu2ss_readl(&preg->EP0_CONTROL);
-               bit_data = EP0_STL;
-
-       } else {
-               data = _nbu2ss_readl(&preg->EP_REGS[epnum - 1].EP_CONTROL);
-               if ((data & EPN_EN) == 0)
-                       return -1;
-
-               if (ep_adrs & USB_ENDPOINT_DIR_MASK)
-                       bit_data = EPN_ISTL;
-               else
-                       bit_data = EPN_OSTL;
-       }
-
-       if ((data & bit_data) == 0)
-               return 0;
-       return 1;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline int _nbu2ss_req_feature(struct nbu2ss_udc *udc, bool bset)
-{
-       u8      recipient = (u8)(udc->ctrl.bRequestType & USB_RECIP_MASK);
-       u8      direction = (u8)(udc->ctrl.bRequestType & USB_DIR_IN);
-       u16     selector  = le16_to_cpu(udc->ctrl.wValue);
-       u16     wIndex    = le16_to_cpu(udc->ctrl.wIndex);
-       u8      ep_adrs;
-       int     result = -EOPNOTSUPP;
-
-       if ((udc->ctrl.wLength != 0x0000) ||
-           (direction != USB_DIR_OUT)) {
-               return -EINVAL;
-       }
-
-       switch (recipient) {
-       case USB_RECIP_DEVICE:
-               if (bset)
-                       result =
-                       _nbu2ss_set_feature_device(udc, selector, wIndex);
-               break;
-
-       case USB_RECIP_ENDPOINT:
-               if (0x0000 == (wIndex & 0xFF70)) {
-                       if (selector == USB_ENDPOINT_HALT) {
-                               ep_adrs = wIndex & 0xFF;
-                               if (!bset) {
-                                       _nbu2ss_endpoint_toggle_reset(udc,
-                                                                     ep_adrs);
-                               }
-
-                               _nbu2ss_set_endpoint_stall(udc, ep_adrs, bset);
-
-                               result = 0;
-                       }
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       if (result >= 0)
-               _nbu2ss_create_ep0_packet(udc, udc->ep0_buf, 0);
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline enum usb_device_speed _nbu2ss_get_speed(struct nbu2ss_udc *udc)
-{
-       u32             data;
-       enum usb_device_speed speed = USB_SPEED_FULL;
-
-       data = _nbu2ss_readl(&udc->p_regs->USB_STATUS);
-       if (data & HIGH_SPEED)
-               speed = USB_SPEED_HIGH;
-
-       return speed;
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_epn_set_stall(struct nbu2ss_udc *udc,
-                                 struct nbu2ss_ep *ep)
-{
-       u8      ep_adrs;
-       u32     regdata;
-       int     limit_cnt = 0;
-
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (ep->direct == USB_DIR_IN) {
-               for (limit_cnt = 0
-                       ; limit_cnt < IN_DATA_EMPTY_COUNT
-                       ; limit_cnt++) {
-                       regdata = _nbu2ss_readl(&preg->EP_REGS[ep->epnum - 1].EP_STATUS);
-
-                       if ((regdata & EPN_IN_DATA) == 0)
-                               break;
-
-                       mdelay(1);
-               }
-       }
-
-       ep_adrs = ep->epnum | ep->direct;
-       _nbu2ss_set_endpoint_stall(udc, ep_adrs, 1);
-}
-
-/*-------------------------------------------------------------------------*/
-static int std_req_get_status(struct nbu2ss_udc *udc)
-{
-       u32     length;
-       u16     status_data = 0;
-       u8      recipient = (u8)(udc->ctrl.bRequestType & USB_RECIP_MASK);
-       u8      direction = (u8)(udc->ctrl.bRequestType & USB_DIR_IN);
-       u8      ep_adrs;
-       int     result = -EINVAL;
-
-       if ((udc->ctrl.wValue != 0x0000) || (direction != USB_DIR_IN))
-               return result;
-
-       length =
-               min_t(u16, le16_to_cpu(udc->ctrl.wLength), sizeof(status_data));
-       switch (recipient) {
-       case USB_RECIP_DEVICE:
-               if (udc->ctrl.wIndex == 0x0000) {
-                       if (udc->gadget.is_selfpowered)
-                               status_data |= BIT(USB_DEVICE_SELF_POWERED);
-
-                       if (udc->remote_wakeup)
-                               status_data |= BIT(USB_DEVICE_REMOTE_WAKEUP);
-
-                       result = 0;
-               }
-               break;
-
-       case USB_RECIP_ENDPOINT:
-               if (0x0000 == (le16_to_cpu(udc->ctrl.wIndex) & 0xFF70)) {
-                       ep_adrs = (u8)(le16_to_cpu(udc->ctrl.wIndex) & 0xFF);
-                       result = _nbu2ss_get_ep_stall(udc, ep_adrs);
-
-                       if (result > 0)
-                               status_data |= BIT(USB_ENDPOINT_HALT);
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       if (result >= 0) {
-               memcpy(udc->ep0_buf, &status_data, length);
-               _nbu2ss_create_ep0_packet(udc, udc->ep0_buf, length);
-               _nbu2ss_ep0_in_transfer(udc, &udc->ep0_req);
-
-       } else {
-               dev_err(udc->dev, " Error GET_STATUS\n");
-       }
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int std_req_clear_feature(struct nbu2ss_udc *udc)
-{
-       return _nbu2ss_req_feature(udc, false);
-}
-
-/*-------------------------------------------------------------------------*/
-static int std_req_set_feature(struct nbu2ss_udc *udc)
-{
-       return _nbu2ss_req_feature(udc, true);
-}
-
-/*-------------------------------------------------------------------------*/
-static int std_req_set_address(struct nbu2ss_udc *udc)
-{
-       int             result = 0;
-       u32             wValue = le16_to_cpu(udc->ctrl.wValue);
-
-       if ((udc->ctrl.bRequestType != 0x00)    ||
-           (udc->ctrl.wIndex != 0x0000)        ||
-               (udc->ctrl.wLength != 0x0000)) {
-               return -EINVAL;
-       }
-
-       if (wValue != (wValue & 0x007F))
-               return -EINVAL;
-
-       wValue <<= USB_ADRS_SHIFT;
-
-       _nbu2ss_writel(&udc->p_regs->USB_ADDRESS, wValue);
-       _nbu2ss_create_ep0_packet(udc, udc->ep0_buf, 0);
-
-       return result;
-}
-
-/*-------------------------------------------------------------------------*/
-static int std_req_set_configuration(struct nbu2ss_udc *udc)
-{
-       u32 config_value = (u32)(le16_to_cpu(udc->ctrl.wValue) & 0x00ff);
-
-       if ((udc->ctrl.wIndex != 0x0000)        ||
-           (udc->ctrl.wLength != 0x0000)       ||
-               (udc->ctrl.bRequestType != 0x00)) {
-               return -EINVAL;
-       }
-
-       udc->curr_config = config_value;
-
-       if (config_value > 0) {
-               _nbu2ss_bitset(&udc->p_regs->USB_CONTROL, CONF);
-               udc->devstate = USB_STATE_CONFIGURED;
-
-       } else {
-               _nbu2ss_bitclr(&udc->p_regs->USB_CONTROL, CONF);
-               udc->devstate = USB_STATE_ADDRESS;
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_read_request_data(struct nbu2ss_udc *udc, u32 *pdata)
-{
-       *pdata = _nbu2ss_readl(&udc->p_regs->SETUP_DATA0);
-       pdata++;
-       *pdata = _nbu2ss_readl(&udc->p_regs->SETUP_DATA1);
-}
-
-/*-------------------------------------------------------------------------*/
-static inline int _nbu2ss_decode_request(struct nbu2ss_udc *udc)
-{
-       bool                    bcall_back = true;
-       int                     nret = -EINVAL;
-       struct usb_ctrlrequest  *p_ctrl;
-
-       p_ctrl = &udc->ctrl;
-       _nbu2ss_read_request_data(udc, (u32 *)p_ctrl);
-
-       /* ep0 state control */
-       if (p_ctrl->wLength == 0) {
-               udc->ep0state = EP0_IN_STATUS_PHASE;
-
-       } else {
-               if (p_ctrl->bRequestType & USB_DIR_IN)
-                       udc->ep0state = EP0_IN_DATA_PHASE;
-               else
-                       udc->ep0state = EP0_OUT_DATA_PHASE;
-       }
-
-       if ((p_ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
-               switch (p_ctrl->bRequest) {
-               case USB_REQ_GET_STATUS:
-                       nret = std_req_get_status(udc);
-                       bcall_back = false;
-                       break;
-
-               case USB_REQ_CLEAR_FEATURE:
-                       nret = std_req_clear_feature(udc);
-                       bcall_back = false;
-                       break;
-
-               case USB_REQ_SET_FEATURE:
-                       nret = std_req_set_feature(udc);
-                       bcall_back = false;
-                       break;
-
-               case USB_REQ_SET_ADDRESS:
-                       nret = std_req_set_address(udc);
-                       bcall_back = false;
-                       break;
-
-               case USB_REQ_SET_CONFIGURATION:
-                       nret = std_req_set_configuration(udc);
-                       break;
-
-               default:
-                       break;
-               }
-       }
-
-       if (!bcall_back) {
-               if (udc->ep0state == EP0_IN_STATUS_PHASE) {
-                       if (nret >= 0) {
-                               /*--------------------------------------*/
-                               /* Status Stage */
-                               nret = EP0_send_NULL(udc, true);
-                       }
-               }
-
-       } else {
-               spin_unlock(&udc->lock);
-               nret = udc->driver->setup(&udc->gadget, &udc->ctrl);
-               spin_lock(&udc->lock);
-       }
-
-       if (nret < 0)
-               udc->ep0state = EP0_IDLE;
-
-       return nret;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline int _nbu2ss_ep0_in_data_stage(struct nbu2ss_udc *udc)
-{
-       int                     nret;
-       struct nbu2ss_req       *req;
-       struct nbu2ss_ep        *ep = &udc->ep[0];
-
-       req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
-       if (!req)
-               req = &udc->ep0_req;
-
-       req->req.actual += req->div_len;
-       req->div_len = 0;
-
-       nret = _nbu2ss_ep0_in_transfer(udc, req);
-       if (nret == 0) {
-               udc->ep0state = EP0_OUT_STATUS_PAHSE;
-               EP0_receive_NULL(udc, true);
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline int _nbu2ss_ep0_out_data_stage(struct nbu2ss_udc *udc)
-{
-       int                     nret;
-       struct nbu2ss_req       *req;
-       struct nbu2ss_ep        *ep = &udc->ep[0];
-
-       req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
-       if (!req)
-               req = &udc->ep0_req;
-
-       nret = _nbu2ss_ep0_out_transfer(udc, req);
-       if (nret == 0) {
-               udc->ep0state = EP0_IN_STATUS_PHASE;
-               EP0_send_NULL(udc, true);
-
-       } else if (nret < 0) {
-               _nbu2ss_bitset(&udc->p_regs->EP0_CONTROL, EP0_BCLR);
-               req->req.status = nret;
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline int _nbu2ss_ep0_status_stage(struct nbu2ss_udc *udc)
-{
-       struct nbu2ss_req       *req;
-       struct nbu2ss_ep        *ep = &udc->ep[0];
-
-       req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
-       if (!req) {
-               req = &udc->ep0_req;
-               if (req->req.complete)
-                       req->req.complete(&ep->ep, &req->req);
-
-       } else {
-               if (req->req.complete)
-                       _nbu2ss_ep_done(ep, req, 0);
-       }
-
-       udc->ep0state = EP0_IDLE;
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_ep0_int(struct nbu2ss_udc *udc)
-{
-       int             i;
-       u32             status;
-       u32             intr;
-       int             nret = -1;
-
-       status = _nbu2ss_readl(&udc->p_regs->EP0_STATUS);
-       intr = status & EP0_STATUS_RW_BIT;
-       _nbu2ss_writel(&udc->p_regs->EP0_STATUS, ~intr);
-
-       status &= (SETUP_INT | EP0_IN_INT | EP0_OUT_INT
-                       | STG_END_INT | EP0_OUT_NULL_INT);
-
-       if (status == 0) {
-               dev_info(udc->dev, "%s Not Decode Interrupt\n", __func__);
-               dev_info(udc->dev, "EP0_STATUS = 0x%08x\n", intr);
-               return;
-       }
-
-       if (udc->gadget.speed == USB_SPEED_UNKNOWN)
-               udc->gadget.speed = _nbu2ss_get_speed(udc);
-
-       for (i = 0; i < EP0_END_XFER; i++) {
-               switch (udc->ep0state) {
-               case EP0_IDLE:
-                       if (status & SETUP_INT) {
-                               status = 0;
-                               nret = _nbu2ss_decode_request(udc);
-                       }
-                       break;
-
-               case EP0_IN_DATA_PHASE:
-                       if (status & EP0_IN_INT) {
-                               status &= ~EP0_IN_INT;
-                               nret = _nbu2ss_ep0_in_data_stage(udc);
-                       }
-                       break;
-
-               case EP0_OUT_DATA_PHASE:
-                       if (status & EP0_OUT_INT) {
-                               status &= ~EP0_OUT_INT;
-                               nret = _nbu2ss_ep0_out_data_stage(udc);
-                       }
-                       break;
-
-               case EP0_IN_STATUS_PHASE:
-                       if ((status & STG_END_INT) || (status & SETUP_INT)) {
-                               status &= ~(STG_END_INT | EP0_IN_INT);
-                               nret = _nbu2ss_ep0_status_stage(udc);
-                       }
-                       break;
-
-               case EP0_OUT_STATUS_PAHSE:
-                       if ((status & STG_END_INT) || (status & SETUP_INT) ||
-                           (status & EP0_OUT_NULL_INT)) {
-                               status &= ~(STG_END_INT
-                                               | EP0_OUT_INT
-                                               | EP0_OUT_NULL_INT);
-
-                               nret = _nbu2ss_ep0_status_stage(udc);
-                       }
-
-                       break;
-
-               default:
-                       status = 0;
-                       break;
-               }
-
-               if (status == 0)
-                       break;
-       }
-
-       if (nret < 0) {
-               /* Send Stall */
-               _nbu2ss_set_endpoint_stall(udc, 0, true);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_ep_done(struct nbu2ss_ep *ep,
-                           struct nbu2ss_req *req,
-                           int status)
-{
-       struct nbu2ss_udc *udc = ep->udc;
-
-       list_del_init(&req->queue);
-
-       if (status == -ECONNRESET)
-               _nbu2ss_fifo_flush(udc, ep);
-
-       if (likely(req->req.status == -EINPROGRESS))
-               req->req.status = status;
-
-       if (ep->stalled) {
-               _nbu2ss_epn_set_stall(udc, ep);
-       } else {
-               if (!list_empty(&ep->queue))
-                       _nbu2ss_restert_transfer(ep);
-       }
-
-#ifdef USE_DMA
-       if ((ep->direct == USB_DIR_OUT) && (ep->epnum > 0) &&
-           (req->req.dma != 0))
-               _nbu2ss_dma_unmap_single(udc, ep, req, USB_DIR_OUT);
-#endif
-
-       spin_unlock(&udc->lock);
-       req->req.complete(&ep->ep, &req->req);
-       spin_lock(&udc->lock);
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_epn_in_int(struct nbu2ss_udc *udc,
-                                     struct nbu2ss_ep *ep,
-                                     struct nbu2ss_req *req)
-{
-       int     result = 0;
-       u32     status;
-
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (req->dma_flag)
-               return;         /* DMA is forwarded */
-
-       req->req.actual += req->div_len;
-       req->div_len = 0;
-
-       if (req->req.actual != req->req.length) {
-               /*---------------------------------------------------------*/
-               /* remainder of data */
-               result = _nbu2ss_epn_in_transfer(udc, ep, req);
-
-       } else {
-               if (req->zero && ((req->req.actual % ep->ep.maxpacket) == 0)) {
-                       status =
-                       _nbu2ss_readl(&preg->EP_REGS[ep->epnum - 1].EP_STATUS);
-
-                       if ((status & EPN_IN_FULL) == 0) {
-                               /*-----------------------------------------*/
-                               /* 0 Length Packet */
-                               req->zero = false;
-                               _nbu2ss_zero_len_pkt(udc, ep->epnum);
-                       }
-                       return;
-               }
-       }
-
-       if (result <= 0) {
-               /*---------------------------------------------------------*/
-               /* Complete */
-               _nbu2ss_ep_done(ep, req, result);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_epn_out_int(struct nbu2ss_udc *udc,
-                                      struct nbu2ss_ep *ep,
-                                      struct nbu2ss_req *req)
-{
-       int     result;
-
-       result = _nbu2ss_epn_out_transfer(udc, ep, req);
-       if (result <= 0)
-               _nbu2ss_ep_done(ep, req, result);
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_epn_in_dma_int(struct nbu2ss_udc *udc,
-                                         struct nbu2ss_ep *ep,
-                                         struct nbu2ss_req *req)
-{
-       u32             mpkt;
-       u32             size;
-       struct usb_request *preq;
-
-       preq = &req->req;
-
-       if (!req->dma_flag)
-               return;
-
-       preq->actual += req->div_len;
-       req->div_len = 0;
-       req->dma_flag = false;
-
-#ifdef USE_DMA
-       _nbu2ss_dma_unmap_single(udc, ep, req, USB_DIR_IN);
-#endif
-
-       if (preq->actual != preq->length) {
-               _nbu2ss_epn_in_transfer(udc, ep, req);
-       } else {
-               mpkt = ep->ep.maxpacket;
-               size = preq->actual % mpkt;
-               if (size > 0) {
-                       if (((preq->actual & 0x03) == 0) && (size < mpkt))
-                               _nbu2ss_ep_in_end(udc, ep->epnum, 0, 0);
-               } else {
-                       _nbu2ss_epn_in_int(udc, ep, req);
-               }
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_epn_out_dma_int(struct nbu2ss_udc *udc,
-                                          struct nbu2ss_ep *ep,
-                                          struct nbu2ss_req *req)
-{
-       int             i;
-       u32             num;
-       u32             dmacnt, ep_dmacnt;
-       u32             mpkt;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       num = ep->epnum - 1;
-
-       if (req->req.actual == req->req.length) {
-               if ((req->req.length % ep->ep.maxpacket) && !req->zero) {
-                       req->div_len = 0;
-                       req->dma_flag = false;
-                       _nbu2ss_ep_done(ep, req, 0);
-                       return;
-               }
-       }
-
-       ep_dmacnt = _nbu2ss_readl(&preg->EP_REGS[num].EP_LEN_DCNT)
-                & EPN_DMACNT;
-       ep_dmacnt >>= 16;
-
-       for (i = 0; i < EPC_PLL_LOCK_COUNT; i++) {
-               dmacnt = _nbu2ss_readl(&preg->EP_DCR[num].EP_DCR1)
-                        & DCR1_EPN_DMACNT;
-               dmacnt >>= 16;
-               if (ep_dmacnt == dmacnt)
-                       break;
-       }
-
-       _nbu2ss_bitclr(&preg->EP_DCR[num].EP_DCR1, DCR1_EPN_REQEN);
-
-       if (dmacnt != 0) {
-               mpkt = ep->ep.maxpacket;
-               if ((req->div_len % mpkt) == 0)
-                       req->div_len -= mpkt * dmacnt;
-       }
-
-       if ((req->req.actual % ep->ep.maxpacket) > 0) {
-               if (req->req.actual == req->div_len) {
-                       req->div_len = 0;
-                       req->dma_flag = false;
-                       _nbu2ss_ep_done(ep, req, 0);
-                       return;
-               }
-       }
-
-       req->req.actual += req->div_len;
-       req->div_len = 0;
-       req->dma_flag = false;
-
-       _nbu2ss_epn_out_int(udc, ep, req);
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_epn_int(struct nbu2ss_udc *udc, u32 epnum)
-{
-       u32     num;
-       u32     status;
-
-       struct nbu2ss_req       *req;
-       struct nbu2ss_ep        *ep = &udc->ep[epnum];
-
-       num = epnum - 1;
-
-       /* Interrupt Status */
-       status = _nbu2ss_readl(&udc->p_regs->EP_REGS[num].EP_STATUS);
-
-       /* Interrupt Clear */
-       _nbu2ss_writel(&udc->p_regs->EP_REGS[num].EP_STATUS, ~status);
-
-       req = list_first_entry_or_null(&ep->queue, struct nbu2ss_req, queue);
-       if (!req) {
-               /* pr_warn("=== %s(%d) req == NULL\n", __func__, epnum); */
-               return;
-       }
-
-       if (status & EPN_OUT_END_INT) {
-               status &= ~EPN_OUT_INT;
-               _nbu2ss_epn_out_dma_int(udc, ep, req);
-       }
-
-       if (status & EPN_OUT_INT)
-               _nbu2ss_epn_out_int(udc, ep, req);
-
-       if (status & EPN_IN_END_INT) {
-               status &= ~EPN_IN_INT;
-               _nbu2ss_epn_in_dma_int(udc, ep, req);
-       }
-
-       if (status & EPN_IN_INT)
-               _nbu2ss_epn_in_int(udc, ep, req);
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_ep_int(struct nbu2ss_udc *udc, u32 epnum)
-{
-       if (epnum == 0)
-               _nbu2ss_ep0_int(udc);
-       else
-               _nbu2ss_epn_int(udc, epnum);
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_ep0_enable(struct nbu2ss_udc *udc)
-{
-       _nbu2ss_bitset(&udc->p_regs->EP0_CONTROL, (EP0_AUTO | EP0_BCLR));
-       _nbu2ss_writel(&udc->p_regs->EP0_INT_ENA, EP0_INT_EN_BIT);
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_nuke(struct nbu2ss_udc *udc,
-                       struct nbu2ss_ep *ep,
-                       int status)
-{
-       struct nbu2ss_req *req, *n;
-
-       /* Endpoint Disable */
-       _nbu2ss_epn_exit(udc, ep);
-
-       /* DMA Disable */
-       _nbu2ss_ep_dma_exit(udc, ep);
-
-       if (list_empty(&ep->queue))
-               return 0;
-
-       /* called with irqs blocked */
-       list_for_each_entry_safe(req, n, &ep->queue, queue) {
-               _nbu2ss_ep_done(ep, req, status);
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_quiesce(struct nbu2ss_udc *udc)
-{
-       struct nbu2ss_ep        *ep;
-
-       udc->gadget.speed = USB_SPEED_UNKNOWN;
-
-       _nbu2ss_nuke(udc, &udc->ep[0], -ESHUTDOWN);
-
-       /* Endpoint n */
-       list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
-               _nbu2ss_nuke(udc, ep, -ESHUTDOWN);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_pullup(struct nbu2ss_udc *udc, int is_on)
-{
-       u32     reg_dt;
-
-       if (udc->vbus_active == 0)
-               return -ESHUTDOWN;
-
-       if (is_on) {
-               /* D+ Pullup */
-               if (udc->driver) {
-                       reg_dt = (_nbu2ss_readl(&udc->p_regs->USB_CONTROL)
-                               | PUE2) & ~(u32)CONNECTB;
-
-                       _nbu2ss_writel(&udc->p_regs->USB_CONTROL, reg_dt);
-               }
-
-       } else {
-               /* D+ Pulldown */
-               reg_dt = (_nbu2ss_readl(&udc->p_regs->USB_CONTROL) | CONNECTB)
-                       & ~(u32)PUE2;
-
-               _nbu2ss_writel(&udc->p_regs->USB_CONTROL, reg_dt);
-               udc->gadget.speed = USB_SPEED_UNKNOWN;
-       }
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_fifo_flush(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep)
-{
-       struct fc_regs __iomem *p = udc->p_regs;
-
-       if (udc->vbus_active == 0)
-               return;
-
-       if (ep->epnum == 0) {
-               /* EP0 */
-               _nbu2ss_bitset(&p->EP0_CONTROL, EP0_BCLR);
-
-       } else {
-               /* EPN */
-               _nbu2ss_ep_dma_abort(udc, ep);
-               _nbu2ss_bitset(&p->EP_REGS[ep->epnum - 1].EP_CONTROL, EPN_BCLR);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static int _nbu2ss_enable_controller(struct nbu2ss_udc *udc)
-{
-       int     waitcnt = 0;
-
-       if (udc->udc_enabled)
-               return 0;
-
-       /* Reset */
-       _nbu2ss_bitset(&udc->p_regs->EPCTR, (DIRPD | EPC_RST));
-       udelay(EPC_RST_DISABLE_TIME);   /* 1us wait */
-
-       _nbu2ss_bitclr(&udc->p_regs->EPCTR, DIRPD);
-       mdelay(EPC_DIRPD_DISABLE_TIME); /* 1ms wait */
-
-       _nbu2ss_bitclr(&udc->p_regs->EPCTR, EPC_RST);
-
-       _nbu2ss_writel(&udc->p_regs->AHBSCTR, WAIT_MODE);
-
-       _nbu2ss_writel(&udc->p_regs->AHBMCTR,
-                      HBUSREQ_MODE | HTRANS_MODE | WBURST_TYPE);
-
-       while (!(_nbu2ss_readl(&udc->p_regs->EPCTR) & PLL_LOCK)) {
-               waitcnt++;
-               udelay(1);      /* 1us wait */
-               if (waitcnt == EPC_PLL_LOCK_COUNT) {
-                       dev_err(udc->dev, "*** Reset Cancel failed\n");
-                       return -EINVAL;
-               }
-       }
-
-       _nbu2ss_bitset(&udc->p_regs->UTMI_CHARACTER_1, USB_SQUSET);
-
-       _nbu2ss_bitset(&udc->p_regs->USB_CONTROL, (INT_SEL | SOF_RCV));
-
-       /* EP0 */
-       _nbu2ss_ep0_enable(udc);
-
-       /* USB Interrupt Enable */
-       _nbu2ss_bitset(&udc->p_regs->USB_INT_ENA, USB_INT_EN_BIT);
-
-       udc->udc_enabled = true;
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_reset_controller(struct nbu2ss_udc *udc)
-{
-       _nbu2ss_bitset(&udc->p_regs->EPCTR, EPC_RST);
-       _nbu2ss_bitclr(&udc->p_regs->EPCTR, EPC_RST);
-}
-
-/*-------------------------------------------------------------------------*/
-static void _nbu2ss_disable_controller(struct nbu2ss_udc *udc)
-{
-       if (udc->udc_enabled) {
-               udc->udc_enabled = false;
-               _nbu2ss_reset_controller(udc);
-               _nbu2ss_bitset(&udc->p_regs->EPCTR, (DIRPD | EPC_RST));
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_check_vbus(struct nbu2ss_udc *udc)
-{
-       int     nret;
-       u32     reg_dt;
-
-       /* chattering */
-       mdelay(VBUS_CHATTERING_MDELAY);         /* wait (ms) */
-
-       /* VBUS ON Check*/
-       reg_dt = gpiod_get_value(vbus_gpio);
-       if (reg_dt == 0) {
-               udc->linux_suspended = 0;
-
-               _nbu2ss_reset_controller(udc);
-               dev_info(udc->dev, " ----- VBUS OFF\n");
-
-               if (udc->vbus_active == 1) {
-                       /* VBUS OFF */
-                       udc->vbus_active = 0;
-                       if (udc->usb_suspended) {
-                               udc->usb_suspended = 0;
-                               /* _nbu2ss_reset_controller(udc); */
-                       }
-                       udc->devstate = USB_STATE_NOTATTACHED;
-
-                       _nbu2ss_quiesce(udc);
-                       if (udc->driver) {
-                               spin_unlock(&udc->lock);
-                               udc->driver->disconnect(&udc->gadget);
-                               spin_lock(&udc->lock);
-                       }
-
-                       _nbu2ss_disable_controller(udc);
-               }
-       } else {
-               mdelay(5);              /* wait (5ms) */
-               reg_dt = gpiod_get_value(vbus_gpio);
-               if (reg_dt == 0)
-                       return;
-
-               dev_info(udc->dev, " ----- VBUS ON\n");
-
-               if (udc->linux_suspended)
-                       return;
-
-               if (udc->vbus_active == 0) {
-                       /* VBUS ON */
-                       udc->vbus_active = 1;
-                       udc->devstate = USB_STATE_POWERED;
-
-                       nret = _nbu2ss_enable_controller(udc);
-                       if (nret < 0) {
-                               _nbu2ss_disable_controller(udc);
-                               udc->vbus_active = 0;
-                               return;
-                       }
-
-                       _nbu2ss_pullup(udc, 1);
-
-#ifdef UDC_DEBUG_DUMP
-                       _nbu2ss_dump_register(udc);
-#endif /* UDC_DEBUG_DUMP */
-
-               } else {
-                       if (udc->devstate == USB_STATE_POWERED)
-                               _nbu2ss_pullup(udc, 1);
-               }
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_int_bus_reset(struct nbu2ss_udc *udc)
-{
-       udc->devstate           = USB_STATE_DEFAULT;
-       udc->remote_wakeup      = 0;
-
-       _nbu2ss_quiesce(udc);
-
-       udc->ep0state = EP0_IDLE;
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_int_usb_resume(struct nbu2ss_udc *udc)
-{
-       if (udc->usb_suspended == 1) {
-               udc->usb_suspended = 0;
-               if (udc->driver && udc->driver->resume) {
-                       spin_unlock(&udc->lock);
-                       udc->driver->resume(&udc->gadget);
-                       spin_lock(&udc->lock);
-               }
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static inline void _nbu2ss_int_usb_suspend(struct nbu2ss_udc *udc)
-{
-       u32     reg_dt;
-
-       if (udc->usb_suspended == 0) {
-               reg_dt = gpiod_get_value(vbus_gpio);
-
-               if (reg_dt == 0)
-                       return;
-
-               udc->usb_suspended = 1;
-               if (udc->driver && udc->driver->suspend) {
-                       spin_unlock(&udc->lock);
-                       udc->driver->suspend(&udc->gadget);
-                       spin_lock(&udc->lock);
-               }
-
-               _nbu2ss_bitset(&udc->p_regs->USB_CONTROL, SUSPEND);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-/* VBUS (GPIO153) Interrupt */
-static irqreturn_t _nbu2ss_vbus_irq(int irq, void *_udc)
-{
-       struct nbu2ss_udc       *udc = (struct nbu2ss_udc *)_udc;
-
-       spin_lock(&udc->lock);
-       _nbu2ss_check_vbus(udc);
-       spin_unlock(&udc->lock);
-
-       return IRQ_HANDLED;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Interrupt (udc) */
-static irqreturn_t _nbu2ss_udc_irq(int irq, void *_udc)
-{
-       u8      suspend_flag = 0;
-       u32     status;
-       u32     epnum, int_bit;
-
-       struct nbu2ss_udc       *udc = (struct nbu2ss_udc *)_udc;
-       struct fc_regs __iomem *preg = udc->p_regs;
-
-       if (gpiod_get_value(vbus_gpio) == 0) {
-               _nbu2ss_writel(&preg->USB_INT_STA, ~USB_INT_STA_RW);
-               _nbu2ss_writel(&preg->USB_INT_ENA, 0);
-               return IRQ_HANDLED;
-       }
-
-       spin_lock(&udc->lock);
-
-       for (;;) {
-               if (gpiod_get_value(vbus_gpio) == 0) {
-                       _nbu2ss_writel(&preg->USB_INT_STA, ~USB_INT_STA_RW);
-                       _nbu2ss_writel(&preg->USB_INT_ENA, 0);
-                       status = 0;
-               } else {
-                       status = _nbu2ss_readl(&preg->USB_INT_STA);
-               }
-
-               if (status == 0)
-                       break;
-
-               _nbu2ss_writel(&preg->USB_INT_STA, ~(status & USB_INT_STA_RW));
-
-               if (status & USB_RST_INT) {
-                       /* USB Reset */
-                       _nbu2ss_int_bus_reset(udc);
-               }
-
-               if (status & RSUM_INT) {
-                       /* Resume */
-                       _nbu2ss_int_usb_resume(udc);
-               }
-
-               if (status & SPND_INT) {
-                       /* Suspend */
-                       suspend_flag = 1;
-               }
-
-               if (status & EPN_INT) {
-                       /* EP INT */
-                       int_bit = status >> 8;
-
-                       for (epnum = 0; epnum < NUM_ENDPOINTS; epnum++) {
-                               if (0x01 & int_bit)
-                                       _nbu2ss_ep_int(udc, epnum);
-
-                               int_bit >>= 1;
-
-                               if (int_bit == 0)
-                                       break;
-                       }
-               }
-       }
-
-       if (suspend_flag)
-               _nbu2ss_int_usb_suspend(udc);
-
-       spin_unlock(&udc->lock);
-
-       return IRQ_HANDLED;
-}
-
-/*-------------------------------------------------------------------------*/
-/* usb_ep_ops */
-static int nbu2ss_ep_enable(struct usb_ep *_ep,
-                           const struct usb_endpoint_descriptor *desc)
-{
-       u8              ep_type;
-       unsigned long   flags;
-
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-
-       if (!_ep || !desc) {
-               pr_err(" *** %s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-       if (!ep->udc) {
-               pr_err(" *** %s, ep == NULL !!\n", __func__);
-               return -EINVAL;
-       }
-
-       ep_type = usb_endpoint_type(desc);
-       if ((ep_type == USB_ENDPOINT_XFER_CONTROL) ||
-           (ep_type == USB_ENDPOINT_XFER_ISOC)) {
-               pr_err(" *** %s, bat bmAttributes\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = ep->udc;
-       if (udc->vbus_active == 0)
-               return -ESHUTDOWN;
-
-       if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
-               dev_err(ep->udc->dev, " *** %s, udc !!\n", __func__);
-               return -ESHUTDOWN;
-       }
-
-       spin_lock_irqsave(&udc->lock, flags);
-
-       ep->desc = desc;
-       ep->epnum = usb_endpoint_num(desc);
-       ep->direct = desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-       ep->ep_type = ep_type;
-       ep->wedged = 0;
-       ep->halted = false;
-       ep->stalled = false;
-
-       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
-
-       /* DMA setting */
-       _nbu2ss_ep_dma_init(udc, ep);
-
-       /* Endpoint setting */
-       _nbu2ss_ep_init(udc, ep);
-
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_ep_disable(struct usb_ep *_ep)
-{
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-
-       if (!_ep) {
-               pr_err(" *** %s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-       if (!ep->udc) {
-               pr_err("udc: *** %s, ep == NULL !!\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = ep->udc;
-       if (udc->vbus_active == 0)
-               return -ESHUTDOWN;
-
-       spin_lock_irqsave(&udc->lock, flags);
-       _nbu2ss_nuke(udc, ep, -EINPROGRESS);            /* dequeue request */
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static struct usb_request *nbu2ss_ep_alloc_request(struct usb_ep *ep,
-                                                  gfp_t gfp_flags)
-{
-       struct nbu2ss_req *req;
-
-       req = kzalloc(sizeof(*req), gfp_flags);
-       if (!req)
-               return NULL;
-
-#ifdef USE_DMA
-       req->req.dma = DMA_ADDR_INVALID;
-#endif
-       INIT_LIST_HEAD(&req->queue);
-
-       return &req->req;
-}
-
-/*-------------------------------------------------------------------------*/
-static void nbu2ss_ep_free_request(struct usb_ep *_ep,
-                                  struct usb_request *_req)
-{
-       struct nbu2ss_req *req;
-
-       if (_req) {
-               req = container_of(_req, struct nbu2ss_req, req);
-
-               kfree(req);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_ep_queue(struct usb_ep *_ep,
-                          struct usb_request *_req, gfp_t gfp_flags)
-{
-       struct nbu2ss_req       *req;
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-       bool                    bflag;
-       int                     result = -EINVAL;
-
-       /* catch various bogus parameters */
-       if (!_ep || !_req) {
-               if (!_ep)
-                       pr_err("udc: %s --- _ep == NULL\n", __func__);
-
-               if (!_req)
-                       pr_err("udc: %s --- _req == NULL\n", __func__);
-
-               return -EINVAL;
-       }
-
-       req = container_of(_req, struct nbu2ss_req, req);
-       if (unlikely(!_req->complete ||
-                    !_req->buf ||
-                    !list_empty(&req->queue))) {
-               if (!_req->complete)
-                       pr_err("udc: %s --- !_req->complete\n", __func__);
-
-               if (!_req->buf)
-                       pr_err("udc:%s --- !_req->buf\n", __func__);
-
-               if (!list_empty(&req->queue))
-                       pr_err("%s --- !list_empty(&req->queue)\n", __func__);
-
-               return -EINVAL;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-       udc = ep->udc;
-
-       if (udc->vbus_active == 0) {
-               dev_info(udc->dev, "Can't ep_queue (VBUS OFF)\n");
-               return -ESHUTDOWN;
-       }
-
-       if (unlikely(!udc->driver)) {
-               dev_err(udc->dev, "%s, bogus device state %p\n", __func__,
-                       udc->driver);
-               return -ESHUTDOWN;
-       }
-
-       spin_lock_irqsave(&udc->lock, flags);
-
-#ifdef USE_DMA
-       if ((uintptr_t)req->req.buf & 0x3)
-               req->unaligned = true;
-       else
-               req->unaligned = false;
-
-       if (req->unaligned) {
-               if (!ep->virt_buf) {
-                       ep->virt_buf = dma_alloc_coherent(udc->dev, PAGE_SIZE,
-                                                         &ep->phys_buf,
-                                                         GFP_ATOMIC | GFP_DMA);
-                       if (!ep->virt_buf) {
-                               spin_unlock_irqrestore(&udc->lock, flags);
-                               return -ENOMEM;
-                       }
-               }
-               if (ep->epnum > 0)  {
-                       if (ep->direct == USB_DIR_IN)
-                               memcpy(ep->virt_buf, req->req.buf,
-                                      req->req.length);
-               }
-       }
-
-       if ((ep->epnum > 0) && (ep->direct == USB_DIR_OUT) &&
-           (req->req.dma != 0))
-               _nbu2ss_dma_map_single(udc, ep, req, USB_DIR_OUT);
-#endif
-
-       _req->status = -EINPROGRESS;
-       _req->actual = 0;
-
-       bflag = list_empty(&ep->queue);
-       list_add_tail(&req->queue, &ep->queue);
-
-       if (bflag && !ep->stalled) {
-               result = _nbu2ss_start_transfer(udc, ep, req, false);
-               if (result < 0) {
-                       dev_err(udc->dev, " *** %s, result = %d\n", __func__,
-                               result);
-                       list_del(&req->queue);
-               } else if ((ep->epnum > 0) && (ep->direct == USB_DIR_OUT)) {
-#ifdef USE_DMA
-                       if (req->req.length < 4 &&
-                           req->req.length == req->req.actual)
-#else
-                       if (req->req.length == req->req.actual)
-#endif
-                               _nbu2ss_ep_done(ep, req, result);
-               }
-       }
-
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
-       struct nbu2ss_req       *req;
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-       unsigned long flags;
-
-       /* catch various bogus parameters */
-       if (!_ep || !_req) {
-               /* pr_err("%s, bad param(1)\n", __func__); */
-               return -EINVAL;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-
-       udc = ep->udc;
-       if (!udc)
-               return -EINVAL;
-
-       spin_lock_irqsave(&udc->lock, flags);
-
-       /* make sure it's actually queued on this endpoint */
-       list_for_each_entry(req, &ep->queue, queue) {
-               if (&req->req == _req) {
-                       _nbu2ss_ep_done(ep, req, -ECONNRESET);
-                       spin_unlock_irqrestore(&udc->lock, flags);
-                       return 0;
-               }
-       }
-
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       pr_debug("%s no queue(EINVAL)\n", __func__);
-
-       return -EINVAL;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_ep_set_halt(struct usb_ep *_ep, int value)
-{
-       u8              ep_adrs;
-       unsigned long   flags;
-
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-
-       if (!_ep) {
-               pr_err("%s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-
-       udc = ep->udc;
-       if (!udc) {
-               dev_err(ep->udc->dev, " *** %s, bad udc\n", __func__);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&udc->lock, flags);
-
-       ep_adrs = ep->epnum | ep->direct;
-       if (value == 0) {
-               _nbu2ss_set_endpoint_stall(udc, ep_adrs, value);
-               ep->stalled = false;
-       } else {
-               if (list_empty(&ep->queue))
-                       _nbu2ss_epn_set_stall(udc, ep);
-               else
-                       ep->stalled = true;
-       }
-
-       if (value == 0)
-               ep->wedged = 0;
-
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-static int nbu2ss_ep_set_wedge(struct usb_ep *_ep)
-{
-       return nbu2ss_ep_set_halt(_ep, 1);
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_ep_fifo_status(struct usb_ep *_ep)
-{
-       u32             data;
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-       struct fc_regs  __iomem *preg;
-
-       if (!_ep) {
-               pr_err("%s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-
-       udc = ep->udc;
-       if (!udc) {
-               dev_err(ep->udc->dev, "%s, bad udc\n", __func__);
-               return -EINVAL;
-       }
-
-       preg = udc->p_regs;
-
-       data = gpiod_get_value(vbus_gpio);
-       if (data == 0)
-               return -EINVAL;
-
-       spin_lock_irqsave(&udc->lock, flags);
-
-       if (ep->epnum == 0) {
-               data = _nbu2ss_readl(&preg->EP0_LENGTH) & EP0_LDATA;
-
-       } else {
-               data = _nbu2ss_readl(&preg->EP_REGS[ep->epnum - 1].EP_LEN_DCNT)
-                       & EPN_LDATA;
-       }
-
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static void  nbu2ss_ep_fifo_flush(struct usb_ep *_ep)
-{
-       u32                     data;
-       struct nbu2ss_ep        *ep;
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-
-       if (!_ep) {
-               pr_err("udc: %s, bad param\n", __func__);
-               return;
-       }
-
-       ep = container_of(_ep, struct nbu2ss_ep, ep);
-
-       udc = ep->udc;
-       if (!udc) {
-               dev_err(ep->udc->dev, "%s, bad udc\n", __func__);
-               return;
-       }
-
-       data = gpiod_get_value(vbus_gpio);
-       if (data == 0)
-               return;
-
-       spin_lock_irqsave(&udc->lock, flags);
-       _nbu2ss_fifo_flush(udc, ep);
-       spin_unlock_irqrestore(&udc->lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-static const struct usb_ep_ops nbu2ss_ep_ops = {
-       .enable         = nbu2ss_ep_enable,
-       .disable        = nbu2ss_ep_disable,
-
-       .alloc_request  = nbu2ss_ep_alloc_request,
-       .free_request   = nbu2ss_ep_free_request,
-
-       .queue          = nbu2ss_ep_queue,
-       .dequeue        = nbu2ss_ep_dequeue,
-
-       .set_halt       = nbu2ss_ep_set_halt,
-       .set_wedge      = nbu2ss_ep_set_wedge,
-
-       .fifo_status    = nbu2ss_ep_fifo_status,
-       .fifo_flush     = nbu2ss_ep_fifo_flush,
-};
-
-/*-------------------------------------------------------------------------*/
-/* usb_gadget_ops */
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_get_frame(struct usb_gadget *pgadget)
-{
-       u32                     data;
-       struct nbu2ss_udc       *udc;
-
-       if (!pgadget) {
-               pr_err("udc: %s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = container_of(pgadget, struct nbu2ss_udc, gadget);
-       data = gpiod_get_value(vbus_gpio);
-       if (data == 0)
-               return -EINVAL;
-
-       return _nbu2ss_readl(&udc->p_regs->USB_ADDRESS) & FRAME;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget)
-{
-       int     i;
-       u32     data;
-
-       struct nbu2ss_udc       *udc;
-
-       if (!pgadget) {
-               pr_err("%s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = container_of(pgadget, struct nbu2ss_udc, gadget);
-
-       data = gpiod_get_value(vbus_gpio);
-       if (data == 0) {
-               dev_warn(&pgadget->dev, "VBUS LEVEL = %d\n", data);
-               return -EINVAL;
-       }
-
-       _nbu2ss_bitset(&udc->p_regs->EPCTR, PLL_RESUME);
-
-       for (i = 0; i < EPC_PLL_LOCK_COUNT; i++) {
-               data = _nbu2ss_readl(&udc->p_regs->EPCTR);
-
-               if (data & PLL_LOCK)
-                       break;
-       }
-
-       _nbu2ss_bitclr(&udc->p_regs->EPCTR, PLL_RESUME);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
-                                     int is_selfpowered)
-{
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-
-       if (!pgadget) {
-               pr_err("%s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = container_of(pgadget, struct nbu2ss_udc, gadget);
-
-       spin_lock_irqsave(&udc->lock, flags);
-       pgadget->is_selfpowered = (is_selfpowered != 0);
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_vbus_session(struct usb_gadget *pgadget, int is_active)
-{
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_vbus_draw(struct usb_gadget *pgadget, unsigned int mA)
-{
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-
-       if (!pgadget) {
-               pr_err("%s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = container_of(pgadget, struct nbu2ss_udc, gadget);
-
-       spin_lock_irqsave(&udc->lock, flags);
-       udc->mA = mA;
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_pullup(struct usb_gadget *pgadget, int is_on)
-{
-       struct nbu2ss_udc       *udc;
-       unsigned long           flags;
-
-       if (!pgadget) {
-               pr_err("%s, bad param\n", __func__);
-               return -EINVAL;
-       }
-
-       udc = container_of(pgadget, struct nbu2ss_udc, gadget);
-
-       if (!udc->driver) {
-               pr_warn("%s, Not Regist Driver\n", __func__);
-               return -EINVAL;
-       }
-
-       if (udc->vbus_active == 0)
-               return -ESHUTDOWN;
-
-       spin_lock_irqsave(&udc->lock, flags);
-       _nbu2ss_pullup(udc, is_on);
-       spin_unlock_irqrestore(&udc->lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_gad_ioctl(struct usb_gadget *pgadget,
-                           unsigned int code, unsigned long param)
-{
-       return 0;
-}
-
-static const struct usb_gadget_ops nbu2ss_gadget_ops = {
-       .get_frame              = nbu2ss_gad_get_frame,
-       .wakeup                 = nbu2ss_gad_wakeup,
-       .set_selfpowered        = nbu2ss_gad_set_selfpowered,
-       .vbus_session           = nbu2ss_gad_vbus_session,
-       .vbus_draw              = nbu2ss_gad_vbus_draw,
-       .pullup                 = nbu2ss_gad_pullup,
-       .ioctl                  = nbu2ss_gad_ioctl,
-};
-
-static const struct {
-       const char *name;
-       const struct usb_ep_caps caps;
-} ep_info[NUM_ENDPOINTS] = {
-#define EP_INFO(_name, _caps) \
-       { \
-               .name = _name, \
-               .caps = _caps, \
-       }
-
-       EP_INFO("ep0",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep1-bulk",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep2-bulk",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep3in-int",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
-       EP_INFO("ep4-iso",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep5-iso",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep6-bulk",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep7-bulk",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("ep8in-int",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
-       EP_INFO("ep9-iso",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("epa-iso",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("epb-bulk",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("epc-bulk",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
-       EP_INFO("epdin-int",
-               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
-
-#undef EP_INFO
-};
-
-/*-------------------------------------------------------------------------*/
-static void nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
-{
-       int     i;
-
-       INIT_LIST_HEAD(&udc->gadget.ep_list);
-       udc->gadget.ep0 = &udc->ep[0].ep;
-
-       for (i = 0; i < NUM_ENDPOINTS; i++) {
-               struct nbu2ss_ep *ep = &udc->ep[i];
-
-               ep->udc = udc;
-               ep->desc = NULL;
-
-               ep->ep.driver_data = NULL;
-               ep->ep.name = ep_info[i].name;
-               ep->ep.caps = ep_info[i].caps;
-               ep->ep.ops = &nbu2ss_ep_ops;
-
-               usb_ep_set_maxpacket_limit(&ep->ep,
-                                          i == 0 ? EP0_PACKETSIZE
-                                          : EP_PACKETSIZE);
-
-               list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
-               INIT_LIST_HEAD(&ep->queue);
-       }
-
-       list_del_init(&udc->ep[0].ep.ep_list);
-}
-
-/*-------------------------------------------------------------------------*/
-/* platform_driver */
-static int nbu2ss_drv_contest_init(struct platform_device *pdev,
-                                  struct nbu2ss_udc *udc)
-{
-       spin_lock_init(&udc->lock);
-       udc->dev = &pdev->dev;
-
-       udc->gadget.is_selfpowered = 1;
-       udc->devstate = USB_STATE_NOTATTACHED;
-       udc->pdev = pdev;
-       udc->mA = 0;
-
-       udc->pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-
-       /* init Endpoint */
-       nbu2ss_drv_ep_init(udc);
-
-       /* init Gadget */
-       udc->gadget.ops = &nbu2ss_gadget_ops;
-       udc->gadget.ep0 = &udc->ep[0].ep;
-       udc->gadget.speed = USB_SPEED_UNKNOWN;
-       udc->gadget.name = driver_name;
-       /* udc->gadget.is_dualspeed = 1; */
-
-       device_initialize(&udc->gadget.dev);
-
-       dev_set_name(&udc->gadget.dev, "gadget");
-       udc->gadget.dev.parent = &pdev->dev;
-       udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
-       return 0;
-}
-
-/*
- *     probe - binds to the platform device
- */
-static int nbu2ss_drv_probe(struct platform_device *pdev)
-{
-       int status;
-       struct nbu2ss_udc *udc;
-       int irq;
-       void __iomem *mmio_base;
-
-       udc = &udc_controller;
-       memset(udc, 0, sizeof(struct nbu2ss_udc));
-
-       platform_set_drvdata(pdev, udc);
-
-       /* require I/O memory and IRQ to be provided as resources */
-       mmio_base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(mmio_base))
-               return PTR_ERR(mmio_base);
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-       status = devm_request_irq(&pdev->dev, irq, _nbu2ss_udc_irq,
-                                 0, driver_name, udc);
-
-       /* IO Memory */
-       udc->p_regs = (struct fc_regs __iomem *)mmio_base;
-
-       /* USB Function Controller Interrupt */
-       if (status != 0) {
-               dev_err(udc->dev, "request_irq(USB_UDC_IRQ_1) failed\n");
-               return status;
-       }
-
-       /* Driver Initialization */
-       status = nbu2ss_drv_contest_init(pdev, udc);
-       if (status < 0) {
-               /* Error */
-               return status;
-       }
-
-       /* VBUS Interrupt */
-       vbus_irq = gpiod_to_irq(vbus_gpio);
-       irq_set_irq_type(vbus_irq, IRQ_TYPE_EDGE_BOTH);
-       status = request_irq(vbus_irq,
-                            _nbu2ss_vbus_irq, IRQF_SHARED, driver_name, udc);
-
-       if (status != 0) {
-               dev_err(udc->dev, "request_irq(vbus_irq) failed\n");
-               return status;
-       }
-
-       return status;
-}
-
-/*-------------------------------------------------------------------------*/
-static void nbu2ss_drv_shutdown(struct platform_device *pdev)
-{
-       struct nbu2ss_udc       *udc;
-
-       udc = platform_get_drvdata(pdev);
-       if (!udc)
-               return;
-
-       _nbu2ss_disable_controller(udc);
-}
-
-/*-------------------------------------------------------------------------*/
-static void nbu2ss_drv_remove(struct platform_device *pdev)
-{
-       struct nbu2ss_udc       *udc;
-       struct nbu2ss_ep        *ep;
-       int     i;
-
-       udc = &udc_controller;
-
-       for (i = 0; i < NUM_ENDPOINTS; i++) {
-               ep = &udc->ep[i];
-               if (ep->virt_buf)
-                       dma_free_coherent(udc->dev, PAGE_SIZE, (void *)ep->virt_buf,
-                                         ep->phys_buf);
-       }
-
-       /* Interrupt Handler - Release */
-       free_irq(vbus_irq, udc);
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_drv_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct nbu2ss_udc       *udc;
-
-       udc = platform_get_drvdata(pdev);
-       if (!udc)
-               return 0;
-
-       if (udc->vbus_active) {
-               udc->vbus_active = 0;
-               udc->devstate = USB_STATE_NOTATTACHED;
-               udc->linux_suspended = 1;
-
-               if (udc->usb_suspended) {
-                       udc->usb_suspended = 0;
-                       _nbu2ss_reset_controller(udc);
-               }
-
-               _nbu2ss_quiesce(udc);
-       }
-       _nbu2ss_disable_controller(udc);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-static int nbu2ss_drv_resume(struct platform_device *pdev)
-{
-       u32     data;
-       struct nbu2ss_udc       *udc;
-
-       udc = platform_get_drvdata(pdev);
-       if (!udc)
-               return 0;
-
-       data = gpiod_get_value(vbus_gpio);
-       if (data) {
-               udc->vbus_active = 1;
-               udc->devstate = USB_STATE_POWERED;
-               _nbu2ss_enable_controller(udc);
-               _nbu2ss_pullup(udc, 1);
-       }
-
-       udc->linux_suspended = 0;
-
-       return 0;
-}
-
-static struct platform_driver udc_driver = {
-       .probe          = nbu2ss_drv_probe,
-       .shutdown       = nbu2ss_drv_shutdown,
-       .remove_new     = nbu2ss_drv_remove,
-       .suspend        = nbu2ss_drv_suspend,
-       .resume         = nbu2ss_drv_resume,
-       .driver         = {
-               .name   = driver_name,
-       },
-};
-
-module_platform_driver(udc_driver);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Renesas Electronics Corporation");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/emxx_udc/emxx_udc.h b/drivers/staging/emxx_udc/emxx_udc.h
deleted file mode 100644 (file)
index c9e37a1..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  EMXX FCD (Function Controller Driver) for USB.
- *
- *  Copyright (C) 2010 Renesas Electronics Corporation
- */
-
-#ifndef _LINUX_EMXX_H
-#define _LINUX_EMXX_H
-
-/*---------------------------------------------------------------------------*/
-
-/*----------------- Default define */
-#define        USE_DMA 1
-#define USE_SUSPEND_WAIT       1
-
-/*------------ Board dependence(Resource) */
-#define        VBUS_VALUE              GPIO_VBUS
-
-/* below hacked up for staging integration */
-#define GPIO_VBUS 0 /* GPIO_P153 on KZM9D */
-#define INT_VBUS 0 /* IRQ for GPIO_P153 */
-
-/*------------ Board dependence(Wait) */
-
-/* CHATTERING wait time ms */
-#define VBUS_CHATTERING_MDELAY         1
-/* DMA Abort wait time ms */
-#define DMA_DISABLE_TIME               10
-
-/*------------ Controller dependence */
-#define NUM_ENDPOINTS          14              /* Endpoint */
-#define REG_EP_NUM             15              /* Endpoint Register */
-#define DMA_MAX_COUNT          256             /* DMA Block */
-
-#define EPC_RST_DISABLE_TIME           1       /* 1 usec */
-#define EPC_DIRPD_DISABLE_TIME         1       /* 1 msec */
-#define EPC_PLL_LOCK_COUNT             1000    /* 1000 */
-#define IN_DATA_EMPTY_COUNT            1000    /* 1000 */
-
-#define CHATGER_TIME                   700     /* 700msec */
-#define USB_SUSPEND_TIME               2000    /* 2 sec */
-
-/* U2F FLAG */
-#define U2F_ENABLE             1
-#define U2F_DISABLE            0
-
-#define TEST_FORCE_ENABLE              (BIT(18) | BIT(16))
-
-#define INT_SEL                                BIT(10)
-#define CONSTFS                                BIT(9)
-#define SOF_RCV                                BIT(8)
-#define RSUM_IN                                BIT(7)
-#define SUSPEND                                BIT(6)
-#define CONF                           BIT(5)
-#define DEFAULT                                BIT(4)
-#define CONNECTB                       BIT(3)
-#define PUE2                           BIT(2)
-
-#define MAX_TEST_MODE_NUM              0x05
-#define TEST_MODE_SHIFT                        16
-
-/*------- (0x0004) USB Status Register */
-#define SPEED_MODE                     BIT(6)
-#define HIGH_SPEED                     BIT(6)
-
-#define CONF                           BIT(5)
-#define DEFAULT                                BIT(4)
-#define USB_RST                                BIT(3)
-#define SPND_OUT                       BIT(2)
-#define RSUM_OUT                       BIT(1)
-
-/*------- (0x0008) USB Address Register */
-#define USB_ADDR                       0x007F0000
-#define SOF_STATUS                     BIT(15)
-#define UFRAME                         (BIT(14) | BIT(13) | BIT(12))
-#define FRAME                          0x000007FF
-
-#define USB_ADRS_SHIFT                 16
-
-/*------- (0x000C) UTMI Characteristic 1 Register */
-#define SQUSET                         (BIT(7) | BIT(6) | BIT(5) | BIT(4))
-
-#define USB_SQUSET                     (BIT(6) | BIT(5) | BIT(4))
-
-/*------- (0x0010) TEST Control Register */
-#define FORCEHS                                BIT(2)
-#define CS_TESTMODEEN                  BIT(1)
-#define LOOPBACK                       BIT(0)
-
-/*------- (0x0018) Setup Data 0 Register */
-/*------- (0x001C) Setup Data 1 Register */
-
-/*------- (0x0020) USB Interrupt Status Register */
-#define EPN_INT                                0x00FFFF00
-#define EP15_INT                       BIT(23)
-#define EP14_INT                       BIT(22)
-#define EP13_INT                       BIT(21)
-#define EP12_INT                       BIT(20)
-#define EP11_INT                       BIT(19)
-#define EP10_INT                       BIT(18)
-#define EP9_INT                                BIT(17)
-#define EP8_INT                                BIT(16)
-#define EP7_INT                                BIT(15)
-#define EP6_INT                                BIT(14)
-#define EP5_INT                                BIT(13)
-#define EP4_INT                                BIT(12)
-#define EP3_INT                                BIT(11)
-#define EP2_INT                                BIT(10)
-#define EP1_INT                                BIT(9)
-#define EP0_INT                                BIT(8)
-#define SPEED_MODE_INT                 BIT(6)
-#define SOF_ERROR_INT                  BIT(5)
-#define SOF_INT                                BIT(4)
-#define USB_RST_INT                    BIT(3)
-#define SPND_INT                       BIT(2)
-#define RSUM_INT                       BIT(1)
-
-#define USB_INT_STA_RW                 0x7E
-
-/*------- (0x0024) USB Interrupt Enable Register */
-#define EP15_0_EN                      0x00FFFF00
-#define EP15_EN                                BIT(23)
-#define EP14_EN                                BIT(22)
-#define EP13_EN                                BIT(21)
-#define EP12_EN                                BIT(20)
-#define EP11_EN                                BIT(19)
-#define EP10_EN                                BIT(18)
-#define EP9_EN                         BIT(17)
-#define EP8_EN                         BIT(16)
-#define EP7_EN                         BIT(15)
-#define EP6_EN                         BIT(14)
-#define EP5_EN                         BIT(13)
-#define EP4_EN                         BIT(12)
-#define EP3_EN                         BIT(11)
-#define EP2_EN                         BIT(10)
-#define EP1_EN                         BIT(9)
-#define EP0_EN                         BIT(8)
-#define SPEED_MODE_EN                  BIT(6)
-#define SOF_ERROR_EN                   BIT(5)
-#define SOF_EN                         BIT(4)
-#define USB_RST_EN                     BIT(3)
-#define SPND_EN                                BIT(2)
-#define RSUM_EN                                BIT(1)
-
-#define USB_INT_EN_BIT \
-       (EP0_EN | SPEED_MODE_EN | USB_RST_EN | SPND_EN | RSUM_EN)
-
-/*------- (0x0028) EP0 Control Register */
-#define EP0_STGSEL                     BIT(18)
-#define EP0_OVERSEL                    BIT(17)
-#define EP0_AUTO                       BIT(16)
-#define EP0_PIDCLR                     BIT(9)
-#define EP0_BCLR                       BIT(8)
-#define EP0_DEND                       BIT(7)
-#define EP0_DW                         (BIT(6) | BIT(5))
-#define EP0_DW4                                0
-#define EP0_DW3                                (BIT(6) | BIT(5))
-#define EP0_DW2                                BIT(6)
-#define EP0_DW1                                BIT(5)
-
-#define EP0_INAK_EN                    BIT(4)
-#define EP0_PERR_NAK_CLR               BIT(3)
-#define EP0_STL                                BIT(2)
-#define EP0_INAK                       BIT(1)
-#define EP0_ONAK                       BIT(0)
-
-/*------- (0x002C) EP0 Status Register */
-#define EP0_PID                                BIT(18)
-#define EP0_PERR_NAK                   BIT(17)
-#define EP0_PERR_NAK_INT               BIT(16)
-#define EP0_OUT_NAK_INT                        BIT(15)
-#define EP0_OUT_NULL                   BIT(14)
-#define EP0_OUT_FULL                   BIT(13)
-#define EP0_OUT_EMPTY                  BIT(12)
-#define EP0_IN_NAK_INT                 BIT(11)
-#define EP0_IN_DATA                    BIT(10)
-#define EP0_IN_FULL                    BIT(9)
-#define EP0_IN_EMPTY                   BIT(8)
-#define EP0_OUT_NULL_INT               BIT(7)
-#define EP0_OUT_OR_INT                 BIT(6)
-#define EP0_OUT_INT                    BIT(5)
-#define EP0_IN_INT                     BIT(4)
-#define EP0_STALL_INT                  BIT(3)
-#define STG_END_INT                    BIT(2)
-#define STG_START_INT                  BIT(1)
-#define SETUP_INT                      BIT(0)
-
-#define EP0_STATUS_RW_BIT      (BIT(16) | BIT(15) | BIT(11) | 0xFF)
-
-/*------- (0x0030) EP0 Interrupt Enable Register */
-#define EP0_PERR_NAK_EN                        BIT(16)
-#define EP0_OUT_NAK_EN                 BIT(15)
-
-#define EP0_IN_NAK_EN                  BIT(11)
-
-#define EP0_OUT_NULL_EN                        BIT(7)
-#define EP0_OUT_OR_EN                  BIT(6)
-#define EP0_OUT_EN                     BIT(5)
-#define EP0_IN_EN                      BIT(4)
-#define EP0_STALL_EN                   BIT(3)
-#define STG_END_EN                     BIT(2)
-#define STG_START_EN                   BIT(1)
-#define SETUP_EN                       BIT(0)
-
-#define EP0_INT_EN_BIT \
-       (EP0_OUT_OR_EN | EP0_OUT_EN | EP0_IN_EN | STG_END_EN | SETUP_EN)
-
-/*------- (0x0034) EP0 Length Register */
-#define EP0_LDATA                      0x0000007F
-
-/*------- (0x0038) EP0 Read Register */
-/*------- (0x003C) EP0 Write Register */
-
-/*------- (0x0040:) EPN Control Register */
-#define EPN_EN                         BIT(31)
-#define EPN_BUF_TYPE                   BIT(30)
-#define EPN_BUF_SINGLE                 BIT(30)
-
-#define EPN_DIR0                       BIT(26)
-#define EPN_MODE                       (BIT(25) | BIT(24))
-#define EPN_BULK                       0
-#define EPN_INTERRUPT                  BIT(24)
-#define EPN_ISO                                BIT(25)
-
-#define EPN_OVERSEL                    BIT(17)
-#define EPN_AUTO                       BIT(16)
-
-#define EPN_IPIDCLR                    BIT(11)
-#define EPN_OPIDCLR                    BIT(10)
-#define EPN_BCLR                       BIT(9)
-#define EPN_CBCLR                      BIT(8)
-#define EPN_DEND                       BIT(7)
-#define EPN_DW                         (BIT(6) | BIT(5))
-#define EPN_DW4                                0
-#define EPN_DW3                                (BIT(6) | BIT(5))
-#define EPN_DW2                                BIT(6)
-#define EPN_DW1                                BIT(5)
-
-#define EPN_OSTL_EN                    BIT(4)
-#define EPN_ISTL                       BIT(3)
-#define EPN_OSTL                       BIT(2)
-
-#define EPN_ONAK                       BIT(0)
-
-/*------- (0x0044:) EPN Status Register        */
-#define EPN_ISO_PIDERR                 BIT(29)         /* R */
-#define EPN_OPID                       BIT(28)         /* R */
-#define EPN_OUT_NOTKN                  BIT(27)         /* R */
-#define EPN_ISO_OR                     BIT(26)         /* R */
-
-#define EPN_ISO_CRC                    BIT(24)         /* R */
-#define EPN_OUT_END_INT                        BIT(23)         /* RW */
-#define EPN_OUT_OR_INT                 BIT(22)         /* RW */
-#define EPN_OUT_NAK_ERR_INT            BIT(21)         /* RW */
-#define EPN_OUT_STALL_INT              BIT(20)         /* RW */
-#define EPN_OUT_INT                    BIT(19)         /* RW */
-#define EPN_OUT_NULL_INT               BIT(18)         /* RW */
-#define EPN_OUT_FULL                   BIT(17)         /* R */
-#define EPN_OUT_EMPTY                  BIT(16)         /* R */
-
-#define EPN_IPID                       BIT(10)         /* R */
-#define EPN_IN_NOTKN                   BIT(9)          /* R */
-#define EPN_ISO_UR                     BIT(8)          /* R */
-#define EPN_IN_END_INT                 BIT(7)          /* RW */
-
-#define EPN_IN_NAK_ERR_INT             BIT(5)          /* RW */
-#define EPN_IN_STALL_INT               BIT(4)          /* RW */
-#define EPN_IN_INT                     BIT(3)          /* RW */
-#define EPN_IN_DATA                    BIT(2)          /* R */
-#define EPN_IN_FULL                    BIT(1)          /* R */
-#define EPN_IN_EMPTY                   BIT(0)          /* R */
-
-#define EPN_INT_EN     \
-       (EPN_OUT_END_INT | EPN_OUT_INT | EPN_IN_END_INT | EPN_IN_INT)
-
-/*------- (0x0048:) EPN Interrupt Enable Register */
-#define EPN_OUT_END_EN                 BIT(23)         /* RW */
-#define EPN_OUT_OR_EN                  BIT(22)         /* RW */
-#define EPN_OUT_NAK_ERR_EN             BIT(21)         /* RW */
-#define EPN_OUT_STALL_EN               BIT(20)         /* RW */
-#define EPN_OUT_EN                     BIT(19)         /* RW */
-#define EPN_OUT_NULL_EN                        BIT(18)         /* RW */
-
-#define EPN_IN_END_EN                  BIT(7)          /* RW */
-
-#define EPN_IN_NAK_ERR_EN              BIT(5)          /* RW */
-#define EPN_IN_STALL_EN                        BIT(4)          /* RW */
-#define EPN_IN_EN                      BIT(3)          /* RW */
-
-/*------- (0x004C:) EPN Interrupt Enable Register */
-#define EPN_STOP_MODE                  BIT(11)
-#define EPN_DEND_SET                   BIT(10)
-#define EPN_BURST_SET                  BIT(9)
-#define EPN_STOP_SET                   BIT(8)
-
-#define EPN_DMA_EN                     BIT(4)
-
-#define EPN_DMAMODE0                   BIT(0)
-
-/*------- (0x0050:) EPN MaxPacket & BaseAddress Register */
-#define EPN_BASEAD                     0x1FFF0000
-#define EPN_MPKT                       0x000007FF
-
-/*------- (0x0054:) EPN Length & DMA Count Register */
-#define EPN_DMACNT                     0x01FF0000
-#define EPN_LDATA                      0x000007FF
-
-/*------- (0x0058:) EPN Read Register */
-/*------- (0x005C:) EPN Write Register */
-
-/*------- (0x1000) AHBSCTR Register */
-#define WAIT_MODE                      BIT(0)
-
-/*------- (0x1004) AHBMCTR Register */
-#define ARBITER_CTR                    BIT(31)         /* RW */
-#define MCYCLE_RST                     BIT(12)         /* RW */
-
-#define ENDIAN_CTR                     (BIT(9) | BIT(8))       /* RW */
-#define ENDIAN_BYTE_SWAP               BIT(9)
-#define ENDIAN_HALF_WORD_SWAP          ENDIAN_CTR
-
-#define HBUSREQ_MODE                   BIT(5)          /* RW */
-#define HTRANS_MODE                    BIT(4)          /* RW */
-
-#define WBURST_TYPE                    BIT(2)          /* RW */
-#define BURST_TYPE                     (BIT(1) | BIT(0))       /* RW */
-#define BURST_MAX_16                   0
-#define BURST_MAX_8                    BIT(0)
-#define BURST_MAX_4                    BIT(1)
-#define BURST_SINGLE                   BURST_TYPE
-
-/*------- (0x1008) AHBBINT Register */
-#define DMA_ENDINT                     0xFFFE0000      /* RW */
-
-#define AHB_VBUS_INT                   BIT(13)         /* RW */
-
-#define MBUS_ERRINT                    BIT(6)          /* RW */
-
-#define SBUS_ERRINT0                   BIT(4)          /* RW */
-#define ERR_MASTER                     0x0000000F      /* R */
-
-/*------- (0x100C) AHBBINTEN Register */
-#define DMA_ENDINTEN                   0xFFFE0000      /* RW */
-
-#define VBUS_INTEN                     BIT(13)         /* RW */
-
-#define MBUS_ERRINTEN                  BIT(6)          /* RW */
-
-#define SBUS_ERRINT0EN                 BIT(4)          /* RW */
-
-/*------- (0x1010) EPCTR Register */
-#define DIRPD                          BIT(12)         /* RW */
-
-#define VBUS_LEVEL                     BIT(8)          /* R */
-
-#define PLL_RESUME                     BIT(5)          /* RW */
-#define PLL_LOCK                       BIT(4)          /* R */
-
-#define EPC_RST                                BIT(0)          /* RW */
-
-/*------- (0x1014) USBF_EPTEST Register */
-#define LINESTATE                      (BIT(9) | BIT(8))       /* R */
-#define DM_LEVEL                       BIT(9)          /* R */
-#define DP_LEVEL                       BIT(8)          /* R */
-
-#define PHY_TST                                BIT(1)          /* RW */
-#define PHY_TSTCLK                     BIT(0)          /* RW */
-
-/*------- (0x1020) USBSSVER Register */
-#define AHBB_VER                       0x00FF0000      /* R */
-#define EPC_VER                                0x0000FF00      /* R */
-#define SS_VER                         0x000000FF      /* R */
-
-/*------- (0x1024) USBSSCONF Register */
-#define EP_AVAILABLE                   0xFFFF0000      /* R */
-#define DMA_AVAILABLE                  0x0000FFFF      /* R */
-
-/*------- (0x1110:) EPNDCR1 Register */
-#define DCR1_EPN_DMACNT                        0x00FF0000      /* RW */
-
-#define DCR1_EPN_DIR0                  BIT(1)          /* RW */
-#define DCR1_EPN_REQEN                 BIT(0)          /* RW */
-
-/*------- (0x1114:) EPNDCR2 Register */
-#define DCR2_EPN_LMPKT                 0x07FF0000      /* RW */
-
-#define DCR2_EPN_MPKT                  0x000007FF      /* RW */
-
-/*------- (0x1118:) EPNTADR Register */
-#define EPN_TADR                       0xFFFFFFFF      /* RW */
-
-/*===========================================================================*/
-/* Struct */
-/*------- ep_regs */
-struct ep_regs {
-       u32 EP_CONTROL;                 /* EP Control */
-       u32 EP_STATUS;                  /* EP Status */
-       u32 EP_INT_ENA;                 /* EP Interrupt Enable */
-       u32 EP_DMA_CTRL;                /* EP DMA Control */
-       u32 EP_PCKT_ADRS;               /* EP Maxpacket & BaseAddress */
-       u32 EP_LEN_DCNT;                /* EP Length & DMA count */
-       u32 EP_READ;                    /* EP Read */
-       u32 EP_WRITE;                   /* EP Write */
-};
-
-/*------- ep_dcr */
-struct ep_dcr {
-       u32 EP_DCR1;                    /* EP_DCR1 */
-       u32 EP_DCR2;                    /* EP_DCR2 */
-       u32 EP_TADR;                    /* EP_TADR */
-       u32 Reserved;                   /* Reserved */
-};
-
-/*------- Function Registers */
-struct fc_regs {
-       u32 USB_CONTROL;                /* (0x0000) USB Control */
-       u32 USB_STATUS;                 /* (0x0004) USB Status */
-       u32 USB_ADDRESS;                /* (0x0008) USB Address */
-       u32 UTMI_CHARACTER_1;           /* (0x000C) UTMI Setting */
-       u32 TEST_CONTROL;               /* (0x0010) TEST Control */
-       u32 reserved_14;                /* (0x0014) Reserved */
-       u32 SETUP_DATA0;                /* (0x0018) Setup Data0 */
-       u32 SETUP_DATA1;                /* (0x001C) Setup Data1 */
-       u32 USB_INT_STA;                /* (0x0020) USB Interrupt Status */
-       u32 USB_INT_ENA;                /* (0x0024) USB Interrupt Enable */
-       u32 EP0_CONTROL;                /* (0x0028) EP0 Control */
-       u32 EP0_STATUS;                 /* (0x002C) EP0 Status */
-       u32 EP0_INT_ENA;                /* (0x0030) EP0 Interrupt Enable */
-       u32 EP0_LENGTH;                 /* (0x0034) EP0 Length */
-       u32 EP0_READ;                   /* (0x0038) EP0 Read */
-       u32 EP0_WRITE;                  /* (0x003C) EP0 Write */
-
-       struct ep_regs EP_REGS[REG_EP_NUM];     /* Endpoint Register */
-
-       u8 reserved_220[0x1000 - 0x220];        /* (0x0220:0x0FFF) Reserved */
-
-       u32 AHBSCTR;                    /* (0x1000) AHBSCTR */
-       u32 AHBMCTR;                    /* (0x1004) AHBMCTR */
-       u32 AHBBINT;                    /* (0x1008) AHBBINT */
-       u32 AHBBINTEN;                  /* (0x100C) AHBBINTEN */
-       u32 EPCTR;                      /* (0x1010) EPCTR */
-       u32 USBF_EPTEST;                /* (0x1014) USBF_EPTEST */
-
-       u8 reserved_1018[0x20 - 0x18];  /* (0x1018:0x101F) Reserved */
-
-       u32 USBSSVER;                   /* (0x1020) USBSSVER */
-       u32 USBSSCONF;                  /* (0x1024) USBSSCONF */
-
-       u8 reserved_1028[0x110 - 0x28]; /* (0x1028:0x110F) Reserved */
-
-       struct ep_dcr EP_DCR[REG_EP_NUM];       /* */
-
-       u8 reserved_1200[0x1000 - 0x200];       /* Reserved */
-} __aligned(32);
-
-#define EP0_PACKETSIZE                 64
-#define EP_PACKETSIZE                  1024
-
-/* EPN RAM SIZE */
-#define D_RAM_SIZE_CTRL                        64
-
-/* EPN Bulk Endpoint Max Packet Size */
-#define D_FS_RAM_SIZE_BULK             64
-#define D_HS_RAM_SIZE_BULK             512
-
-struct nbu2ss_udc;
-
-enum ep0_state {
-       EP0_IDLE,
-       EP0_IN_DATA_PHASE,
-       EP0_OUT_DATA_PHASE,
-       EP0_IN_STATUS_PHASE,
-       EP0_OUT_STATUS_PAHSE,
-       EP0_END_XFER,
-       EP0_SUSPEND,
-       EP0_STALL,
-};
-
-struct nbu2ss_req {
-       struct usb_request              req;
-       struct list_head                queue;
-
-       u32                     div_len;
-       bool            dma_flag;
-       bool            zero;
-
-       bool            unaligned;
-
-       unsigned                        mapped:1;
-};
-
-struct nbu2ss_ep {
-       struct usb_ep                   ep;
-       struct list_head                queue;
-
-       struct nbu2ss_udc               *udc;
-
-       const struct usb_endpoint_descriptor *desc;
-
-       u8              epnum;
-       u8              direct;
-       u8              ep_type;
-
-       unsigned                wedged:1;
-       unsigned                halted:1;
-       unsigned                stalled:1;
-
-       u8              *virt_buf;
-       dma_addr_t      phys_buf;
-};
-
-struct nbu2ss_udc {
-       struct usb_gadget gadget;
-       struct usb_gadget_driver *driver;
-       struct platform_device *pdev;
-       struct device *dev;
-       spinlock_t lock; /* Protects nbu2ss_udc structure fields */
-       struct completion               *pdone;
-
-       enum ep0_state                  ep0state;
-       enum usb_device_state   devstate;
-       struct usb_ctrlrequest  ctrl;
-       struct nbu2ss_req               ep0_req;
-       u8              ep0_buf[EP0_PACKETSIZE];
-
-       struct nbu2ss_ep        ep[NUM_ENDPOINTS];
-
-       unsigned                softconnect:1;
-       unsigned                vbus_active:1;
-       unsigned                linux_suspended:1;
-       unsigned                linux_resume:1;
-       unsigned                usb_suspended:1;
-       unsigned                remote_wakeup:1;
-       unsigned                udc_enabled:1;
-
-       unsigned int            mA;
-
-       u32             curr_config;    /* Current Configuration Number */
-
-       struct fc_regs __iomem *p_regs;
-};
-
-/* USB register access structure */
-union usb_reg_access {
-       struct {
-               unsigned char   DATA[4];
-       } byte;
-       unsigned int            dw;
-};
-
-/*-------------------------------------------------------------------------*/
-
-#endif  /* _LINUX_EMXX_H */
index 68add4d598ae8655b5a6fa3e26d3d8342d408419..38845f23023fe705a168023b0b1ec122f9b6465f 100644 (file)
@@ -327,7 +327,6 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagereflis
        unsigned int dirty_lines_start, dirty_lines_end;
        struct fb_deferred_io_pageref *pageref;
        unsigned int y_low = 0, y_high = 0;
-       int count = 0;
 
        spin_lock(&par->dirty_lock);
        dirty_lines_start = par->dirty_lines_start;
@@ -339,7 +338,6 @@ static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagereflis
 
        /* Mark display lines as dirty */
        list_for_each_entry(pageref, pagereflist, list) {
-               count++;
                y_low = pageref->offset / info->fix.line_length;
                y_high = (pageref->offset + PAGE_SIZE - 1) / info->fix.line_length;
                dev_dbg(info->device,
index 34d18b09beddcb951bf86047b6e6d9a2e9238f90..fcd3e3722ae017f7714e7bac786e48b48eb2b33c 100644 (file)
@@ -285,7 +285,7 @@ static int controller_probe(struct platform_device *pdev)
                }
        }
 
-       id = ida_simple_get(&controller_index_ida, 0, 0, GFP_KERNEL);
+       id = ida_alloc(&controller_index_ida, GFP_KERNEL);
        if (id < 0) {
                err = id;
                goto out_reset;
@@ -318,7 +318,7 @@ static int controller_probe(struct platform_device *pdev)
 out_dev:
        put_device(cd->class_dev);
 out_ida:
-       ida_simple_remove(&controller_index_ida, id);
+       ida_free(&controller_index_ida, id);
 out_reset:
        gpiod_set_value_cansleep(cd->reset_gpiod, 1);
        return err;
@@ -330,7 +330,7 @@ static void controller_remove(struct platform_device *pdev)
        int id = cd->class_dev->id;
 
        device_unregister(cd->class_dev);
-       ida_simple_remove(&controller_index_ida, id);
+       ida_free(&controller_index_ida, id);
        gpiod_set_value_cansleep(cd->reset_gpiod, 1);
 }
 
index cd86b9c9e3458d9daf23032d17be7aa87108ff68..410e6f8073c0bbdba4bd91a81b949b07dae1072b 100644 (file)
@@ -1195,7 +1195,7 @@ static void anybus_bus_remove(struct device *dev)
                adrv->remove(to_anybuss_client(dev));
 }
 
-static struct bus_type anybus_bus = {
+static const struct bus_type anybus_bus = {
        .name           = "anybuss",
        .match          = anybus_bus_match,
        .probe          = anybus_bus_probe,
index bf1812d8924fa5c5a5b885373da569fd9bc92412..0053ebd91442de3ffa1e0fbabcb3f7152f27053e 100644 (file)
@@ -152,7 +152,7 @@ static const struct attribute_group fieldbus_group = {
 };
 __ATTRIBUTE_GROUPS(fieldbus);
 
-static struct class fieldbus_class = {
+static const struct class fieldbus_class = {
        .name =         "fieldbus_dev",
        .dev_groups =   fieldbus_groups,
 };
@@ -247,7 +247,7 @@ static void __fieldbus_dev_unregister(struct fieldbus_dev *fb)
                return;
        device_destroy(&fieldbus_class, fb->cdev.dev);
        cdev_del(&fb->cdev);
-       ida_simple_remove(&fieldbus_ida, fb->id);
+       ida_free(&fieldbus_ida, fb->id);
 }
 
 void fieldbus_dev_unregister(struct fieldbus_dev *fb)
@@ -267,7 +267,7 @@ static int __fieldbus_dev_register(struct fieldbus_dev *fb)
                return -EINVAL;
        if (!fb->read_area || !fb->write_area || !fb->fieldbus_id_get)
                return -EINVAL;
-       fb->id = ida_simple_get(&fieldbus_ida, 0, MAX_FIELDBUSES, GFP_KERNEL);
+       fb->id = ida_alloc_max(&fieldbus_ida, MAX_FIELDBUSES - 1, GFP_KERNEL);
        if (fb->id < 0)
                return fb->id;
        devno = MKDEV(MAJOR(fieldbus_devt), fb->id);
@@ -290,7 +290,7 @@ static int __fieldbus_dev_register(struct fieldbus_dev *fb)
 err_dev_create:
        cdev_del(&fb->cdev);
 err_cdev:
-       ida_simple_remove(&fieldbus_ida, fb->id);
+       ida_free(&fieldbus_ida, fb->id);
        return err;
 }
 
index 5703a9ddb6d0d88a56bf84d8fbaad874465500d2..eb754b231429be1aed1ba06052a93e0b4af9f632 100644 (file)
@@ -43,7 +43,7 @@ static struct {
        struct sock *sock;
 } lte_event;
 
-static struct device_type wwan_type = {
+static const struct device_type wwan_type = {
        .name   = "wwan",
 };
 
index efec0f815efd1f30a1d7b753e7017070a72cec18..ab707d310129d0e1a9e8498b1188c480919bb3a6 100644 (file)
@@ -65,7 +65,6 @@
 struct audio_apbridgea_hdr {
        __u8    type;
        __le16  i2s_port;
-       __u8    data[];
 } __packed;
 
 struct audio_apbridgea_set_config_request {
index 9a3f7c034ab49e7f141408f35f225798dc395f7c..fa43d35bbcece49967f4072bd5ffab4f4d5a8bf5 100644 (file)
@@ -44,14 +44,14 @@ int gb_audio_manager_add(struct gb_audio_manager_module_descriptor *desc)
        int id;
        int err;
 
-       id = ida_simple_get(&module_id, 0, 0, GFP_KERNEL);
+       id = ida_alloc(&module_id, GFP_KERNEL);
        if (id < 0)
                return id;
 
        err = gb_audio_manager_module_create(&module, manager_kset,
                                             id, desc);
        if (err) {
-               ida_simple_remove(&module_id, id);
+               ida_free(&module_id, id);
                return err;
        }
 
@@ -78,7 +78,7 @@ int gb_audio_manager_remove(int id)
        list_del(&module->list);
        kobject_put(&module->kobj);
        up_write(&modules_rwsem);
-       ida_simple_remove(&module_id, id);
+       ida_free(&module_id, id);
        return 0;
 }
 EXPORT_SYMBOL_GPL(gb_audio_manager_remove);
@@ -92,7 +92,7 @@ void gb_audio_manager_remove_all(void)
 
        list_for_each_entry_safe(module, next, &modules_list, list) {
                list_del(&module->list);
-               ida_simple_remove(&module_id, module->id);
+               ida_free(&module_id, module->id);
                kobject_put(&module->kobj);
        }
 
index 08e6a807c1327dd1c500bc5b9f2e026f0160bf2c..5dc4721105d445ba120a758345e07d2e3c58f42f 100644 (file)
@@ -761,7 +761,6 @@ static int gbcodec_enum_dapm_ctl_put(struct snd_kcontrol *kcontrol,
 {
        int ret, wi, ctl_id;
        unsigned int val, mux, change;
-       unsigned int mask;
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct gb_audio_ctl_elem_value gbvalue;
@@ -802,7 +801,6 @@ static int gbcodec_enum_dapm_ctl_put(struct snd_kcontrol *kcontrol,
 
        mux = ucontrol->value.enumerated.item[0];
        val = mux << e->shift_l;
-       mask = e->mask << e->shift_l;
 
        if (le32_to_cpu(gbvalue.value.enumerated_item[0]) !=
            ucontrol->value.enumerated.item[0]) {
@@ -815,7 +813,6 @@ static int gbcodec_enum_dapm_ctl_put(struct snd_kcontrol *kcontrol,
                if (ucontrol->value.enumerated.item[1] > e->items - 1)
                        return -EINVAL;
                val |= ucontrol->value.enumerated.item[1] << e->shift_r;
-               mask |= e->mask << e->shift_r;
                if (le32_to_cpu(gbvalue.value.enumerated_item[1]) !=
                    ucontrol->value.enumerated.item[1]) {
                        change = 1;
index b67315641d18ea68898f3346b2c529f62f8ce0e3..d53e58f92e8176eb005aab7f0ada6fa2831261fb 100644 (file)
@@ -324,7 +324,7 @@ int gb_cap_connection_init(struct gb_connection *connection)
        if (ret)
                goto err_list_del;
 
-       minor = ida_simple_get(&cap_minors_map, 0, NUM_MINORS, GFP_KERNEL);
+       minor = ida_alloc_max(&cap_minors_map, NUM_MINORS - 1, GFP_KERNEL);
        if (minor < 0) {
                ret = minor;
                goto err_connection_disable;
@@ -351,7 +351,7 @@ int gb_cap_connection_init(struct gb_connection *connection)
 err_del_cdev:
        cdev_del(&cap->cdev);
 err_remove_ida:
-       ida_simple_remove(&cap_minors_map, minor);
+       ida_free(&cap_minors_map, minor);
 err_connection_disable:
        gb_connection_disable(connection);
 err_list_del:
@@ -375,7 +375,7 @@ void gb_cap_connection_exit(struct gb_connection *connection)
 
        device_destroy(&cap_class, cap->dev_num);
        cdev_del(&cap->cdev);
-       ida_simple_remove(&cap_minors_map, MINOR(cap->dev_num));
+       ida_free(&cap_minors_map, MINOR(cap->dev_num));
 
        /*
         * Disallow any new ioctl operations on the char device and wait for
index 79581457c4afbc151b86df74aef62466689e7ba2..c0d338db6b525a95ca4e3d6f1b733d67486c6c51 100644 (file)
@@ -243,10 +243,10 @@ static int gb_bootrom_get_firmware(struct gb_operation *op)
        struct gb_bootrom *bootrom = gb_connection_get_data(op->connection);
        const struct firmware *fw;
        struct gb_bootrom_get_firmware_request *firmware_request;
-       struct gb_bootrom_get_firmware_response *firmware_response;
        struct device *dev = &op->connection->bundle->dev;
        unsigned int offset, size;
        enum next_request_type next_request;
+       u8 *firmware_response;
        int ret = 0;
 
        /* Disable timeouts */
@@ -280,15 +280,15 @@ static int gb_bootrom_get_firmware(struct gb_operation *op)
                goto unlock;
        }
 
-       if (!gb_operation_response_alloc(op, sizeof(*firmware_response) + size,
-                                        GFP_KERNEL)) {
+       /* gb_bootrom_get_firmware_response contains only a byte array */
+       if (!gb_operation_response_alloc(op, size, GFP_KERNEL)) {
                dev_err(dev, "%s: error allocating response\n", __func__);
                ret = -ENOMEM;
                goto unlock;
        }
 
        firmware_response = op->response->payload;
-       memcpy(firmware_response->data, fw->data + offset, size);
+       memcpy(firmware_response, fw->data + offset, size);
 
        dev_dbg(dev, "responding with firmware (offs = %u, size = %u)\n",
                offset, size);
index 543692c567f926a89fb88e958305974c3911469f..9a09bd3af79ba0dcf7efa683f4e86246bcd473a5 100644 (file)
@@ -63,8 +63,7 @@ static void fw_req_release(struct kref *kref)
         * just hope that it never happens.
         */
        if (!fw_req->timedout)
-               ida_simple_remove(&fw_req->fw_download->id_map,
-                                 fw_req->firmware_id);
+               ida_free(&fw_req->fw_download->id_map, fw_req->firmware_id);
 
        kfree(fw_req);
 }
@@ -171,7 +170,7 @@ static struct fw_request *find_firmware(struct fw_download *fw_download,
                return ERR_PTR(-ENOMEM);
 
        /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
-       ret = ida_simple_get(&fw_download->id_map, 1, 256, GFP_KERNEL);
+       ret = ida_alloc_range(&fw_download->id_map, 1, 255, GFP_KERNEL);
        if (ret < 0) {
                dev_err(fw_download->parent,
                        "failed to allocate firmware id (%d)\n", ret);
@@ -212,7 +211,7 @@ static struct fw_request *find_firmware(struct fw_download *fw_download,
        return fw_req;
 
 err_free_id:
-       ida_simple_remove(&fw_download->id_map, fw_req->firmware_id);
+       ida_free(&fw_download->id_map, fw_req->firmware_id);
 err_free_req:
        kfree(fw_req);
 
@@ -271,11 +270,11 @@ static int fw_download_fetch_firmware(struct gb_operation *op)
        struct gb_connection *connection = op->connection;
        struct fw_download *fw_download = gb_connection_get_data(connection);
        struct gb_fw_download_fetch_firmware_request *request;
-       struct gb_fw_download_fetch_firmware_response *response;
        struct fw_request *fw_req;
        const struct firmware *fw;
        unsigned int offset, size;
        u8 firmware_id;
+       u8 *response;
        int ret = 0;
 
        if (op->request->payload_size != sizeof(*request)) {
@@ -325,8 +324,8 @@ static int fw_download_fetch_firmware(struct gb_operation *op)
                goto put_fw;
        }
 
-       if (!gb_operation_response_alloc(op, sizeof(*response) + size,
-                                        GFP_KERNEL)) {
+       /* gb_fw_download_fetch_firmware_response contains only a byte array */
+       if (!gb_operation_response_alloc(op, size, GFP_KERNEL)) {
                dev_err(fw_download->parent,
                        "error allocating fetch firmware response\n");
                ret = -ENOMEM;
@@ -334,7 +333,7 @@ static int fw_download_fetch_firmware(struct gb_operation *op)
        }
 
        response = op->response->payload;
-       memcpy(response->data, fw->data + offset, size);
+       memcpy(response, fw->data + offset, size);
 
        dev_dbg(fw_download->parent,
                "responding with firmware (offs = %u, size = %u)\n", offset,
index 93137a3c4907c75f25d47180ddc341e3890364f7..3054f084d777b5507711a8a6f29af2c5c51e7cbc 100644 (file)
@@ -165,7 +165,7 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
        }
 
        /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
-       ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
+       ret = ida_alloc_range(&fw_mgmt->id_map, 1, 255, GFP_KERNEL);
        if (ret < 0) {
                dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
                        ret);
@@ -180,8 +180,7 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt,
                                GB_FW_MGMT_TYPE_LOAD_AND_VALIDATE_FW, &request,
                                sizeof(request), NULL, 0);
        if (ret) {
-               ida_simple_remove(&fw_mgmt->id_map,
-                                 fw_mgmt->intf_fw_request_id);
+               ida_free(&fw_mgmt->id_map, fw_mgmt->intf_fw_request_id);
                fw_mgmt->intf_fw_request_id = 0;
                dev_err(fw_mgmt->parent,
                        "load and validate firmware request failed (%d)\n",
@@ -220,7 +219,7 @@ static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op)
                return -ENODEV;
        }
 
-       ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->intf_fw_request_id);
+       ida_free(&fw_mgmt->id_map, fw_mgmt->intf_fw_request_id);
        fw_mgmt->intf_fw_request_id = 0;
        fw_mgmt->intf_fw_status = request->status;
        fw_mgmt->intf_fw_major = le16_to_cpu(request->major);
@@ -316,7 +315,7 @@ static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt,
        }
 
        /* Allocate ids from 1 to 255 (u8-max), 0 is an invalid id */
-       ret = ida_simple_get(&fw_mgmt->id_map, 1, 256, GFP_KERNEL);
+       ret = ida_alloc_range(&fw_mgmt->id_map, 1, 255, GFP_KERNEL);
        if (ret < 0) {
                dev_err(fw_mgmt->parent, "failed to allocate request id (%d)\n",
                        ret);
@@ -330,8 +329,7 @@ static int fw_mgmt_backend_fw_update_operation(struct fw_mgmt *fw_mgmt,
                                GB_FW_MGMT_TYPE_BACKEND_FW_UPDATE, &request,
                                sizeof(request), NULL, 0);
        if (ret) {
-               ida_simple_remove(&fw_mgmt->id_map,
-                                 fw_mgmt->backend_fw_request_id);
+               ida_free(&fw_mgmt->id_map, fw_mgmt->backend_fw_request_id);
                fw_mgmt->backend_fw_request_id = 0;
                dev_err(fw_mgmt->parent,
                        "backend %s firmware update request failed (%d)\n", tag,
@@ -369,7 +367,7 @@ static int fw_mgmt_backend_fw_updated_operation(struct gb_operation *op)
                return -ENODEV;
        }
 
-       ida_simple_remove(&fw_mgmt->id_map, fw_mgmt->backend_fw_request_id);
+       ida_free(&fw_mgmt->id_map, fw_mgmt->backend_fw_request_id);
        fw_mgmt->backend_fw_request_id = 0;
        fw_mgmt->backend_fw_status = request->status;
 
@@ -617,7 +615,7 @@ int gb_fw_mgmt_connection_init(struct gb_connection *connection)
        if (ret)
                goto err_list_del;
 
-       minor = ida_simple_get(&fw_mgmt_minors_map, 0, NUM_MINORS, GFP_KERNEL);
+       minor = ida_alloc_max(&fw_mgmt_minors_map, NUM_MINORS - 1, GFP_KERNEL);
        if (minor < 0) {
                ret = minor;
                goto err_connection_disable;
@@ -645,7 +643,7 @@ int gb_fw_mgmt_connection_init(struct gb_connection *connection)
 err_del_cdev:
        cdev_del(&fw_mgmt->cdev);
 err_remove_ida:
-       ida_simple_remove(&fw_mgmt_minors_map, minor);
+       ida_free(&fw_mgmt_minors_map, minor);
 err_connection_disable:
        gb_connection_disable(connection);
 err_list_del:
@@ -669,7 +667,7 @@ void gb_fw_mgmt_connection_exit(struct gb_connection *connection)
 
        device_destroy(&fw_mgmt_class, fw_mgmt->dev_num);
        cdev_del(&fw_mgmt->cdev);
-       ida_simple_remove(&fw_mgmt_minors_map, MINOR(fw_mgmt->dev_num));
+       ida_free(&fw_mgmt_minors_map, MINOR(fw_mgmt->dev_num));
 
        /*
         * Disallow any new ioctl operations on the char device and wait for
index 6a7d8cf2a1ebc1f74f1f4575e4e7f438dc9513f6..d827f03f525380e0cb9a6f5dd3628980d01a64c1 100644 (file)
@@ -46,7 +46,7 @@ static void gbphy_dev_release(struct device *dev)
 {
        struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);
 
-       ida_simple_remove(&gbphy_id, gbphy_dev->id);
+       ida_free(&gbphy_id, gbphy_dev->id);
        kfree(gbphy_dev);
 }
 
@@ -182,7 +182,7 @@ static void gbphy_dev_remove(struct device *dev)
        pm_runtime_dont_use_autosuspend(dev);
 }
 
-static struct bus_type gbphy_bus_type = {
+static const struct bus_type gbphy_bus_type = {
        .name =         "gbphy",
        .match =        gbphy_dev_match,
        .probe =        gbphy_dev_probe,
@@ -225,13 +225,13 @@ static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle,
        int retval;
        int id;
 
-       id = ida_simple_get(&gbphy_id, 1, 0, GFP_KERNEL);
+       id = ida_alloc_min(&gbphy_id, 1, GFP_KERNEL);
        if (id < 0)
                return ERR_PTR(id);
 
        gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL);
        if (!gbphy_dev) {
-               ida_simple_remove(&gbphy_id, id);
+               ida_free(&gbphy_id, id);
                return ERR_PTR(-ENOMEM);
        }
 
index 48b4a9794d3c81b3a1efad5d479b5fb884390d82..ee88f880cfe3b845a5e1cf31fc177c7a188ca0a2 100644 (file)
@@ -44,7 +44,7 @@
 /* IOCTL support */
 struct cap_ioc_get_endpoint_uid {
        __u8                    uid[8];
-} __attribute__ ((__packed__));
+} __packed;
 
 struct cap_ioc_get_ims_certificate {
        __u32                   certificate_class;
@@ -53,7 +53,7 @@ struct cap_ioc_get_ims_certificate {
        __u8                    result_code;
        __u32                   cert_size;
        __u8                    certificate[CAP_CERTIFICATE_MAX_SIZE];
-} __attribute__ ((__packed__));
+} __packed;
 
 struct cap_ioc_authenticate {
        __u32                   auth_type;
@@ -64,7 +64,7 @@ struct cap_ioc_authenticate {
        __u8                    response[64];
        __u32                   signature_size;
        __u8                    signature[CAP_SIGNATURE_MAX_SIZE];
-} __attribute__ ((__packed__));
+} __packed;
 
 #define CAP_IOCTL_BASE                 'C'
 #define CAP_IOC_GET_ENDPOINT_UID       _IOR(CAP_IOCTL_BASE, 0, struct cap_ioc_get_endpoint_uid)
index f68fd5e25321766b748a8f043671353e7d73327e..b6042a82ada476af14b98dec560499e1d7c4058b 100644 (file)
@@ -41,14 +41,14 @@ struct fw_mgmt_ioc_get_intf_version {
        __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
        __u16 major;
        __u16 minor;
-} __attribute__ ((__packed__));
+} __packed;
 
 struct fw_mgmt_ioc_get_backend_version {
        __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
        __u16 major;
        __u16 minor;
        __u8 status;
-} __attribute__ ((__packed__));
+} __packed;
 
 struct fw_mgmt_ioc_intf_load_and_validate {
        __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
@@ -56,12 +56,12 @@ struct fw_mgmt_ioc_intf_load_and_validate {
        __u8 status;
        __u16 major;
        __u16 minor;
-} __attribute__ ((__packed__));
+} __packed;
 
 struct fw_mgmt_ioc_backend_fw_update {
        __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE];
        __u8 status;
-} __attribute__ ((__packed__));
+} __packed;
 
 #define FW_MGMT_IOCTL_BASE                     'F'
 #define FW_MGMT_IOC_GET_INTF_FW                        _IOR(FW_MGMT_IOCTL_BASE, 0, struct fw_mgmt_ioc_get_intf_version)
index d62f97249aca678886f064d4b8f7cf3304f6afa2..a5c2fe963866db66a487eaa824d53329ffc0c080 100644 (file)
@@ -95,15 +95,15 @@ static struct led_classdev *get_channel_cdev(struct gb_channel *channel)
 static struct gb_channel *get_channel_from_mode(struct gb_light *light,
                                                u32 mode)
 {
-       struct gb_channel *channel = NULL;
+       struct gb_channel *channel;
        int i;
 
        for (i = 0; i < light->channels_count; i++) {
                channel = &light->channels[i];
-               if (channel && channel->mode == mode)
-                       break;
+               if (channel->mode == mode)
+                       return channel;
        }
-       return channel;
+       return NULL;
 }
 
 static int __gb_lights_flash_intensity_set(struct gb_channel *channel,
index d7b39f3bb6525f6d0ffe864f34f0b74ee550a569..bb33379b5297eb9692905fcf108e428eea642d41 100644 (file)
@@ -1028,7 +1028,7 @@ static int gb_loopback_probe(struct gb_bundle *bundle,
        gb->file = debugfs_create_file(name, S_IFREG | 0444, gb_dev.root, gb,
                                       &gb_loopback_dbgfs_latency_fops);
 
-       gb->id = ida_simple_get(&loopback_ida, 0, 0, GFP_KERNEL);
+       gb->id = ida_alloc(&loopback_ida, GFP_KERNEL);
        if (gb->id < 0) {
                retval = gb->id;
                goto out_debugfs_remove;
@@ -1079,7 +1079,7 @@ out_conn:
 out_connection_disable:
        gb_connection_disable(connection);
 out_ida_remove:
-       ida_simple_remove(&loopback_ida, gb->id);
+       ida_free(&loopback_ida, gb->id);
 out_debugfs_remove:
        debugfs_remove(gb->file);
 out_connection_destroy:
@@ -1121,7 +1121,7 @@ static void gb_loopback_disconnect(struct gb_bundle *bundle)
        spin_unlock_irqrestore(&gb_dev.lock, flags);
 
        device_unregister(gb->dev);
-       ida_simple_remove(&loopback_ida, gb->id);
+       ida_free(&loopback_ida, gb->id);
 
        gb_connection_destroy(gb->connection);
        kfree(gb);
index b9c6eff7cdc11c5ce6da52c438e670421ad2d24d..836d35e5fa8594e06ce1ac5d42cf954bf460d0fd 100644 (file)
@@ -181,7 +181,7 @@ static int gb_raw_probe(struct gb_bundle *bundle,
        raw->connection = connection;
        greybus_set_drvdata(bundle, raw);
 
-       minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
+       minor = ida_alloc(&minors, GFP_KERNEL);
        if (minor < 0) {
                retval = minor;
                goto error_connection_destroy;
@@ -214,7 +214,7 @@ error_connection_disable:
        gb_connection_disable(connection);
 
 error_remove_ida:
-       ida_simple_remove(&minors, minor);
+       ida_free(&minors, minor);
 
 error_connection_destroy:
        gb_connection_destroy(connection);
@@ -235,7 +235,7 @@ static void gb_raw_disconnect(struct gb_bundle *bundle)
        device_destroy(&raw_class, raw->dev);
        cdev_del(&raw->cdev);
        gb_connection_disable(connection);
-       ida_simple_remove(&minors, MINOR(raw->dev));
+       ida_free(&minors, MINOR(raw->dev));
        gb_connection_destroy(connection);
 
        mutex_lock(&raw->list_lock);
index 227e18d92a958a094ae81c8fc3df6414e24f01ae..89bef8045549681e93649f51daf9dde9118b1cf7 100644 (file)
@@ -153,7 +153,7 @@ static int gb_vibrator_probe(struct gb_bundle *bundle,
         * there is a "real" device somewhere in the kernel for this, but I
         * can't find it at the moment...
         */
-       vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL);
+       vib->minor = ida_alloc(&minors, GFP_KERNEL);
        if (vib->minor < 0) {
                retval = vib->minor;
                goto err_connection_disable;
@@ -173,7 +173,7 @@ static int gb_vibrator_probe(struct gb_bundle *bundle,
        return 0;
 
 err_ida_remove:
-       ida_simple_remove(&minors, vib->minor);
+       ida_free(&minors, vib->minor);
 err_connection_disable:
        gb_connection_disable(connection);
 err_connection_destroy:
@@ -197,7 +197,7 @@ static void gb_vibrator_disconnect(struct gb_bundle *bundle)
                turn_off(vib);
 
        device_unregister(vib->dev);
-       ida_simple_remove(&minors, vib->minor);
+       ida_free(&minors, vib->minor);
        gb_connection_disable(vib->connection);
        gb_connection_destroy(vib->connection);
        kfree(vib);
index e4d85d9b46817ac5e4f53b0bad261619a0c170a6..8afde3ccc960e8c48f946076ae37e4b0b53d7e9a 100644 (file)
@@ -1,6 +1,5 @@
 ToDo list (incomplete, unordered)
-       - add compile as module support
-       - move half of the nvec init stuff to i2c-tegra.c
-       - move event handling to nvec_events
+       - move the driver to the new i2c slave framework
        - finish suspend/resume support
-       - add support for more device implementations
+       - fix udelay in the isr
+       - add atomic ops in order to fix shutoff/reboot problems
index 2823cacde130937f33638604c89d1d077647df60..282a664c917634a6170c5f3a4294866aad8deeb5 100644 (file)
@@ -709,10 +709,11 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
                status & RNW ? " RNW" : "");
 
        /*
-        * TODO: A correct fix needs to be found for this.
+        * TODO: replace the udelay with a read back after each writel above
+        * in order to work around a hardware issue, see i2c-tegra.c
         *
-        * We experience less incomplete messages with this delay than without
-        * it, but we don't know why. Help is appreciated.
+        * Unfortunately, this change causes an intialisation issue with the
+        * touchpad, which needs to be fixed first.
         */
        udelay(100);
 
index b3049108edc45a79dd85df9ff5bd912ad485f540..211423059e303f26d43b08ab06158b5fe331c283 100644 (file)
@@ -10,7 +10,6 @@
 #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"
@@ -22,7 +21,6 @@ static void cvm_oct_get_drvinfo(struct net_device *dev,
                                struct ethtool_drvinfo *info)
 {
        strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
-       strscpy(info->version, UTS_RELEASE, sizeof(info->version));
        strscpy(info->bus_info, "Builtin", sizeof(info->bus_info));
 }
 
index 3e7b92cd2e35e69ad2e43429cb7068c83ea867b9..44cced319c111236f5820f7154efb7f7129c2154 100644 (file)
@@ -1362,7 +1362,7 @@ static inline struct cvmx_wqe *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait)
 }
 
 static inline int cvmx_spi_restart_interface(int interface,
-                                       cvmx_spi_mode_t mode, int timeout)
+                                            cvmx_spi_mode_t mode, int timeout)
 {
        return 0;
 }
index 0ec3130225db16f2aafafcf911fb3295dd3b5cae..b6c4917d515e690cc3021c65019661a1db81cfd1 100644 (file)
@@ -49,6 +49,7 @@
 #define N_PI433_MINORS         BIT(MINORBITS) /*32*/   /* ... up to 256 */
 #define MAX_MSG_SIZE           900     /* min: FIFO_SIZE! */
 #define MSG_FIFO_SIZE          65536   /* 65536 = 2^16  */
+#define FIFO_THRESHOLD 15              /* bytes */
 #define NUM_DIO                        2
 
 static dev_t pi433_dev;
index 8c7fab6a46bb291399948ffb129f69933e0c2aa5..5a1c362badb6148f1db2514d0f3d358ddee46ebb 100644 (file)
@@ -8,12 +8,12 @@
 
 #include <linux/types.h>
 #include <linux/spi/spi.h>
+#include <linux/units.h>
 
 #include "rf69.h"
 #include "rf69_registers.h"
 
-#define F_OSC    32000000 /* in Hz */
-#define FIFO_SIZE 66      /* in byte */
+#define F_OSC (32 * HZ_PER_MHZ)
 
 /*-------------------------------------------------------------------------*/
 
index 78fa0b8bab8b0084a65c749ff6f8531e885d17ec..76f0f9896a524bb0eb864afa80c2dfae391dcc9d 100644 (file)
 #include "rf69_enum.h"
 #include "rf69_registers.h"
 
-/* NOTE: Modifying FREQUENCY value impacts CE certification */
-#define F_OSC          32000000        /* Hz */
-#define FREQUENCY      433920000       /* Hz */
 #define FIFO_SIZE      66              /* bytes */
-#define FIFO_THRESHOLD 15              /* bytes */
 
 u8 rf69_read_reg(struct spi_device *spi, u8 addr);
 int rf69_get_version(struct spi_device *spi);
index c7a2eae2fdb90c46912d23f904d1eab5df388cb9..e3ed709a7674eed1e521c0b0b8e5b7c311304e5f 100644 (file)
@@ -164,7 +164,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val)
                                    eACI);
                        break;
                }
-               priv->rtllib->SetHwRegHandler(dev, HW_VAR_ACM_CTRL,
+               priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACM_CTRL,
                                              &pAcParam);
                break;
        }
@@ -693,11 +693,10 @@ void rtl92e_link_change(struct net_device *dev)
                u32 reg;
 
                reg = rtl92e_readl(dev, RCR);
-               if (priv->rtllib->link_state == MAC80211_LINKED) {
+               if (priv->rtllib->link_state == MAC80211_LINKED)
                        priv->receive_config = reg |= RCR_CBSSID;
-               } else {
+               else
                        priv->receive_config = reg &= ~RCR_CBSSID;
-               }
 
                rtl92e_writel(dev, RCR, reg);
        }
@@ -1296,7 +1295,6 @@ static void _rtl92e_query_rxphystatus(
                pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all);
 
                pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all;
-               pstats->RxPower = precord_stats->RxPower =      rx_pwr_all;
                pstats->RecvSignalPower = rx_pwr_all;
                if (pdrvinfo->RxHT && pdrvinfo->RxRate >= DESC90_RATEMCS8 &&
                    pdrvinfo->RxRate <= DESC90_RATEMCS15)
@@ -1348,14 +1346,7 @@ static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer,
        static u32 slide_beacon_adc_pwdb_index;
        static u32 slide_beacon_adc_pwdb_statistics;
        static u32 last_beacon_adc_pwdb;
-       struct ieee80211_hdr_3addr *hdr;
-       u16 sc;
-       unsigned int seq;
 
-       hdr = (struct ieee80211_hdr_3addr *)buffer;
-       sc = le16_to_cpu(hdr->seq_ctrl);
-       seq = WLAN_GET_SEQ_SEQ(sc);
-       curr_st->Seq_Num = seq;
        if (!prev_st->bIsAMPDU)
                bcheck = true;
 
@@ -1536,7 +1527,7 @@ static void _rtl92e_update_received_rate_histogram_stats(
 {
        struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
        u32 rcvType = 1;
-       u32 rateIndex;
+       u32 rate_index;
 
        if (pstats->bCRC)
                rcvType = 2;
@@ -1545,95 +1536,95 @@ static void _rtl92e_update_received_rate_histogram_stats(
 
        switch (pstats->rate) {
        case MGN_1M:
-               rateIndex = 0;
+               rate_index = 0;
                break;
        case MGN_2M:
-               rateIndex = 1;
+               rate_index = 1;
                break;
        case MGN_5_5M:
-               rateIndex = 2;
+               rate_index = 2;
                break;
        case MGN_11M:
-               rateIndex = 3;
+               rate_index = 3;
                break;
        case MGN_6M:
-               rateIndex = 4;
+               rate_index = 4;
                break;
        case MGN_9M:
-               rateIndex = 5;
+               rate_index = 5;
                break;
        case MGN_12M:
-               rateIndex = 6;
+               rate_index = 6;
                break;
        case MGN_18M:
-               rateIndex = 7;
+               rate_index = 7;
                break;
        case MGN_24M:
-               rateIndex = 8;
+               rate_index = 8;
                break;
        case MGN_36M:
-               rateIndex = 9;
+               rate_index = 9;
                break;
        case MGN_48M:
-               rateIndex = 10;
+               rate_index = 10;
                break;
        case MGN_54M:
-               rateIndex = 11;
+               rate_index = 11;
                break;
        case MGN_MCS0:
-               rateIndex = 12;
+               rate_index = 12;
                break;
        case MGN_MCS1:
-               rateIndex = 13;
+               rate_index = 13;
                break;
        case MGN_MCS2:
-               rateIndex = 14;
+               rate_index = 14;
                break;
        case MGN_MCS3:
-               rateIndex = 15;
+               rate_index = 15;
                break;
        case MGN_MCS4:
-               rateIndex = 16;
+               rate_index = 16;
                break;
        case MGN_MCS5:
-               rateIndex = 17;
+               rate_index = 17;
                break;
        case MGN_MCS6:
-               rateIndex = 18;
+               rate_index = 18;
                break;
        case MGN_MCS7:
-               rateIndex = 19;
+               rate_index = 19;
                break;
        case MGN_MCS8:
-               rateIndex = 20;
+               rate_index = 20;
                break;
        case MGN_MCS9:
-               rateIndex = 21;
+               rate_index = 21;
                break;
        case MGN_MCS10:
-               rateIndex = 22;
+               rate_index = 22;
                break;
        case MGN_MCS11:
-               rateIndex = 23;
+               rate_index = 23;
                break;
        case MGN_MCS12:
-               rateIndex = 24;
+               rate_index = 24;
                break;
        case MGN_MCS13:
-               rateIndex = 25;
+               rate_index = 25;
                break;
        case MGN_MCS14:
-               rateIndex = 26;
+               rate_index = 26;
                break;
        case MGN_MCS15:
-               rateIndex = 27;
+               rate_index = 27;
                break;
        default:
-               rateIndex = 28;
+               rate_index = 28;
                break;
        }
-       priv->stats.received_rate_histogram[0][rateIndex]++;
-       priv->stats.received_rate_histogram[rcvType][rateIndex]++;
+       priv->stats.received_rate_histogram[0][rate_index]++;
+       priv->stats.received_rate_histogram[rcvType][rate_index]++;
 }
 
 bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
@@ -1650,7 +1641,6 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
                stats->bHwError |= 1;
 
        if (stats->bHwError) {
-               stats->bShift = false;
                return false;
        }
 
@@ -1662,7 +1652,6 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
 
        stats->rate = _rtl92e_rate_hw_to_mgn((bool)pDrvInfo->RxHT,
                                             pDrvInfo->RxRate);
-       stats->bShortPreamble = pDrvInfo->SPLCP;
 
        _rtl92e_update_received_rate_histogram_stats(dev, stats);
 
@@ -1673,19 +1662,9 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
        stats->TimeStampLow = pDrvInfo->TSFL;
        stats->TimeStampHigh = rtl92e_readl(dev, TSFR + 4);
 
-       if ((stats->RxBufShift + stats->RxDrvInfoSize) > 0)
-               stats->bShift = 1;
-
-       stats->RxIs40MHzPacket = pDrvInfo->BW;
-
        _rtl92e_translate_rx_signal_stats(dev, skb, stats, pdesc, pDrvInfo);
        skb_trim(skb, skb->len - S_CRC_LEN);
 
-
-       stats->packetlength = stats->Length - 4;
-       stats->fraglength = stats->packetlength;
-       stats->fragoffset = 0;
-       stats->ntotalfrag = 1;
        return true;
 }
 
@@ -1698,7 +1677,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset)
        u32     ulRegRead;
 
        op_mode = RT_OP_MODE_NO_LINK;
-       priv->rtllib->SetHwRegHandler(dev, HW_VAR_MEDIA_STATUS, &op_mode);
+       priv->rtllib->set_hw_reg_handler(dev, HW_VAR_MEDIA_STATUS, &op_mode);
 
        if (!priv->rtllib->bSupportRemoteWakeUp) {
                u1bTmp = 0x0;
@@ -1852,7 +1831,7 @@ bool rtl92e_is_rx_stuck(struct net_device *dev)
        u16               RegRxCounter = rtl92e_readw(dev, 0x130);
        bool              bStuck = false;
        static u8         rx_chk_cnt;
-       u32             SlotIndex = 0, TotalRxStuckCount = 0;
+       u32             slot_index = 0, TotalRxStuckCount = 0;
        u8              i;
        u8              SilentResetRxSoltNum = 4;
 
@@ -1882,10 +1861,10 @@ bool rtl92e_is_rx_stuck(struct net_device *dev)
        }
 
 
-       SlotIndex = (priv->silent_reset_rx_slot_index++) % SilentResetRxSoltNum;
+       slot_index = (priv->silent_reset_rx_slot_index++) % SilentResetRxSoltNum;
 
        if (priv->rx_ctr == RegRxCounter) {
-               priv->silent_reset_rx_stuck_event[SlotIndex] = 1;
+               priv->silent_reset_rx_stuck_event[slot_index] = 1;
 
                for (i = 0; i < SilentResetRxSoltNum; i++)
                        TotalRxStuckCount += priv->silent_reset_rx_stuck_event[i];
@@ -1897,7 +1876,7 @@ bool rtl92e_is_rx_stuck(struct net_device *dev)
                                         priv->silent_reset_rx_stuck_event[i];
                }
        } else {
-               priv->silent_reset_rx_stuck_event[SlotIndex] = 0;
+               priv->silent_reset_rx_stuck_event[slot_index] = 0;
        }
 
        priv->rx_ctr = RegRxCounter;
@@ -1938,5 +1917,5 @@ bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev)
        struct r8192_priv *priv = rtllib_priv(dev);
        struct rtllib_device *ieee = priv->rtllib;
 
-       return ieee->bHalfWirelessN24GMode;
+       return ieee->half_wireless_n24g_mode;
 }
index e1bd4d67e862b6056fe4e0dae2dde55d6e4b319d..18b948d4d86d399f973fb04b557c438ce99b24fe 100644 (file)
@@ -714,7 +714,6 @@ void rtl92e_set_channel(struct net_device *dev, u8 channel)
        if (priv->up)
                _rtl92e_phy_switch_channel_work_item(dev);
        priv->sw_chnl_in_progress = false;
-       return;
 }
 
 static void _rtl92e_cck_tx_power_track_bw_switch_tssi(struct net_device *dev)
index 6815d18a7919e4c8aae9c9ae9826621c75ef0401..649b529657bab87718fb134cb0900b35112ff14d 100644 (file)
@@ -172,7 +172,7 @@ bool rtl92e_set_rf_state(struct net_device *dev,
                                        priv->blinked_ingpio = true;
                                else
                                        priv->blinked_ingpio = false;
-                               rtllib_MgntDisconnect(priv->rtllib,
+                               rtllib_mgnt_disconnect(priv->rtllib,
                                                      WLAN_REASON_DISASSOC_STA_HAS_LEFT);
                        }
                }
@@ -236,14 +236,14 @@ static void _rtl92e_update_cap(struct net_device *dev, u16 cap)
                if (priv->dot11_current_preamble_mode != PREAMBLE_SHORT) {
                        ShortPreamble = true;
                        priv->dot11_current_preamble_mode = PREAMBLE_SHORT;
-                       priv->rtllib->SetHwRegHandler(dev, HW_VAR_ACK_PREAMBLE,
+                       priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE,
                                        (unsigned char *)&ShortPreamble);
                }
        } else {
                if (priv->dot11_current_preamble_mode != PREAMBLE_LONG) {
                        ShortPreamble = false;
                        priv->dot11_current_preamble_mode = PREAMBLE_LONG;
-                       priv->rtllib->SetHwRegHandler(dev, HW_VAR_ACK_PREAMBLE,
+                       priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE,
                                              (unsigned char *)&ShortPreamble);
                }
        }
@@ -256,13 +256,13 @@ static void _rtl92e_update_cap(struct net_device *dev, u16 cap)
                   (!priv->rtllib->ht_info->current_rt2rt_long_slot_time)) {
                        if (cur_slot_time != SHORT_SLOT_TIME) {
                                slot_time_val = SHORT_SLOT_TIME;
-                               priv->rtllib->SetHwRegHandler(dev,
+                               priv->rtllib->set_hw_reg_handler(dev,
                                         HW_VAR_SLOT_TIME, &slot_time_val);
                        }
                } else {
                        if (cur_slot_time != NON_SHORT_SLOT_TIME) {
                                slot_time_val = NON_SHORT_SLOT_TIME;
-                               priv->rtllib->SetHwRegHandler(dev,
+                               priv->rtllib->set_hw_reg_handler(dev,
                                         HW_VAR_SLOT_TIME, &slot_time_val);
                        }
                }
@@ -301,7 +301,7 @@ static void _rtl92e_qos_activate(void *data)
                goto success;
 
        for (i = 0; i <  QOS_QUEUE_NUM; i++)
-               priv->rtllib->SetHwRegHandler(dev, HW_VAR_AC_PARAM, (u8 *)(&i));
+               priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM, (u8 *)(&i));
 
 success:
        mutex_unlock(&priv->mutex);
@@ -656,12 +656,12 @@ static void _rtl92e_init_priv_handler(struct net_device *dev)
        priv->rtllib->enter_sleep_state = rtl92e_enter_sleep;
        priv->rtllib->ps_is_queue_empty = _rtl92e_is_tx_queue_empty;
 
-       priv->rtllib->GetNmodeSupportBySecCfg = rtl92e_get_nmode_support_by_sec;
-       priv->rtllib->GetHalfNmodeSupportByAPsHandler =
+       priv->rtllib->get_nmode_support_by_sec_cfg = rtl92e_get_nmode_support_by_sec;
+       priv->rtllib->get_half_nmode_support_by_aps_handler =
                                                rtl92e_is_halfn_supported_by_ap;
 
-       priv->rtllib->SetHwRegHandler = rtl92e_set_reg;
-       priv->rtllib->AllowAllDestAddrHandler = rtl92e_set_monitor_mode;
+       priv->rtllib->set_hw_reg_handler = rtl92e_set_reg;
+       priv->rtllib->allow_all_dest_addr_handler = rtl92e_set_monitor_mode;
        priv->rtllib->init_gain_handler = rtl92e_init_gain;
        priv->rtllib->rtllib_ips_leave_wq = rtl92e_rtllib_ips_leave_wq;
        priv->rtllib->rtllib_ips_leave = rtl92e_rtllib_ips_leave;
@@ -705,7 +705,7 @@ static void _rtl92e_init_priv_variable(struct net_device *dev)
        priv->hw_rf_off_action = 0;
        priv->set_rf_pwr_state_in_progress = false;
        priv->rtllib->pwr_save_ctrl.bLeisurePs = true;
-       priv->rtllib->LPSDelayCnt = 0;
+       priv->rtllib->lps_delay_cnt = 0;
        priv->rtllib->sta_sleep = LPS_IS_WAKE;
        priv->rtllib->rf_power_state = rf_on;
 
@@ -909,25 +909,24 @@ static void _rtl92e_if_check_reset(struct net_device *dev)
                netdev_info(dev, "%s(): TxResetType is %d, RxResetType is %d\n",
                            __func__, TxResetType, RxResetType);
        }
-       return;
 }
 
 static void _rtl92e_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum,
                                    u32 *TotalRxDataNum)
 {
-       u16     SlotIndex;
+       u16     slot_index;
        u8      i;
 
        *TotalRxBcnNum = 0;
        *TotalRxDataNum = 0;
 
-       SlotIndex = (priv->rtllib->link_detect_info.SlotIndex++) %
-                       (priv->rtllib->link_detect_info.SlotNum);
-       priv->rtllib->link_detect_info.RxBcnNum[SlotIndex] =
-                       priv->rtllib->link_detect_info.NumRecvBcnInPeriod;
-       priv->rtllib->link_detect_info.RxDataNum[SlotIndex] =
-                       priv->rtllib->link_detect_info.NumRecvDataInPeriod;
-       for (i = 0; i < priv->rtllib->link_detect_info.SlotNum; i++) {
+       slot_index = (priv->rtllib->link_detect_info.slot_index++) %
+                       (priv->rtllib->link_detect_info.slot_num);
+       priv->rtllib->link_detect_info.RxBcnNum[slot_index] =
+                       priv->rtllib->link_detect_info.num_recv_bcn_in_period;
+       priv->rtllib->link_detect_info.RxDataNum[slot_index] =
+                       priv->rtllib->link_detect_info.num_recv_data_in_period;
+       for (i = 0; i < priv->rtllib->link_detect_info.slot_num; i++) {
                *TotalRxBcnNum += priv->rtllib->link_detect_info.RxBcnNum[i];
                *TotalRxDataNum += priv->rtllib->link_detect_info.RxDataNum[i];
        }
@@ -943,7 +942,7 @@ static void _rtl92e_watchdog_wq_cb(void *data)
        unsigned long flags;
        struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *)
                                        (&priv->rtllib->pwr_save_ctrl);
-       bool bBusyTraffic = false;
+       bool busy_traffic = false;
        bool    bHigherBusyTraffic = false;
        bool    bHigherBusyRxTraffic = false;
        bool bEnterPS = false;
@@ -965,15 +964,14 @@ static void _rtl92e_watchdog_wq_cb(void *data)
                     MAC80211_NOLINK) &&
                     (ieee->rf_power_state == rf_on) && !ieee->is_set_key &&
                     (!ieee->proto_stoppping) && !ieee->wx_set_enc) {
-                       if (ieee->pwr_save_ctrl.ReturnPoint == IPS_CALLBACK_NONE) {
+                       if (ieee->pwr_save_ctrl.ReturnPoint == IPS_CALLBACK_NONE)
                                rtl92e_ips_enter(dev);
-                       }
                }
        }
        if ((ieee->link_state == MAC80211_LINKED) && (ieee->iw_mode == IW_MODE_INFRA)) {
                if (ieee->link_detect_info.num_rx_ok_in_period > 100 ||
                ieee->link_detect_info.num_tx_ok_in_period > 100)
-                       bBusyTraffic = true;
+                       busy_traffic = true;
 
                if (ieee->link_detect_info.num_rx_ok_in_period > 4000 ||
                    ieee->link_detect_info.num_tx_ok_in_period > 4000) {
@@ -984,9 +982,9 @@ static void _rtl92e_watchdog_wq_cb(void *data)
                                bHigherBusyRxTraffic = false;
                }
 
-               if (((ieee->link_detect_info.NumRxUnicastOkInPeriod +
+               if (((ieee->link_detect_info.num_rx_unicast_ok_in_period +
                    ieee->link_detect_info.num_tx_ok_in_period) > 8) ||
-                   (ieee->link_detect_info.NumRxUnicastOkInPeriod > 2))
+                   (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2))
                        bEnterPS = false;
                else
                        bEnterPS = true;
@@ -1005,8 +1003,8 @@ static void _rtl92e_watchdog_wq_cb(void *data)
 
        ieee->link_detect_info.num_rx_ok_in_period = 0;
        ieee->link_detect_info.num_tx_ok_in_period = 0;
-       ieee->link_detect_info.NumRxUnicastOkInPeriod = 0;
-       ieee->link_detect_info.bBusyTraffic = bBusyTraffic;
+       ieee->link_detect_info.num_rx_unicast_ok_in_period = 0;
+       ieee->link_detect_info.busy_traffic = busy_traffic;
 
        ieee->link_detect_info.bHigherBusyTraffic = bHigherBusyTraffic;
        ieee->link_detect_info.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
@@ -1032,7 +1030,7 @@ static void _rtl92e_watchdog_wq_cb(void *data)
 
                        ieee->link_state = RTLLIB_ASSOCIATING;
 
-                       RemovePeerTS(priv->rtllib,
+                       remove_peer_ts(priv->rtllib,
                                     priv->rtllib->current_network.bssid);
                        ieee->is_roaming = true;
                        ieee->is_set_key = false;
@@ -1046,8 +1044,8 @@ static void _rtl92e_watchdog_wq_cb(void *data)
 
                        priv->check_roaming_cnt = 0;
                }
-               ieee->link_detect_info.NumRecvBcnInPeriod = 0;
-               ieee->link_detect_info.NumRecvDataInPeriod = 0;
+               ieee->link_detect_info.num_recv_bcn_in_period = 0;
+               ieee->link_detect_info.num_recv_data_in_period = 0;
        }
 
        spin_lock_irqsave(&priv->tx_lock, flags);
@@ -1257,7 +1255,7 @@ static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb)
        int   idx;
        u32 fwinfo_size = 0;
 
-       priv->rtllib->bAwakePktSent = true;
+       priv->rtllib->awake_pkt_sent = true;
 
        fwinfo_size = sizeof(struct tx_fwinfo_8190pci);
 
@@ -1502,8 +1500,6 @@ static void _rtl92e_rx_normal(struct net_device *dev)
        };
        unsigned int count = priv->rxringcount;
 
-       stats.nic_type = NIC_8192E;
-
        while (count--) {
                struct rx_desc *pdesc = &priv->rx_ring
                                        [priv->rx_idx];
index 92143c50c149a7e3e77945e7712a06f3f2791351..c34087af973cf11ca6acfb6103cb28f5f9ee53ac 100644 (file)
@@ -354,7 +354,7 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
                        }
                }
 
-               if (priv->rtllib->GetHalfNmodeSupportByAPsHandler(dev))
+               if (priv->rtllib->get_half_nmode_support_by_aps_handler(dev))
                        target_ratr &=  0xf00fffff;
 
                current_ratr = rtl92e_readl(dev, RATR0);
@@ -1185,7 +1185,7 @@ static void _rtl92e_dm_check_edca_turbo(struct net_device *dev)
                if (priv->bcurrent_turbo_EDCA) {
                        u8 tmp = AC0_BE;
 
-                       priv->rtllib->SetHwRegHandler(dev, HW_VAR_AC_PARAM,
+                       priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM,
                                                      (u8 *)(&tmp));
                        priv->bcurrent_turbo_EDCA = false;
                }
@@ -1523,7 +1523,7 @@ static void _rtl92e_dm_init_fsync(struct net_device *dev)
        priv->rtllib->fsync_multiple_timeinterval = 3;
        priv->rtllib->fsync_firstdiff_ratethreshold = 100;
        priv->rtllib->fsync_seconddiff_ratethreshold = 200;
-       priv->rtllib->fsync_state = Default_Fsync;
+       priv->rtllib->fsync_state = DEFAULT_FSYNC;
 
        timer_setup(&priv->fsync_timer, _rtl92e_dm_fsync_timer_callback, 0);
 }
@@ -1636,7 +1636,7 @@ static void _rtl92e_dm_start_hw_fsync(struct net_device *dev)
        struct r8192_priv *priv = rtllib_priv(dev);
 
        rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cf);
-       priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING,
+       priv->rtllib->set_hw_reg_handler(dev, HW_VAR_RF_TIMING,
                                      (u8 *)(&rf_timing));
        rtl92e_writeb(dev, 0xc3b, 0x41);
 }
@@ -1647,7 +1647,7 @@ static void _rtl92e_dm_end_hw_fsync(struct net_device *dev)
        struct r8192_priv *priv = rtllib_priv(dev);
 
        rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd);
-       priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, (u8 *)
+       priv->rtllib->set_hw_reg_handler(dev, HW_VAR_RF_TIMING, (u8 *)
                                     (&rf_timing));
        rtl92e_writeb(dev, 0xc3b, 0x49);
 }
@@ -1716,31 +1716,29 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev)
            priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) {
                if (priv->rtllib->bfsync_enable == 0) {
                        switch (priv->rtllib->fsync_state) {
-                       case Default_Fsync:
+                       case DEFAULT_FSYNC:
                                _rtl92e_dm_start_hw_fsync(dev);
-                               priv->rtllib->fsync_state = HW_Fsync;
+                               priv->rtllib->fsync_state = HW_FSYNC;
                                break;
-                       case SW_Fsync:
+                       case SW_FSYNC:
                                _rtl92e_dm_end_sw_fsync(dev);
                                _rtl92e_dm_start_hw_fsync(dev);
-                               priv->rtllib->fsync_state = HW_Fsync;
+                               priv->rtllib->fsync_state = HW_FSYNC;
                                break;
-                       case HW_Fsync:
                        default:
                                break;
                        }
                } else {
                        switch (priv->rtllib->fsync_state) {
-                       case Default_Fsync:
+                       case DEFAULT_FSYNC:
                                _rtl92e_dm_start_sw_fsync(dev);
-                               priv->rtllib->fsync_state = SW_Fsync;
+                               priv->rtllib->fsync_state = SW_FSYNC;
                                break;
-                       case HW_Fsync:
+                       case HW_FSYNC:
                                _rtl92e_dm_end_hw_fsync(dev);
                                _rtl92e_dm_start_sw_fsync(dev);
-                               priv->rtllib->fsync_state = SW_Fsync;
+                               priv->rtllib->fsync_state = SW_FSYNC;
                                break;
-                       case SW_Fsync:
                        default:
                                break;
                        }
@@ -1752,15 +1750,14 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev)
                }
        } else {
                switch (priv->rtllib->fsync_state) {
-               case HW_Fsync:
+               case HW_FSYNC:
                        _rtl92e_dm_end_hw_fsync(dev);
-                       priv->rtllib->fsync_state = Default_Fsync;
+                       priv->rtllib->fsync_state = DEFAULT_FSYNC;
                        break;
-               case SW_Fsync:
+               case SW_FSYNC:
                        _rtl92e_dm_end_sw_fsync(dev);
-                       priv->rtllib->fsync_state = Default_Fsync;
+                       priv->rtllib->fsync_state = DEFAULT_FSYNC;
                        break;
-               case Default_Fsync:
                default:
                        break;
                }
index 44a9fe83184975aa9d59e1f1917de70f9dcdcbdf..5aac9110bff686a611b1e3e7efdf9a29a5a7f780 100644 (file)
@@ -208,12 +208,12 @@ void rtl92e_leisure_ps_enter(struct net_device *dev)
                return;
 
        if (psc->bLeisurePs) {
-               if (psc->LpsIdleCount >= RT_CHECK_FOR_HANG_PERIOD) {
+               if (psc->lps_idle_count >= RT_CHECK_FOR_HANG_PERIOD) {
 
                        if (priv->rtllib->ps == RTLLIB_PS_DISABLED)
                                _rtl92e_ps_set_mode(dev, RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST);
                } else {
-                       psc->LpsIdleCount++;
+                       psc->lps_idle_count++;
                }
        }
 }
index 4c884c5277f94be222aef10faa2e0305d15bf2ad..d131ef525f46307644d6f9465b3e5018fe839b18 100644 (file)
@@ -253,7 +253,7 @@ static int _rtl92e_wx_set_scan(struct net_device *dev,
        rt_state = priv->rtllib->rf_power_state;
        if (!priv->up)
                return -ENETDOWN;
-       if (priv->rtllib->link_detect_info.bBusyTraffic)
+       if (priv->rtllib->link_detect_info.busy_traffic)
                return -EAGAIN;
 
        if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
@@ -269,7 +269,7 @@ static int _rtl92e_wx_set_scan(struct net_device *dev,
 
        mutex_lock(&priv->wx_mutex);
 
-       priv->rtllib->FirstIe_InScan = true;
+       priv->rtllib->first_ie_in_scan = true;
 
        if (priv->rtllib->link_state != MAC80211_LINKED) {
                if (rt_state == rf_off) {
index ee9ce392155c310cc4c1a7c5e461768e3a7979b9..834329886ea2efa0d101118d5fe75ca3fd6061f8 100644 (file)
@@ -125,7 +125,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *dst,
 
 static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
                                    struct ba_record *ba,
-                                   enum tr_select TxRxSelect, u16 reason_code)
+                                   enum tr_select tx_rx_select, u16 reason_code)
 {
        union delba_param_set del_ba_param_set;
        struct sk_buff *skb = NULL;
@@ -139,7 +139,7 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
 
        memset(&del_ba_param_set, 0, 2);
 
-       del_ba_param_set.field.initiator = (TxRxSelect == TX_DIR) ? 1 : 0;
+       del_ba_param_set.field.initiator = (tx_rx_select == TX_DIR) ? 1 : 0;
        del_ba_param_set.field.tid      = ba->ba_param_set.field.tid;
 
        skb = dev_alloc_skb(len + sizeof(struct ieee80211_hdr_3addr));
@@ -173,8 +173,8 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
        return skb;
 }
 
-static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst,
-                                struct ba_record *ba)
+static void rtllib_send_add_ba_req(struct rtllib_device *ieee, u8 *dst,
+                                  struct ba_record *ba)
 {
        struct sk_buff *skb;
 
@@ -186,8 +186,8 @@ static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst,
                netdev_dbg(ieee->dev, "Failed to generate ADDBAReq packet.\n");
 }
 
-static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst,
-                                struct ba_record *ba, u16 status_code)
+static void rtllib_send_add_ba_rsp(struct rtllib_device *ieee, u8 *dst,
+                                  struct ba_record *ba, u16 status_code)
 {
        struct sk_buff *skb;
 
@@ -199,19 +199,19 @@ static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst,
 }
 
 static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst,
-                             struct ba_record *ba, enum tr_select TxRxSelect,
+                             struct ba_record *ba, enum tr_select tx_rx_select,
                              u16 reason_code)
 {
        struct sk_buff *skb;
 
-       skb = rtllib_DELBA(ieee, dst, ba, TxRxSelect, reason_code);
+       skb = rtllib_DELBA(ieee, dst, ba, tx_rx_select, reason_code);
        if (skb)
                softmac_mgmt_xmit(skb, ieee);
        else
                netdev_dbg(ieee->dev, "Failed to generate DELBA packet.\n");
 }
 
-int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
+int rtllib_rx_add_ba_req(struct rtllib_device *ieee, struct sk_buff *skb)
 {
        struct ieee80211_hdr_3addr *req = NULL;
        u16 rc = 0;
@@ -251,13 +251,13 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
                            "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n",
                            ieee->current_network.qos_data.active,
                            ieee->ht_info->current_ht_support);
-               goto OnADDBAReq_Fail;
+               goto on_add_ba_req_fail;
        }
        if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
-                  (u8)(ba_param_set->field.tid), RX_DIR, true)) {
+                          (u8)(ba_param_set->field.tid), RX_DIR, true)) {
                rc = ADDBA_STATUS_REFUSED;
                netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
-               goto OnADDBAReq_Fail;
+               goto on_add_ba_req_fail;
        }
        ba = &ts->rx_admitted_ba_record;
 
@@ -265,10 +265,10 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
                rc = ADDBA_STATUS_INVALID_PARAM;
                netdev_warn(ieee->dev, "%s(): BA Policy is not correct\n",
                            __func__);
-               goto OnADDBAReq_Fail;
+               goto on_add_ba_req_fail;
        }
 
-       rtllib_FlushRxTsPendingPkts(ieee, ts);
+       rtllib_flush_rx_ts_pending_pkts(ieee, ts);
 
        deactivate_ba_entry(ieee, ba);
        ba->dialog_token = *dialog_token;
@@ -276,18 +276,18 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
        ba->ba_timeout_value = *ba_timeout_value;
        ba->ba_start_seq_ctrl = *ba_start_seq_ctrl;
 
-       if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) ||
-          (ieee->ht_info->iot_action & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT))
+       if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev) ||
+           (ieee->ht_info->iot_action & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT))
                ba->ba_param_set.field.buffer_size = 1;
        else
                ba->ba_param_set.field.buffer_size = 32;
 
        activate_ba_entry(ba, 0);
-       rtllib_send_ADDBARsp(ieee, dst, ba, ADDBA_STATUS_SUCCESS);
+       rtllib_send_add_ba_rsp(ieee, dst, ba, ADDBA_STATUS_SUCCESS);
 
        return 0;
 
-OnADDBAReq_Fail:
+on_add_ba_req_fail:
        {
                struct ba_record BA;
 
@@ -295,12 +295,12 @@ OnADDBAReq_Fail:
                BA.ba_timeout_value = *ba_timeout_value;
                BA.dialog_token = *dialog_token;
                BA.ba_param_set.field.ba_policy = BA_POLICY_IMMEDIATE;
-               rtllib_send_ADDBARsp(ieee, dst, &BA, rc);
+               rtllib_send_add_ba_rsp(ieee, dst, &BA, rc);
                return 0;
        }
 }
 
-int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
+int rtllib_rx_add_ba_rsp(struct rtllib_device *ieee, struct sk_buff *skb)
 {
        struct ieee80211_hdr_3addr *rsp = NULL;
        struct ba_record *pending_ba, *admitted_ba;
@@ -334,14 +334,14 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
                            ieee->ht_info->current_ht_support,
                            ieee->ht_info->current_ampdu_enable);
                reason_code = DELBA_REASON_UNKNOWN_BA;
-               goto OnADDBARsp_Reject;
+               goto on_add_ba_rsp_reject;
        }
 
        if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
-                  (u8)(ba_param_set->field.tid), TX_DIR, false)) {
+                          (u8)(ba_param_set->field.tid), TX_DIR, false)) {
                netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
                reason_code = DELBA_REASON_UNKNOWN_BA;
-               goto OnADDBARsp_Reject;
+               goto on_add_ba_rsp_reject;
        }
 
        ts->add_ba_req_in_progress = false;
@@ -358,7 +358,7 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
                            "%s(): ADDBA Rsp. BA invalid, DELBA!\n",
                            __func__);
                reason_code = DELBA_REASON_UNKNOWN_BA;
-               goto OnADDBARsp_Reject;
+               goto on_add_ba_rsp_reject;
        } else {
                netdev_dbg(ieee->dev,
                           "%s(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n",
@@ -371,7 +371,7 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
                        ts->add_ba_req_delayed = true;
                        deactivate_ba_entry(ieee, admitted_ba);
                        reason_code = DELBA_REASON_END_BA;
-                       goto OnADDBARsp_Reject;
+                       goto on_add_ba_rsp_reject;
                }
 
                admitted_ba->dialog_token = *dialog_token;
@@ -384,12 +384,12 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
                ts->add_ba_req_delayed = true;
                ts->disable_add_ba = true;
                reason_code = DELBA_REASON_END_BA;
-               goto OnADDBARsp_Reject;
+               goto on_add_ba_rsp_reject;
        }
 
        return 0;
 
-OnADDBARsp_Reject:
+on_add_ba_rsp_reject:
        {
                struct ba_record BA;
 
@@ -433,7 +433,7 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
                struct rx_ts_record *ts;
 
                if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
-                          (u8)del_ba_param_set->field.tid, RX_DIR, false)) {
+                                  (u8)del_ba_param_set->field.tid, RX_DIR, false)) {
                        netdev_warn(ieee->dev,
                                    "%s(): can't get TS for RXTS. dst:%pM TID:%d\n",
                                    __func__, dst,
@@ -446,7 +446,7 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
                struct tx_ts_record *ts;
 
                if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
-                          (u8)del_ba_param_set->field.tid, TX_DIR, false)) {
+                                  (u8)del_ba_param_set->field.tid, TX_DIR, false)) {
                        netdev_warn(ieee->dev, "%s(): can't get TS for TXTS\n",
                                    __func__);
                        return -1;
@@ -481,14 +481,14 @@ void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
 
        activate_ba_entry(ba, BA_SETUP_TIMEOUT);
 
-       rtllib_send_ADDBAReq(ieee, ts->ts_common_info.addr, ba);
+       rtllib_send_add_ba_req(ieee, ts->ts_common_info.addr, ba);
 }
 
 void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
                           struct ts_common_info *ts_common_info,
-                          enum tr_select TxRxSelect)
+                          enum tr_select tx_rx_select)
 {
-       if (TxRxSelect == TX_DIR) {
+       if (tx_rx_select == TX_DIR) {
                struct tx_ts_record *ts =
                         (struct tx_ts_record *)ts_common_info;
 
@@ -497,14 +497,14 @@ void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
                                          (ts->tx_admitted_ba_record.b_valid) ?
                                         (&ts->tx_admitted_ba_record) :
                                        (&ts->tx_pending_ba_record),
-                                        TxRxSelect, DELBA_REASON_END_BA);
-       } else if (TxRxSelect == RX_DIR) {
+                                        tx_rx_select, DELBA_REASON_END_BA);
+       } else if (tx_rx_select == RX_DIR) {
                struct rx_ts_record *ts =
                                 (struct rx_ts_record *)ts_common_info;
                if (rx_ts_delete_ba(ieee, ts))
                        rtllib_send_DELBA(ieee, ts_common_info->addr,
                                          &ts->rx_admitted_ba_record,
-                                         TxRxSelect, DELBA_REASON_END_BA);
+                                         tx_rx_select, DELBA_REASON_END_BA);
        }
 }
 
index 68577bffb936d079279e95ac4ee8e372da6c34d4..a4580445305d91767f6e1344b0d38f7e4aba3f67 100644 (file)
@@ -98,9 +98,9 @@ struct rt_hi_throughput {
        u8 cur_short_gi_40mhz;
        u8 cur_short_gi_20mhz;
        enum ht_spec_ver peer_ht_spec_ver;
-       struct ht_capab_ele SelfHTCap;
-       u8 PeerHTCapBuf[32];
-       u8 PeerHTInfoBuf[32];
+       struct ht_capab_ele self_ht_cap;
+       u8 peer_ht_cap_buf[32];
+       u8 peer_ht_info_buf[32];
        u8 ampdu_enable;
        u8 current_ampdu_enable;
        u8 ampdu_factor;
index 6d0912f90198f463685e9788f480f1efe6ae187f..fa96a2c2c9161cd44de197e8599a9edc294931ae 100644 (file)
@@ -252,7 +252,7 @@ void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap,
        }
 
        cap_ele->AdvCoding              = 0;
-       if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
+       if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev))
                cap_ele->ChlWidth = 0;
        else
                cap_ele->ChlWidth = 1;
@@ -301,7 +301,7 @@ void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap,
                if (ht->iot_action & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI)
                        cap_ele->ShortGI40Mhz           = 0;
 
-               if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) {
+               if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) {
                        cap_ele->ChlWidth = 0;
                        cap_ele->MCS[1] = 0;
                }
@@ -408,7 +408,7 @@ static u8 ht_filter_mcs_rate(struct rtllib_device *ieee, u8 *pSupportMCS,
 
        ht_pick_mcs_rate(ieee, pOperateMCS);
 
-       if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
+       if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev))
                pOperateMCS[1] = 0;
 
        for (i = 2; i <= 15; i++)
@@ -437,16 +437,16 @@ void ht_on_assoc_rsp(struct rtllib_device *ieee)
        }
        netdev_dbg(ieee->dev, "%s(): HT_ENABLE\n", __func__);
 
-       if (!memcmp(ht_info->PeerHTCapBuf, EWC11NHTCap, sizeof(EWC11NHTCap)))
-               pPeerHTCap = (struct ht_capab_ele *)(&ht_info->PeerHTCapBuf[4]);
+       if (!memcmp(ht_info->peer_ht_cap_buf, EWC11NHTCap, sizeof(EWC11NHTCap)))
+               pPeerHTCap = (struct ht_capab_ele *)(&ht_info->peer_ht_cap_buf[4]);
        else
-               pPeerHTCap = (struct ht_capab_ele *)(ht_info->PeerHTCapBuf);
+               pPeerHTCap = (struct ht_capab_ele *)(ht_info->peer_ht_cap_buf);
 
-       if (!memcmp(ht_info->PeerHTInfoBuf, EWC11NHTInfo, sizeof(EWC11NHTInfo)))
+       if (!memcmp(ht_info->peer_ht_info_buf, EWC11NHTInfo, sizeof(EWC11NHTInfo)))
                pPeerHTInfo = (struct ht_info_ele *)
-                            (&ht_info->PeerHTInfoBuf[4]);
+                            (&ht_info->peer_ht_info_buf[4]);
        else
-               pPeerHTInfo = (struct ht_info_ele *)(ht_info->PeerHTInfoBuf);
+               pPeerHTInfo = (struct ht_info_ele *)(ht_info->peer_ht_info_buf);
 
 #ifdef VERBOSE_DEBUG
        print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE,
@@ -480,9 +480,9 @@ void ht_on_assoc_rsp(struct rtllib_device *ieee)
        }
 
        ht_info->current_mpdu_density = pPeerHTCap->MPDUDensity;
-       if (ht_info->iot_action & HT_IOT_ACT_TX_USE_AMSDU_8K) {
+       if (ht_info->iot_action & HT_IOT_ACT_TX_USE_AMSDU_8K)
                ht_info->current_ampdu_enable = false;
-       }
+
        ht_info->cur_rx_reorder_enable = 1;
 
        if (pPeerHTCap->MCS[0] == 0)
@@ -516,12 +516,12 @@ void ht_initialize_ht_info(struct rtllib_device *ieee)
        ht_info->current_mpdu_density = 0;
        ht_info->CurrentAMPDUFactor = ht_info->ampdu_factor;
 
-       memset((void *)(&ht_info->SelfHTCap), 0,
-              sizeof(ht_info->SelfHTCap));
-       memset((void *)(&ht_info->PeerHTCapBuf), 0,
-              sizeof(ht_info->PeerHTCapBuf));
-       memset((void *)(&ht_info->PeerHTInfoBuf), 0,
-              sizeof(ht_info->PeerHTInfoBuf));
+       memset((void *)(&ht_info->self_ht_cap), 0,
+              sizeof(ht_info->self_ht_cap));
+       memset((void *)(&ht_info->peer_ht_cap_buf), 0,
+              sizeof(ht_info->peer_ht_cap_buf));
+       memset((void *)(&ht_info->peer_ht_info_buf), 0,
+              sizeof(ht_info->peer_ht_info_buf));
 
        ht_info->sw_bw_in_progress = false;
 
@@ -572,15 +572,15 @@ void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee,
                ht_info->peer_ht_spec_ver = pNetwork->bssht.bd_ht_spec_ver;
 
                if (pNetwork->bssht.bd_ht_cap_len > 0 &&
-                   pNetwork->bssht.bd_ht_cap_len <= sizeof(ht_info->PeerHTCapBuf))
-                       memcpy(ht_info->PeerHTCapBuf,
+                   pNetwork->bssht.bd_ht_cap_len <= sizeof(ht_info->peer_ht_cap_buf))
+                       memcpy(ht_info->peer_ht_cap_buf,
                               pNetwork->bssht.bd_ht_cap_buf,
                               pNetwork->bssht.bd_ht_cap_len);
 
                if (pNetwork->bssht.bd_ht_info_len > 0 &&
                    pNetwork->bssht.bd_ht_info_len <=
-                   sizeof(ht_info->PeerHTInfoBuf))
-                       memcpy(ht_info->PeerHTInfoBuf,
+                   sizeof(ht_info->peer_ht_info_buf))
+                       memcpy(ht_info->peer_ht_info_buf,
                               pNetwork->bssht.bd_ht_info_buf,
                               pNetwork->bssht.bd_ht_info_len);
 
@@ -666,7 +666,7 @@ void ht_set_connect_bw_mode(struct rtllib_device *ieee,
 {
        struct rt_hi_throughput *ht_info = ieee->ht_info;
 
-       if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
+       if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev))
                bandwidth = HT_CHANNEL_WIDTH_20;
 
        if (ht_info->sw_bw_in_progress) {
index 50e01ca49a4ce5bf17004f3ac74e33ec60082689..dc991100742f43353ff848193916964460e68afc 100644 (file)
@@ -13,7 +13,7 @@ struct qos_tsinfo {
 };
 
 struct octet_string {
-       u8 *Octet;
+       u8 *octet;
        u16 Length;
 };
 
index 7e73d31dcccfcf1f5cc5d20bc24bdb4ecb45d02d..9903fe3f3c77cbfba74b72579bb22d859963a030 100644 (file)
@@ -171,14 +171,14 @@ void rtllib_ts_init(struct rtllib_device *ieee)
 
 static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
                                                  u8 *addr, u8 TID,
-                                                 enum tr_select TxRxSelect)
+                                                 enum tr_select tx_rx_select)
 {
        u8      dir;
        bool    search_dir[4] = {0};
        struct list_head *psearch_list;
        struct ts_common_info *pRet = NULL;
 
-       if (TxRxSelect == TX_DIR) {
+       if (tx_rx_select == TX_DIR) {
                search_dir[DIR_UP] = true;
                search_dir[DIR_BI_DIR] = true;
                search_dir[DIR_DIRECT] = true;
@@ -188,7 +188,7 @@ static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
                search_dir[DIR_DIRECT] = true;
        }
 
-       if (TxRxSelect == TX_DIR)
+       if (tx_rx_select == TX_DIR)
                psearch_list = &ieee->Tx_TS_Admit_List;
        else
                psearch_list = &ieee->Rx_TS_Admit_List;
@@ -225,7 +225,7 @@ static void MakeTSEntry(struct ts_common_info *ts_common_info, u8 *addr,
 }
 
 bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
-          u8 *addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
+          u8 *addr, u8 TID, enum tr_select tx_rx_select, bool bAddNewTs)
 {
        u8      UP = 0;
        struct qos_tsinfo tspec;
@@ -265,7 +265,7 @@ bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
                }
        }
 
-       *ppTS = SearchAdmitTRStream(ieee, addr, UP, TxRxSelect);
+       *ppTS = SearchAdmitTRStream(ieee, addr, UP, tx_rx_select);
        if (*ppTS)
                return true;
 
@@ -274,21 +274,21 @@ bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
                return false;
        }
 
-       pUnusedList = (TxRxSelect == TX_DIR) ?
+       pUnusedList = (tx_rx_select == TX_DIR) ?
                                (&ieee->Tx_TS_Unused_List) :
                                (&ieee->Rx_TS_Unused_List);
 
-       pAddmitList = (TxRxSelect == TX_DIR) ?
+       pAddmitList = (tx_rx_select == TX_DIR) ?
                                (&ieee->Tx_TS_Admit_List) :
                                (&ieee->Rx_TS_Admit_List);
 
-       Dir = ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
+       Dir = ((tx_rx_select == TX_DIR) ? DIR_UP : DIR_DOWN);
 
        if (!list_empty(pUnusedList)) {
                (*ppTS) = list_entry(pUnusedList->next,
                          struct ts_common_info, list);
                list_del_init(&(*ppTS)->list);
-               if (TxRxSelect == TX_DIR) {
+               if (tx_rx_select == TX_DIR) {
                        struct tx_ts_record *tmp =
                                container_of(*ppTS,
                                struct tx_ts_record,
@@ -321,11 +321,11 @@ bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
 }
 
 static void RemoveTsEntry(struct rtllib_device *ieee,
-                         struct ts_common_info *pTs, enum tr_select TxRxSelect)
+                         struct ts_common_info *pTs, enum tr_select tx_rx_select)
 {
-       rtllib_ts_init_del_ba(ieee, pTs, TxRxSelect);
+       rtllib_ts_init_del_ba(ieee, pTs, tx_rx_select);
 
-       if (TxRxSelect == RX_DIR) {
+       if (tx_rx_select == RX_DIR) {
                struct rx_reorder_entry *pRxReorderEntry;
                struct rx_ts_record *ts = (struct rx_ts_record *)pTs;
 
@@ -360,7 +360,7 @@ static void RemoveTsEntry(struct rtllib_device *ieee,
        }
 }
 
-void RemovePeerTS(struct rtllib_device *ieee, u8 *addr)
+void remove_peer_ts(struct rtllib_device *ieee, u8 *addr)
 {
        struct ts_common_info *ts, *pTmpTS;
 
@@ -400,9 +400,9 @@ void RemovePeerTS(struct rtllib_device *ieee, u8 *addr)
                }
        }
 }
-EXPORT_SYMBOL(RemovePeerTS);
+EXPORT_SYMBOL(remove_peer_ts);
 
-void RemoveAllTS(struct rtllib_device *ieee)
+void remove_all_ts(struct rtllib_device *ieee)
 {
        struct ts_common_info *ts, *pTmpTS;
 
index 7b39a1987fdd69183ee45476d33b1cd6e8568271..6fbf11ac168f5d98c7e6ca8bdbea80cf2bd0b2c0 100644 (file)
@@ -123,7 +123,7 @@ struct cb_desc {
        u8 bPacketBW:1;
        u8 bRTSUseShortPreamble:1;
        u8 bRTSUseShortGI:1;
-       u8 bMulticast:1;
+       u8 multicast:1;
        u8 bBroadcast:1;
        u8 drv_agg_enable:1;
        u8 reserved2:1;
@@ -474,47 +474,30 @@ struct rtllib_rx_stats {
        u8  control;
        u8  mask;
        u16 len;
-       u64 tsf;
-       u32 beacon_time;
-       u8  nic_type;
        u16 Length;
        u8  SignalQuality;
        s32 RecvSignalPower;
-       s8  RxPower;
        u8  SignalStrength;
        u16 bHwError:1;
        u16 bCRC:1;
        u16 bICV:1;
-       u16 bShortPreamble:1;
-       u16 Antenna:1;
        u16 Decrypted:1;
-       u16 Wakeup:1;
-       u16 Reserved0:1;
-       u8  AGC;
        u32 TimeStampLow;
        u32 TimeStampHigh;
-       bool bShift;
-       bool bIsQosData;
 
        u8    RxDrvInfoSize;
        u8    RxBufShift;
        bool  bIsAMPDU;
        bool  bFirstMPDU;
        bool  bContainHTC;
-       bool  RxIs40MHzPacket;
        u32   RxPWDBAll;
        u8    RxMIMOSignalStrength[4];
        s8    RxMIMOSignalQuality[2];
        bool  bPacketMatchBSSID;
        bool  bIsCCK;
        bool  bPacketToSelf;
-       u16    packetlength;
-       u16    fraglength;
-       u16    fragoffset;
-       u16    ntotalfrag;
        bool   bPacketBeacon;
        bool   bToSelfBA;
-       u16    Seq_Num;
 };
 
 /* IEEE 802.11 requires that STA supports concurrent reception of at least
@@ -928,14 +911,14 @@ struct rtllib_network {
        struct rtllib_qos_data qos_data;
 
        bool    bWithAironetIE;
-       bool    bCkipSupported;
-       bool    bCcxRmEnable;
+       bool    ckip_supported;
+       bool    ccx_rm_enable;
        u8      CcxRmState[2];
        bool    bMBssidValid;
        u8      MBssidMask;
        u8      MBssid[ETH_ALEN];
        bool    bWithCcxVerNum;
-       u8      BssCcxVerNumber;
+       u8      bss_ccx_ver_number;
        /* These are network statistics */
        struct rtllib_rx_stats stats;
        u16 capability;
@@ -965,7 +948,7 @@ struct rtllib_network {
 
        u8 wmm_info;
        struct rtllib_wmm_ac_param wmm_param[4];
-       u8 Turbo_Enable;
+       u8 turbo_enable;
        u16 CountryIeLen;
        u8 CountryIeBuf[MAX_IE_LEN];
        struct bss_ht bssht;
@@ -1048,9 +1031,9 @@ struct rx_reorder_entry {
 };
 
 enum fsync_state {
-       Default_Fsync,
-       HW_Fsync,
-       SW_Fsync
+       DEFAULT_FSYNC,
+       HW_FSYNC,
+       SW_FSYNC
 };
 
 enum ips_callback_function {
@@ -1071,8 +1054,8 @@ struct rt_pwr_save_ctrl {
        enum ips_callback_function ReturnPoint;
 
        bool                            bLeisurePs;
-       u8                              LpsIdleCount;
-       u8                              LPSAwakeIntvl;
+       u8                              lps_idle_count;
+       u8                              lps_awake_intvl;
 
        u32                             CurPsLevel;
 };
@@ -1110,18 +1093,18 @@ enum scan_op_backup_opt {
 
 #define RT_MAX_LD_SLOT_NUM     10
 struct rt_link_detect {
-       u32                             NumRecvBcnInPeriod;
-       u32                             NumRecvDataInPeriod;
+       u32                             num_recv_bcn_in_period;
+       u32                             num_recv_data_in_period;
 
        u32                             RxBcnNum[RT_MAX_LD_SLOT_NUM];
        u32                             RxDataNum[RT_MAX_LD_SLOT_NUM];
-       u16                             SlotNum;
-       u16                             SlotIndex;
+       u16                             slot_num;
+       u16                             slot_index;
 
        u32                             num_tx_ok_in_period;
        u32                             num_rx_ok_in_period;
-       u32                             NumRxUnicastOkInPeriod;
-       bool                            bBusyTraffic;
+       u32                             num_rx_unicast_ok_in_period;
+       bool                            busy_traffic;
        bool                            bHigherBusyTraffic;
        bool                            bHigherBusyRxTraffic;
 };
@@ -1161,7 +1144,7 @@ struct rate_adaptive {
 
 #define        NUM_PMKID_CACHE         16
 struct rt_pmkid_list {
-       u8 Bssid[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
        u8 PMKID[16];
        u8 SsidBuf[33];
        u8 used;
@@ -1193,7 +1176,7 @@ struct rtllib_device {
        u8 *assocreq_ies, *assocresp_ies;
        size_t assocreq_ies_len, assocresp_ies_len;
 
-       bool    bForcedBgMode;
+       bool    forced_bg_mode;
 
        u8 hwsec_active;
        bool is_roaming;
@@ -1201,7 +1184,7 @@ struct rtllib_device {
        bool cannot_notify;
        bool bSupportRemoteWakeUp;
        bool actscanning;
-       bool FirstIe_InScan;
+       bool first_ie_in_scan;
        bool be_scan_inprogress;
        bool beinretry;
        enum rt_rf_power_state rf_power_state;
@@ -1264,7 +1247,7 @@ struct rtllib_device {
        int ieee802_1x; /* is IEEE 802.1X used */
 
        /* WPA data */
-       bool bHalfWirelessN24GMode;
+       bool half_wireless_n24g_mode;
        int wpa_enabled;
        int drop_unencrypted;
        int tkip_countermeasures;
@@ -1281,7 +1264,7 @@ struct rtllib_device {
 
        struct sw_cam_table swcamtable[TOTAL_CAM_ENTRY];
 
-       struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE];
+       struct rt_pmkid_list pmkid_list[NUM_PMKID_CACHE];
 
        /* Fragmentation structures */
        struct rtllib_frag_entry frag_cache[17][RTLLIB_FRAG_CACHE_LEN];
@@ -1374,14 +1357,14 @@ struct rtllib_device {
 
        /* for PS mode */
        unsigned long last_rx_ps_time;
-       bool                    bAwakePktSent;
-       u8                      LPSDelayCnt;
+       bool                    awake_pkt_sent;
+       u8                      lps_delay_cnt;
 
        /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */
        struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM];
        int mgmt_queue_head;
        int mgmt_queue_tail;
-       u8 AsocRetryCount;
+       u8 asoc_retry_count;
        struct sk_buff_head skb_waitq[MAX_QUEUE_SIZE];
 
        bool    bdynamic_txpower_enable;
@@ -1484,17 +1467,18 @@ struct rtllib_device {
        void (*set_bw_mode_handler)(struct net_device *dev,
                                    enum ht_channel_width bandwidth,
                                    enum ht_extchnl_offset Offset);
-       bool (*GetNmodeSupportBySecCfg)(struct net_device *dev);
+       bool (*get_nmode_support_by_sec_cfg)(struct net_device *dev);
        void (*set_wireless_mode)(struct net_device *dev, u8 wireless_mode);
-       bool (*GetHalfNmodeSupportByAPsHandler)(struct net_device *dev);
+       bool (*get_half_nmode_support_by_aps_handler)(struct net_device *dev);
        u8   (*rtllib_ap_sec_type)(struct rtllib_device *ieee);
        void (*init_gain_handler)(struct net_device *dev, u8 Operation);
        void (*ScanOperationBackupHandler)(struct net_device *dev,
                                           u8 Operation);
-       void (*SetHwRegHandler)(struct net_device *dev, u8 variable, u8 *val);
+       void (*set_hw_reg_handler)(struct net_device *dev, u8 variable, u8 *val);
 
-       void (*AllowAllDestAddrHandler)(struct net_device *dev,
-                                       bool bAllowAllDA, bool WriteIntoReg);
+       void (*allow_all_dest_addr_handler)(struct net_device *dev,
+                                           bool bAllowAllDA,
+                                           bool WriteIntoReg);
 
        void (*rtllib_ips_leave_wq)(struct net_device *dev);
        void (*rtllib_ips_leave)(struct net_device *dev);
@@ -1662,7 +1646,7 @@ int rtllib_rx_frame_softmac(struct rtllib_device *ieee, struct sk_buff *skb,
 void rtllib_softmac_new_net(struct rtllib_device *ieee,
                            struct rtllib_network *net);
 
-void SendDisassociation(struct rtllib_device *ieee, bool deauth, u16 asRsn);
+void send_disassociation(struct rtllib_device *ieee, bool deauth, u16 rsn);
 void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee);
 
 int rtllib_softmac_init(struct rtllib_device *ieee);
@@ -1771,25 +1755,25 @@ u8 ht_c_check(struct rtllib_device *ieee, u8 *pFrame);
 void ht_reset_iot_setting(struct rt_hi_throughput *ht_info);
 bool is_ht_half_nmode_aps(struct rtllib_device *ieee);
 u16  tx_count_to_data_rate(struct rtllib_device *ieee, u8 nDataRate);
-int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb);
-int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb);
+int rtllib_rx_add_ba_req(struct rtllib_device *ieee, struct sk_buff *skb);
+int rtllib_rx_add_ba_rsp(struct rtllib_device *ieee, struct sk_buff *skb);
 int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb);
 void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
                           u8 policy, u8 overwrite_pending);
 void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
                           struct ts_common_info *ts_common_info,
-                          enum tr_select TxRxSelect);
+                          enum tr_select tx_rx_select);
 void rtllib_ba_setup_timeout(struct timer_list *t);
 void rtllib_tx_ba_inact_timeout(struct timer_list *t);
 void rtllib_rx_ba_inact_timeout(struct timer_list *t);
 void rtllib_reset_ba_entry(struct ba_record *ba);
 bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS, u8 *addr,
-          u8 TID, enum tr_select TxRxSelect, bool bAddNewTs);
+          u8 TID, enum tr_select tx_rx_select, bool bAddNewTs);
 void rtllib_ts_init(struct rtllib_device *ieee);
 void TsStartAddBaProcess(struct rtllib_device *ieee,
                         struct tx_ts_record *pTxTS);
-void RemovePeerTS(struct rtllib_device *ieee, u8 *addr);
-void RemoveAllTS(struct rtllib_device *ieee);
+void remove_peer_ts(struct rtllib_device *ieee, u8 *addr);
+void remove_all_ts(struct rtllib_device *ieee);
 
 static inline const char *escape_essid(const char *essid, u8 essid_len)
 {
@@ -1805,13 +1789,13 @@ static inline const char *escape_essid(const char *essid, u8 essid_len)
 }
 
 /* fun with the built-in rtllib stack... */
-bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn);
+bool rtllib_mgnt_disconnect(struct rtllib_device *rtllib, u8 rsn);
 
 /* For the function is more related to hardware setting, it's better to use the
  * ieee handler to refer to it.
  */
-void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee,
-                                struct rx_ts_record *ts);
+void rtllib_flush_rx_ts_pending_pkts(struct rtllib_device *ieee,
+                                    struct rx_ts_record *ts);
 int rtllib_parse_info_param(struct rtllib_device *ieee,
                            struct rtllib_info_element *info_element,
                            u16 length,
@@ -1821,6 +1805,6 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
 void rtllib_indicate_packets(struct rtllib_device *ieee,
                             struct rtllib_rxb **prxbIndicateArray, u8  index);
 #define RT_ASOC_RETRY_LIMIT    5
-u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee);
+u8 mgnt_query_tx_rate_exclude_cck_rates(struct rtllib_device *ieee);
 
 #endif /* RTLLIB_H */
index 4df20f4d6bf919140c95946b8cd5cf65ea8b361e..ebf8a2fd36d354e43a1d15da67e34eca0b9d8194 100644 (file)
@@ -487,8 +487,8 @@ void rtllib_indicate_packets(struct rtllib_device *ieee,
        }
 }
 
-void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee,
-                                struct rx_ts_record *ts)
+void rtllib_flush_rx_ts_pending_pkts(struct rtllib_device *ieee,
+                                    struct rx_ts_record *ts)
 {
        struct rx_reorder_entry *pRxReorderEntry;
        u8 RfdCnt = 0;
@@ -865,9 +865,6 @@ static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee,
                rx_stats->bContainHTC = true;
        }
 
-       if (RTLLIB_QOS_HAS_SEQ(fc))
-               rx_stats->bIsQosData = true;
-
        return hdrlen;
 }
 
@@ -943,10 +940,9 @@ static void rtllib_rx_extract_addr(struct rtllib_device *ieee,
 static int rtllib_rx_data_filter(struct rtllib_device *ieee, struct ieee80211_hdr *hdr,
                                 u8 *dst, u8 *src, u8 *bssid, u8 *addr2)
 {
-       u8 type, stype;
        u16 fc = le16_to_cpu(hdr->frame_control);
-       type = WLAN_FC_GET_TYPE(fc);
-       stype = WLAN_FC_GET_STYPE(fc);
+       u8 type = WLAN_FC_GET_TYPE(fc);
+       u8 stype = WLAN_FC_GET_STYPE(fc);
 
        /* Filter frames from different BSS */
        if (ieee80211_has_a4(hdr->frame_control) &&
@@ -1149,9 +1145,9 @@ static void rtllib_rx_check_leave_lps(struct rtllib_device *ieee, u8 unicast,
 {
        if (unicast) {
                if (ieee->link_state == MAC80211_LINKED) {
-                       if (((ieee->link_detect_info.NumRxUnicastOkInPeriod +
+                       if (((ieee->link_detect_info.num_rx_unicast_ok_in_period +
                            ieee->link_detect_info.num_tx_ok_in_period) > 8) ||
-                           (ieee->link_detect_info.NumRxUnicastOkInPeriod > 2)) {
+                           (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2)) {
                                ieee->leisure_ps_leave(ieee->dev);
                        }
                }
@@ -1284,7 +1280,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
        /* Filter WAPI DATA Frame */
 
        /* Update statstics for AP roaming */
-       ieee->link_detect_info.NumRecvDataInPeriod++;
+       ieee->link_detect_info.num_recv_data_in_period++;
        ieee->link_detect_info.num_rx_ok_in_period++;
 
        /* Data frame - extract src/dst addresses */
@@ -1363,7 +1359,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
        else
                nr_subframes = 1;
        if (unicast)
-               ieee->link_detect_info.NumRxUnicastOkInPeriod += nr_subframes;
+               ieee->link_detect_info.num_rx_unicast_ok_in_period += nr_subframes;
        rtllib_rx_check_leave_lps(ieee, unicast, nr_subframes);
 
        /* Indicate packets to upper layer or Rx Reorder */
@@ -1689,7 +1685,7 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
            info_element->data[2] == 0x4c &&
            info_element->data[3] == 0x01 &&
            info_element->data[4] == 0x02)
-               network->Turbo_Enable = 1;
+               network->turbo_enable = 1;
 
        if (*tmp_htcap_len == 0) {
                if (info_element->len >= 4 &&
@@ -1819,9 +1815,9 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
                if (info_element->len == 6) {
                        memcpy(network->CcxRmState, &info_element->data[4], 2);
                        if (network->CcxRmState[0] != 0)
-                               network->bCcxRmEnable = true;
+                               network->ccx_rm_enable = true;
                        else
-                               network->bCcxRmEnable = false;
+                               network->ccx_rm_enable = false;
                        network->MBssidMask = network->CcxRmState[1] & 0x07;
                        if (network->MBssidMask != 0) {
                                network->bMBssidValid = true;
@@ -1834,7 +1830,7 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
                                network->bMBssidValid = false;
                        }
                } else {
-                       network->bCcxRmEnable = false;
+                       network->ccx_rm_enable = false;
                }
        }
        if (info_element->len > 4  &&
@@ -1844,10 +1840,10 @@ static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
            info_element->data[3] == 0x03) {
                if (info_element->len == 5) {
                        network->bWithCcxVerNum = true;
-                       network->BssCcxVerNumber = info_element->data[4];
+                       network->bss_ccx_ver_number = info_element->data[4];
                } else {
                        network->bWithCcxVerNum = false;
-                       network->BssCcxVerNumber = 0;
+                       network->bss_ccx_ver_number = 0;
                }
        }
        if (info_element->len > 4  &&
@@ -2100,12 +2096,12 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
                                     & SUPPORT_CKIP_MIC) ||
                                     (info_element->data[IE_CISCO_FLAG_POSITION]
                                     & SUPPORT_CKIP_PK))
-                                       network->bCkipSupported = true;
+                                       network->ckip_supported = true;
                                else
-                                       network->bCkipSupported = false;
+                                       network->ckip_supported = false;
                        } else {
                                network->bWithAironetIE = false;
-                               network->bCkipSupported = false;
+                               network->ckip_supported = false;
                        }
                        break;
                case MFIE_TYPE_QOS_PARAMETER:
@@ -2184,7 +2180,7 @@ static inline int rtllib_network_init(
        network->realtek_cap_exit = false;
        network->marvell_cap_exist = false;
        network->airgo_cap_exist = false;
-       network->Turbo_Enable = 0;
+       network->turbo_enable = 0;
        network->SignalStrength = stats->SignalStrength;
        network->RSSI = stats->SignalStrength;
        network->CountryIeLen = 0;
@@ -2344,20 +2340,20 @@ static inline void update_network(struct rtllib_device *ieee,
 
        dst->SignalStrength = src->SignalStrength;
        dst->RSSI = src->RSSI;
-       dst->Turbo_Enable = src->Turbo_Enable;
+       dst->turbo_enable = src->turbo_enable;
 
        dst->CountryIeLen = src->CountryIeLen;
        memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen);
 
        dst->bWithAironetIE = src->bWithAironetIE;
-       dst->bCkipSupported = src->bCkipSupported;
+       dst->ckip_supported = src->ckip_supported;
        memcpy(dst->CcxRmState, src->CcxRmState, 2);
-       dst->bCcxRmEnable = src->bCcxRmEnable;
+       dst->ccx_rm_enable = src->ccx_rm_enable;
        dst->MBssidMask = src->MBssidMask;
        dst->bMBssidValid = src->bMBssidValid;
        memcpy(dst->MBssid, src->MBssid, 6);
        dst->bWithCcxVerNum = src->bWithCcxVerNum;
-       dst->BssCcxVerNumber = src->BssCcxVerNumber;
+       dst->bss_ccx_ver_number = src->bss_ccx_ver_number;
 }
 
 static int IsPassiveChannel(struct rtllib_device *rtllib, u8 channel)
@@ -2470,7 +2466,7 @@ static inline void rtllib_process_probe_response(
                }
                if (ieee80211_is_beacon(frame_ctl)) {
                        if (ieee->link_state >= MAC80211_LINKED)
-                               ieee->link_detect_info.NumRecvBcnInPeriod++;
+                               ieee->link_detect_info.num_recv_bcn_in_period++;
                }
        }
        list_for_each_entry(target, &ieee->network_list, list) {
index b9278b26accd854fc1a790ab87997ba42b4c3137..97fdca828da70dd8bb41cede0db142cab98efa60 100644 (file)
@@ -138,7 +138,7 @@ static void init_mgmt_queue(struct rtllib_device *ieee)
        ieee->mgmt_queue_head = 0;
 }
 
-u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee)
+u8 mgnt_query_tx_rate_exclude_cck_rates(struct rtllib_device *ieee)
 {
        u16     i;
        u8      query_rate = 0;
@@ -163,7 +163,7 @@ u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee)
        return query_rate;
 }
 
-static u8 MgntQuery_MgntFrameTxRate(struct rtllib_device *ieee)
+static u8 mgnt_query_mgnt_frame_tx_rate(struct rtllib_device *ieee)
 {
        struct rt_hi_throughput *ht_info = ieee->ht_info;
        u8 rate;
@@ -201,7 +201,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee)
        if (ieee->disable_mgnt_queue)
                tcb_desc->queue_index = HIGH_QUEUE;
 
-       tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee);
+       tcb_desc->data_rate = mgnt_query_mgnt_frame_tx_rate(ieee);
        tcb_desc->ratr_index = 7;
        tcb_desc->tx_dis_rate_fallback = 1;
        tcb_desc->tx_use_drv_assinged_rate = 1;
@@ -277,7 +277,7 @@ softmac_ps_mgmt_xmit(struct sk_buff *skb,
        if (ieee->disable_mgnt_queue)
                tcb_desc->queue_index = HIGH_QUEUE;
 
-       tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee);
+       tcb_desc->data_rate = mgnt_query_mgnt_frame_tx_rate(ieee);
        tcb_desc->ratr_index = 7;
        tcb_desc->tx_dis_rate_fallback = 1;
        tcb_desc->tx_use_drv_assinged_rate = 1;
@@ -355,20 +355,19 @@ void rtllib_enable_net_monitor_mode(struct net_device *dev,
 
        netdev_info(dev, "========>Enter Monitor Mode\n");
 
-       ieee->AllowAllDestAddrHandler(dev, true, !init_state);
+       ieee->allow_all_dest_addr_handler(dev, true, !init_state);
 }
 
 /* Disables network monitor mode. Only packets destinated to
  * us will be received.
  */
-void rtllib_disable_net_monitor_mode(struct net_device *dev,
-               bool init_state)
+void rtllib_disable_net_monitor_mode(struct net_device *dev, bool init_state)
 {
        struct rtllib_device *ieee = netdev_priv_rsl(dev);
 
        netdev_info(dev, "========>Exit Monitor Mode\n");
 
-       ieee->AllowAllDestAddrHandler(dev, false, !init_state);
+       ieee->allow_all_dest_addr_handler(dev, false, !init_state);
 }
 
 static void rtllib_send_probe(struct rtllib_device *ieee)
@@ -665,13 +664,13 @@ static struct sk_buff *rtllib_pspoll_func(struct rtllib_device *ieee)
        return skb;
 }
 
-static inline int SecIsInPMKIDList(struct rtllib_device *ieee, u8 *bssid)
+static inline int sec_is_in_pmkid_list(struct rtllib_device *ieee, u8 *bssid)
 {
        int i = 0;
 
        do {
-               if ((ieee->PMKIDList[i].used) &&
-                  (memcmp(ieee->PMKIDList[i].Bssid, bssid, ETH_ALEN) == 0))
+               if ((ieee->pmkid_list[i].used) &&
+                   (memcmp(ieee->pmkid_list[i].bssid, bssid, ETH_ALEN) == 0))
                        break;
                i++;
        } while (i < NUM_PMKID_CACHE);
@@ -700,7 +699,7 @@ rtllib_association_req(struct rtllib_network *beacon,
        unsigned int cxvernum_ie_len = 0;
        struct lib80211_crypt_data *crypt;
        int encrypt;
-       int     PMKCacheIdx;
+       int     pmk_cache_idx;
 
        unsigned int rate_len = (beacon->rates_len ?
                                (beacon->rates_len + 2) : 0) +
@@ -708,7 +707,7 @@ rtllib_association_req(struct rtllib_network *beacon,
                                2 : 0);
 
        unsigned int wmm_info_len = beacon->qos_data.supported ? 9 : 0;
-       unsigned int turbo_info_len = beacon->Turbo_Enable ? 9 : 0;
+       unsigned int turbo_info_len = beacon->turbo_enable ? 9 : 0;
 
        int len = 0;
 
@@ -722,14 +721,14 @@ rtllib_association_req(struct rtllib_network *beacon,
 
        if ((ieee->rtllib_ap_sec_type &&
            (ieee->rtllib_ap_sec_type(ieee) & SEC_ALG_TKIP)) ||
-           ieee->bForcedBgMode) {
+           ieee->forced_bg_mode) {
                ieee->ht_info->enable_ht = 0;
                ieee->mode = WIRELESS_MODE_G;
        }
 
        if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
-               ht_cap_buf = (u8 *)&ieee->ht_info->SelfHTCap;
-               ht_cap_len = sizeof(ieee->ht_info->SelfHTCap);
+               ht_cap_buf = (u8 *)&ieee->ht_info->self_ht_cap;
+               ht_cap_len = sizeof(ieee->ht_info->self_ht_cap);
                ht_construct_capability_element(ieee, ht_cap_buf, &ht_cap_len,
                                             encrypt, true);
                if (ieee->ht_info->current_rt2rt_aggregation) {
@@ -741,15 +740,15 @@ rtllib_association_req(struct rtllib_network *beacon,
                }
        }
 
-       if (beacon->bCkipSupported)
+       if (beacon->ckip_supported)
                ckip_ie_len = 30 + 2;
-       if (beacon->bCcxRmEnable)
+       if (beacon->ccx_rm_enable)
                ccxrm_ie_len = 6 + 2;
-       if (beacon->BssCcxVerNumber >= 2)
+       if (beacon->bss_ccx_ver_number >= 2)
                cxvernum_ie_len = 5 + 2;
 
-       PMKCacheIdx = SecIsInPMKIDList(ieee, ieee->current_network.bssid);
-       if (PMKCacheIdx >= 0) {
+       pmk_cache_idx = sec_is_in_pmkid_list(ieee, ieee->current_network.bssid);
+       if (pmk_cache_idx >= 0) {
                wpa_ie_len += 18;
                netdev_info(ieee->dev, "[PMK cache]: WPA2 IE length: %x\n",
                            wpa_ie_len);
@@ -818,52 +817,52 @@ rtllib_association_req(struct rtllib_network *beacon,
                        *tag++ = beacon->rates_ex[i];
        }
 
-       if (beacon->bCkipSupported) {
-               static const u8 AironetIeOui[] = {0x00, 0x01, 0x66};
-               u8      CcxAironetBuf[30];
-               struct octet_string osCcxAironetIE;
+       if (beacon->ckip_supported) {
+               static const u8 aironet_ie_oui[] = {0x00, 0x01, 0x66};
+               u8      ccx_aironet_buf[30];
+               struct octet_string os_ccx_aironet_ie;
 
-               memset(CcxAironetBuf, 0, 30);
-               osCcxAironetIE.Octet = CcxAironetBuf;
-               osCcxAironetIE.Length = sizeof(CcxAironetBuf);
-               memcpy(osCcxAironetIE.Octet, AironetIeOui,
-                      sizeof(AironetIeOui));
+               memset(ccx_aironet_buf, 0, 30);
+               os_ccx_aironet_ie.octet = ccx_aironet_buf;
+               os_ccx_aironet_ie.Length = sizeof(ccx_aironet_buf);
+               memcpy(os_ccx_aironet_ie.octet, aironet_ie_oui,
+                      sizeof(aironet_ie_oui));
 
-               osCcxAironetIE.Octet[IE_CISCO_FLAG_POSITION] |=
+               os_ccx_aironet_ie.octet[IE_CISCO_FLAG_POSITION] |=
                                         (SUPPORT_CKIP_PK | SUPPORT_CKIP_MIC);
                tag = skb_put(skb, ckip_ie_len);
                *tag++ = MFIE_TYPE_AIRONET;
-               *tag++ = osCcxAironetIE.Length;
-               memcpy(tag, osCcxAironetIE.Octet, osCcxAironetIE.Length);
-               tag += osCcxAironetIE.Length;
+               *tag++ = os_ccx_aironet_ie.Length;
+               memcpy(tag, os_ccx_aironet_ie.octet, os_ccx_aironet_ie.Length);
+               tag += os_ccx_aironet_ie.Length;
        }
 
-       if (beacon->bCcxRmEnable) {
-               static const u8 CcxRmCapBuf[] = {0x00, 0x40, 0x96, 0x01, 0x01,
+       if (beacon->ccx_rm_enable) {
+               static const u8 ccx_rm_cap_buf[] = {0x00, 0x40, 0x96, 0x01, 0x01,
                        0x00};
-               struct octet_string osCcxRmCap;
+               struct octet_string os_ccx_rm_cap;
 
-               osCcxRmCap.Octet = (u8 *)CcxRmCapBuf;
-               osCcxRmCap.Length = sizeof(CcxRmCapBuf);
+               os_ccx_rm_cap.octet = (u8 *)ccx_rm_cap_buf;
+               os_ccx_rm_cap.Length = sizeof(ccx_rm_cap_buf);
                tag = skb_put(skb, ccxrm_ie_len);
                *tag++ = MFIE_TYPE_GENERIC;
-               *tag++ = osCcxRmCap.Length;
-               memcpy(tag, osCcxRmCap.Octet, osCcxRmCap.Length);
-               tag += osCcxRmCap.Length;
+               *tag++ = os_ccx_rm_cap.Length;
+               memcpy(tag, os_ccx_rm_cap.octet, os_ccx_rm_cap.Length);
+               tag += os_ccx_rm_cap.Length;
        }
 
-       if (beacon->BssCcxVerNumber >= 2) {
-               u8 CcxVerNumBuf[] = {0x00, 0x40, 0x96, 0x03, 0x00};
-               struct octet_string osCcxVerNum;
+       if (beacon->bss_ccx_ver_number >= 2) {
+               u8 ccx_ver_num_buf[] = {0x00, 0x40, 0x96, 0x03, 0x00};
+               struct octet_string os_ccx_ver_num;
 
-               CcxVerNumBuf[4] = beacon->BssCcxVerNumber;
-               osCcxVerNum.Octet = CcxVerNumBuf;
-               osCcxVerNum.Length = sizeof(CcxVerNumBuf);
+               ccx_ver_num_buf[4] = beacon->bss_ccx_ver_number;
+               os_ccx_ver_num.octet = ccx_ver_num_buf;
+               os_ccx_ver_num.Length = sizeof(ccx_ver_num_buf);
                tag = skb_put(skb, cxvernum_ie_len);
                *tag++ = MFIE_TYPE_GENERIC;
-               *tag++ = osCcxVerNum.Length;
-               memcpy(tag, osCcxVerNum.Octet, osCcxVerNum.Length);
-               tag += osCcxVerNum.Length;
+               *tag++ = os_ccx_ver_num.Length;
+               memcpy(tag, os_ccx_ver_num.octet, os_ccx_ver_num.Length);
+               tag += os_ccx_ver_num.Length;
        }
        if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
                if (ieee->ht_info->peer_ht_spec_ver != HT_SPEC_VER_EWC) {
@@ -878,11 +877,11 @@ rtllib_association_req(struct rtllib_network *beacon,
        if (wpa_ie_len) {
                skb_put_data(skb, ieee->wpa_ie, ieee->wpa_ie_len);
 
-               if (PMKCacheIdx >= 0) {
+               if (pmk_cache_idx >= 0) {
                        tag = skb_put(skb, 18);
                        *tag = 1;
                        *(tag + 1) = 0;
-                       memcpy((tag + 2), &ieee->PMKIDList[PMKCacheIdx].PMKID,
+                       memcpy((tag + 2), &ieee->pmkid_list[pmk_cache_idx].PMKID,
                               16);
                }
        }
@@ -1072,17 +1071,16 @@ static void rtllib_associate_complete_wq(void *data)
                            ieee->ht_info->enable_ht);
                memset(ieee->dot11ht_oper_rate_set, 0, 16);
        }
-       ieee->link_detect_info.SlotNum = 2 * (1 +
+       ieee->link_detect_info.slot_num = 2 * (1 +
                                       ieee->current_network.beacon_interval /
                                       500);
-       if (ieee->link_detect_info.NumRecvBcnInPeriod == 0 ||
-           ieee->link_detect_info.NumRecvDataInPeriod == 0) {
-               ieee->link_detect_info.NumRecvBcnInPeriod = 1;
-               ieee->link_detect_info.NumRecvDataInPeriod = 1;
+       if (ieee->link_detect_info.num_recv_bcn_in_period == 0 ||
+           ieee->link_detect_info.num_recv_data_in_period == 0) {
+               ieee->link_detect_info.num_recv_bcn_in_period = 1;
+               ieee->link_detect_info.num_recv_data_in_period = 1;
        }
-       psc->LpsIdleCount = 0;
+       psc->lps_idle_count = 0;
        ieee->link_change(ieee->dev);
-
 }
 
 static void rtllib_sta_send_associnfo(struct rtllib_device *ieee)
@@ -1209,18 +1207,18 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
                                    ieee->current_network.flags);
 
                        if ((rtllib_act_scanning(ieee, false)) &&
-                          !(ieee->softmac_features & IEEE_SOFTMAC_SCAN))
+                           !(ieee->softmac_features & IEEE_SOFTMAC_SCAN))
                                rtllib_stop_scan_syncro(ieee);
 
                        ht_reset_iot_setting(ieee->ht_info);
                        ieee->wmm_acm = 0;
                        if (ieee->iw_mode == IW_MODE_INFRA) {
                                /* Join the network for the first time */
-                               ieee->AsocRetryCount = 0;
+                               ieee->asoc_retry_count = 0;
                                if ((ieee->current_network.qos_data.supported == 1) &&
                                    ieee->current_network.bssht.bd_support_ht)
                                        ht_reset_self_and_save_peer_setting(ieee,
-                                                &(ieee->current_network));
+                                                &ieee->current_network);
                                else
                                        ieee->ht_info->current_ht_support = false;
 
@@ -1319,10 +1317,10 @@ static inline u16 assoc_parse(struct rtllib_device *ieee, struct sk_buff *skb,
           status_code == WLAN_STATUS_CAPS_UNSUPPORTED) &&
           ((ieee->mode == WIRELESS_MODE_G) &&
           (ieee->current_network.mode == WIRELESS_MODE_N_24G) &&
-          (ieee->AsocRetryCount++ < (RT_ASOC_RETRY_LIMIT - 1)))) {
+          (ieee->asoc_retry_count++ < (RT_ASOC_RETRY_LIMIT - 1)))) {
                ieee->ht_info->iot_action |= HT_IOT_ACT_PURE_N_MODE;
        } else {
-               ieee->AsocRetryCount = 0;
+               ieee->asoc_retry_count = 0;
        }
 
        return le16_to_cpu(response_head->status);
@@ -1351,8 +1349,8 @@ static short rtllib_sta_ps_sleep(struct rtllib_device *ieee, u64 *time)
        u8 dtim;
        struct rt_pwr_save_ctrl *psc = &ieee->pwr_save_ctrl;
 
-       if (ieee->LPSDelayCnt) {
-               ieee->LPSDelayCnt--;
+       if (ieee->lps_delay_cnt) {
+               ieee->lps_delay_cnt--;
                return 0;
        }
 
@@ -1378,45 +1376,45 @@ static short rtllib_sta_ps_sleep(struct rtllib_device *ieee, u64 *time)
                return 0;
 
        if (time) {
-               if (ieee->bAwakePktSent) {
-                       psc->LPSAwakeIntvl = 1;
+               if (ieee->awake_pkt_sent) {
+                       psc->lps_awake_intvl = 1;
                } else {
-                       u8 MaxPeriod = 5;
+                       u8 max_period = 5;
 
-                       if (psc->LPSAwakeIntvl == 0)
-                               psc->LPSAwakeIntvl = 1;
-                       psc->LPSAwakeIntvl = (psc->LPSAwakeIntvl >=
-                                              MaxPeriod) ? MaxPeriod :
-                                              (psc->LPSAwakeIntvl + 1);
+                       if (psc->lps_awake_intvl == 0)
+                               psc->lps_awake_intvl = 1;
+                       psc->lps_awake_intvl = (psc->lps_awake_intvl >=
+                                              max_period) ? max_period :
+                                              (psc->lps_awake_intvl + 1);
                }
                {
-                       u8 LPSAwakeIntvl_tmp = 0;
+                       u8 lps_awake_intvl_tmp = 0;
                        u8 period = ieee->current_network.dtim_period;
                        u8 count = ieee->current_network.tim.tim_count;
 
                        if (count == 0) {
-                               if (psc->LPSAwakeIntvl > period)
-                                       LPSAwakeIntvl_tmp = period +
-                                                (psc->LPSAwakeIntvl -
+                               if (psc->lps_awake_intvl > period)
+                                       lps_awake_intvl_tmp = period +
+                                                (psc->lps_awake_intvl -
                                                 period) -
-                                                ((psc->LPSAwakeIntvl - period) %
+                                                ((psc->lps_awake_intvl - period) %
                                                 period);
                                else
-                                       LPSAwakeIntvl_tmp = psc->LPSAwakeIntvl;
+                                       lps_awake_intvl_tmp = psc->lps_awake_intvl;
 
                        } else {
-                               if (psc->LPSAwakeIntvl >
+                               if (psc->lps_awake_intvl >
                                    ieee->current_network.tim.tim_count)
-                                       LPSAwakeIntvl_tmp = count +
-                                       (psc->LPSAwakeIntvl - count) -
-                                       ((psc->LPSAwakeIntvl - count) % period);
+                                       lps_awake_intvl_tmp = count +
+                                       (psc->lps_awake_intvl - count) -
+                                       ((psc->lps_awake_intvl - count) % period);
                                else
-                                       LPSAwakeIntvl_tmp = psc->LPSAwakeIntvl;
+                                       lps_awake_intvl_tmp = psc->lps_awake_intvl;
                        }
 
                *time = ieee->current_network.last_dtim_sta_time
                        + msecs_to_jiffies(ieee->current_network.beacon_interval *
-                       LPSAwakeIntvl_tmp);
+                       lps_awake_intvl_tmp);
        }
        }
 
@@ -1461,7 +1459,7 @@ static inline void rtllib_sta_ps(struct work_struct *work)
                        spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
                }
 
-               ieee->bAwakePktSent = false;
+               ieee->awake_pkt_sent = false;
 
        } else if (sleep == 2) {
                spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
@@ -1553,10 +1551,10 @@ static void rtllib_process_action(struct rtllib_device *ieee,
        case ACT_CAT_BA:
                switch (*act) {
                case ACT_ADDBAREQ:
-                       rtllib_rx_ADDBAReq(ieee, skb);
+                       rtllib_rx_add_ba_req(ieee, skb);
                        break;
                case ACT_ADDBARSP:
-                       rtllib_rx_ADDBARsp(ieee, skb);
+                       rtllib_rx_add_ba_rsp(ieee, skb);
                        break;
                case ACT_DELBA:
                        rtllib_rx_DELBA(ieee, skb);
@@ -1606,10 +1604,10 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb,
                                        kfree(network);
                                        return 1;
                                }
-                               memcpy(ieee->ht_info->PeerHTCapBuf,
+                               memcpy(ieee->ht_info->peer_ht_cap_buf,
                                       network->bssht.bd_ht_cap_buf,
                                       network->bssht.bd_ht_cap_len);
-                               memcpy(ieee->ht_info->PeerHTInfoBuf,
+                               memcpy(ieee->ht_info->peer_ht_info_buf,
                                       network->bssht.bd_ht_info_buf,
                                       network->bssht.bd_ht_info_len);
                                ieee->handle_assoc_response(ieee->dev,
@@ -1634,7 +1632,7 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb,
                        netdev_info(ieee->dev,
                                    "Association response status code 0x%x\n",
                                    errcode);
-                       if (ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT)
+                       if (ieee->asoc_retry_count < RT_ASOC_RETRY_LIMIT)
                                schedule_delayed_work(&ieee->associate_procedure_wq, 0);
                        else
                                rtllib_associate_abort(ieee);
@@ -1648,7 +1646,7 @@ static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb)
        int errcode;
        u8 *challenge;
        int chlen = 0;
-       bool bSupportNmode = true, bHalfSupportNmode = false;
+       bool support_nmode = true, half_support_nmode = false;
 
        errcode = auth_parse(ieee->dev, skb, &challenge, &chlen);
 
@@ -1664,18 +1662,18 @@ static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb)
                ieee->link_state = RTLLIB_ASSOCIATING_AUTHENTICATED;
                ieee->softmac_stats.rx_auth_rs_ok++;
                if (!(ieee->ht_info->iot_action & HT_IOT_ACT_PURE_N_MODE)) {
-                       if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) {
+                       if (!ieee->get_nmode_support_by_sec_cfg(ieee->dev)) {
                                if (is_ht_half_nmode_aps(ieee)) {
-                                       bSupportNmode = true;
-                                       bHalfSupportNmode = true;
+                                       support_nmode = true;
+                                       half_support_nmode = true;
                                } else {
-                                       bSupportNmode = false;
-                                       bHalfSupportNmode = false;
+                                       support_nmode = false;
+                                       half_support_nmode = false;
                                }
                        }
                }
                /* Dummy wirless mode setting to avoid encryption issue */
-               if (bSupportNmode) {
+               if (support_nmode) {
                        ieee->set_wireless_mode(ieee->dev,
                                              ieee->current_network.mode);
                } else {
@@ -1684,11 +1682,11 @@ static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb)
                }
 
                if ((ieee->current_network.mode == WIRELESS_MODE_N_24G) &&
-                   bHalfSupportNmode) {
+                   half_support_nmode) {
                        netdev_info(ieee->dev, "======>enter half N mode\n");
-                       ieee->bHalfWirelessN24GMode = true;
+                       ieee->half_wireless_n24g_mode = true;
                } else {
-                       ieee->bHalfWirelessN24GMode = false;
+                       ieee->half_wireless_n24g_mode = false;
                }
                rtllib_associate_step2(ieee);
        } else {
@@ -1734,13 +1732,11 @@ rtllib_rx_deauth(struct rtllib_device *ieee, struct sk_buff *skb)
                ieee->link_state = RTLLIB_ASSOCIATING;
                ieee->softmac_stats.reassoc++;
                ieee->is_roaming = true;
-               ieee->link_detect_info.bBusyTraffic = false;
+               ieee->link_detect_info.busy_traffic = false;
                rtllib_disassociate(ieee);
-               RemovePeerTS(ieee, header->addr2);
-               if (!(ieee->rtllib_ap_sec_type(ieee) &
-                   (SEC_ALG_CCMP | SEC_ALG_TKIP)))
-                       schedule_delayed_work(
-                                      &ieee->associate_procedure_wq, 5);
+               remove_peer_ts(ieee, header->addr2);
+               if (!(ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_CCMP | SEC_ALG_TKIP)))
+                       schedule_delayed_work(&ieee->associate_procedure_wq, 5);
        }
        return 0;
 }
@@ -1816,7 +1812,7 @@ void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee)
        /* update the tx status */
        tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb +
                   MAX_DEV_ADDR_SIZE);
-       if (tcb_desc->bMulticast)
+       if (tcb_desc->multicast)
                ieee->stats.multicast++;
 
        /* if xmit available, just xmit it immediately, else just insert it to
@@ -1998,11 +1994,11 @@ void rtllib_stop_protocol(struct rtllib_device *ieee)
 
        if (ieee->link_state == MAC80211_LINKED) {
                if (ieee->iw_mode == IW_MODE_INFRA)
-                       SendDisassociation(ieee, 1, WLAN_REASON_DEAUTH_LEAVING);
+                       send_disassociation(ieee, 1, WLAN_REASON_DEAUTH_LEAVING);
                rtllib_disassociate(ieee);
        }
 
-       RemoveAllTS(ieee);
+       remove_all_ts(ieee);
        ieee->proto_stoppping = 0;
 
        kfree(ieee->assocreq_ies);
@@ -2072,13 +2068,13 @@ int rtllib_softmac_init(struct rtllib_device *ieee)
        for (i = 0; i < 5; i++)
                ieee->seq_ctrl[i] = 0;
 
-       ieee->link_detect_info.SlotIndex = 0;
-       ieee->link_detect_info.SlotNum = 2;
-       ieee->link_detect_info.NumRecvBcnInPeriod = 0;
-       ieee->link_detect_info.NumRecvDataInPeriod = 0;
+       ieee->link_detect_info.slot_index = 0;
+       ieee->link_detect_info.slot_num = 2;
+       ieee->link_detect_info.num_recv_bcn_in_period = 0;
+       ieee->link_detect_info.num_recv_data_in_period = 0;
        ieee->link_detect_info.num_tx_ok_in_period = 0;
        ieee->link_detect_info.num_rx_ok_in_period = 0;
-       ieee->link_detect_info.NumRxUnicastOkInPeriod = 0;
+       ieee->link_detect_info.num_rx_unicast_ok_in_period = 0;
        ieee->is_aggregate_frame = false;
        ieee->assoc_id = 0;
        ieee->queue_stop = 0;
@@ -2101,7 +2097,7 @@ int rtllib_softmac_init(struct rtllib_device *ieee)
        ieee->reg_dot11tx_ht_oper_rate_set[1] = 0xff;
        ieee->reg_dot11tx_ht_oper_rate_set[4] = 0x01;
 
-       ieee->FirstIe_InScan = false;
+       ieee->first_ie_in_scan = false;
        ieee->actscanning = false;
        ieee->beinretry = false;
        ieee->is_set_key = false;
@@ -2148,7 +2144,7 @@ void rtllib_softmac_free(struct rtllib_device *ieee)
 
 static inline struct sk_buff *
 rtllib_disauth_skb(struct rtllib_network *beacon,
-                  struct rtllib_device *ieee, u16 asRsn)
+                  struct rtllib_device *ieee, u16 rsn)
 {
        struct sk_buff *skb;
        struct rtllib_disauth *disauth;
@@ -2168,13 +2164,13 @@ rtllib_disauth_skb(struct rtllib_network *beacon,
        ether_addr_copy(disauth->header.addr2, ieee->dev->dev_addr);
        ether_addr_copy(disauth->header.addr3, beacon->bssid);
 
-       disauth->reason = cpu_to_le16(asRsn);
+       disauth->reason = cpu_to_le16(rsn);
        return skb;
 }
 
 static inline struct sk_buff *
 rtllib_disassociate_skb(struct rtllib_network *beacon,
-                       struct rtllib_device *ieee, u16 asRsn)
+                       struct rtllib_device *ieee, u16 rsn)
 {
        struct sk_buff *skb;
        struct rtllib_disassoc *disass;
@@ -2195,19 +2191,19 @@ rtllib_disassociate_skb(struct rtllib_network *beacon,
        ether_addr_copy(disass->header.addr2, ieee->dev->dev_addr);
        ether_addr_copy(disass->header.addr3, beacon->bssid);
 
-       disass->reason = cpu_to_le16(asRsn);
+       disass->reason = cpu_to_le16(rsn);
        return skb;
 }
 
-void SendDisassociation(struct rtllib_device *ieee, bool deauth, u16 asRsn)
+void send_disassociation(struct rtllib_device *ieee, bool deauth, u16 rsn)
 {
        struct rtllib_network *beacon = &ieee->current_network;
        struct sk_buff *skb;
 
        if (deauth)
-               skb = rtllib_disauth_skb(beacon, ieee, asRsn);
+               skb = rtllib_disauth_skb(beacon, ieee, rsn);
        else
-               skb = rtllib_disassociate_skb(beacon, ieee, asRsn);
+               skb = rtllib_disassociate_skb(beacon, ieee, rsn);
 
        if (skb)
                softmac_mgmt_xmit(skb, ieee);
@@ -2241,56 +2237,56 @@ u8 rtllib_ap_sec_type(struct rtllib_device *ieee)
        }
 }
 
-static void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib,
-                                          u8 *asSta, u8 asRsn)
+static void rtllib_mlme_disassociate_request(struct rtllib_device *rtllib,
+                                            u8 *addr, u8 rsn)
 {
        u8 i;
        u8      op_mode;
 
-       RemovePeerTS(rtllib, asSta);
+       remove_peer_ts(rtllib, addr);
 
-       if (memcmp(rtllib->current_network.bssid, asSta, 6) == 0) {
+       if (memcmp(rtllib->current_network.bssid, addr, 6) == 0) {
                rtllib->link_state = MAC80211_NOLINK;
 
                for (i = 0; i < 6; i++)
                        rtllib->current_network.bssid[i] = 0x22;
                op_mode = RT_OP_MODE_NO_LINK;
                rtllib->op_mode = RT_OP_MODE_NO_LINK;
-               rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_MEDIA_STATUS,
+               rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_MEDIA_STATUS,
                                        (u8 *)(&op_mode));
                rtllib_disassociate(rtllib);
 
-               rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_BSSID,
+               rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_BSSID,
                                        rtllib->current_network.bssid);
        }
 }
 
-static void rtllib_MgntDisconnectAP(struct rtllib_device *rtllib, u8 asRsn)
+static void rtllib_mgnt_disconnect_ap(struct rtllib_device *rtllib, u8 rsn)
 {
-       bool bFilterOutNonAssociatedBSSID = false;
+       bool filter_out_nonassociated_bssid = false;
 
-       bFilterOutNonAssociatedBSSID = false;
-       rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_CECHK_BSSID,
-                               (u8 *)(&bFilterOutNonAssociatedBSSID));
-       rtllib_MlmeDisassociateRequest(rtllib, rtllib->current_network.bssid,
-                                      asRsn);
+       filter_out_nonassociated_bssid = false;
+       rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_CECHK_BSSID,
+                               (u8 *)(&filter_out_nonassociated_bssid));
+       rtllib_mlme_disassociate_request(rtllib, rtllib->current_network.bssid,
+                                        rsn);
 
        rtllib->link_state = MAC80211_NOLINK;
 }
 
-bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn)
+bool rtllib_mgnt_disconnect(struct rtllib_device *rtllib, u8 rsn)
 {
        if (rtllib->ps != RTLLIB_PS_DISABLED)
                rtllib->sta_wake_up(rtllib->dev);
 
        if (rtllib->link_state == MAC80211_LINKED) {
                if (rtllib->iw_mode == IW_MODE_INFRA)
-                       rtllib_MgntDisconnectAP(rtllib, asRsn);
+                       rtllib_mgnt_disconnect_ap(rtllib, rsn);
        }
 
        return true;
 }
-EXPORT_SYMBOL(rtllib_MgntDisconnect);
+EXPORT_SYMBOL(rtllib_mgnt_disconnect);
 
 void notify_wx_assoc_event(struct rtllib_device *ieee)
 {
index 2afa701e5445be7100d7623c86086c79f2dfbabb..d6bc74ba9092b6e541bffb6cc28c421ffef6741b 100644 (file)
@@ -347,10 +347,10 @@ void rtllib_wx_sync_scan_wq(void *data)
        /* Notify AP that I wake up again */
        rtllib_sta_ps_send_null_frame(ieee, 0);
 
-       if (ieee->link_detect_info.NumRecvBcnInPeriod == 0 ||
-           ieee->link_detect_info.NumRecvDataInPeriod == 0) {
-               ieee->link_detect_info.NumRecvBcnInPeriod = 1;
-               ieee->link_detect_info.NumRecvDataInPeriod = 1;
+       if (ieee->link_detect_info.num_recv_bcn_in_period == 0 ||
+           ieee->link_detect_info.num_recv_data_in_period == 0) {
+               ieee->link_detect_info.num_recv_bcn_in_period = 1;
+               ieee->link_detect_info.num_recv_data_in_period = 1;
        }
        rtllib_wake_all_queues(ieee);
 
index f7098a2ba8b0b332f6c45eda6b7434348b117477..54100dd81505b166dbdec48fc81349162eccc6cf 100644 (file)
@@ -286,7 +286,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
        if (ht_info->iot_action & HT_IOT_ACT_TX_NO_AGGREGATION)
                return;
 
-       if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
+       if (!ieee->get_nmode_support_by_sec_cfg(ieee->dev))
                return;
        if (ht_info->current_ampdu_enable) {
                if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), hdr->addr1,
@@ -356,7 +356,7 @@ static void rtllib_query_BandwidthMode(struct rtllib_device *ieee,
        if (!ht_info->current_ht_support || !ht_info->enable_ht)
                return;
 
-       if (tcb_desc->bMulticast || tcb_desc->bBroadcast)
+       if (tcb_desc->multicast || tcb_desc->bBroadcast)
                return;
 
        if ((tcb_desc->data_rate & 0x80) == 0)
@@ -378,7 +378,7 @@ static void rtllib_query_protectionmode(struct rtllib_device *ieee,
        tcb_desc->RTSSC                         = 0;
        tcb_desc->bRTSBW                        = false;
 
-       if (tcb_desc->bBroadcast || tcb_desc->bMulticast)
+       if (tcb_desc->bBroadcast || tcb_desc->multicast)
                return;
 
        if (is_broadcast_ether_addr(skb->data + 16))
@@ -595,14 +595,14 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
                                   ((((u8 *)udp)[1] == 67) &&
                                   (((u8 *)udp)[3] == 68))) {
                                        bdhcp = true;
-                                       ieee->LPSDelayCnt = 200;
+                                       ieee->lps_delay_cnt = 200;
                                }
                        }
                } else if (ether_type == ETH_P_ARP) {
                        netdev_info(ieee->dev,
                                    "=================>DHCP Protocol start tx ARP pkt!!\n");
                        bdhcp = true;
-                       ieee->LPSDelayCnt =
+                       ieee->lps_delay_cnt =
                                 ieee->current_network.tim.tim_count;
                }
        }
@@ -832,7 +832,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
                        if (ieee->ht_info->iot_action &
                            HT_IOT_ACT_WA_IOT_Broadcom) {
                                tcb_desc->data_rate =
-                                        MgntQuery_TxRateExcludeCCKRates(ieee);
+                                        mgnt_query_tx_rate_exclude_cck_rates(ieee);
                                tcb_desc->tx_dis_rate_fallback = false;
                        } else {
                                tcb_desc->data_rate = ieee->basic_rate;
@@ -843,11 +843,11 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
                        tcb_desc->tx_use_drv_assinged_rate = 1;
                } else {
                        if (is_multicast_ether_addr(header.addr1))
-                               tcb_desc->bMulticast = 1;
+                               tcb_desc->multicast = 1;
                        if (is_broadcast_ether_addr(header.addr1))
                                tcb_desc->bBroadcast = 1;
                        rtllib_txrate_selectmode(ieee, tcb_desc);
-                       if (tcb_desc->bMulticast ||  tcb_desc->bBroadcast)
+                       if (tcb_desc->multicast ||  tcb_desc->bBroadcast)
                                tcb_desc->data_rate = ieee->basic_rate;
                        else
                                tcb_desc->data_rate = rtllib_current_rate(ieee);
@@ -856,7 +856,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
                                if (ieee->ht_info->iot_action &
                                    HT_IOT_ACT_WA_IOT_Broadcom) {
                                        tcb_desc->data_rate =
-                                          MgntQuery_TxRateExcludeCCKRates(ieee);
+                                          mgnt_query_tx_rate_exclude_cck_rates(ieee);
                                        tcb_desc->tx_dis_rate_fallback = false;
                                } else {
                                        tcb_desc->data_rate = MGN_1M;
index f92ec0faf4d5647ff486f4b82d65d5d7a2f4a779..55a3e4222cd67a67508709a9a4de63579a2771a4 100644 (file)
@@ -636,7 +636,7 @@ int rtllib_wx_set_mlme(struct rtllib_device *ieee,
 
                ieee->cannot_notify = true;
 
-               SendDisassociation(ieee, deauth, mlme->reason_code);
+               send_disassociation(ieee, deauth, mlme->reason_code);
                rtllib_disassociate(ieee);
 
                ieee->wap_set = 0;
index 30e7457a9c3120682514499db57d9d429f970a84..b89e88d6a82d527bf6f60b1de02cc5ebaadb70cd 100644 (file)
@@ -1035,8 +1035,8 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork)
        u16 wpa_len = 0, rsn_len = 0;
        struct HT_info_element *pht_info = NULL;
        struct ieee80211_ht_cap *pht_cap = NULL;
-       unsigned int            len;
-       unsigned char   *p;
+       unsigned int len;
+       unsigned char *p;
        __le16 le_cap;
 
        memcpy((u8 *)&le_cap, rtw_get_capability_from_ie(pnetwork->network.ies), 2);
index b221913733fb6179a4c95bec55a665139bcd0b0d..bfb27f902753428def47b2a96222148ddaa6303e 100644 (file)
@@ -169,7 +169,6 @@ void _rtw_free_network(struct       mlme_priv *pmlmepriv, struct wlan_network *pnetwor
 {
        unsigned int delta_time;
        u32 lifetime = SCANQUEUE_LIFETIME;
-/*     _irqL irqL; */
        struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
 
        if (!pnetwork)
@@ -389,7 +388,6 @@ int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst, u8 fea
        d_cap = le16_to_cpu(tmpd);
 
        return (src->ssid.ssid_length == dst->ssid.ssid_length) &&
-               /*      (src->configuration.ds_config == dst->configuration.ds_config) && */
                        ((!memcmp(src->mac_address, dst->mac_address, ETH_ALEN))) &&
                        ((!memcmp(src->ssid.ssid, dst->ssid.ssid, src->ssid.ssid_length))) &&
                        ((s_cap & WLAN_CAPABILITY_IBSS) ==
@@ -1548,9 +1546,9 @@ void _rtw_join_timeout_handler(struct timer_list *t)
                                int do_join_r;
 
                                do_join_r = rtw_do_join(adapter);
-                               if (do_join_r != _SUCCESS) {
+                               if (do_join_r != _SUCCESS)
                                        continue;
-                               }
+
                                break;
                        } else {
                                rtw_indicate_disconnect(adapter);
@@ -2432,9 +2430,8 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe
                return;
 
        /* maybe needs check if ap supports rx ampdu. */
-       if (!(phtpriv->ampdu_enable) && pregistrypriv->ampdu_enable == 1) {
+       if (!(phtpriv->ampdu_enable) && pregistrypriv->ampdu_enable == 1)
                phtpriv->ampdu_enable = true;
-       }
 
        /* check Max Rx A-MPDU Size */
        len = 0;
index 1593980d2c6a07774807dc703b50ab899e952c13..0145c4da5ac0696ddba4ecc362efb5a4be3df14f 100644 (file)
@@ -127,9 +127,8 @@ void kfree_all_stainfo(struct sta_priv *pstapriv)
        phead = get_list_head(&pstapriv->free_sta_queue);
        plist = get_next(phead);
 
-       while (phead != plist) {
+       while (phead != plist)
                plist = get_next(plist);
-       }
 
        spin_unlock_bh(&pstapriv->sta_hash_lock);
 }
index c5219a4a4919d7996ff9317a55873ee5bf1f7719..7a5c3a98183b490f78a44c718dcf71ffeb00c585 100644 (file)
@@ -954,7 +954,7 @@ static u16 hal_EfuseGetCurrentSize_WiFi(
 #endif
        u16 efuse_addr = 0;
        u16 start_addr = 0; /*  for debug */
-       u8 hoffset = 0, hworden = 0;
+       u8 hworden = 0;
        u8 efuse_data, word_cnts = 0;
        u32 count = 0; /*  for debug */
 
@@ -1001,16 +1001,13 @@ static u16 hal_EfuseGetCurrentSize_WiFi(
                }
 
                if (EXT_HEADER(efuse_data)) {
-                       hoffset = GET_HDR_OFFSET_2_0(efuse_data);
                        efuse_addr++;
                        efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest);
                        if (ALL_WORDS_DISABLED(efuse_data))
                                continue;
 
-                       hoffset |= ((efuse_data & 0xF0) >> 1);
                        hworden = efuse_data & 0x0F;
                } else {
-                       hoffset = (efuse_data>>4) & 0x0F;
                        hworden = efuse_data & 0x0F;
                }
 
@@ -1047,7 +1044,7 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest)
        u16 btusedbytes;
        u16 efuse_addr;
        u8 bank, startBank;
-       u8 hoffset = 0, hworden = 0;
+       u8 hworden = 0;
        u8 efuse_data, word_cnts = 0;
        u16 retU2 = 0;
 
@@ -1085,7 +1082,6 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest)
                                break;
 
                        if (EXT_HEADER(efuse_data)) {
-                               hoffset = GET_HDR_OFFSET_2_0(efuse_data);
                                efuse_addr++;
                                efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest);
 
@@ -1094,11 +1090,8 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest)
                                        continue;
                                }
 
-/*                             hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); */
-                               hoffset |= ((efuse_data & 0xF0) >> 1);
                                hworden = efuse_data & 0x0F;
                        } else {
-                               hoffset = (efuse_data>>4) & 0x0F;
                                hworden =  efuse_data & 0x0F;
                        }
 
@@ -1114,18 +1107,15 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest)
        ) {
                        if (efuse_data != 0xFF) {
                                if ((efuse_data&0x1F) == 0x0F) { /* extended header */
-                                       hoffset = efuse_data;
                                        efuse_addr++;
                                        efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest);
                                        if ((efuse_data & 0x0F) == 0x0F) {
                                                efuse_addr++;
                                                continue;
                                        } else {
-                                               hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
                                                hworden = efuse_data & 0x0F;
                                        }
                                } else {
-                                       hoffset = (efuse_data>>4) & 0x0F;
                                        hworden =  efuse_data & 0x0F;
                                }
                                word_cnts = Efuse_CalculateWordCnts(hworden);
index 1ff763c10064be933061c8a2f1206ab5f407cd3b..65a450fcdce77c48a5b4a74f440cfc8a5eadd537 100644 (file)
@@ -1259,8 +1259,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
                goto check_need_indicate_scan_done;
        }
 
-       ssid = kzalloc(RTW_SSID_SCAN_AMOUNT * sizeof(struct ndis_802_11_ssid),
-                      GFP_KERNEL);
+       ssid = kcalloc(RTW_SSID_SCAN_AMOUNT, sizeof(*ssid), GFP_KERNEL);
        if (!ssid) {
                ret = -ENOMEM;
                goto check_need_indicate_scan_done;
index e6e89784d84b93b28d5b285562db30ecbdb6647c..c3ba490e53cb4b32746a2987a716edfcf5a3ff76 100644 (file)
@@ -350,12 +350,11 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
                        if (is_capturing(dev)) {
                                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                                         "Grab another frame");
-                               vchiq_mmal_port_parameter_set(
-                                       instance,
-                                       dev->capture.camera_port,
-                                       MMAL_PARAMETER_CAPTURE,
-                                       &dev->capture.frame_count,
-                                       sizeof(dev->capture.frame_count));
+                               vchiq_mmal_port_parameter_set(instance,
+                                                             dev->capture.camera_port,
+                                                             MMAL_PARAMETER_CAPTURE,
+                                                             &dev->capture.frame_count,
+                                                             sizeof(dev->capture.frame_count));
                        }
                        if (vchiq_mmal_submit_buffer(instance, port,
                                                     &buf->mmal))
@@ -406,12 +405,11 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
            is_capturing(dev)) {
                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                         "Grab another frame as buffer has EOS");
-               vchiq_mmal_port_parameter_set(
-                       instance,
-                       dev->capture.camera_port,
-                       MMAL_PARAMETER_CAPTURE,
-                       &dev->capture.frame_count,
-                       sizeof(dev->capture.frame_count));
+               vchiq_mmal_port_parameter_set(instance,
+                                             dev->capture.camera_port,
+                                             MMAL_PARAMETER_CAPTURE,
+                                             &dev->capture.frame_count,
+                                             sizeof(dev->capture.frame_count));
        }
 }
 
@@ -420,11 +418,10 @@ static int enable_camera(struct bcm2835_mmal_dev *dev)
        int ret;
 
        if (!dev->camera_use_count) {
-               ret = vchiq_mmal_port_parameter_set(
-                       dev->instance,
-                       &dev->component[COMP_CAMERA]->control,
-                       MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
-                       sizeof(dev->camera_num));
+               ret = vchiq_mmal_port_parameter_set(dev->instance,
+                                                   &dev->component[COMP_CAMERA]->control,
+                                                   MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
+                                                   sizeof(dev->camera_num));
                if (ret < 0) {
                        v4l2_err(&dev->v4l2_dev,
                                 "Failed setting camera num, ret %d\n", ret);
@@ -468,11 +465,11 @@ static int disable_camera(struct bcm2835_mmal_dev *dev)
                                 "Failed disabling camera, ret %d\n", ret);
                        return -EINVAL;
                }
-               vchiq_mmal_port_parameter_set(
-                       dev->instance,
-                       &dev->component[COMP_CAMERA]->control,
-                       MMAL_PARAMETER_CAMERA_NUM, &i,
-                       sizeof(i));
+               vchiq_mmal_port_parameter_set(dev->instance,
+                                             &dev->component[COMP_CAMERA]->control,
+                                             MMAL_PARAMETER_CAMERA_NUM,
+                                             &i,
+                                             sizeof(i));
        }
        v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                 "Camera refcount now %d\n", dev->camera_use_count);
@@ -786,9 +783,8 @@ static int vidioc_overlay(struct file *file, void *f, unsigned int on)
                        ret = vchiq_mmal_port_connect_tunnel(dev->instance, src,
                                                             NULL);
                if (ret >= 0)
-                       ret = vchiq_mmal_component_disable(
-                                       dev->instance,
-                                       dev->component[COMP_PREVIEW]);
+                       ret = vchiq_mmal_component_disable(dev->instance,
+                                                          dev->component[COMP_PREVIEW]);
 
                disable_camera(dev);
                return ret;
@@ -1006,7 +1002,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-
 static int mmal_setup_video_component(struct bcm2835_mmal_dev *dev,
                                      struct v4l2_format *f)
 {
@@ -1042,8 +1037,8 @@ static int mmal_setup_video_component(struct bcm2835_mmal_dev *dev,
 
        if (overlay_enabled) {
                ret = vchiq_mmal_port_connect_tunnel(dev->instance,
-                               preview_port,
-                               &dev->component[COMP_PREVIEW]->input[0]);
+                                                    preview_port,
+                                                    &dev->component[COMP_PREVIEW]->input[0]);
                if (ret)
                        return ret;
 
@@ -1720,11 +1715,11 @@ static int mmal_init(struct bcm2835_mmal_dev *dev)
        {
                unsigned int enable = 1;
 
-               vchiq_mmal_port_parameter_set(
-                       dev->instance,
-                       &dev->component[COMP_VIDEO_ENCODE]->control,
-                       MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
-                       &enable, sizeof(enable));
+               vchiq_mmal_port_parameter_set(dev->instance,
+                                             &dev->component[COMP_VIDEO_ENCODE]->control,
+                                             MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
+                                             &enable,
+                                             sizeof(enable));
 
                vchiq_mmal_port_parameter_set(dev->instance,
                                              &dev->component[COMP_VIDEO_ENCODE]->control,
index 933027e0011ecf8d72568735b36ed5f2cbccf1f2..68f830d7553108facd16a3c0e33827cc4e83c028 100644 (file)
@@ -37,7 +37,7 @@ static int vchiq_bus_probe(struct device *dev)
        return driver->probe(device);
 }
 
-struct bus_type vchiq_bus_type = {
+const struct bus_type vchiq_bus_type = {
        .name   = "vchiq-bus",
        .match  = vchiq_bus_type_match,
        .uevent = vchiq_bus_uevent,
index caa6fdf25bb1df69fd2a2fb0b1885f12884f9754..4db86e76edbd40a131c370db120a0428fb799536 100644 (file)
@@ -34,7 +34,7 @@ static inline struct vchiq_driver *to_vchiq_driver(struct device_driver *d)
        return container_of(d, struct vchiq_driver, driver);
 }
 
-extern struct bus_type vchiq_bus_type;
+extern const struct bus_type vchiq_bus_type;
 
 struct vchiq_device *
 vchiq_device_register(struct device *parent, const char *name);
index e9461a7a7ab8ba40ed8978134928a5d669f44f5c..0cd370ab1008813f076e6fdce5af928078b4992f 100644 (file)
@@ -1970,7 +1970,7 @@ static void vme_bus_remove(struct device *dev)
                driver->remove(vdev);
 }
 
-struct bus_type vme_bus_type = {
+const struct bus_type vme_bus_type = {
        .name = "vme",
        .match = vme_bus_match,
        .probe = vme_bus_probe,
index 06504dccd5ff0cef4fcdad990624b8251cd0e7cb..26aa40f78a74f70176027bbdb79eb99c895c856a 100644 (file)
@@ -81,7 +81,7 @@ struct vme_resource {
        struct list_head *entry;
 };
 
-extern struct bus_type vme_bus_type;
+extern const struct bus_type vme_bus_type;
 
 /* Number of VME interrupt vectors */
 #define VME_NUM_STATUSID       256
index 4dd224d0b86e912cb3cbcb0f6dbfe89dfa8d207b..db246cbc54c39b8e55e578f0b44bbc0863d30ed5 100644 (file)
@@ -691,8 +691,7 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0,
 
 #define TSI148_LCSR_VMCTRL_RMWEN       BIT(20) /* RMW Enable */
 
-#define TSI148_LCSR_VMCTRL_ATO_M       (7 << 16)       /* Master Access Time-out Mask
-                                                */
+#define TSI148_LCSR_VMCTRL_ATO_M       (7 << 16)       /* Master Access Time-out Mask */
 #define TSI148_LCSR_VMCTRL_ATO_32      (0 << 16)       /* 32 us */
 #define TSI148_LCSR_VMCTRL_ATO_128     BIT(16) /* 128 us */
 #define TSI148_LCSR_VMCTRL_ATO_512     (2 << 16)       /* 512 us */
@@ -753,8 +752,7 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0,
 #define TSI148_LCSR_VCTRL_DLT_16384    (0xB << 24)     /* 16384 VCLKS */
 #define TSI148_LCSR_VCTRL_DLT_32768    (0xC << 24)     /* 32768 VCLKS */
 
-#define TSI148_LCSR_VCTRL_NERBB        BIT(20) /* No Early Release of Bus Busy
-                                                */
+#define TSI148_LCSR_VCTRL_NERBB        BIT(20) /* No Early Release of Bus Busy */
 
 #define TSI148_LCSR_VCTRL_SRESET       BIT(17) /* System Reset */
 #define TSI148_LCSR_VCTRL_LRESET       BIT(16) /* Local Reset */
index 36183f2a64c11af1470df0b376bd4b3d4443b3d6..688c870d89bc065aeb36f0fc6c25294ad62bcde9 100644 (file)
@@ -81,9 +81,9 @@ static void vt6655_mac_set_bb_type(void __iomem *iobase, u32 mask)
  * Return Value: none
  */
 static void calculate_ofdmr_parameter(unsigned char rate,
-                                      u8 bb_type,
-                                      unsigned char *tx_rate,
-                                      unsigned char *rsv_time)
+                                     u8 bb_type,
+                                     unsigned char *tx_rate,
+                                     unsigned char *rsv_time)
 {
        switch (rate) {
        case RATE_6M:
@@ -288,7 +288,7 @@ bool card_set_phy_parameter(struct vnt_private *priv, u8 bb_type)
  * Return Value: none
  */
 bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate,
-                   u64 bss_timestamp)
+                    u64 bss_timestamp)
 {
        u64 local_tsf;
        u64 tsf_offset = 0;
@@ -297,7 +297,7 @@ bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate,
 
        if (bss_timestamp != local_tsf) {
                tsf_offset = card_get_tsf_offset(rx_rate, bss_timestamp,
-                                               local_tsf);
+                                                local_tsf);
                /* adjust TSF, HW's TSF add TSF Offset reg */
                tsf_offset =  le64_to_cpu(tsf_offset);
                iowrite32((u32)tsf_offset, priv->port_offset + MAC_REG_TSFOFST);
@@ -321,7 +321,7 @@ bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate,
  * Return Value: true if succeed; otherwise false
  */
 bool card_set_beacon_period(struct vnt_private *priv,
-                         unsigned short beacon_interval)
+                           unsigned short beacon_interval)
 {
        u64 next_tbtt;
 
@@ -586,61 +586,61 @@ void card_set_rspinf(struct vnt_private *priv, u8 bb_type)
 
        /* RSPINF_a_6 */
        calculate_ofdmr_parameter(RATE_6M,
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_6);
        /* RSPINF_a_9 */
        calculate_ofdmr_parameter(RATE_9M,
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_9);
        /* RSPINF_a_12 */
        calculate_ofdmr_parameter(RATE_12M,
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_12);
        /* RSPINF_a_18 */
        calculate_ofdmr_parameter(RATE_18M,
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_18);
        /* RSPINF_a_24 */
        calculate_ofdmr_parameter(RATE_24M,
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_24);
        /* RSPINF_a_36 */
        calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv,
-                                                          RATE_36M),
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                                         RATE_36M),
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_36);
        /* RSPINF_a_48 */
        calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv,
-                                                          RATE_48M),
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                                         RATE_48M),
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_48);
        /* RSPINF_a_54 */
        calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv,
-                                                          RATE_54M),
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                                         RATE_54M),
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_54);
        /* RSPINF_a_72 */
        calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv,
-                                                          RATE_54M),
-                                  bb_type,
-                                  &byTxRate,
-                                  &byRsvTime);
+                                                         RATE_54M),
+                                 bb_type,
+                                 &byTxRate,
+                                 &byRsvTime);
        iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_72);
        /* Set to Page0 */
        VT6655_MAC_SELECT_PAGE0(priv->port_offset);
index a67757c9bb5ca225bfe950f41e7cf65332c8fe53..be1e5180d57b8c6b7462f2c9a12a8901927303e2 100644 (file)
@@ -19,7 +19,6 @@
 #define DEFAULT_MSDU_LIFETIME_RES_64us 8000 /* 64us */
 #define DEFAULT_MGN_LIFETIME_RES_64us  125  /* 64us */
 
-
 /*---------------------  Export Definitions -------------------------*/
 
 /*---------------------  Export Variables  --------------------------*/
index d77d7fe99a84aa3fb1f8059cd8c58f643741b1db..5cdf7d68687f43b3a0f62c15bcb78235e16de679 100644 (file)
@@ -43,7 +43,7 @@ obj-$(CONFIG_RCAR_GEN3_THERMAL)       += rcar_gen3_thermal.o
 obj-$(CONFIG_RZG2L_THERMAL)    += rzg2l_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-y                          += samsung/
-obj-$(CONFIG_DOVE_THERMAL)     += dove_thermal.o
+obj-$(CONFIG_DOVE_THERMAL)     += dove_thermal.o
 obj-$(CONFIG_DB8500_THERMAL)   += db8500_thermal.o
 obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
 obj-$(CONFIG_IMX_THERMAL)      += imx_thermal.o
index 8b0edb2048443d9e7f05dd09977e447b4b594a20..9ee2e7283435acfcbb1a956303b6122a08affecc 100644 (file)
@@ -690,6 +690,9 @@ static const struct mtk_thermal_data mt7986_thermal_data = {
        .adcpnp = mt7986_adcpnp,
        .sensor_mux_values = mt7986_mux_values,
        .version = MTK_THERMAL_V3,
+       .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1,
+       .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3),
+       .apmixed_buffer_ctl_set = BIT(0),
 };
 
 static bool mtk_thermal_temp_is_valid(int temp)
index 98d9c80bd4c6279385efa97fea52b0a2651348ea..fd4bd650c77a6ae8a0deebb7d8cfb13415d9214e 100644 (file)
@@ -719,8 +719,10 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td
 
                lvts_td->calib = devm_krealloc(dev, lvts_td->calib,
                                               lvts_td->calib_len + len, GFP_KERNEL);
-               if (!lvts_td->calib)
+               if (!lvts_td->calib) {
+                       kfree(efuse);
                        return -ENOMEM;
+               }
 
                memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len);
 
index ccc2eea7f9f548a184646cb38a39068238b978b3..404f01cca4dab581aa3dff8799d37b38f03ebc1d 100644 (file)
@@ -57,6 +57,9 @@
 #define REGS_TTRnCR(n) (0xf10 + 4 * (n)) /* Temperature Range n
                                           * Control Register
                                           */
+#define NUM_TTRCR_V1   4
+#define NUM_TTRCR_MAX  16
+
 #define REGS_IPBRR(n)          (0xbf8 + 4 * (n)) /* IP Block Revision
                                                   * Register n
                                                   */
@@ -71,6 +74,7 @@ struct qoriq_sensor {
 
 struct qoriq_tmu_data {
        int ver;
+       u32 ttrcr[NUM_TTRCR_MAX];
        struct regmap *regmap;
        struct clk *clk;
        struct qoriq_sensor     sensor[SITES_MAX];
@@ -182,17 +186,17 @@ static int qoriq_tmu_calibration(struct device *dev,
                                 struct qoriq_tmu_data *data)
 {
        int i, val, len;
-       u32 range[4];
        const u32 *calibration;
        struct device_node *np = dev->of_node;
 
        len = of_property_count_u32_elems(np, "fsl,tmu-range");
-       if (len < 0 || len > 4) {
+       if (len < 0 || (data->ver == TMU_VER1 && len > NUM_TTRCR_V1) ||
+           (data->ver > TMU_VER1 && len > NUM_TTRCR_MAX)) {
                dev_err(dev, "invalid range data.\n");
                return len;
        }
 
-       val = of_property_read_u32_array(np, "fsl,tmu-range", range, len);
+       val = of_property_read_u32_array(np, "fsl,tmu-range", data->ttrcr, len);
        if (val != 0) {
                dev_err(dev, "failed to read range data.\n");
                return val;
@@ -200,7 +204,7 @@ static int qoriq_tmu_calibration(struct device *dev,
 
        /* Init temperature range registers */
        for (i = 0; i < len; i++)
-               regmap_write(data->regmap, REGS_TTRnCR(i), range[i]);
+               regmap_write(data->regmap, REGS_TTRnCR(i), data->ttrcr[i]);
 
        calibration = of_get_property(np, "fsl,tmu-calibration", &len);
        if (calibration == NULL || len % 8) {
index cafcb6d6e235be442375ac3180429a5daaeef707..a764cb1115a575620dbceb897ee04cc176c4082f 100644 (file)
@@ -428,6 +428,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
                .compatible = "renesas,r8a779g0-thermal",
                .data = &rcar_gen4_thermal_info,
        },
+       {
+               .compatible = "renesas,r8a779h0-thermal",
+               .data = &rcar_gen4_thermal_info,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
index 75a84e6ec6a729bfce9027b467526f90713c33ee..8639d9165c9b9d56a184db198bb24b692a2d8472 100644 (file)
@@ -38,10 +38,10 @@ struct st_thermal_sensor;
  *
  * @power_ctrl:                Function for powering on/off a sensor. Clock to the
  *                     sensor is also controlled from this function.
- * @alloc_regfields:   Allocate regmap register fields, specific to a sensor.
- * @do_memmap_regmap:  Memory map the thermal register space and init regmap
+ * @alloc_regfields:   Allocate regmap register fields, specific to a sensor.
+ * @do_memmap_regmap:  Memory map the thermal register space and init regmap
  *                     instance or find regmap instance.
- * @register_irq:      Register an interrupt handler for a sensor.
+ * @register_irq:      Register an interrupt handler for a sensor.
  */
 struct st_thermal_sensor_ops {
        int (*power_ctrl)(struct st_thermal_sensor *, enum st_thermal_power_state);
@@ -56,15 +56,15 @@ struct st_thermal_sensor_ops {
  *
  * @reg_fields:                Pointer to the regfields array for a sensor.
  * @sys_compat:                Pointer to the syscon node compatible string.
- * @ops:               Pointer to private thermal ops for a sensor.
- * @calibration_val:   Default calibration value to be written to the DCORRECT
+ * @ops:               Pointer to private thermal ops for a sensor.
+ * @calibration_val:   Default calibration value to be written to the DCORRECT
  *                     register field for a sensor.
- * @temp_adjust_val:   Value to be added/subtracted from the data read from
+ * @temp_adjust_val:   Value to be added/subtracted from the data read from
  *                     the sensor. If value needs to be added please provide a
  *                     positive value and if it is to be subtracted please
- *                     provide a negative value.
- * @crit_temp:                 The temperature beyond which the SoC should be shutdown
- *                     to prevent damage.
+ *                     provide a negative value.
+ * @crit_temp:         The temperature beyond which the SoC should be shutdown
+ *                     to prevent damage.
  */
 struct st_thermal_compat_data {
        char *sys_compat;
index e8cfa83b724a774b53e0be33d1e462601b070f07..29c2269b0fb35ced3d9a9b623494fd6f0ca76e78 100644 (file)
@@ -27,7 +27,7 @@ static const struct reg_field st_mmap_thermal_regfields[MAX_REGFIELDS] = {
         * written simultaneously for powering on and off the temperature
         * sensor. regmap_update_bits() will be used to update the register.
         */
-       [INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH,     0,  7),
+       [INT_THRESH_HI] = REG_FIELD(STIH416_MPE_INT_THRESH,     0,  7),
        [DCORRECT]      = REG_FIELD(STIH416_MPE_CONF,           5,  9),
        [OVERFLOW]      = REG_FIELD(STIH416_MPE_STATUS,         9,  9),
        [DATA]          = REG_FIELD(STIH416_MPE_STATUS,         11, 18),
index 6a8e386dbc8dc2972461c59295d3d3661f1d6248..3203d8bd13a8fc2a9e5a59b3547cefc2440542c6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
@@ -50,7 +51,8 @@
 #define SUN8I_THS_CTRL2_T_ACQ1(x)              ((GENMASK(15, 0) & (x)) << 16)
 #define SUN8I_THS_DATA_IRQ_STS(x)              BIT(x + 8)
 
-#define SUN50I_THS_CTRL0_T_ACQ(x)              ((GENMASK(15, 0) & (x)) << 16)
+#define SUN50I_THS_CTRL0_T_ACQ(x)              (GENMASK(15, 0) & ((x) - 1))
+#define SUN50I_THS_CTRL0_T_SAMPLE_PER(x)       ((GENMASK(15, 0) & ((x) - 1)) << 16)
 #define SUN50I_THS_FILTER_EN                   BIT(2)
 #define SUN50I_THS_FILTER_TYPE(x)              (GENMASK(1, 0) & (x))
 #define SUN50I_H6_THS_PC_TEMP_PERIOD(x)                ((GENMASK(19, 0) & (x)) << 12)
@@ -65,6 +67,7 @@ struct tsensor {
 struct ths_thermal_chip {
        bool            has_mod_clk;
        bool            has_bus_clk_reset;
+       bool            needs_sram;
        int             sensor_num;
        int             offset;
        int             scale;
@@ -82,12 +85,16 @@ struct ths_device {
        const struct ths_thermal_chip           *chip;
        struct device                           *dev;
        struct regmap                           *regmap;
+       struct regmap_field                     *sram_regmap_field;
        struct reset_control                    *reset;
        struct clk                              *bus_clk;
        struct clk                              *mod_clk;
        struct tsensor                          sensor[MAX_SENSOR_NUM];
 };
 
+/* The H616 needs to have a bit 16 in the SRAM control register cleared. */
+static const struct reg_field sun8i_ths_sram_reg_field = REG_FIELD(0x0, 16, 16);
+
 /* Temp Unit: millidegree Celsius */
 static int sun8i_ths_calc_temp(struct ths_device *tmdev,
                               int id, int reg)
@@ -188,6 +195,9 @@ static irqreturn_t sun8i_irq_thread(int irq, void *data)
        int i;
 
        for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) {
+               /* We allow some zones to not register. */
+               if (IS_ERR(tmdev->sensor[i].tzd))
+                       continue;
                thermal_zone_device_update(tmdev->sensor[i].tzd,
                                           THERMAL_EVENT_UNSPECIFIED);
        }
@@ -221,16 +231,21 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
        struct device *dev = tmdev->dev;
        int i, ft_temp;
 
-       if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num)
+       if (!caldata[0])
                return -EINVAL;
 
        /*
         * efuse layout:
         *
-        *      0   11  16       32
-        *      +-------+-------+-------+
-        *      |temp|  |sensor0|sensor1|
-        *      +-------+-------+-------+
+        * 0      11  16     27   32     43   48    57
+        * +----------+-----------+-----------+-----------+
+        * |  temp |  |sensor0|   |sensor1|   |sensor2|   |
+        * +----------+-----------+-----------+-----------+
+        *                      ^           ^           ^
+        *                      |           |           |
+        *                      |           |           sensor3[11:8]
+        *                      |           sensor3[7:4]
+        *                      sensor3[3:0]
         *
         * The calibration data on the H6 is the ambient temperature and
         * sensor values that are filled during the factory test stage.
@@ -243,9 +258,16 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
        ft_temp = (caldata[0] & FT_TEMP_MASK) * 100;
 
        for (i = 0; i < tmdev->chip->sensor_num; i++) {
-               int sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK;
-               int cdata, offset;
-               int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
+               int sensor_reg, sensor_temp, cdata, offset;
+
+               if (i == 3)
+                       sensor_reg = (caldata[1] >> 12)
+                                    | ((caldata[2] >> 12) << 4)
+                                    | ((caldata[3] >> 12) << 8);
+               else
+                       sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK;
+
+               sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
 
                /*
                 * Calibration data is CALIBRATE_DEFAULT - (calculated
@@ -324,6 +346,34 @@ static void sun8i_ths_reset_control_assert(void *data)
        reset_control_assert(data);
 }
 
+static struct regmap *sun8i_ths_get_sram_regmap(struct device_node *node)
+{
+       struct device_node *sram_node;
+       struct platform_device *sram_pdev;
+       struct regmap *regmap = NULL;
+
+       sram_node = of_parse_phandle(node, "allwinner,sram", 0);
+       if (!sram_node)
+               return ERR_PTR(-ENODEV);
+
+       sram_pdev = of_find_device_by_node(sram_node);
+       if (!sram_pdev) {
+               /* platform device might not be probed yet */
+               regmap = ERR_PTR(-EPROBE_DEFER);
+               goto out_put_node;
+       }
+
+       /* If no regmap is found then the other device driver is at fault */
+       regmap = dev_get_regmap(&sram_pdev->dev, NULL);
+       if (!regmap)
+               regmap = ERR_PTR(-EINVAL);
+
+       platform_device_put(sram_pdev);
+out_put_node:
+       of_node_put(sram_node);
+       return regmap;
+}
+
 static int sun8i_ths_resource_init(struct ths_device *tmdev)
 {
        struct device *dev = tmdev->dev;
@@ -368,6 +418,19 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
        if (ret)
                return ret;
 
+       if (tmdev->chip->needs_sram) {
+               struct regmap *regmap;
+
+               regmap = sun8i_ths_get_sram_regmap(dev->of_node);
+               if (IS_ERR(regmap))
+                       return PTR_ERR(regmap);
+               tmdev->sram_regmap_field = devm_regmap_field_alloc(dev,
+                                                     regmap,
+                                                     sun8i_ths_sram_reg_field);
+               if (IS_ERR(tmdev->sram_regmap_field))
+                       return PTR_ERR(tmdev->sram_regmap_field);
+       }
+
        ret = sun8i_ths_calibrate(tmdev);
        if (ret)
                return ret;
@@ -410,25 +473,31 @@ static int sun8i_h3_thermal_init(struct ths_device *tmdev)
        return 0;
 }
 
-/*
- * Without this undocumented value, the returned temperatures would
- * be higher than real ones by about 20C.
- */
-#define SUN50I_H6_CTRL0_UNK 0x0000002f
-
 static int sun50i_h6_thermal_init(struct ths_device *tmdev)
 {
        int val;
 
+       /* The H616 needs to have a bit in the SRAM control register cleared. */
+       if (tmdev->sram_regmap_field)
+               regmap_field_write(tmdev->sram_regmap_field, 0);
+
        /*
-        * T_acq = 20us
-        * clkin = 24MHz
-        *
-        * x = T_acq * clkin - 1
-        *   = 479
+        * The manual recommends an overall sample frequency of 50 KHz (20us,
+        * 480 cycles at 24 MHz), which provides plenty of time for both the
+        * acquisition time (>24 cycles) and the actual conversion time
+        * (>14 cycles).
+        * The lower half of the CTRL register holds the "acquire time", in
+        * clock cycles, which the manual recommends to be 2us:
+        * 24MHz * 2us = 48 cycles.
+        * The high half of THS_CTRL encodes the sample frequency, in clock
+        * cycles: 24MHz * 20us = 480 cycles.
+        * This is explained in the H616 manual, but apparently wrongly
+        * described in the H6 manual, although the BSP code does the same
+        * for both SoCs.
         */
        regmap_write(tmdev->regmap, SUN50I_THS_CTRL0,
-                    SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479));
+                    SUN50I_THS_CTRL0_T_ACQ(48) |
+                    SUN50I_THS_CTRL0_T_SAMPLE_PER(480));
        /* average over 4 samples */
        regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC,
                     SUN50I_THS_FILTER_EN |
@@ -465,8 +534,17 @@ static int sun8i_ths_register(struct ths_device *tmdev)
                                                      i,
                                                      &tmdev->sensor[i],
                                                      &ths_ops);
-               if (IS_ERR(tmdev->sensor[i].tzd))
-                       return PTR_ERR(tmdev->sensor[i].tzd);
+
+               /*
+                * If an individual zone fails to register for reasons
+                * other than probe deferral (eg, a bad DT) then carry
+                * on, other zones might register successfully.
+                */
+               if (IS_ERR(tmdev->sensor[i].tzd)) {
+                       if (PTR_ERR(tmdev->sensor[i].tzd) == -EPROBE_DEFER)
+                               return PTR_ERR(tmdev->sensor[i].tzd);
+                       continue;
+               }
 
                devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd);
        }
@@ -618,6 +696,20 @@ static const struct ths_thermal_chip sun20i_d1_ths = {
        .calc_temp = sun8i_ths_calc_temp,
 };
 
+static const struct ths_thermal_chip sun50i_h616_ths = {
+       .sensor_num = 4,
+       .has_bus_clk_reset = true,
+       .needs_sram = true,
+       .ft_deviation = 8000,
+       .offset = 263655,
+       .scale = 810,
+       .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
+       .calibrate = sun50i_h6_ths_calibrate,
+       .init = sun50i_h6_thermal_init,
+       .irq_ack = sun50i_h6_irq_ack,
+       .calc_temp = sun8i_ths_calc_temp,
+};
+
 static const struct of_device_id of_ths_match[] = {
        { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
        { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
@@ -627,6 +719,7 @@ static const struct of_device_id of_ths_match[] = {
        { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths },
        { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths },
        { .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths },
+       { .compatible = "allwinner,sun50i-h616-ths", .data = &sun50i_h616_ths },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, of_ths_match);
index f1cbf9aa62cfedc2f621d6d619f3226f4a46f2e9..aa34b6e82e268bce2cb964ad5fcea02122f046c1 100644 (file)
@@ -227,14 +227,18 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
        int ret;
 
        ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
-       if (ret < 0) {
-               pr_err("%pOFn: missing polling-delay-passive property\n", np);
+       if (ret == -EINVAL) {
+               *pdelay = 0;
+       } else if (ret < 0) {
+               pr_err("%pOFn: Couldn't get polling-delay-passive: %d\n", np, ret);
                return ret;
        }
 
        ret = of_property_read_u32(np, "polling-delay", delay);
-       if (ret < 0) {
-               pr_err("%pOFn: missing polling-delay property\n", np);
+       if (ret == -EINVAL) {
+               *delay = 0;
+       } else if (ret < 0) {
+               pr_err("%pOFn: Couldn't get polling-delay: %d\n", np, ret);
                return ret;
        }
 
@@ -460,7 +464,7 @@ static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
  * @ops: A set of thermal sensor ops
  *
  * Return: a valid thermal zone structure pointer on success.
- *     - EINVAL: if the device tree thermal description is malformed
+ *     - EINVAL: if the device tree thermal description is malformed
  *     - ENOMEM: if one structure can not be allocated
  *     - Other negative errors are returned by the underlying called functions
  */
index c8b3d7b780982f18c5e4b6c927b08662c38ec440..b44b32dcb8322612c1851b34efc9ef7fe837b02c 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
+ccflags-y := -I$(src)
 obj-${CONFIG_USB4} := thunderbolt.o
 thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o
 thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o
index d997a4c545f7965e799dcb4ef06b1cee3491306b..4bdb2d45e0bffc2261b5d846edfd570d20a04e01 100644 (file)
@@ -15,6 +15,8 @@
 
 #include "ctl.h"
 
+#define CREATE_TRACE_POINTS
+#include "trace.h"
 
 #define TB_CTL_RX_PKG_COUNT    10
 #define TB_CTL_RETRIES         4
@@ -32,6 +34,7 @@
  * @timeout_msec: Default timeout for non-raw control messages
  * @callback: Callback called when hotplug message is received
  * @callback_data: Data passed to @callback
+ * @index: Domain number. This will be output with the trace record.
  */
 struct tb_ctl {
        struct tb_nhi *nhi;
@@ -47,6 +50,8 @@ struct tb_ctl {
        int timeout_msec;
        event_cb callback;
        void *callback_data;
+
+       int index;
 };
 
 
@@ -369,6 +374,9 @@ static int tb_ctl_tx(struct tb_ctl *ctl, const void *data, size_t len,
        pkg->frame.size = len + 4;
        pkg->frame.sof = type;
        pkg->frame.eof = type;
+
+       trace_tb_tx(ctl->index, type, data, len);
+
        cpu_to_be32_array(pkg->buffer, data, len / 4);
        *(__be32 *) (pkg->buffer + len) = tb_crc(pkg->buffer, len);
 
@@ -384,6 +392,7 @@ static int tb_ctl_tx(struct tb_ctl *ctl, const void *data, size_t len,
 static bool tb_ctl_handle_event(struct tb_ctl *ctl, enum tb_cfg_pkg_type type,
                                struct ctl_pkg *pkg, size_t size)
 {
+       trace_tb_event(ctl->index, type, pkg->buffer, size);
        return ctl->callback(ctl->callback_data, type, pkg->buffer, size);
 }
 
@@ -489,6 +498,9 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame,
         * triggered from messing with the active requests.
         */
        req = tb_cfg_request_find(pkg->ctl, pkg);
+
+       trace_tb_rx(pkg->ctl->index, frame->eof, pkg->buffer, frame->size, !req);
+
        if (req) {
                if (req->copy(req, pkg))
                        schedule_work(&req->work);
@@ -614,6 +626,7 @@ struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl,
 /**
  * tb_ctl_alloc() - allocate a control channel
  * @nhi: Pointer to NHI
+ * @index: Domain number
  * @timeout_msec: Default timeout used with non-raw control messages
  * @cb: Callback called for plug events
  * @cb_data: Data passed to @cb
@@ -622,14 +635,16 @@ struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl,
  *
  * Return: Returns a pointer on success or NULL on failure.
  */
-struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int timeout_msec, event_cb cb,
-                           void *cb_data)
+struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int index, int timeout_msec,
+                           event_cb cb, void *cb_data)
 {
        int i;
        struct tb_ctl *ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
        if (!ctl)
                return NULL;
+
        ctl->nhi = nhi;
+       ctl->index = index;
        ctl->timeout_msec = timeout_msec;
        ctl->callback = cb;
        ctl->callback_data = cb_data;
index eec5c953c743cf7e1023d1df14bf30b618d40d03..bf930a19147237d75d349b7dfde0a977be0ba21d 100644 (file)
@@ -21,8 +21,8 @@ struct tb_ctl;
 typedef bool (*event_cb)(void *data, enum tb_cfg_pkg_type type,
                         const void *buf, size_t size);
 
-struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int timeout_msec, event_cb cb,
-                           void *cb_data);
+struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int index, int timeout_msec,
+                           event_cb cb, void *cb_data);
 void tb_ctl_start(struct tb_ctl *ctl);
 void tb_ctl_stop(struct tb_ctl *ctl);
 void tb_ctl_free(struct tb_ctl *ctl);
index 9fb1a64f3300b8fcf7ebc1f7dafa6a68778da122..0023017299f7613d151d793bea0dc9519dc9f9c2 100644 (file)
@@ -321,12 +321,12 @@ static void tb_domain_release(struct device *dev)
 
        tb_ctl_free(tb->ctl);
        destroy_workqueue(tb->wq);
-       ida_simple_remove(&tb_domain_ida, tb->index);
+       ida_free(&tb_domain_ida, tb->index);
        mutex_destroy(&tb->lock);
        kfree(tb);
 }
 
-struct device_type tb_domain_type = {
+const struct device_type tb_domain_type = {
        .name = "thunderbolt_domain",
        .release = tb_domain_release,
 };
@@ -389,7 +389,7 @@ struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize
        tb->nhi = nhi;
        mutex_init(&tb->lock);
 
-       tb->index = ida_simple_get(&tb_domain_ida, 0, 0, GFP_KERNEL);
+       tb->index = ida_alloc(&tb_domain_ida, GFP_KERNEL);
        if (tb->index < 0)
                goto err_free;
 
@@ -397,7 +397,7 @@ struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize
        if (!tb->wq)
                goto err_remove_ida;
 
-       tb->ctl = tb_ctl_alloc(nhi, timeout_msec, tb_domain_event_cb, tb);
+       tb->ctl = tb_ctl_alloc(nhi, tb->index, timeout_msec, tb_domain_event_cb, tb);
        if (!tb->ctl)
                goto err_destroy_wq;
 
@@ -413,7 +413,7 @@ struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize
 err_destroy_wq:
        destroy_workqueue(tb->wq);
 err_remove_ida:
-       ida_simple_remove(&tb_domain_ida, tb->index);
+       ida_free(&tb_domain_ida, tb->index);
 err_free:
        kfree(tb);
 
@@ -423,6 +423,7 @@ err_free:
 /**
  * tb_domain_add() - Add domain to the system
  * @tb: Domain to add
+ * @reset: Issue reset to the host router
  *
  * Starts the domain and adds it to the system. Hotplugging devices will
  * work after this has been returned successfully. In order to remove
@@ -431,7 +432,7 @@ err_free:
  *
  * Return: %0 in case of success and negative errno in case of error
  */
-int tb_domain_add(struct tb *tb)
+int tb_domain_add(struct tb *tb, bool reset)
 {
        int ret;
 
@@ -460,7 +461,7 @@ int tb_domain_add(struct tb *tb)
 
        /* Start the domain */
        if (tb->cm_ops->start) {
-               ret = tb->cm_ops->start(tb);
+               ret = tb->cm_ops->start(tb, reset);
                if (ret)
                        goto err_domain_del;
        }
@@ -505,6 +506,10 @@ void tb_domain_remove(struct tb *tb)
        mutex_unlock(&tb->lock);
 
        flush_workqueue(tb->wq);
+
+       if (tb->cm_ops->deinit)
+               tb->cm_ops->deinit(tb);
+
        device_unregister(&tb->dev);
 }
 
index 56790d50f9e3296bd3607162f6b2030fe28dc77a..baf10d099c7780ee9c83846f391ab1cf796f6f84 100644 (file)
@@ -2144,7 +2144,7 @@ static int icm_runtime_resume(struct tb *tb)
        return 0;
 }
 
-static int icm_start(struct tb *tb)
+static int icm_start(struct tb *tb, bool not_used)
 {
        struct icm *icm = tb_priv(tb);
        int ret;
index 633970fbe9b05904ca4f46876a3561265ed83318..63cb4b6afb718aca9689a01695d9625d83d29d03 100644 (file)
@@ -6,6 +6,8 @@
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
  */
 
+#include <linux/delay.h>
+
 #include "tb.h"
 
 /**
@@ -45,6 +47,49 @@ static int find_port_lc_cap(struct tb_port *port)
        return sw->cap_lc + start + phys * size;
 }
 
+/**
+ * tb_lc_reset_port() - Trigger downstream port reset through LC
+ * @port: Port that is reset
+ *
+ * Triggers downstream port reset through link controller registers.
+ * Returns %0 in case of success negative errno otherwise. Only supports
+ * non-USB4 routers with link controller (that's Thunderbolt 2 and
+ * Thunderbolt 3).
+ */
+int tb_lc_reset_port(struct tb_port *port)
+{
+       struct tb_switch *sw = port->sw;
+       int cap, ret;
+       u32 mode;
+
+       if (sw->generation < 2)
+               return -EINVAL;
+
+       cap = find_port_lc_cap(port);
+       if (cap < 0)
+               return cap;
+
+       ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+       if (ret)
+               return ret;
+
+       mode |= TB_LC_PORT_MODE_DPR;
+
+       ret = tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+       if (ret)
+               return ret;
+
+       fsleep(10000);
+
+       ret = tb_sw_read(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+       if (ret)
+               return ret;
+
+       mode &= ~TB_LC_PORT_MODE_DPR;
+
+       return tb_sw_write(sw, &mode, TB_CFG_SWITCH, cap + TB_LC_PORT_MODE, 1);
+}
+
 static int tb_lc_set_port_configured(struct tb_port *port, bool configured)
 {
        bool upstream = tb_is_upstream_port(port);
index fb4f46e51753ab8f3952c7093489571d6a40a1b7..7af2642b97cb8133f1e4d49854cb41f323c2c8ed 100644 (file)
@@ -48,7 +48,7 @@
 
 static bool host_reset = true;
 module_param(host_reset, bool, 0444);
-MODULE_PARM_DESC(host_reset, "reset USBv2 host router (default: true)");
+MODULE_PARM_DESC(host_reset, "reset USB4 host router (default: true)");
 
 static int ring_interrupt_index(const struct tb_ring *ring)
 {
@@ -465,7 +465,7 @@ static int ring_request_msix(struct tb_ring *ring, bool no_suspend)
        if (!nhi->pdev->msix_enabled)
                return 0;
 
-       ret = ida_simple_get(&nhi->msix_ida, 0, MSIX_MAX_VECS, GFP_KERNEL);
+       ret = ida_alloc_max(&nhi->msix_ida, MSIX_MAX_VECS - 1, GFP_KERNEL);
        if (ret < 0)
                return ret;
 
@@ -485,7 +485,7 @@ static int ring_request_msix(struct tb_ring *ring, bool no_suspend)
        return 0;
 
 err_ida_remove:
-       ida_simple_remove(&nhi->msix_ida, ring->vector);
+       ida_free(&nhi->msix_ida, ring->vector);
 
        return ret;
 }
@@ -496,7 +496,7 @@ static void ring_release_msix(struct tb_ring *ring)
                return;
 
        free_irq(ring->irq, ring);
-       ida_simple_remove(&ring->nhi->msix_ida, ring->vector);
+       ida_free(&ring->nhi->msix_ida, ring->vector);
        ring->vector = 0;
        ring->irq = 0;
 }
@@ -1364,7 +1364,6 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        nhi_check_quirks(nhi);
        nhi_check_iommu(nhi);
-
        nhi_reset(nhi);
 
        res = nhi_init_msi(nhi);
@@ -1392,7 +1391,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        dev_dbg(dev, "NHI initialized, starting thunderbolt\n");
 
-       res = tb_domain_add(tb);
+       res = tb_domain_add(tb, host_reset);
        if (res) {
                /*
                 * At this point the RX/TX rings might already have been
index 69fb3b0fa34fa34323b2c0f74788a7e5f2b67dd2..8901db2de327cdbbdcc0a52fd69f187b29f76353 100644 (file)
@@ -330,7 +330,7 @@ struct tb_nvm *tb_nvm_alloc(struct device *dev)
        if (!nvm)
                return ERR_PTR(-ENOMEM);
 
-       ret = ida_simple_get(&nvm_ida, 0, 0, GFP_KERNEL);
+       ret = ida_alloc(&nvm_ida, GFP_KERNEL);
        if (ret < 0) {
                kfree(nvm);
                return ERR_PTR(ret);
@@ -528,7 +528,7 @@ void tb_nvm_free(struct tb_nvm *nvm)
                nvmem_unregister(nvm->non_active);
                nvmem_unregister(nvm->active);
                vfree(nvm->buf);
-               ida_simple_remove(&nvm_ida, nvm->id);
+               ida_free(&nvm_ida, nvm->id);
        }
        kfree(nvm);
 }
index 091a81bbdbdc94623b1fda9a059c1b6396595c15..f760e54cd9bd1f9cc8caf8ad43990e1d32996437 100644 (file)
@@ -446,6 +446,19 @@ static int __tb_path_deactivate_hop(struct tb_port *port, int hop_index,
        return -ETIMEDOUT;
 }
 
+/**
+ * tb_path_deactivate_hop() - Deactivate one path in path config space
+ * @port: Lane or protocol adapter
+ * @hop_index: HopID of the path to be cleared
+ *
+ * This deactivates or clears a single path config space entry at
+ * @hop_index. Returns %0 in success and negative errno otherwise.
+ */
+int tb_path_deactivate_hop(struct tb_port *port, int hop_index)
+{
+       return __tb_path_deactivate_hop(port, hop_index, true);
+}
+
 static void __tb_path_deactivate_hops(struct tb_path *path, int first_hop)
 {
        int i, res;
index e6bfa63b40aee4675293620c5326cdb160af9a19..e81de9c30eac9acc8f9a41941cbeacb82bbebd66 100644 (file)
@@ -43,6 +43,12 @@ static void quirk_usb3_maximum_bandwidth(struct tb_switch *sw)
        }
 }
 
+static void quirk_block_rpm_in_redrive(struct tb_switch *sw)
+{
+       sw->quirks |= QUIRK_KEEP_POWER_IN_DP_REDRIVE;
+       tb_sw_dbg(sw, "preventing runtime PM in DP redrive mode\n");
+}
+
 struct tb_quirk {
        u16 hw_vendor_id;
        u16 hw_device_id;
@@ -86,6 +92,14 @@ static const struct tb_quirk tb_quirks[] = {
                  quirk_usb3_maximum_bandwidth },
        { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_40G_BRIDGE, 0x0000, 0x0000,
                  quirk_usb3_maximum_bandwidth },
+       /*
+        * Block Runtime PM in DP redrive mode for Intel Barlow Ridge host
+        * controllers.
+        */
+       { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI, 0x0000, 0x0000,
+                 quirk_block_rpm_in_redrive },
+       { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI, 0x0000, 0x0000,
+                 quirk_block_rpm_in_redrive },
        /*
         * CLx is not supported on AMD USB4 Yellow Carp and Pink Sardine platforms.
         */
index d49d6628dbf29970a398e381b1603875ec1d7f0c..6bb49bdcd6c18e6f1f56b981b40c522f67db0861 100644 (file)
@@ -356,7 +356,7 @@ static void tb_retimer_release(struct device *dev)
        kfree(rt);
 }
 
-struct device_type tb_retimer_type = {
+const struct device_type tb_retimer_type = {
        .name = "thunderbolt_retimer",
        .groups = retimer_groups,
        .release = tb_retimer_release,
index fad40c4bc710341f27b7f98f6d4317aef6627ae0..6ffc4e81ffed78bedaac182b5a77742390c6cd74 100644 (file)
@@ -676,6 +676,13 @@ int tb_port_disable(struct tb_port *port)
        return __tb_port_enable(port, false);
 }
 
+static int tb_port_reset(struct tb_port *port)
+{
+       if (tb_switch_is_usb4(port->sw))
+               return port->cap_usb4 ? usb4_port_reset(port) : 0;
+       return tb_lc_reset_port(port);
+}
+
 /*
  * tb_init_port() - initialize a port
  *
@@ -771,7 +778,7 @@ static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid,
        if (max_hopid < 0 || max_hopid > port_max_hopid)
                max_hopid = port_max_hopid;
 
-       return ida_simple_get(ida, min_hopid, max_hopid + 1, GFP_KERNEL);
+       return ida_alloc_range(ida, min_hopid, max_hopid, GFP_KERNEL);
 }
 
 /**
@@ -809,7 +816,7 @@ int tb_port_alloc_out_hopid(struct tb_port *port, int min_hopid, int max_hopid)
  */
 void tb_port_release_in_hopid(struct tb_port *port, int hopid)
 {
-       ida_simple_remove(&port->in_hopids, hopid);
+       ida_free(&port->in_hopids, hopid);
 }
 
 /**
@@ -819,7 +826,7 @@ void tb_port_release_in_hopid(struct tb_port *port, int hopid)
  */
 void tb_port_release_out_hopid(struct tb_port *port, int hopid)
 {
-       ida_simple_remove(&port->out_hopids, hopid);
+       ida_free(&port->out_hopids, hopid);
 }
 
 static inline bool tb_switch_is_reachable(const struct tb_switch *parent,
@@ -1120,7 +1127,7 @@ int tb_port_lane_bonding_enable(struct tb_port *port)
                ret = tb_port_set_link_width(port->dual_link_port,
                                             TB_LINK_WIDTH_DUAL);
                if (ret)
-                       goto err_lane0;
+                       goto err_lane1;
        }
 
        /*
@@ -1534,29 +1541,124 @@ static void tb_dump_switch(const struct tb *tb, const struct tb_switch *sw)
               regs->__unknown1, regs->__unknown4);
 }
 
+static int tb_switch_reset_host(struct tb_switch *sw)
+{
+       if (sw->generation > 1) {
+               struct tb_port *port;
+
+               tb_switch_for_each_port(sw, port) {
+                       int i, ret;
+
+                       /*
+                        * For lane adapters we issue downstream port
+                        * reset and clear up path config spaces.
+                        *
+                        * For protocol adapters we disable the path and
+                        * clear path config space one by one (from 8 to
+                        * Max Input HopID of the adapter).
+                        */
+                       if (tb_port_is_null(port) && !tb_is_upstream_port(port)) {
+                               ret = tb_port_reset(port);
+                               if (ret)
+                                       return ret;
+                       } else if (tb_port_is_usb3_down(port) ||
+                                  tb_port_is_usb3_up(port)) {
+                               tb_usb3_port_enable(port, false);
+                       } else if (tb_port_is_dpin(port) ||
+                                  tb_port_is_dpout(port)) {
+                               tb_dp_port_enable(port, false);
+                       } else if (tb_port_is_pcie_down(port) ||
+                                  tb_port_is_pcie_up(port)) {
+                               tb_pci_port_enable(port, false);
+                       } else {
+                               continue;
+                       }
+
+                       /* Cleanup path config space of protocol adapter */
+                       for (i = TB_PATH_MIN_HOPID;
+                            i <= port->config.max_in_hop_id; i++) {
+                               ret = tb_path_deactivate_hop(port, i);
+                               if (ret)
+                                       return ret;
+                       }
+               }
+       } else {
+               struct tb_cfg_result res;
+
+               /* Thunderbolt 1 uses the "reset" config space packet */
+               res.err = tb_sw_write(sw, ((u32 *) &sw->config) + 2,
+                                     TB_CFG_SWITCH, 2, 2);
+               if (res.err)
+                       return res.err;
+               res = tb_cfg_reset(sw->tb->ctl, tb_route(sw));
+               if (res.err > 0)
+                       return -EIO;
+               else if (res.err < 0)
+                       return res.err;
+       }
+
+       return 0;
+}
+
+static int tb_switch_reset_device(struct tb_switch *sw)
+{
+       return tb_port_reset(tb_switch_downstream_port(sw));
+}
+
+static bool tb_switch_enumerated(struct tb_switch *sw)
+{
+       u32 val;
+       int ret;
+
+       /*
+        * Read directly from the hardware because we use this also
+        * during system sleep where sw->config.enabled is already set
+        * by us.
+        */
+       ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, ROUTER_CS_3, 1);
+       if (ret)
+               return false;
+
+       return !!(val & ROUTER_CS_3_V);
+}
+
 /**
- * tb_switch_reset() - reconfigure route, enable and send TB_CFG_PKG_RESET
- * @sw: Switch to reset
+ * tb_switch_reset() - Perform reset to the router
+ * @sw: Router to reset
  *
- * Return: Returns 0 on success or an error code on failure.
+ * Issues reset to the router @sw. Can be used for any router. For host
+ * routers, resets all the downstream ports and cleans up path config
+ * spaces accordingly. For device routers issues downstream port reset
+ * through the parent router, so as side effect there will be unplug
+ * soon after this is finished.
+ *
+ * If the router is not enumerated does nothing.
+ *
+ * Returns %0 on success or negative errno in case of failure.
  */
 int tb_switch_reset(struct tb_switch *sw)
 {
-       struct tb_cfg_result res;
+       int ret;
 
-       if (sw->generation > 1)
+       /*
+        * We cannot access the port config spaces unless the router is
+        * already enumerated. If the router is not enumerated it is
+        * equal to being reset so we can skip that here.
+        */
+       if (!tb_switch_enumerated(sw))
                return 0;
 
-       tb_sw_dbg(sw, "resetting switch\n");
+       tb_sw_dbg(sw, "resetting\n");
 
-       res.err = tb_sw_write(sw, ((u32 *) &sw->config) + 2,
-                             TB_CFG_SWITCH, 2, 2);
-       if (res.err)
-               return res.err;
-       res = tb_cfg_reset(sw->tb->ctl, tb_route(sw));
-       if (res.err > 0)
-               return -EIO;
-       return res.err;
+       if (tb_route(sw))
+               ret = tb_switch_reset_device(sw);
+       else
+               ret = tb_switch_reset_host(sw);
+
+       if (ret)
+               tb_sw_warn(sw, "failed to reset\n");
+
+       return ret;
 }
 
 /**
@@ -2228,7 +2330,7 @@ static const struct dev_pm_ops tb_switch_pm_ops = {
                           NULL)
 };
 
-struct device_type tb_switch_type = {
+const struct device_type tb_switch_type = {
        .name = "thunderbolt_device",
        .release = tb_switch_release,
        .uevent = tb_switch_uevent,
index 846d2813bb1a51db8744948298d57d5e5fcdb36e..c5ce7a694b27df774aeb0e9d6bf8fd7c1cd6a82e 100644 (file)
@@ -17,6 +17,7 @@
 #include "tunnel.h"
 
 #define TB_TIMEOUT             100     /* ms */
+#define TB_RELEASE_BW_TIMEOUT  10000   /* ms */
 
 /*
  * Minimum bandwidth (in Mb/s) that is needed in the single transmitter/receiver
@@ -75,112 +76,6 @@ struct tb_hotplug_event {
        bool unplug;
 };
 
-static void tb_init_bandwidth_groups(struct tb_cm *tcm)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
-               struct tb_bandwidth_group *group = &tcm->groups[i];
-
-               group->tb = tcm_to_tb(tcm);
-               group->index = i + 1;
-               INIT_LIST_HEAD(&group->ports);
-       }
-}
-
-static void tb_bandwidth_group_attach_port(struct tb_bandwidth_group *group,
-                                          struct tb_port *in)
-{
-       if (!group || WARN_ON(in->group))
-               return;
-
-       in->group = group;
-       list_add_tail(&in->group_list, &group->ports);
-
-       tb_port_dbg(in, "attached to bandwidth group %d\n", group->index);
-}
-
-static struct tb_bandwidth_group *tb_find_free_bandwidth_group(struct tb_cm *tcm)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
-               struct tb_bandwidth_group *group = &tcm->groups[i];
-
-               if (list_empty(&group->ports))
-                       return group;
-       }
-
-       return NULL;
-}
-
-static struct tb_bandwidth_group *
-tb_attach_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
-                         struct tb_port *out)
-{
-       struct tb_bandwidth_group *group;
-       struct tb_tunnel *tunnel;
-
-       /*
-        * Find all DP tunnels that go through all the same USB4 links
-        * as this one. Because we always setup tunnels the same way we
-        * can just check for the routers at both ends of the tunnels
-        * and if they are the same we have a match.
-        */
-       list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
-               if (!tb_tunnel_is_dp(tunnel))
-                       continue;
-
-               if (tunnel->src_port->sw == in->sw &&
-                   tunnel->dst_port->sw == out->sw) {
-                       group = tunnel->src_port->group;
-                       if (group) {
-                               tb_bandwidth_group_attach_port(group, in);
-                               return group;
-                       }
-               }
-       }
-
-       /* Pick up next available group then */
-       group = tb_find_free_bandwidth_group(tcm);
-       if (group)
-               tb_bandwidth_group_attach_port(group, in);
-       else
-               tb_port_warn(in, "no available bandwidth groups\n");
-
-       return group;
-}
-
-static void tb_discover_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
-                                       struct tb_port *out)
-{
-       if (usb4_dp_port_bandwidth_mode_enabled(in)) {
-               int index, i;
-
-               index = usb4_dp_port_group_id(in);
-               for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
-                       if (tcm->groups[i].index == index) {
-                               tb_bandwidth_group_attach_port(&tcm->groups[i], in);
-                               return;
-                       }
-               }
-       }
-
-       tb_attach_bandwidth_group(tcm, in, out);
-}
-
-static void tb_detach_bandwidth_group(struct tb_port *in)
-{
-       struct tb_bandwidth_group *group = in->group;
-
-       if (group) {
-               in->group = NULL;
-               list_del_init(&in->group_list);
-
-               tb_port_dbg(in, "detached from bandwidth group %d\n", group->index);
-       }
-}
-
 static void tb_handle_hotplug(struct work_struct *work);
 
 static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug)
@@ -472,34 +367,6 @@ static void tb_switch_discover_tunnels(struct tb_switch *sw,
        }
 }
 
-static void tb_discover_tunnels(struct tb *tb)
-{
-       struct tb_cm *tcm = tb_priv(tb);
-       struct tb_tunnel *tunnel;
-
-       tb_switch_discover_tunnels(tb->root_switch, &tcm->tunnel_list, true);
-
-       list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
-               if (tb_tunnel_is_pci(tunnel)) {
-                       struct tb_switch *parent = tunnel->dst_port->sw;
-
-                       while (parent != tunnel->src_port->sw) {
-                               parent->boot = true;
-                               parent = tb_switch_parent(parent);
-                       }
-               } else if (tb_tunnel_is_dp(tunnel)) {
-                       struct tb_port *in = tunnel->src_port;
-                       struct tb_port *out = tunnel->dst_port;
-
-                       /* Keep the domain from powering down */
-                       pm_runtime_get_sync(&in->sw->dev);
-                       pm_runtime_get_sync(&out->sw->dev);
-
-                       tb_discover_bandwidth_group(tcm, in, out);
-               }
-       }
-}
-
 static int tb_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd)
 {
        if (tb_switch_is_usb4(port->sw))
@@ -681,6 +548,10 @@ static int tb_consumed_usb3_pcie_bandwidth(struct tb *tb,
  * Calculates consumed DP bandwidth at @port between path from @src_port
  * to @dst_port. Does not take tunnel starting from @src_port and ending
  * from @src_port into account.
+ *
+ * If there is bandwidth reserved for any of the groups between
+ * @src_port and @dst_port (but not yet used) that is also taken into
+ * account in the returned consumed bandwidth.
  */
 static int tb_consumed_dp_bandwidth(struct tb *tb,
                                    struct tb_port *src_port,
@@ -689,9 +560,11 @@ static int tb_consumed_dp_bandwidth(struct tb *tb,
                                    int *consumed_up,
                                    int *consumed_down)
 {
+       int group_reserved[MAX_GROUPS] = {};
        struct tb_cm *tcm = tb_priv(tb);
        struct tb_tunnel *tunnel;
-       int ret;
+       bool downstream;
+       int i, ret;
 
        *consumed_up = *consumed_down = 0;
 
@@ -700,6 +573,7 @@ static int tb_consumed_dp_bandwidth(struct tb *tb,
         * their consumed bandwidth from the available.
         */
        list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
+               const struct tb_bandwidth_group *group;
                int dp_consumed_up, dp_consumed_down;
 
                if (tb_tunnel_is_invalid(tunnel))
@@ -711,6 +585,15 @@ static int tb_consumed_dp_bandwidth(struct tb *tb,
                if (!tb_tunnel_port_on_path(tunnel, port))
                        continue;
 
+               /*
+                * Calculate what is reserved for groups crossing the
+                * same ports only once (as that is reserved for all the
+                * tunnels in the group).
+                */
+               group = tunnel->src_port->group;
+               if (group && group->reserved && !group_reserved[group->index])
+                       group_reserved[group->index] = group->reserved;
+
                /*
                 * Ignore the DP tunnel between src_port and dst_port
                 * because it is the same tunnel and we may be
@@ -729,6 +612,14 @@ static int tb_consumed_dp_bandwidth(struct tb *tb,
                *consumed_down += dp_consumed_down;
        }
 
+       downstream = tb_port_path_direction_downstream(src_port, dst_port);
+       for (i = 0; i < ARRAY_SIZE(group_reserved); i++) {
+               if (downstream)
+                       *consumed_down += group_reserved[i];
+               else
+                       *consumed_up += group_reserved[i];
+       }
+
        return 0;
 }
 
@@ -1181,8 +1072,6 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
  * @tb: Domain structure
  * @src_port: Source adapter to start the transition
  * @dst_port: Destination adapter
- * @requested_up: New lower bandwidth request upstream (Mb/s)
- * @requested_down: New lower bandwidth request downstream (Mb/s)
  * @keep_asym: Keep asymmetric link if preferred
  *
  * Goes over each link from @src_port to @dst_port and tries to
@@ -1190,8 +1079,7 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
  * allows and link asymmetric preference is ignored (if @keep_asym is %false).
  */
 static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
-                           struct tb_port *dst_port, int requested_up,
-                           int requested_down, bool keep_asym)
+                           struct tb_port *dst_port, bool keep_asym)
 {
        bool clx = false, clx_disabled = false, downstream;
        struct tb_switch *sw;
@@ -1230,10 +1118,10 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
                         * guard band 10%) as the link was configured asymmetric
                         * already.
                         */
-                       if (consumed_down + requested_down >= asym_threshold)
+                       if (consumed_down >= asym_threshold)
                                continue;
                } else {
-                       if (consumed_up + requested_up >= asym_threshold)
+                       if (consumed_up >= asym_threshold)
                                continue;
                }
 
@@ -1306,7 +1194,7 @@ static void tb_configure_link(struct tb_port *down, struct tb_port *up,
                struct tb_port *host_port;
 
                host_port = tb_port_at(tb_route(sw), tb->root_switch);
-               tb_configure_sym(tb, host_port, up, 0, 0, false);
+               tb_configure_sym(tb, host_port, up, false);
        }
 
        /* Set the link configured */
@@ -1464,73 +1352,364 @@ out_rpm_put:
        }
 }
 
-static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
+static void
+tb_recalc_estimated_bandwidth_for_group(struct tb_bandwidth_group *group)
 {
-       struct tb_port *src_port, *dst_port;
-       struct tb *tb;
+       struct tb_tunnel *first_tunnel;
+       struct tb *tb = group->tb;
+       struct tb_port *in;
+       int ret;
 
-       if (!tunnel)
-               return;
+       tb_dbg(tb, "re-calculating bandwidth estimation for group %u\n",
+              group->index);
 
-       tb_tunnel_deactivate(tunnel);
-       list_del(&tunnel->list);
+       first_tunnel = NULL;
+       list_for_each_entry(in, &group->ports, group_list) {
+               int estimated_bw, estimated_up, estimated_down;
+               struct tb_tunnel *tunnel;
+               struct tb_port *out;
 
-       tb = tunnel->tb;
-       src_port = tunnel->src_port;
-       dst_port = tunnel->dst_port;
+               if (!usb4_dp_port_bandwidth_mode_enabled(in))
+                       continue;
+
+               tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
+               if (WARN_ON(!tunnel))
+                       break;
+
+               if (!first_tunnel) {
+                       /*
+                        * Since USB3 bandwidth is shared by all DP
+                        * tunnels under the host router USB4 port, even
+                        * if they do not begin from the host router, we
+                        * can release USB3 bandwidth just once and not
+                        * for each tunnel separately.
+                        */
+                       first_tunnel = tunnel;
+                       ret = tb_release_unused_usb3_bandwidth(tb,
+                               first_tunnel->src_port, first_tunnel->dst_port);
+                       if (ret) {
+                               tb_tunnel_warn(tunnel,
+                                       "failed to release unused bandwidth\n");
+                               break;
+                       }
+               }
+
+               out = tunnel->dst_port;
+               ret = tb_available_bandwidth(tb, in, out, &estimated_up,
+                                            &estimated_down, true);
+               if (ret) {
+                       tb_tunnel_warn(tunnel,
+                               "failed to re-calculate estimated bandwidth\n");
+                       break;
+               }
 
-       switch (tunnel->type) {
-       case TB_TUNNEL_DP:
-               tb_detach_bandwidth_group(src_port);
-               /*
-                * In case of DP tunnel make sure the DP IN resource is
-                * deallocated properly.
-                */
-               tb_switch_dealloc_dp_resource(src_port->sw, src_port);
                /*
-                * If bandwidth on a link is < asym_threshold
-                * transition the link to symmetric.
+                * Estimated bandwidth includes:
+                *  - already allocated bandwidth for the DP tunnel
+                *  - available bandwidth along the path
+                *  - bandwidth allocated for USB 3.x but not used.
                 */
-               tb_configure_sym(tb, src_port, dst_port, 0, 0, true);
-               /* Now we can allow the domain to runtime suspend again */
-               pm_runtime_mark_last_busy(&dst_port->sw->dev);
-               pm_runtime_put_autosuspend(&dst_port->sw->dev);
-               pm_runtime_mark_last_busy(&src_port->sw->dev);
-               pm_runtime_put_autosuspend(&src_port->sw->dev);
-               fallthrough;
-
-       case TB_TUNNEL_USB3:
-               tb_reclaim_usb3_bandwidth(tb, src_port, dst_port);
-               break;
+               if (tb_tunnel_direction_downstream(tunnel))
+                       estimated_bw = estimated_down;
+               else
+                       estimated_bw = estimated_up;
 
-       default:
                /*
-                * PCIe and DMA tunnels do not consume guaranteed
-                * bandwidth.
+                * If there is reserved bandwidth for the group that is
+                * not yet released we report that too.
                 */
-               break;
+               tb_tunnel_dbg(tunnel,
+                             "re-calculated estimated bandwidth %u (+ %u reserved) = %u Mb/s\n",
+                             estimated_bw, group->reserved,
+                             estimated_bw + group->reserved);
+
+               if (usb4_dp_port_set_estimated_bandwidth(in,
+                               estimated_bw + group->reserved))
+                       tb_tunnel_warn(tunnel,
+                                      "failed to update estimated bandwidth\n");
        }
 
-       tb_tunnel_free(tunnel);
+       if (first_tunnel)
+               tb_reclaim_usb3_bandwidth(tb, first_tunnel->src_port,
+                                         first_tunnel->dst_port);
+
+       tb_dbg(tb, "bandwidth estimation for group %u done\n", group->index);
 }
 
-/*
- * tb_free_invalid_tunnels() - destroy tunnels of devices that have gone away
- */
-static void tb_free_invalid_tunnels(struct tb *tb)
+static void tb_recalc_estimated_bandwidth(struct tb *tb)
 {
        struct tb_cm *tcm = tb_priv(tb);
-       struct tb_tunnel *tunnel;
-       struct tb_tunnel *n;
+       int i;
 
-       list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
-               if (tb_tunnel_is_invalid(tunnel))
-                       tb_deactivate_and_free_tunnel(tunnel);
-       }
-}
+       tb_dbg(tb, "bandwidth consumption changed, re-calculating estimated bandwidth\n");
 
-/*
- * tb_free_unplugged_children() - traverse hierarchy and free unplugged switches
+       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+               struct tb_bandwidth_group *group = &tcm->groups[i];
+
+               if (!list_empty(&group->ports))
+                       tb_recalc_estimated_bandwidth_for_group(group);
+       }
+
+       tb_dbg(tb, "bandwidth re-calculation done\n");
+}
+
+static bool __release_group_bandwidth(struct tb_bandwidth_group *group)
+{
+       if (group->reserved) {
+               tb_dbg(group->tb, "group %d released total %d Mb/s\n", group->index,
+                       group->reserved);
+               group->reserved = 0;
+               return true;
+       }
+       return false;
+}
+
+static void __configure_group_sym(struct tb_bandwidth_group *group)
+{
+       struct tb_tunnel *tunnel;
+       struct tb_port *in;
+
+       if (list_empty(&group->ports))
+               return;
+
+       /*
+        * All the tunnels in the group go through the same USB4 links
+        * so we find the first one here and pass the IN and OUT
+        * adapters to tb_configure_sym() which now transitions the
+        * links back to symmetric if bandwidth requirement < asym_threshold.
+        *
+        * We do this here to avoid unnecessary transitions (for example
+        * if the graphics released bandwidth for other tunnel in the
+        * same group).
+        */
+       in = list_first_entry(&group->ports, struct tb_port, group_list);
+       tunnel = tb_find_tunnel(group->tb, TB_TUNNEL_DP, in, NULL);
+       if (tunnel)
+               tb_configure_sym(group->tb, in, tunnel->dst_port, true);
+}
+
+static void tb_bandwidth_group_release_work(struct work_struct *work)
+{
+       struct tb_bandwidth_group *group =
+               container_of(work, typeof(*group), release_work.work);
+       struct tb *tb = group->tb;
+
+       mutex_lock(&tb->lock);
+       if (__release_group_bandwidth(group))
+               tb_recalc_estimated_bandwidth(tb);
+       __configure_group_sym(group);
+       mutex_unlock(&tb->lock);
+}
+
+static void tb_init_bandwidth_groups(struct tb_cm *tcm)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+               struct tb_bandwidth_group *group = &tcm->groups[i];
+
+               group->tb = tcm_to_tb(tcm);
+               group->index = i + 1;
+               INIT_LIST_HEAD(&group->ports);
+               INIT_DELAYED_WORK(&group->release_work,
+                                 tb_bandwidth_group_release_work);
+       }
+}
+
+static void tb_bandwidth_group_attach_port(struct tb_bandwidth_group *group,
+                                          struct tb_port *in)
+{
+       if (!group || WARN_ON(in->group))
+               return;
+
+       in->group = group;
+       list_add_tail(&in->group_list, &group->ports);
+
+       tb_port_dbg(in, "attached to bandwidth group %d\n", group->index);
+}
+
+static struct tb_bandwidth_group *tb_find_free_bandwidth_group(struct tb_cm *tcm)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+               struct tb_bandwidth_group *group = &tcm->groups[i];
+
+               if (list_empty(&group->ports))
+                       return group;
+       }
+
+       return NULL;
+}
+
+static struct tb_bandwidth_group *
+tb_attach_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
+                         struct tb_port *out)
+{
+       struct tb_bandwidth_group *group;
+       struct tb_tunnel *tunnel;
+
+       /*
+        * Find all DP tunnels that go through all the same USB4 links
+        * as this one. Because we always setup tunnels the same way we
+        * can just check for the routers at both ends of the tunnels
+        * and if they are the same we have a match.
+        */
+       list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
+               if (!tb_tunnel_is_dp(tunnel))
+                       continue;
+
+               if (tunnel->src_port->sw == in->sw &&
+                   tunnel->dst_port->sw == out->sw) {
+                       group = tunnel->src_port->group;
+                       if (group) {
+                               tb_bandwidth_group_attach_port(group, in);
+                               return group;
+                       }
+               }
+       }
+
+       /* Pick up next available group then */
+       group = tb_find_free_bandwidth_group(tcm);
+       if (group)
+               tb_bandwidth_group_attach_port(group, in);
+       else
+               tb_port_warn(in, "no available bandwidth groups\n");
+
+       return group;
+}
+
+static void tb_discover_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
+                                       struct tb_port *out)
+{
+       if (usb4_dp_port_bandwidth_mode_enabled(in)) {
+               int index, i;
+
+               index = usb4_dp_port_group_id(in);
+               for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+                       if (tcm->groups[i].index == index) {
+                               tb_bandwidth_group_attach_port(&tcm->groups[i], in);
+                               return;
+                       }
+               }
+       }
+
+       tb_attach_bandwidth_group(tcm, in, out);
+}
+
+static void tb_detach_bandwidth_group(struct tb_port *in)
+{
+       struct tb_bandwidth_group *group = in->group;
+
+       if (group) {
+               in->group = NULL;
+               list_del_init(&in->group_list);
+
+               tb_port_dbg(in, "detached from bandwidth group %d\n", group->index);
+
+               /* No more tunnels so release the reserved bandwidth if any */
+               if (list_empty(&group->ports)) {
+                       cancel_delayed_work(&group->release_work);
+                       __release_group_bandwidth(group);
+               }
+       }
+}
+
+static void tb_discover_tunnels(struct tb *tb)
+{
+       struct tb_cm *tcm = tb_priv(tb);
+       struct tb_tunnel *tunnel;
+
+       tb_switch_discover_tunnels(tb->root_switch, &tcm->tunnel_list, true);
+
+       list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
+               if (tb_tunnel_is_pci(tunnel)) {
+                       struct tb_switch *parent = tunnel->dst_port->sw;
+
+                       while (parent != tunnel->src_port->sw) {
+                               parent->boot = true;
+                               parent = tb_switch_parent(parent);
+                       }
+               } else if (tb_tunnel_is_dp(tunnel)) {
+                       struct tb_port *in = tunnel->src_port;
+                       struct tb_port *out = tunnel->dst_port;
+
+                       /* Keep the domain from powering down */
+                       pm_runtime_get_sync(&in->sw->dev);
+                       pm_runtime_get_sync(&out->sw->dev);
+
+                       tb_discover_bandwidth_group(tcm, in, out);
+               }
+       }
+}
+
+static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
+{
+       struct tb_port *src_port, *dst_port;
+       struct tb *tb;
+
+       if (!tunnel)
+               return;
+
+       tb_tunnel_deactivate(tunnel);
+       list_del(&tunnel->list);
+
+       tb = tunnel->tb;
+       src_port = tunnel->src_port;
+       dst_port = tunnel->dst_port;
+
+       switch (tunnel->type) {
+       case TB_TUNNEL_DP:
+               tb_detach_bandwidth_group(src_port);
+               /*
+                * In case of DP tunnel make sure the DP IN resource is
+                * deallocated properly.
+                */
+               tb_switch_dealloc_dp_resource(src_port->sw, src_port);
+               /*
+                * If bandwidth on a link is < asym_threshold
+                * transition the link to symmetric.
+                */
+               tb_configure_sym(tb, src_port, dst_port, true);
+               /* Now we can allow the domain to runtime suspend again */
+               pm_runtime_mark_last_busy(&dst_port->sw->dev);
+               pm_runtime_put_autosuspend(&dst_port->sw->dev);
+               pm_runtime_mark_last_busy(&src_port->sw->dev);
+               pm_runtime_put_autosuspend(&src_port->sw->dev);
+               fallthrough;
+
+       case TB_TUNNEL_USB3:
+               tb_reclaim_usb3_bandwidth(tb, src_port, dst_port);
+               break;
+
+       default:
+               /*
+                * PCIe and DMA tunnels do not consume guaranteed
+                * bandwidth.
+                */
+               break;
+       }
+
+       tb_tunnel_free(tunnel);
+}
+
+/*
+ * tb_free_invalid_tunnels() - destroy tunnels of devices that have gone away
+ */
+static void tb_free_invalid_tunnels(struct tb *tb)
+{
+       struct tb_cm *tcm = tb_priv(tb);
+       struct tb_tunnel *tunnel;
+       struct tb_tunnel *n;
+
+       list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
+               if (tb_tunnel_is_invalid(tunnel))
+                       tb_deactivate_and_free_tunnel(tunnel);
+       }
+}
+
+/*
+ * tb_free_unplugged_children() - traverse hierarchy and free unplugged switches
  */
 static void tb_free_unplugged_children(struct tb_switch *sw)
 {
@@ -1605,101 +1784,6 @@ out:
        return tb_find_unused_port(sw, TB_TYPE_PCIE_DOWN);
 }
 
-static void
-tb_recalc_estimated_bandwidth_for_group(struct tb_bandwidth_group *group)
-{
-       struct tb_tunnel *first_tunnel;
-       struct tb *tb = group->tb;
-       struct tb_port *in;
-       int ret;
-
-       tb_dbg(tb, "re-calculating bandwidth estimation for group %u\n",
-              group->index);
-
-       first_tunnel = NULL;
-       list_for_each_entry(in, &group->ports, group_list) {
-               int estimated_bw, estimated_up, estimated_down;
-               struct tb_tunnel *tunnel;
-               struct tb_port *out;
-
-               if (!usb4_dp_port_bandwidth_mode_enabled(in))
-                       continue;
-
-               tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
-               if (WARN_ON(!tunnel))
-                       break;
-
-               if (!first_tunnel) {
-                       /*
-                        * Since USB3 bandwidth is shared by all DP
-                        * tunnels under the host router USB4 port, even
-                        * if they do not begin from the host router, we
-                        * can release USB3 bandwidth just once and not
-                        * for each tunnel separately.
-                        */
-                       first_tunnel = tunnel;
-                       ret = tb_release_unused_usb3_bandwidth(tb,
-                               first_tunnel->src_port, first_tunnel->dst_port);
-                       if (ret) {
-                               tb_tunnel_warn(tunnel,
-                                       "failed to release unused bandwidth\n");
-                               break;
-                       }
-               }
-
-               out = tunnel->dst_port;
-               ret = tb_available_bandwidth(tb, in, out, &estimated_up,
-                                            &estimated_down, true);
-               if (ret) {
-                       tb_tunnel_warn(tunnel,
-                               "failed to re-calculate estimated bandwidth\n");
-                       break;
-               }
-
-               /*
-                * Estimated bandwidth includes:
-                *  - already allocated bandwidth for the DP tunnel
-                *  - available bandwidth along the path
-                *  - bandwidth allocated for USB 3.x but not used.
-                */
-               tb_tunnel_dbg(tunnel,
-                             "re-calculated estimated bandwidth %u/%u Mb/s\n",
-                             estimated_up, estimated_down);
-
-               if (tb_port_path_direction_downstream(in, out))
-                       estimated_bw = estimated_down;
-               else
-                       estimated_bw = estimated_up;
-
-               if (usb4_dp_port_set_estimated_bandwidth(in, estimated_bw))
-                       tb_tunnel_warn(tunnel,
-                                      "failed to update estimated bandwidth\n");
-       }
-
-       if (first_tunnel)
-               tb_reclaim_usb3_bandwidth(tb, first_tunnel->src_port,
-                                         first_tunnel->dst_port);
-
-       tb_dbg(tb, "bandwidth estimation for group %u done\n", group->index);
-}
-
-static void tb_recalc_estimated_bandwidth(struct tb *tb)
-{
-       struct tb_cm *tcm = tb_priv(tb);
-       int i;
-
-       tb_dbg(tb, "bandwidth consumption changed, re-calculating estimated bandwidth\n");
-
-       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
-               struct tb_bandwidth_group *group = &tcm->groups[i];
-
-               if (!list_empty(&group->ports))
-                       tb_recalc_estimated_bandwidth_for_group(group);
-       }
-
-       tb_dbg(tb, "bandwidth re-calculation done\n");
-}
-
 static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
 {
        struct tb_port *host_port, *port;
@@ -1737,48 +1821,14 @@ static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
        return NULL;
 }
 
-static bool tb_tunnel_one_dp(struct tb *tb)
+static bool tb_tunnel_one_dp(struct tb *tb, struct tb_port *in,
+                            struct tb_port *out)
 {
        int available_up, available_down, ret, link_nr;
        struct tb_cm *tcm = tb_priv(tb);
-       struct tb_port *port, *in, *out;
        int consumed_up, consumed_down;
        struct tb_tunnel *tunnel;
 
-       /*
-        * Find pair of inactive DP IN and DP OUT adapters and then
-        * establish a DP tunnel between them.
-        */
-       tb_dbg(tb, "looking for DP IN <-> DP OUT pairs:\n");
-
-       in = NULL;
-       out = NULL;
-       list_for_each_entry(port, &tcm->dp_resources, list) {
-               if (!tb_port_is_dpin(port))
-                       continue;
-
-               if (tb_port_is_enabled(port)) {
-                       tb_port_dbg(port, "DP IN in use\n");
-                       continue;
-               }
-
-               in = port;
-               tb_port_dbg(in, "DP IN available\n");
-
-               out = tb_find_dp_out(tb, port);
-               if (out)
-                       break;
-       }
-
-       if (!in) {
-               tb_dbg(tb, "no suitable DP IN adapter available, not tunneling\n");
-               return false;
-       }
-       if (!out) {
-               tb_dbg(tb, "no suitable DP OUT adapter available, not tunneling\n");
-               return false;
-       }
-
        /*
         * This is only applicable to links that are not bonded (so
         * when Thunderbolt 1 hardware is involved somewhere in the
@@ -1839,15 +1889,19 @@ static bool tb_tunnel_one_dp(struct tb *tb)
                goto err_free;
        }
 
+       /* If fail reading tunnel's consumed bandwidth, tear it down */
+       ret = tb_tunnel_consumed_bandwidth(tunnel, &consumed_up, &consumed_down);
+       if (ret)
+               goto err_deactivate;
+
        list_add_tail(&tunnel->list, &tcm->tunnel_list);
-       tb_reclaim_usb3_bandwidth(tb, in, out);
 
+       tb_reclaim_usb3_bandwidth(tb, in, out);
        /*
         * Transition the links to asymmetric if the consumption exceeds
         * the threshold.
         */
-       if (!tb_tunnel_consumed_bandwidth(tunnel, &consumed_up, &consumed_down))
-               tb_configure_asym(tb, in, out, consumed_up, consumed_down);
+       tb_configure_asym(tb, in, out, consumed_up, consumed_down);
 
        /* Update the domain with the new bandwidth estimation */
        tb_recalc_estimated_bandwidth(tb);
@@ -1859,6 +1913,8 @@ static bool tb_tunnel_one_dp(struct tb *tb)
        tb_increase_tmu_accuracy(tunnel);
        return true;
 
+err_deactivate:
+       tb_tunnel_deactivate(tunnel);
 err_free:
        tb_tunnel_free(tunnel);
 err_reclaim_usb:
@@ -1878,13 +1934,86 @@ err_rpm_put:
 
 static void tb_tunnel_dp(struct tb *tb)
 {
+       struct tb_cm *tcm = tb_priv(tb);
+       struct tb_port *port, *in, *out;
+
        if (!tb_acpi_may_tunnel_dp()) {
                tb_dbg(tb, "DP tunneling disabled, not creating tunnel\n");
                return;
        }
 
-       while (tb_tunnel_one_dp(tb))
-               ;
+       /*
+        * Find pair of inactive DP IN and DP OUT adapters and then
+        * establish a DP tunnel between them.
+        */
+       tb_dbg(tb, "looking for DP IN <-> DP OUT pairs:\n");
+
+       in = NULL;
+       out = NULL;
+       list_for_each_entry(port, &tcm->dp_resources, list) {
+               if (!tb_port_is_dpin(port))
+                       continue;
+
+               if (tb_port_is_enabled(port)) {
+                       tb_port_dbg(port, "DP IN in use\n");
+                       continue;
+               }
+
+               in = port;
+               tb_port_dbg(in, "DP IN available\n");
+
+               out = tb_find_dp_out(tb, port);
+               if (out)
+                       tb_tunnel_one_dp(tb, in, out);
+               else
+                       tb_port_dbg(in, "no suitable DP OUT adapter available, not tunneling\n");
+       }
+
+       if (!in)
+               tb_dbg(tb, "no suitable DP IN adapter available, not tunneling\n");
+}
+
+static void tb_enter_redrive(struct tb_port *port)
+{
+       struct tb_switch *sw = port->sw;
+
+       if (!(sw->quirks & QUIRK_KEEP_POWER_IN_DP_REDRIVE))
+               return;
+
+       /*
+        * If we get hot-unplug for the DP IN port of the host router
+        * and the DP resource is not available anymore it means there
+        * is a monitor connected directly to the Type-C port and we are
+        * in "redrive" mode. For this to work we cannot enter RTD3 so
+        * we bump up the runtime PM reference count here.
+        */
+       if (!tb_port_is_dpin(port))
+               return;
+       if (tb_route(sw))
+               return;
+       if (!tb_switch_query_dp_resource(sw, port)) {
+               port->redrive = true;
+               pm_runtime_get(&sw->dev);
+               tb_port_dbg(port, "enter redrive mode, keeping powered\n");
+       }
+}
+
+static void tb_exit_redrive(struct tb_port *port)
+{
+       struct tb_switch *sw = port->sw;
+
+       if (!(sw->quirks & QUIRK_KEEP_POWER_IN_DP_REDRIVE))
+               return;
+
+       if (!tb_port_is_dpin(port))
+               return;
+       if (tb_route(sw))
+               return;
+       if (port->redrive && tb_switch_query_dp_resource(sw, port)) {
+               port->redrive = false;
+               pm_runtime_put(&sw->dev);
+               tb_port_dbg(port, "exit redrive mode\n");
+       }
 }
 
 static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port)
@@ -1903,7 +2032,10 @@ static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port)
        }
 
        tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, out);
-       tb_deactivate_and_free_tunnel(tunnel);
+       if (tunnel)
+               tb_deactivate_and_free_tunnel(tunnel);
+       else
+               tb_enter_redrive(port);
        list_del_init(&port->list);
 
        /*
@@ -1930,6 +2062,7 @@ static void tb_dp_resource_available(struct tb *tb, struct tb_port *port)
        tb_port_dbg(port, "DP %s resource available after hotplug\n",
                    tb_port_is_dpin(port) ? "IN" : "OUT");
        list_add_tail(&port->list, &tcm->dp_resources);
+       tb_exit_redrive(port);
 
        /* Look for suitable DP IN <-> DP OUT pairs now */
        tb_tunnel_dp(tb);
@@ -2243,8 +2376,10 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
        int allocated_up, allocated_down, available_up, available_down, ret;
        int requested_up_corrected, requested_down_corrected, granularity;
        int max_up, max_down, max_up_rounded, max_down_rounded;
+       struct tb_bandwidth_group *group;
        struct tb *tb = tunnel->tb;
        struct tb_port *in, *out;
+       bool downstream;
 
        ret = tb_tunnel_allocated_bandwidth(tunnel, &allocated_up, &allocated_down);
        if (ret)
@@ -2270,11 +2405,11 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
         */
        ret = tb_tunnel_maximum_bandwidth(tunnel, &max_up, &max_down);
        if (ret)
-               return ret;
+               goto fail;
 
        ret = usb4_dp_port_granularity(in);
        if (ret < 0)
-               return ret;
+               goto fail;
        granularity = ret;
 
        max_up_rounded = roundup(max_up, granularity);
@@ -2304,24 +2439,48 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
                              "bandwidth request too high (%d/%d Mb/s > %d/%d Mb/s)\n",
                              requested_up_corrected, requested_down_corrected,
                              max_up_rounded, max_down_rounded);
-               return -ENOBUFS;
+               ret = -ENOBUFS;
+               goto fail;
        }
 
+       downstream = tb_tunnel_direction_downstream(tunnel);
+       group = in->group;
+
        if ((*requested_up >= 0 && requested_up_corrected <= allocated_up) ||
            (*requested_down >= 0 && requested_down_corrected <= allocated_down)) {
-               /*
-                * If bandwidth on a link is < asym_threshold transition
-                * the link to symmetric.
-                */
-               tb_configure_sym(tb, in, out, *requested_up, *requested_down, true);
-               /*
-                * If requested bandwidth is less or equal than what is
-                * currently allocated to that tunnel we simply change
-                * the reservation of the tunnel. Since all the tunnels
-                * going out from the same USB4 port are in the same
-                * group the released bandwidth will be taken into
-                * account for the other tunnels automatically below.
-                */
+               if (tunnel->bw_mode) {
+                       int reserved;
+                       /*
+                        * If requested bandwidth is less or equal than
+                        * what is currently allocated to that tunnel we
+                        * simply change the reservation of the tunnel
+                        * and add the released bandwidth for the group
+                        * for the next 10s. Then we release it for
+                        * others to use.
+                        */
+                       if (downstream)
+                               reserved = allocated_down - *requested_down;
+                       else
+                               reserved = allocated_up - *requested_up;
+
+                       if (reserved > 0) {
+                               group->reserved += reserved;
+                               tb_dbg(tb, "group %d reserved %d total %d Mb/s\n",
+                                      group->index, reserved, group->reserved);
+
+                               /*
+                                * If it was not already pending,
+                                * schedule release now. If it is then
+                                * postpone it for the next 10s (unless
+                                * it is already running in which case
+                                * the 10s already expired and we should
+                                * give the reserved back to others).
+                                */
+                               mod_delayed_work(system_wq, &group->release_work,
+                                       msecs_to_jiffies(TB_RELEASE_BW_TIMEOUT));
+                       }
+               }
+
                return tb_tunnel_alloc_bandwidth(tunnel, requested_up,
                                                 requested_down);
        }
@@ -2332,7 +2491,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
         */
        ret = tb_release_unused_usb3_bandwidth(tb, in, out);
        if (ret)
-               return ret;
+               goto fail;
 
        /*
         * Then go over all tunnels that cross the same USB4 ports (they
@@ -2344,11 +2503,15 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
        if (ret)
                goto reclaim;
 
-       tb_tunnel_dbg(tunnel, "bandwidth available for allocation %d/%d Mb/s\n",
-                     available_up, available_down);
+       tb_tunnel_dbg(tunnel, "bandwidth available for allocation %d/%d (+ %u reserved) Mb/s\n",
+                     available_up, available_down, group->reserved);
+
+       if ((*requested_up >= 0 &&
+               available_up + group->reserved >= requested_up_corrected) ||
+           (*requested_down >= 0 &&
+               available_down + group->reserved >= requested_down_corrected)) {
+               int released = 0;
 
-       if ((*requested_up >= 0 && available_up >= requested_up_corrected) ||
-           (*requested_down >= 0 && available_down >= requested_down_corrected)) {
                /*
                 * If bandwidth on a link is >= asym_threshold
                 * transition the link to asymmetric.
@@ -2356,15 +2519,28 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
                ret = tb_configure_asym(tb, in, out, *requested_up,
                                        *requested_down);
                if (ret) {
-                       tb_configure_sym(tb, in, out, 0, 0, true);
-                       return ret;
+                       tb_configure_sym(tb, in, out, true);
+                       goto fail;
                }
 
                ret = tb_tunnel_alloc_bandwidth(tunnel, requested_up,
                                                requested_down);
                if (ret) {
                        tb_tunnel_warn(tunnel, "failed to allocate bandwidth\n");
-                       tb_configure_sym(tb, in, out, 0, 0, true);
+                       tb_configure_sym(tb, in, out, true);
+               }
+
+               if (downstream) {
+                       if (*requested_down > available_down)
+                               released = *requested_down - available_down;
+               } else {
+                       if (*requested_up > available_up)
+                               released = *requested_up - available_up;
+               }
+               if (released) {
+                       group->reserved -= released;
+                       tb_dbg(tb, "group %d released %d total %d Mb/s\n",
+                              group->index, released, group->reserved);
                }
        } else {
                ret = -ENOBUFS;
@@ -2372,6 +2548,18 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
 
 reclaim:
        tb_reclaim_usb3_bandwidth(tb, in, out);
+fail:
+       if (ret && ret != -ENODEV) {
+               /*
+                * Write back the same allocated (so no change), this
+                * makes the DPTX request fail on graphics side.
+                */
+               tb_tunnel_dbg(tunnel,
+                             "failing the request by rewriting allocated %d/%d Mb/s\n",
+                             allocated_up, allocated_down);
+               tb_tunnel_alloc_bandwidth(tunnel, &allocated_up, &allocated_down);
+       }
+
        return ret;
 }
 
@@ -2379,11 +2567,11 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
 {
        struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
        int requested_bw, requested_up, requested_down, ret;
-       struct tb_port *in, *out;
        struct tb_tunnel *tunnel;
        struct tb *tb = ev->tb;
        struct tb_cm *tcm = tb_priv(tb);
        struct tb_switch *sw;
+       struct tb_port *in;
 
        pm_runtime_get_sync(&tb->dev);
 
@@ -2406,32 +2594,48 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
 
        tb_port_dbg(in, "handling bandwidth allocation request\n");
 
+       tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
+       if (!tunnel) {
+               tb_port_warn(in, "failed to find tunnel\n");
+               goto put_sw;
+       }
+
        if (!usb4_dp_port_bandwidth_mode_enabled(in)) {
-               tb_port_warn(in, "bandwidth allocation mode not enabled\n");
+               if (tunnel->bw_mode) {
+                       /*
+                        * Reset the tunnel back to use the legacy
+                        * allocation.
+                        */
+                       tunnel->bw_mode = false;
+                       tb_port_dbg(in, "DPTX disabled bandwidth allocation mode\n");
+               } else {
+                       tb_port_warn(in, "bandwidth allocation mode not enabled\n");
+               }
                goto put_sw;
        }
 
        ret = usb4_dp_port_requested_bandwidth(in);
        if (ret < 0) {
-               if (ret == -ENODATA)
-                       tb_port_dbg(in, "no bandwidth request active\n");
-               else
+               if (ret == -ENODATA) {
+                       /*
+                        * There is no request active so this means the
+                        * BW allocation mode was enabled from graphics
+                        * side. At this point we know that the graphics
+                        * driver has read the DRPX capabilities so we
+                        * can offer an better bandwidth estimatation.
+                        */
+                       tb_port_dbg(in, "DPTX enabled bandwidth allocation mode, updating estimated bandwidth\n");
+                       tb_recalc_estimated_bandwidth(tb);
+               } else {
                        tb_port_warn(in, "failed to read requested bandwidth\n");
+               }
                goto put_sw;
        }
        requested_bw = ret;
 
        tb_port_dbg(in, "requested bandwidth %d Mb/s\n", requested_bw);
 
-       tunnel = tb_find_tunnel(tb, TB_TUNNEL_DP, in, NULL);
-       if (!tunnel) {
-               tb_port_warn(in, "failed to find tunnel\n");
-               goto put_sw;
-       }
-
-       out = tunnel->dst_port;
-
-       if (tb_port_path_direction_downstream(in, out)) {
+       if (tb_tunnel_direction_downstream(tunnel)) {
                requested_up = -1;
                requested_down = requested_bw;
        } else {
@@ -2560,6 +2764,16 @@ static void tb_stop(struct tb *tb)
        tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
 }
 
+static void tb_deinit(struct tb *tb)
+{
+       struct tb_cm *tcm = tb_priv(tb);
+       int i;
+
+       /* Cancel all the release bandwidth workers */
+       for (i = 0; i < ARRAY_SIZE(tcm->groups); i++)
+               cancel_delayed_work_sync(&tcm->groups[i].release_work);
+}
+
 static int tb_scan_finalize_switch(struct device *dev, void *data)
 {
        if (tb_is_switch(dev)) {
@@ -2581,9 +2795,10 @@ static int tb_scan_finalize_switch(struct device *dev, void *data)
        return 0;
 }
 
-static int tb_start(struct tb *tb)
+static int tb_start(struct tb *tb, bool reset)
 {
        struct tb_cm *tcm = tb_priv(tb);
+       bool discover = true;
        int ret;
 
        tb->root_switch = tb_switch_alloc(tb, &tb->dev, 0);
@@ -2622,12 +2837,28 @@ static int tb_start(struct tb *tb)
        tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_MODE_LOWRES);
        /* Enable TMU if it is off */
        tb_switch_tmu_enable(tb->root_switch);
-       /* Full scan to discover devices added before the driver was loaded. */
-       tb_scan_switch(tb->root_switch);
-       /* Find out tunnels created by the boot firmware */
-       tb_discover_tunnels(tb);
-       /* Add DP resources from the DP tunnels created by the boot firmware */
-       tb_discover_dp_resources(tb);
+
+       /*
+        * Boot firmware might have created tunnels of its own. Since we
+        * cannot be sure they are usable for us, tear them down and
+        * reset the ports to handle it as new hotplug for USB4 v1
+        * routers (for USB4 v2 and beyond we already do host reset).
+        */
+       if (reset && tb_switch_is_usb4(tb->root_switch)) {
+               discover = false;
+               if (usb4_switch_version(tb->root_switch) == 1)
+                       tb_switch_reset(tb->root_switch);
+       }
+
+       if (discover) {
+               /* Full scan to discover devices added before the driver was loaded. */
+               tb_scan_switch(tb->root_switch);
+               /* Find out tunnels created by the boot firmware */
+               tb_discover_tunnels(tb);
+               /* Add DP resources from the DP tunnels created by the boot firmware */
+               tb_discover_dp_resources(tb);
+       }
+
        /*
         * If the boot firmware did not create USB 3.x tunnels create them
         * now for the whole topology.
@@ -2698,8 +2929,12 @@ static int tb_resume_noirq(struct tb *tb)
 
        tb_dbg(tb, "resuming...\n");
 
-       /* remove any pci devices the firmware might have setup */
-       tb_switch_reset(tb->root_switch);
+       /*
+        * For non-USB4 hosts (Apple systems) remove any PCIe devices
+        * the firmware might have setup.
+        */
+       if (!tb_switch_is_usb4(tb->root_switch))
+               tb_switch_reset(tb->root_switch);
 
        tb_switch_resume(tb->root_switch);
        tb_free_invalid_tunnels(tb);
@@ -2847,6 +3082,7 @@ static int tb_runtime_resume(struct tb *tb)
 static const struct tb_cm_ops tb_cm_ops = {
        .start = tb_start,
        .stop = tb_stop,
+       .deinit = tb_deinit,
        .suspend_noirq = tb_suspend_noirq,
        .resume_noirq = tb_resume_noirq,
        .freeze_noirq = tb_freeze_noirq,
index 997c5a53690524d80445d3106c8836971bd82eff..feed8ecaf712e84409daacb6a55b3ef121cb05f0 100644 (file)
@@ -23,6 +23,8 @@
 #define QUIRK_FORCE_POWER_LINK_CONTROLLER              BIT(0)
 /* Disable CLx if not supported */
 #define QUIRK_NO_CLX                                   BIT(1)
+/* Need to keep power on while USB4 port is in redrive mode */
+#define QUIRK_KEEP_POWER_IN_DP_REDRIVE                 BIT(2)
 
 /**
  * struct tb_nvm - Structure holding NVM information
@@ -217,6 +219,11 @@ struct tb_switch {
  * @tb: Pointer to the domain the group belongs to
  * @index: Index of the group (aka Group_ID). Valid values %1-%7
  * @ports: DP IN adapters belonging to this group are linked here
+ * @reserved: Bandwidth released by one tunnel in the group, available
+ *           to others. This is reported as part of estimated_bw for
+ *           the group.
+ * @release_work: Worker to release the @reserved if it is not used by
+ *               any of the tunnels.
  *
  * Any tunnel that requires isochronous bandwidth (that's DP for now) is
  * attached to a bandwidth group. All tunnels going through the same
@@ -227,6 +234,8 @@ struct tb_bandwidth_group {
        struct tb *tb;
        int index;
        struct list_head ports;
+       int reserved;
+       struct delayed_work release_work;
 };
 
 /**
@@ -258,6 +267,7 @@ struct tb_bandwidth_group {
  * @group_list: The adapter is linked to the group's list of ports through this
  * @max_bw: Maximum possible bandwidth through this adapter if set to
  *         non-zero.
+ * @redrive: For DP IN, if true the adapter is in redrive mode.
  *
  * In USB4 terminology this structure represents an adapter (protocol or
  * lane adapter).
@@ -286,6 +296,7 @@ struct tb_port {
        struct tb_bandwidth_group *group;
        struct list_head group_list;
        unsigned int max_bw;
+       bool redrive;
 };
 
 /**
@@ -452,6 +463,8 @@ struct tb_path {
  *               ICM to send driver ready message to the firmware.
  * @start: Starts the domain
  * @stop: Stops the domain
+ * @deinit: Perform any cleanup after the domain is stopped but before
+ *          it is unregistered. Called without @tb->lock taken. Optional.
  * @suspend_noirq: Connection manager specific suspend_noirq
  * @resume_noirq: Connection manager specific resume_noirq
  * @suspend: Connection manager specific suspend
@@ -483,8 +496,9 @@ struct tb_path {
  */
 struct tb_cm_ops {
        int (*driver_ready)(struct tb *tb);
-       int (*start)(struct tb *tb);
+       int (*start)(struct tb *tb, bool reset);
        void (*stop)(struct tb *tb);
+       void (*deinit)(struct tb *tb);
        int (*suspend_noirq)(struct tb *tb);
        int (*resume_noirq)(struct tb *tb);
        int (*suspend)(struct tb *tb);
@@ -735,10 +749,10 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
 struct tb *icm_probe(struct tb_nhi *nhi);
 struct tb *tb_probe(struct tb_nhi *nhi);
 
-extern struct device_type tb_domain_type;
-extern struct device_type tb_retimer_type;
-extern struct device_type tb_switch_type;
-extern struct device_type usb4_port_device_type;
+extern const struct device_type tb_domain_type;
+extern const struct device_type tb_retimer_type;
+extern const struct device_type tb_switch_type;
+extern const struct device_type usb4_port_device_type;
 
 int tb_domain_init(void);
 void tb_domain_exit(void);
@@ -746,7 +760,7 @@ int tb_xdomain_init(void);
 void tb_xdomain_exit(void);
 
 struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize);
-int tb_domain_add(struct tb *tb);
+int tb_domain_add(struct tb *tb, bool reset);
 void tb_domain_remove(struct tb *tb);
 int tb_domain_suspend_noirq(struct tb *tb);
 int tb_domain_resume_noirq(struct tb *tb);
@@ -1150,6 +1164,7 @@ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid,
 void tb_path_free(struct tb_path *path);
 int tb_path_activate(struct tb_path *path);
 void tb_path_deactivate(struct tb_path *path);
+int tb_path_deactivate_hop(struct tb_port *port, int hop_index);
 bool tb_path_is_invalid(struct tb_path *path);
 bool tb_path_port_on_path(const struct tb_path *path,
                          const struct tb_port *port);
@@ -1169,6 +1184,7 @@ int tb_drom_read(struct tb_switch *sw);
 int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);
 
 int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid);
+int tb_lc_reset_port(struct tb_port *port);
 int tb_lc_configure_port(struct tb_port *port);
 void tb_lc_unconfigure_port(struct tb_port *port);
 int tb_lc_configure_xdomain(struct tb_port *port);
@@ -1301,6 +1317,7 @@ void usb4_switch_remove_ports(struct tb_switch *sw);
 
 int usb4_port_unlock(struct tb_port *port);
 int usb4_port_hotplug_enable(struct tb_port *port);
+int usb4_port_reset(struct tb_port *port);
 int usb4_port_configure(struct tb_port *port);
 void usb4_port_unconfigure(struct tb_port *port);
 int usb4_port_configure_xdomain(struct tb_port *port, struct tb_xdomain *xd);
index 6f798f6a2b8488ca5011fe813733ffc8b5942f48..4e43b47f9f1195077b3f38a0dbb7cc8264aa0b36 100644 (file)
@@ -194,6 +194,8 @@ struct tb_regs_switch_header {
 #define USB4_VERSION_MAJOR_MASK                        GENMASK(7, 5)
 
 #define ROUTER_CS_1                            0x01
+#define ROUTER_CS_3                            0x03
+#define ROUTER_CS_3_V                          BIT(31)
 #define ROUTER_CS_4                            0x04
 /* Used with the router cmuv field */
 #define ROUTER_CS_4_CMUV_V1                    0x10
@@ -389,6 +391,7 @@ struct tb_regs_port_header {
 #define PORT_CS_18_CSA                         BIT(22)
 #define PORT_CS_18_TIP                         BIT(24)
 #define PORT_CS_19                             0x13
+#define PORT_CS_19_DPR                         BIT(0)
 #define PORT_CS_19_PC                          BIT(3)
 #define PORT_CS_19_PID                         BIT(4)
 #define PORT_CS_19_WOC                         BIT(16)
@@ -584,6 +587,9 @@ struct tb_regs_hop {
 #define TB_LC_POWER                            0x740
 
 /* Link controller registers */
+#define TB_LC_PORT_MODE                                0x26
+#define TB_LC_PORT_MODE_DPR                    BIT(0)
+
 #define TB_LC_CS_42                            0x2a
 #define TB_LC_CS_42_USB_PLUGGED                        BIT(31)
 
diff --git a/drivers/thunderbolt/trace.h b/drivers/thunderbolt/trace.h
new file mode 100644 (file)
index 0000000..4dccfcf
--- /dev/null
@@ -0,0 +1,188 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Thunderbolt tracing support
+ *
+ * Copyright (C) 2024, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *        Gil Fine <gil.fine@intel.com>
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM thunderbolt
+
+#if !defined(TB_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define TB_TRACE_H_
+
+#include <linux/trace_seq.h>
+#include <linux/tracepoint.h>
+
+#include "tb_msgs.h"
+
+#define tb_cfg_type_name(type)         { type, #type }
+#define show_type_name(val)                                    \
+       __print_symbolic(val,                                   \
+               tb_cfg_type_name(TB_CFG_PKG_READ),              \
+               tb_cfg_type_name(TB_CFG_PKG_WRITE),             \
+               tb_cfg_type_name(TB_CFG_PKG_ERROR),             \
+               tb_cfg_type_name(TB_CFG_PKG_NOTIFY_ACK),        \
+               tb_cfg_type_name(TB_CFG_PKG_EVENT),             \
+               tb_cfg_type_name(TB_CFG_PKG_XDOMAIN_REQ),       \
+               tb_cfg_type_name(TB_CFG_PKG_XDOMAIN_RESP),      \
+               tb_cfg_type_name(TB_CFG_PKG_OVERRIDE),          \
+               tb_cfg_type_name(TB_CFG_PKG_RESET),             \
+               tb_cfg_type_name(TB_CFG_PKG_ICM_EVENT),         \
+               tb_cfg_type_name(TB_CFG_PKG_ICM_CMD),           \
+               tb_cfg_type_name(TB_CFG_PKG_ICM_RESP))
+
+#ifndef TB_TRACE_HELPERS
+#define TB_TRACE_HELPERS
+static inline const char *show_data_read_write(struct trace_seq *p,
+                                              const u32 *data)
+{
+       const struct cfg_read_pkg *msg = (const struct cfg_read_pkg *)data;
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       trace_seq_printf(p, "offset=%#x, len=%u, port=%d, config=%#x, seq=%d, ",
+                        msg->addr.offset, msg->addr.length, msg->addr.port,
+                        msg->addr.space, msg->addr.seq);
+
+       return ret;
+}
+
+static inline const char *show_data_error(struct trace_seq *p, const u32 *data)
+{
+       const struct cfg_error_pkg *msg = (const struct cfg_error_pkg *)data;
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       trace_seq_printf(p, "error=%#x, port=%d, plug=%#x, ", msg->error,
+                        msg->port, msg->pg);
+
+       return ret;
+}
+
+static inline const char *show_data_event(struct trace_seq *p, const u32 *data)
+{
+       const struct cfg_event_pkg *msg = (const struct cfg_event_pkg *)data;
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       trace_seq_printf(p, "port=%d, unplug=%#x, ", msg->port, msg->unplug);
+
+       return ret;
+}
+
+static inline const char *show_route(struct trace_seq *p, const u32 *data)
+{
+       const struct tb_cfg_header *header = (const struct tb_cfg_header *)data;
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       trace_seq_printf(p, "route=%llx, ", tb_cfg_get_route(header));
+
+       return ret;
+}
+
+static inline const char *show_data(struct trace_seq *p, u8 type,
+                                   const u32 *data, u32 length)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+       const char *prefix = "";
+       int i;
+
+       show_route(p, data);
+
+       switch (type) {
+       case TB_CFG_PKG_READ:
+       case TB_CFG_PKG_WRITE:
+               show_data_read_write(p, data);
+               break;
+
+       case TB_CFG_PKG_ERROR:
+               show_data_error(p, data);
+               break;
+
+       case TB_CFG_PKG_EVENT:
+               show_data_event(p, data);
+               break;
+
+       default:
+               break;
+       }
+
+       trace_seq_printf(p, "data=[");
+       for (i = 0; i < length; i++) {
+               trace_seq_printf(p, "%s0x%08x", prefix, data[i]);
+               prefix = ", ";
+       }
+       trace_seq_printf(p, "]");
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+#endif
+
+DECLARE_EVENT_CLASS(tb_raw,
+       TP_PROTO(int index, u8 type, const void *data, size_t size),
+       TP_ARGS(index, type, data, size),
+       TP_STRUCT__entry(
+               __field(int, index)
+               __field(u8, type)
+               __field(size_t, size)
+               __dynamic_array(u32, data, size / 4)
+       ),
+       TP_fast_assign(
+               __entry->index = index;
+               __entry->type = type;
+               __entry->size = size / 4;
+               memcpy(__get_dynamic_array(data), data, size);
+       ),
+       TP_printk("type=%s, size=%zd, domain=%d, %s",
+                 show_type_name(__entry->type), __entry->size, __entry->index,
+                 show_data(p, __entry->type, __get_dynamic_array(data),
+                           __entry->size)
+       )
+);
+
+DEFINE_EVENT(tb_raw, tb_tx,
+       TP_PROTO(int index, u8 type, const void *data, size_t size),
+       TP_ARGS(index, type, data, size)
+);
+
+DEFINE_EVENT(tb_raw, tb_event,
+       TP_PROTO(int index, u8 type, const void *data, size_t size),
+       TP_ARGS(index, type, data, size)
+);
+
+TRACE_EVENT(tb_rx,
+       TP_PROTO(int index, u8 type, const void *data, size_t size, bool dropped),
+       TP_ARGS(index, type, data, size, dropped),
+       TP_STRUCT__entry(
+               __field(int, index)
+               __field(u8, type)
+               __field(size_t, size)
+               __dynamic_array(u32, data, size / 4)
+               __field(bool, dropped)
+       ),
+       TP_fast_assign(
+               __entry->index = index;
+               __entry->type = type;
+               __entry->size = size / 4;
+               memcpy(__get_dynamic_array(data), data, size);
+               __entry->dropped = dropped;
+       ),
+       TP_printk("type=%s, dropped=%u, size=%zd, domain=%d, %s",
+                 show_type_name(__entry->type), __entry->dropped,
+                 __entry->size, __entry->index,
+                 show_data(p, __entry->type, __get_dynamic_array(data),
+                           __entry->size)
+       )
+);
+
+#endif /* TB_TRACE_H_ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 6fffb2c82d3d1332a9de5005b7a67099ef5d8582..cb6609a56a03f9d1952707f1d42760de51838a9f 100644 (file)
@@ -706,7 +706,7 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
                      "DP OUT maximum supported bandwidth %u Mb/s x%u = %u Mb/s\n",
                      out_rate, out_lanes, bw);
 
-       if (tb_port_path_direction_downstream(in, out))
+       if (tb_tunnel_direction_downstream(tunnel))
                max_bw = tunnel->max_down;
        else
                max_bw = tunnel->max_up;
@@ -831,7 +831,7 @@ static int tb_dp_bandwidth_alloc_mode_enable(struct tb_tunnel *tunnel)
         * max_up/down fields. For discovery we just read what the
         * estimation was set to.
         */
-       if (tb_port_path_direction_downstream(in, out))
+       if (tb_tunnel_direction_downstream(tunnel))
                estimated_bw = tunnel->max_down;
        else
                estimated_bw = tunnel->max_up;
@@ -926,12 +926,18 @@ static int tb_dp_activate(struct tb_tunnel *tunnel, bool active)
        return 0;
 }
 
-/* max_bw is rounded up to next granularity */
+/**
+ * tb_dp_bandwidth_mode_maximum_bandwidth() - Maximum possible bandwidth
+ * @tunnel: DP tunnel to check
+ * @max_bw_rounded: Maximum bandwidth in Mb/s rounded up to the next granularity
+ *
+ * Returns maximum possible bandwidth for this tunnel in Mb/s.
+ */
 static int tb_dp_bandwidth_mode_maximum_bandwidth(struct tb_tunnel *tunnel,
-                                                 int *max_bw)
+                                                 int *max_bw_rounded)
 {
        struct tb_port *in = tunnel->src_port;
-       int ret, rate, lanes, nrd_bw;
+       int ret, rate, lanes, max_bw;
        u32 cap;
 
        /*
@@ -947,41 +953,26 @@ static int tb_dp_bandwidth_mode_maximum_bandwidth(struct tb_tunnel *tunnel,
                return ret;
 
        rate = tb_dp_cap_get_rate_ext(cap);
-       if (tb_dp_is_uhbr_rate(rate)) {
-               /*
-                * When UHBR is used there is no reduction in lanes so
-                * we can use this directly.
-                */
-               lanes = tb_dp_cap_get_lanes(cap);
-       } else {
-               /*
-                * If there is no UHBR supported then check the
-                * non-reduced rate and lanes.
-                */
-               ret = usb4_dp_port_nrd(in, &rate, &lanes);
-               if (ret)
-                       return ret;
-       }
+       lanes = tb_dp_cap_get_lanes(cap);
 
-       nrd_bw = tb_dp_bandwidth(rate, lanes);
+       max_bw = tb_dp_bandwidth(rate, lanes);
 
-       if (max_bw) {
+       if (max_bw_rounded) {
                ret = usb4_dp_port_granularity(in);
                if (ret < 0)
                        return ret;
-               *max_bw = roundup(nrd_bw, ret);
+               *max_bw_rounded = roundup(max_bw, ret);
        }
 
-       return nrd_bw;
+       return max_bw;
 }
 
 static int tb_dp_bandwidth_mode_consumed_bandwidth(struct tb_tunnel *tunnel,
                                                   int *consumed_up,
                                                   int *consumed_down)
 {
-       struct tb_port *out = tunnel->dst_port;
        struct tb_port *in = tunnel->src_port;
-       int ret, allocated_bw, max_bw;
+       int ret, allocated_bw, max_bw_rounded;
 
        if (!usb4_dp_port_bandwidth_mode_enabled(in))
                return -EOPNOTSUPP;
@@ -995,13 +986,13 @@ static int tb_dp_bandwidth_mode_consumed_bandwidth(struct tb_tunnel *tunnel,
                return ret;
        allocated_bw = ret;
 
-       ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel, &max_bw);
+       ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel, &max_bw_rounded);
        if (ret < 0)
                return ret;
-       if (allocated_bw == max_bw)
+       if (allocated_bw == max_bw_rounded)
                allocated_bw = ret;
 
-       if (tb_port_path_direction_downstream(in, out)) {
+       if (tb_tunnel_direction_downstream(tunnel)) {
                *consumed_up = 0;
                *consumed_down = allocated_bw;
        } else {
@@ -1015,7 +1006,6 @@ static int tb_dp_bandwidth_mode_consumed_bandwidth(struct tb_tunnel *tunnel,
 static int tb_dp_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up,
                                     int *allocated_down)
 {
-       struct tb_port *out = tunnel->dst_port;
        struct tb_port *in = tunnel->src_port;
 
        /*
@@ -1023,20 +1013,21 @@ static int tb_dp_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up
         * Otherwise we read it from the DPRX.
         */
        if (usb4_dp_port_bandwidth_mode_enabled(in) && tunnel->bw_mode) {
-               int ret, allocated_bw, max_bw;
+               int ret, allocated_bw, max_bw_rounded;
 
                ret = usb4_dp_port_allocated_bandwidth(in);
                if (ret < 0)
                        return ret;
                allocated_bw = ret;
 
-               ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel, &max_bw);
+               ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel,
+                                                            &max_bw_rounded);
                if (ret < 0)
                        return ret;
-               if (allocated_bw == max_bw)
+               if (allocated_bw == max_bw_rounded)
                        allocated_bw = ret;
 
-               if (tb_port_path_direction_downstream(in, out)) {
+               if (tb_tunnel_direction_downstream(tunnel)) {
                        *allocated_up = 0;
                        *allocated_down = allocated_bw;
                } else {
@@ -1053,26 +1044,25 @@ static int tb_dp_allocated_bandwidth(struct tb_tunnel *tunnel, int *allocated_up
 static int tb_dp_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up,
                                 int *alloc_down)
 {
-       struct tb_port *out = tunnel->dst_port;
        struct tb_port *in = tunnel->src_port;
-       int max_bw, ret, tmp;
+       int max_bw_rounded, ret, tmp;
 
        if (!usb4_dp_port_bandwidth_mode_enabled(in))
                return -EOPNOTSUPP;
 
-       ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel, &max_bw);
+       ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel, &max_bw_rounded);
        if (ret < 0)
                return ret;
 
-       if (tb_port_path_direction_downstream(in, out)) {
-               tmp = min(*alloc_down, max_bw);
+       if (tb_tunnel_direction_downstream(tunnel)) {
+               tmp = min(*alloc_down, max_bw_rounded);
                ret = usb4_dp_port_allocate_bandwidth(in, tmp);
                if (ret)
                        return ret;
                *alloc_down = tmp;
                *alloc_up = 0;
        } else {
-               tmp = min(*alloc_up, max_bw);
+               tmp = min(*alloc_up, max_bw_rounded);
                ret = usb4_dp_port_allocate_bandwidth(in, tmp);
                if (ret)
                        return ret;
@@ -1150,17 +1140,16 @@ static int tb_dp_read_cap(struct tb_tunnel *tunnel, unsigned int cap, u32 *rate,
 static int tb_dp_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up,
                                   int *max_down)
 {
-       struct tb_port *in = tunnel->src_port;
        int ret;
 
-       if (!usb4_dp_port_bandwidth_mode_enabled(in))
+       if (!usb4_dp_port_bandwidth_mode_enabled(tunnel->src_port))
                return -EOPNOTSUPP;
 
        ret = tb_dp_bandwidth_mode_maximum_bandwidth(tunnel, NULL);
        if (ret < 0)
                return ret;
 
-       if (tb_port_path_direction_downstream(in, tunnel->dst_port)) {
+       if (tb_tunnel_direction_downstream(tunnel)) {
                *max_up = 0;
                *max_down = ret;
        } else {
@@ -1174,8 +1163,7 @@ static int tb_dp_maximum_bandwidth(struct tb_tunnel *tunnel, int *max_up,
 static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
                                    int *consumed_down)
 {
-       struct tb_port *in = tunnel->src_port;
-       const struct tb_switch *sw = in->sw;
+       const struct tb_switch *sw = tunnel->src_port->sw;
        u32 rate = 0, lanes = 0;
        int ret;
 
@@ -1196,17 +1184,13 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
                /*
                 * Then see if the DPRX negotiation is ready and if yes
                 * return that bandwidth (it may be smaller than the
-                * reduced one). Otherwise return the remote (possibly
-                * reduced) caps.
+                * reduced one). According to VESA spec, the DPRX
+                * negotiation shall compete in 5 seconds after tunnel
+                * established. We give it 100ms extra just in case.
                 */
-               ret = tb_dp_wait_dprx(tunnel, 150);
-               if (ret) {
-                       if (ret == -ETIMEDOUT)
-                               ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP,
-                                                    &rate, &lanes);
-                       if (ret)
-                               return ret;
-               }
+               ret = tb_dp_wait_dprx(tunnel, 5100);
+               if (ret)
+                       return ret;
                ret = tb_dp_read_cap(tunnel, DP_COMMON_CAP, &rate, &lanes);
                if (ret)
                        return ret;
@@ -1221,7 +1205,7 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
                return 0;
        }
 
-       if (tb_port_path_direction_downstream(in, tunnel->dst_port)) {
+       if (tb_tunnel_direction_downstream(tunnel)) {
                *consumed_up = 0;
                *consumed_down = tb_dp_bandwidth(rate, lanes);
        } else {
index b4cff5482112d3a3e97758565765607d226327a0..1a27ccd08b86135363e6f78b838807a0eb79d811 100644 (file)
@@ -139,6 +139,12 @@ static inline bool tb_tunnel_is_usb3(const struct tb_tunnel *tunnel)
        return tunnel->type == TB_TUNNEL_USB3;
 }
 
+static inline bool tb_tunnel_direction_downstream(const struct tb_tunnel *tunnel)
+{
+       return tb_port_path_direction_downstream(tunnel->src_port,
+                                                tunnel->dst_port);
+}
+
 const char *tb_tunnel_type_name(const struct tb_tunnel *tunnel);
 
 #define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...)                   \
index 1515eff8cc3e23434202fead2a9aa038080111d6..9860b49d7a2b201c9db051c06243fbf4d7b59fb8 100644 (file)
@@ -1113,6 +1113,45 @@ int usb4_port_hotplug_enable(struct tb_port *port)
        return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_5, 1);
 }
 
+/**
+ * usb4_port_reset() - Issue downstream port reset
+ * @port: USB4 port to reset
+ *
+ * Issues downstream port reset to @port.
+ */
+int usb4_port_reset(struct tb_port *port)
+{
+       int ret;
+       u32 val;
+
+       if (!port->cap_usb4)
+               return -EINVAL;
+
+       ret = tb_port_read(port, &val, TB_CFG_PORT,
+                          port->cap_usb4 + PORT_CS_19, 1);
+       if (ret)
+               return ret;
+
+       val |= PORT_CS_19_DPR;
+
+       ret = tb_port_write(port, &val, TB_CFG_PORT,
+                           port->cap_usb4 + PORT_CS_19, 1);
+       if (ret)
+               return ret;
+
+       fsleep(10000);
+
+       ret = tb_port_read(port, &val, TB_CFG_PORT,
+                          port->cap_usb4 + PORT_CS_19, 1);
+       if (ret)
+               return ret;
+
+       val &= ~PORT_CS_19_DPR;
+
+       return tb_port_write(port, &val, TB_CFG_PORT,
+                            port->cap_usb4 + PORT_CS_19, 1);
+}
+
 static int usb4_port_set_configured(struct tb_port *port, bool configured)
 {
        int ret;
@@ -2819,8 +2858,10 @@ static int usb4_dp_port_wait_and_clear_cm_ack(struct tb_port *port,
                usleep_range(50, 100);
        } while (ktime_before(ktime_get(), end));
 
-       if (val & ADP_DP_CS_8_DR)
+       if (val & ADP_DP_CS_8_DR) {
+               tb_port_warn(port, "timeout waiting for DPTX request to clear\n");
                return -ETIMEDOUT;
+       }
 
        ret = tb_port_read(port, &val, TB_CFG_PORT,
                           port->cap_adap + ADP_DP_CS_2, 1);
index e355bfd6343ff0d0616d1917fbcef9acf123023d..5150879888cac7f2bfa8693fe43b4116829b6f61 100644 (file)
@@ -243,7 +243,7 @@ static void usb4_port_device_release(struct device *dev)
        kfree(usb4);
 }
 
-struct device_type usb4_port_device_type = {
+const struct device_type usb4_port_device_type = {
        .name = "usb4_port",
        .groups = usb4_port_device_groups,
        .release = usb4_port_device_release,
index 9495742913d5c63363cedfffe6ca509ec8b2f3e1..940ae97987ff3821ee312a6c1603cbea9d7b231f 100644 (file)
@@ -997,12 +997,12 @@ static void tb_service_release(struct device *dev)
        struct tb_xdomain *xd = tb_service_parent(svc);
 
        tb_service_debugfs_remove(svc);
-       ida_simple_remove(&xd->service_ids, svc->id);
+       ida_free(&xd->service_ids, svc->id);
        kfree(svc->key);
        kfree(svc);
 }
 
-struct device_type tb_service_type = {
+const struct device_type tb_service_type = {
        .name = "thunderbolt_service",
        .groups = tb_service_attr_groups,
        .uevent = tb_service_uevent,
@@ -1099,7 +1099,7 @@ static void enumerate_services(struct tb_xdomain *xd)
                        break;
                }
 
-               id = ida_simple_get(&xd->service_ids, 0, 0, GFP_KERNEL);
+               id = ida_alloc(&xd->service_ids, GFP_KERNEL);
                if (id < 0) {
                        kfree(svc->key);
                        kfree(svc);
@@ -1791,13 +1791,13 @@ static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr,
 
        switch (xd->link_width) {
        case TB_LINK_WIDTH_SINGLE:
-       case TB_LINK_WIDTH_ASYM_RX:
+       case TB_LINK_WIDTH_ASYM_TX:
                width = 1;
                break;
        case TB_LINK_WIDTH_DUAL:
                width = 2;
                break;
-       case TB_LINK_WIDTH_ASYM_TX:
+       case TB_LINK_WIDTH_ASYM_RX:
                width = 3;
                break;
        default:
@@ -1817,13 +1817,13 @@ static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr,
 
        switch (xd->link_width) {
        case TB_LINK_WIDTH_SINGLE:
-       case TB_LINK_WIDTH_ASYM_TX:
+       case TB_LINK_WIDTH_ASYM_RX:
                width = 1;
                break;
        case TB_LINK_WIDTH_DUAL:
                width = 2;
                break;
-       case TB_LINK_WIDTH_ASYM_RX:
+       case TB_LINK_WIDTH_ASYM_TX:
                width = 3;
                break;
        default:
@@ -1893,7 +1893,7 @@ static const struct dev_pm_ops tb_xdomain_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(tb_xdomain_suspend, tb_xdomain_resume)
 };
 
-struct device_type tb_xdomain_type = {
+const struct device_type tb_xdomain_type = {
        .name = "thunderbolt_xdomain",
        .release = tb_xdomain_release,
        .pm = &tb_xdomain_pm_ops,
index 5646dc6242cd9a3771f09258a95ada92329d5897..a45d423ad10f02c3a818021bbb18655a8b690500 100644 (file)
@@ -75,14 +75,9 @@ config VT_CONSOLE_SLEEP
        def_bool y
        depends on VT_CONSOLE && PM_SLEEP
 
-config HW_CONSOLE
-       bool
-       depends on VT
-       default y
-
 config VT_HW_CONSOLE_BINDING
        bool "Support for binding and unbinding console drivers"
-       depends on HW_CONSOLE
+       depends on VT
        help
          The virtual terminal is the device that interacts with the physical
          terminal through console drivers. On these systems, at least one
index 7716ce0d35bc219608bd67b762aac0d4544bd9b9..e27360652d9b6b6e09976b5fda3ff495ed3f9838 100644 (file)
@@ -1566,7 +1566,7 @@ fail_tty_driver_kref_put:
        return error;
 }
 
-static int __exit amiga_serial_remove(struct platform_device *pdev)
+static void __exit amiga_serial_remove(struct platform_device *pdev)
 {
        struct serial_state *state = platform_get_drvdata(pdev);
 
@@ -1576,12 +1576,10 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
 
        free_irq(IRQ_AMIGA_TBE, state);
        free_irq(IRQ_AMIGA_RBF, state);
-
-       return 0;
 }
 
 static struct platform_driver amiga_serial_driver = {
-       .remove = __exit_p(amiga_serial_remove),
+       .remove_new = __exit_p(amiga_serial_remove),
        .driver   = {
                .name   = "amiga-serial",
        },
index d27979eabfdfbee1397140db3e30f0ee8ab7467c..34421ec06a69e217eab4d0013aa641a0d7b1845d 100644 (file)
@@ -408,7 +408,7 @@ err_unmap:
        return ret;
 }
 
-static int goldfish_tty_remove(struct platform_device *pdev)
+static void goldfish_tty_remove(struct platform_device *pdev)
 {
        struct goldfish_tty *qtty = platform_get_drvdata(pdev);
 
@@ -424,7 +424,6 @@ static int goldfish_tty_remove(struct platform_device *pdev)
        if (goldfish_tty_current_line_count == 0)
                goldfish_tty_delete_driver();
        mutex_unlock(&goldfish_tty_lock);
-       return 0;
 }
 
 #ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE
@@ -462,7 +461,7 @@ MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
 
 static struct platform_driver goldfish_tty_platform_driver = {
        .probe = goldfish_tty_probe,
-       .remove = goldfish_tty_remove,
+       .remove_new = goldfish_tty_remove,
        .driver = {
                .name = "goldfish_tty",
                .of_match_table = goldfish_tty_of_match,
index fdecc0d63731aa268a08ef00bd12cded3b918eca..b1149bc62ca1f35b37d3cd00126c0e81e847b716 100644 (file)
@@ -1035,6 +1035,10 @@ static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
        NULL,
 };
 
+static void hvc_iucv_free(struct device *data)
+{
+       kfree(data);
+}
 
 /**
  * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
@@ -1097,7 +1101,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
        priv->dev->bus = &iucv_bus;
        priv->dev->parent = iucv_root;
        priv->dev->groups = hvc_iucv_dev_attr_groups;
-       priv->dev->release = (void (*)(struct device *)) kfree;
+       priv->dev->release = hvc_iucv_free;
        rc = device_register(priv->dev);
        if (rc) {
                put_device(priv->dev);
index 822a5cd05566647d2bea82e2e978d05d214f79b4..613cb356b918d71562e5d48d237d0f64137b7afb 100644 (file)
@@ -431,7 +431,7 @@ static void serdev_drv_remove(struct device *dev)
        dev_pm_domain_detach(dev, true);
 }
 
-static struct bus_type serdev_bus_type = {
+static const struct bus_type serdev_bus_type = {
        .name           = "serial",
        .match          = serdev_device_match,
        .probe          = serdev_drv_probe,
index e94e090cf0a1a5aa31575b21de671c1fe8fb71f5..3d7ae7fa50186bc01481a9e9685aea41b10b6f2b 100644 (file)
@@ -27,19 +27,17 @@ static size_t ttyport_receive_buf(struct tty_port *port, const u8 *cp,
 {
        struct serdev_controller *ctrl = port->client_data;
        struct serport *serport = serdev_controller_get_drvdata(ctrl);
-       int ret;
+       size_t ret;
 
        if (!test_bit(SERPORT_ACTIVE, &serport->flags))
                return 0;
 
        ret = serdev_controller_receive_buf(ctrl, cp, count);
 
-       dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count,
-                               "receive_buf returns %d (count = %zu)\n",
+       dev_WARN_ONCE(&ctrl->dev, ret > count,
+                               "receive_buf returns %zu (count = %zu)\n",
                                ret, count);
-       if (ret < 0)
-               return 0;
-       else if (ret > count)
+       if (ret > count)
                return count;
 
        return ret;
index 8c2aaf7af7b75c23587f847f8bc9be9330ddadc2..53d8eee9b1c81054b4e813df6c84797fc5ef5636 100644 (file)
@@ -419,8 +419,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
        struct aspeed_vuart *vuart;
        struct device_node *np;
        struct resource *res;
-       u32 clk, prop, sirq[2];
        int rc, sirq_polarity;
+       u32 prop, sirq[2];
        struct clk *vclk;
 
        np = pdev->dev.of_node;
@@ -447,53 +447,35 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
        port.port.status = UPSTAT_SYNC_FIFO;
        port.port.dev = &pdev->dev;
        port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
+       port.port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE |
+                         UPF_NO_THRE_TEST;
        port.bugs |= UART_BUG_TXRACE;
 
        rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
        if (rc < 0)
                return rc;
 
-       if (of_property_read_u32(np, "clock-frequency", &clk)) {
+       rc = uart_read_port_properties(&port.port);
+       if (rc)
+               goto err_sysfs_remove;
+
+       /* Get clk rate through clk driver if present */
+       if (!port.port.uartclk) {
                vclk = devm_clk_get_enabled(dev, NULL);
                if (IS_ERR(vclk)) {
                        rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n");
                        goto err_sysfs_remove;
                }
 
-               clk = clk_get_rate(vclk);
+               port.port.uartclk = clk_get_rate(vclk);
        }
 
        /* If current-speed was set, then try not to change it. */
        if (of_property_read_u32(np, "current-speed", &prop) == 0)
-               port.port.custom_divisor = clk / (16 * prop);
-
-       /* Check for shifted address mapping */
-       if (of_property_read_u32(np, "reg-offset", &prop) == 0)
-               port.port.mapbase += prop;
-
-       /* Check for registers offset within the devices address range */
-       if (of_property_read_u32(np, "reg-shift", &prop) == 0)
-               port.port.regshift = prop;
+               port.port.custom_divisor = port.port.uartclk / (16 * prop);
 
-       /* Check for fifo size */
-       if (of_property_read_u32(np, "fifo-size", &prop) == 0)
-               port.port.fifosize = prop;
-
-       /* Check for a fixed line number */
-       rc = of_alias_get_id(np, "serial");
-       if (rc >= 0)
-               port.port.line = rc;
-
-       port.port.irq = irq_of_parse_and_map(np, 0);
        port.port.handle_irq = aspeed_vuart_handle_irq;
-       port.port.iotype = UPIO_MEM;
        port.port.type = PORT_ASPEED_VUART;
-       port.port.uartclk = clk;
-       port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
-               | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
-
-       if (of_property_read_bool(np, "no-loopback-test"))
-               port.port.flags |= UPF_SKIP_TEST;
 
        if (port.port.fifosize)
                port.capabilities = UART_CAP_FIFO;
@@ -503,7 +485,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
 
        rc = serial8250_register_8250_port(&port);
        if (rc < 0)
-               goto err_clk_disable;
+               goto err_sysfs_remove;
 
        vuart->line = rc;
        vuart->port = serial8250_get_port(vuart->line);
@@ -529,7 +511,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
        rc = aspeed_vuart_set_lpc_address(vuart, prop);
        if (rc < 0) {
                dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n");
-               goto err_clk_disable;
+               goto err_sysfs_remove;
        }
 
        rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2);
@@ -541,14 +523,14 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
        rc = aspeed_vuart_set_sirq(vuart, sirq[0]);
        if (rc < 0) {
                dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n");
-               goto err_clk_disable;
+               goto err_sysfs_remove;
        }
 
        sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]);
        if (sirq_polarity < 0) {
                rc = dev_err_probe(dev, sirq_polarity,
                                   "invalid sirq polarity in aspeed,lpc-interrupts property\n");
-               goto err_clk_disable;
+               goto err_sysfs_remove;
        }
 
        aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity);
@@ -559,8 +541,6 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
 
        return 0;
 
-err_clk_disable:
-       irq_dispose_mapping(port.port.irq);
 err_sysfs_remove:
        sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
        return rc;
index beac6b340acef7cac394456e10b6244be7568deb..121a5ce8605089ae2e1877b56bfc4190c808355d 100644 (file)
@@ -45,10 +45,6 @@ struct bcm2835aux_data {
        u32 cntl;
 };
 
-struct bcm2835_aux_serial_driver_data {
-       resource_size_t offset;
-};
-
 static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
 {
        if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
@@ -85,10 +81,9 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
 
 static int bcm2835aux_serial_probe(struct platform_device *pdev)
 {
-       const struct bcm2835_aux_serial_driver_data *bcm_data;
+       const struct software_node *bcm2835_swnode;
        struct uart_8250_port up = { };
        struct bcm2835aux_data *data;
-       resource_size_t offset = 0;
        struct resource *res;
        unsigned int uartclk;
        int ret;
@@ -101,12 +96,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
        /* initialize data */
        up.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
        up.port.dev = &pdev->dev;
-       up.port.regshift = 2;
        up.port.type = PORT_16550;
-       up.port.iotype = UPIO_MEM;
-       up.port.fifosize = 8;
-       up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
-                       UPF_SKIP_TEST | UPF_IOREMAP;
+       up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP;
        up.port.rs485_config = serial8250_em485_config;
        up.port.rs485_supported = serial8250_em485_supported;
        up.rs485_start_tx = bcm2835aux_rs485_start_tx;
@@ -122,12 +113,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
        if (IS_ERR(data->clk))
                return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n");
 
-       /* get the interrupt */
-       ret = platform_get_irq(pdev, 0);
-       if (ret < 0)
-               return ret;
-       up.port.irq = ret;
-
        /* map the main registers */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -135,52 +120,40 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       bcm_data = device_get_match_data(&pdev->dev);
-
-       /* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
-        * describe the miniuart with a base address that encompasses the auxiliary
-        * registers shared between the miniuart and spi.
-        *
-        * This is due to historical reasons, see discussion here :
-        * https://edk2.groups.io/g/devel/topic/87501357#84349
-        *
-        * We need to add the offset between the miniuart and auxiliary
-        * registers to get the real miniuart base address.
-        */
-       if (bcm_data)
-               offset = bcm_data->offset;
+       up.port.mapbase = res->start;
+       up.port.mapsize = resource_size(res);
+
+       bcm2835_swnode = device_get_match_data(&pdev->dev);
+       if (bcm2835_swnode) {
+               ret = device_add_software_node(&pdev->dev, bcm2835_swnode);
+               if (ret)
+                       return ret;
+       }
 
-       up.port.mapbase = res->start + offset;
-       up.port.mapsize = resource_size(res) - offset;
+       ret = uart_read_port_properties(&up.port);
+       if (ret)
+               goto rm_swnode;
 
-       /* Check for a fixed line number */
-       ret = of_alias_get_id(pdev->dev.of_node, "serial");
-       if (ret >= 0)
-               up.port.line = ret;
+       up.port.regshift = 2;
+       up.port.fifosize = 8;
 
        /* enable the clock as a last step */
        ret = clk_prepare_enable(data->clk);
        if (ret) {
-               dev_err(&pdev->dev, "unable to enable uart clock - %d\n",
-                       ret);
-               return ret;
+               dev_err_probe(&pdev->dev, ret, "unable to enable uart clock\n");
+               goto rm_swnode;
        }
 
        uartclk = clk_get_rate(data->clk);
-       if (!uartclk) {
-               ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk);
-               if (ret) {
-                       dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
-                       goto dis_clk;
-               }
-       }
+       if (uartclk)
+               up.port.uartclk = uartclk;
 
        /* the HW-clock divider for bcm2835aux is 8,
         * but 8250 expects a divider of 16,
         * so we have to multiply the actual clock by 2
         * to get identical baudrates.
         */
-       up.port.uartclk = uartclk * 2;
+       up.port.uartclk *= 2;
 
        /* register the port */
        ret = serial8250_register_8250_port(&up);
@@ -194,6 +167,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
 
 dis_clk:
        clk_disable_unprepare(data->clk);
+rm_swnode:
+       device_remove_software_node(&pdev->dev);
        return ret;
 }
 
@@ -203,10 +178,27 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev)
 
        serial8250_unregister_port(data->line);
        clk_disable_unprepare(data->clk);
+       device_remove_software_node(&pdev->dev);
 }
 
-static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = {
-       .offset = 0x40,
+/*
+ * Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
+ * describe the miniuart with a base address that encompasses the auxiliary
+ * registers shared between the miniuart and spi.
+ *
+ * This is due to historical reasons, see discussion here:
+ * https://edk2.groups.io/g/devel/topic/87501357#84349
+ *
+ * We need to add the offset between the miniuart and auxiliary registers
+ * to get the real miniuart base address.
+ */
+static const struct property_entry bcm2835_acpi_properties[] = {
+       PROPERTY_ENTRY_U32("reg-offset", 0x40),
+       { }
+};
+
+static const struct software_node bcm2835_acpi_node = {
+       .properties = bcm2835_acpi_properties,
 };
 
 static const struct of_device_id bcm2835aux_serial_match[] = {
@@ -216,7 +208,7 @@ static const struct of_device_id bcm2835aux_serial_match[] = {
 MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
 
 static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
-       { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data },
+       { "BCM2836", (kernel_ulong_t)&bcm2835_acpi_node },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
index 504c4c02085776c610e8a6d9010f6982046c674a..5daa38d9c64e01d32cb1c10e48da065998dfbaa3 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/debugfs.h>
+#include <linux/units.h>
 
 #include "8250.h"
 
 #define TX_BUF_SIZE 4096
 #define RX_BUF_SIZE 4096
 #define RX_BUFS_COUNT 2
-#define KHZ    1000
-#define MHZ(x) ((x) * KHZ * KHZ)
 
 static const u32 brcmstb_rate_table[] = {
-       MHZ(81),
-       MHZ(108),
-       MHZ(64),                /* Actually 64285715 for some chips */
-       MHZ(48),
+       81 * HZ_PER_MHZ,
+       108 * HZ_PER_MHZ,
+       64 * HZ_PER_MHZ,                /* Actually 64285715 for some chips */
+       48 * HZ_PER_MHZ,
 };
 
 static const u32 brcmstb_rate_table_7278[] = {
-       MHZ(81),
-       MHZ(108),
+       81 * HZ_PER_MHZ,
+       108 * HZ_PER_MHZ,
        0,
-       MHZ(48),
+       48 * HZ_PER_MHZ,
 };
 
 struct brcmuart_priv {
@@ -936,17 +935,14 @@ static void brcmuart_init_debugfs(struct brcmuart_priv *priv,
 static int brcmuart_probe(struct platform_device *pdev)
 {
        struct resource *regs;
-       struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *of_id = NULL;
        struct uart_8250_port *new_port;
        struct device *dev = &pdev->dev;
        struct brcmuart_priv *priv;
        struct clk *baud_mux_clk;
        struct uart_8250_port up;
-       int irq;
        void __iomem *membase = NULL;
        resource_size_t mapbase = 0;
-       u32 clk_rate = 0;
        int ret;
        int x;
        int dma_irq;
@@ -954,15 +950,12 @@ static int brcmuart_probe(struct platform_device *pdev)
                "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb"
        };
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
        priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv),
                        GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
-       of_id = of_match_node(brcmuart_dt_ids, np);
+       of_id = of_match_node(brcmuart_dt_ids, dev->of_node);
        if (!of_id || !of_id->data)
                priv->rate_table = brcmstb_rate_table;
        else
@@ -1012,7 +1005,23 @@ static int brcmuart_probe(struct platform_device *pdev)
                }
        }
 
-       of_property_read_u32(np, "clock-frequency", &clk_rate);
+       dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not ");
+
+       memset(&up, 0, sizeof(up));
+       up.port.type = PORT_BCM7271;
+       up.port.dev = dev;
+       up.port.mapbase = mapbase;
+       up.port.membase = membase;
+       up.port.handle_irq = brcmuart_handle_irq;
+       up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+       up.port.private_data = priv;
+
+       ret = uart_read_port_properties(&up.port);
+       if (ret)
+               goto release_dma;
+
+       up.port.regshift = 2;
+       up.port.iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
 
        /* See if a Baud clock has been specified */
        baud_mux_clk = devm_clk_get_optional_enabled(dev, "sw_baud");
@@ -1024,39 +1033,11 @@ static int brcmuart_probe(struct platform_device *pdev)
 
                priv->baud_mux_clk = baud_mux_clk;
                init_real_clk_rates(dev, priv);
-               clk_rate = priv->default_mux_rate;
+               up.port.uartclk = priv->default_mux_rate;
        } else {
                dev_dbg(dev, "BAUD MUX clock not specified\n");
        }
 
-       if (clk_rate == 0) {
-               ret = dev_err_probe(dev, -EINVAL, "clock-frequency or clk not defined\n");
-               goto release_dma;
-       }
-
-       dev_dbg(dev, "DMA is %senabled\n", priv->dma_enabled ? "" : "not ");
-
-       memset(&up, 0, sizeof(up));
-       up.port.type = PORT_BCM7271;
-       up.port.uartclk = clk_rate;
-       up.port.dev = dev;
-       up.port.mapbase = mapbase;
-       up.port.membase = membase;
-       up.port.irq = irq;
-       up.port.handle_irq = brcmuart_handle_irq;
-       up.port.regshift = 2;
-       up.port.iotype = of_device_is_big_endian(np) ?
-               UPIO_MEM32BE : UPIO_MEM32;
-       up.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
-               | UPF_FIXED_PORT | UPF_FIXED_TYPE;
-       up.port.dev = dev;
-       up.port.private_data = priv;
-
-       /* Check for a fixed line number */
-       ret = of_alias_get_id(np, "serial");
-       if (ret >= 0)
-               up.port.line = ret;
-
        /* setup HR timer */
        hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        priv->hrt.function = brcmuart_hrtimer_func;
index c1d43f040c43abc517c4ef6b48a5423e936e97f2..a3acbf0f5da1beff6724e839fa14a0a990a15576 100644 (file)
@@ -9,7 +9,6 @@
  * LCR is written whilst busy.  If it is, then a busy detect interrupt is
  * raised, the LCR needs to be rewritten and the uart status register read.
  */
-#include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -17,7 +16,6 @@
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
-#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
@@ -56,6 +54,7 @@
 #define DW_UART_QUIRK_ARMADA_38X       BIT(1)
 #define DW_UART_QUIRK_SKIP_SET_RATE    BIT(2)
 #define DW_UART_QUIRK_IS_DMA_FC                BIT(3)
+#define DW_UART_QUIRK_APMC0D08         BIT(4)
 
 static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
 {
@@ -445,44 +444,29 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
 
 static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
 {
-       struct device_node *np = p->dev->of_node;
+       unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
 
-       if (np) {
-               unsigned int quirks = data->pdata->quirks;
-               int id;
-
-               /* get index of serial line, if found in DT aliases */
-               id = of_alias_get_id(np, "serial");
-               if (id >= 0)
-                       p->line = id;
 #ifdef CONFIG_64BIT
-               if (quirks & DW_UART_QUIRK_OCTEON) {
-                       p->serial_in = dw8250_serial_inq;
-                       p->serial_out = dw8250_serial_outq;
-                       p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-                       p->type = PORT_OCTEON;
-                       data->skip_autocfg = true;
-               }
+       if (quirks & DW_UART_QUIRK_OCTEON) {
+               p->serial_in = dw8250_serial_inq;
+               p->serial_out = dw8250_serial_outq;
+               p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+               p->type = PORT_OCTEON;
+               data->skip_autocfg = true;
+       }
 #endif
 
-               if (of_device_is_big_endian(np)) {
-                       p->iotype = UPIO_MEM32BE;
-                       p->serial_in = dw8250_serial_in32be;
-                       p->serial_out = dw8250_serial_out32be;
-               }
-
-               if (quirks & DW_UART_QUIRK_ARMADA_38X)
-                       p->serial_out = dw8250_serial_out38x;
-               if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
-                       p->set_termios = dw8250_do_set_termios;
-               if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
-                       data->data.dma.txconf.device_fc = 1;
-                       data->data.dma.rxconf.device_fc = 1;
-                       data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
-                       data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
-               }
-
-       } else if (acpi_dev_present("APMC0D08", NULL, -1)) {
+       if (quirks & DW_UART_QUIRK_ARMADA_38X)
+               p->serial_out = dw8250_serial_out38x;
+       if (quirks & DW_UART_QUIRK_SKIP_SET_RATE)
+               p->set_termios = dw8250_do_set_termios;
+       if (quirks & DW_UART_QUIRK_IS_DMA_FC) {
+               data->data.dma.txconf.device_fc = 1;
+               data->data.dma.rxconf.device_fc = 1;
+               data->data.dma.prepare_tx_dma = dw8250_prepare_tx_dma;
+               data->data.dma.prepare_rx_dma = dw8250_prepare_rx_dma;
+       }
+       if (quirks & DW_UART_QUIRK_APMC0D08) {
                p->iotype = UPIO_MEM32;
                p->regshift = 2;
                p->serial_in = dw8250_serial_in32;
@@ -510,39 +494,21 @@ static int dw8250_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct dw8250_data *data;
        struct resource *regs;
-       int irq;
        int err;
-       u32 val;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
                return dev_err_probe(dev, -EINVAL, "no registers defined\n");
 
-       irq = platform_get_irq_optional(pdev, 0);
-       /* no interrupt -> fall back to polling */
-       if (irq == -ENXIO)
-               irq = 0;
-       if (irq < 0)
-               return irq;
-
        spin_lock_init(&p->lock);
-       p->mapbase      = regs->start;
-       p->irq          = irq;
        p->handle_irq   = dw8250_handle_irq;
        p->pm           = dw8250_do_pm;
        p->type         = PORT_8250;
-       p->flags        = UPF_SHARE_IRQ | UPF_FIXED_PORT;
+       p->flags        = UPF_FIXED_PORT;
        p->dev          = dev;
-       p->iotype       = UPIO_MEM;
-       p->serial_in    = dw8250_serial_in;
-       p->serial_out   = dw8250_serial_out;
        p->set_ldisc    = dw8250_set_ldisc;
        p->set_termios  = dw8250_set_termios;
 
-       p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
-       if (!p->membase)
-               return -ENOMEM;
-
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
@@ -554,15 +520,35 @@ static int dw8250_probe(struct platform_device *pdev)
        data->uart_16550_compatible = device_property_read_bool(dev,
                                                "snps,uart-16550-compatible");
 
-       err = device_property_read_u32(dev, "reg-shift", &val);
-       if (!err)
-               p->regshift = val;
+       p->mapbase = regs->start;
+       p->mapsize = resource_size(regs);
 
-       err = device_property_read_u32(dev, "reg-io-width", &val);
-       if (!err && val == 4) {
-               p->iotype = UPIO_MEM32;
+       p->membase = devm_ioremap(dev, p->mapbase, p->mapsize);
+       if (!p->membase)
+               return -ENOMEM;
+
+       err = uart_read_port_properties(p);
+       /* no interrupt -> fall back to polling */
+       if (err == -ENXIO)
+               err = 0;
+       if (err)
+               return err;
+
+       switch (p->iotype) {
+       case UPIO_MEM:
+               p->serial_in = dw8250_serial_in;
+               p->serial_out = dw8250_serial_out;
+               break;
+       case UPIO_MEM32:
                p->serial_in = dw8250_serial_in32;
                p->serial_out = dw8250_serial_out32;
+               break;
+       case UPIO_MEM32BE:
+               p->serial_in = dw8250_serial_in32be;
+               p->serial_out = dw8250_serial_out32be;
+               break;
+       default:
+               return -ENODEV;
        }
 
        if (device_property_read_bool(dev, "dcd-override")) {
@@ -589,15 +575,13 @@ static int dw8250_probe(struct platform_device *pdev)
                data->msr_mask_off |= UART_MSR_TERI;
        }
 
-       /* Always ask for fixed clock rate from a property. */
-       device_property_read_u32(dev, "clock-frequency", &p->uartclk);
-
        /* If there is separate baudclk, get the rate from it. */
        data->clk = devm_clk_get_optional_enabled(dev, "baudclk");
        if (data->clk == NULL)
                data->clk = devm_clk_get_optional_enabled(dev, NULL);
        if (IS_ERR(data->clk))
-               return PTR_ERR(data->clk);
+               return dev_err_probe(dev, PTR_ERR(data->clk),
+                                    "failed to get baudclk\n");
 
        INIT_WORK(&data->clk_work, dw8250_clk_work_cb);
        data->clk_notifier.notifier_call = dw8250_clk_notifier_cb;
@@ -762,13 +746,18 @@ static const struct of_device_id dw8250_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dw8250_of_match);
 
+static const struct dw8250_platform_data dw8250_apmc0d08 = {
+       .usr_reg = DW_UART_USR,
+       .quirks = DW_UART_QUIRK_APMC0D08,
+};
+
 static const struct acpi_device_id dw8250_acpi_match[] = {
        { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
        { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
        { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
        { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
        { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
-       { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
+       { "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 },
        { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
        { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
        { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
index 23366f868ae3a8391f631e9952eb70baf9959076..0440df7de1ed74379e8862adbf965c320cfc5611 100644 (file)
@@ -6,23 +6,29 @@
  *
  *  Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved.
  */
-#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/dmi.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/kernel.h>
+#include <linux/math.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/property.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
 
 #include <asm/byteorder.h>
 
 #include "8250.h"
+#include "8250_pcilib.h"
 
 #define PCI_DEVICE_ID_ACCESSIO_COM_2S          0x1052
 #define PCI_DEVICE_ID_ACCESSIO_COM_4S          0x105d
@@ -229,13 +235,12 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
                         struct uart_8250_port *port)
 {
        const struct exar8250_board *board = priv->board;
-       unsigned int bar = 0;
        unsigned char status;
+       int err;
 
-       port->port.iotype = UPIO_MEM;
-       port->port.mapbase = pci_resource_start(pcidev, bar) + offset;
-       port->port.membase = priv->virt + offset;
-       port->port.regshift = board->reg_shift;
+       err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift);
+       if (err)
+               return err;
 
        /*
         * XR17V35x UARTs have an extra divisor register, DLD that gets enabled
@@ -375,7 +380,7 @@ static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev,
                return NULL;
 
        pdev->dev.parent = &pcidev->dev;
-       ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev));
+       device_set_node(&pdev->dev, dev_fwnode(&pcidev->dev));
 
        if (device_add_software_node(&pdev->dev, node) < 0 ||
            platform_device_add(pdev) < 0) {
@@ -713,14 +718,14 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
        uart.port.irq = pci_irq_vector(pcidev, 0);
        uart.port.dev = &pcidev->dev;
 
+       /* Clear interrupts */
+       exar_misc_clear(priv);
+
        rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler,
                         IRQF_SHARED, "exar_uart", priv);
        if (rc)
                return rc;
 
-       /* Clear interrupts */
-       exar_misc_clear(priv);
-
        for (i = 0; i < nr_ports && i < maxnr; i++) {
                rc = board->setup(priv, pcidev, &uart, i);
                if (rc) {
@@ -753,28 +758,24 @@ static void exar_pci_remove(struct pci_dev *pcidev)
        for (i = 0; i < priv->nr; i++)
                serial8250_unregister_port(priv->line[i]);
 
+       /* Ensure that every init quirk is properly torn down */
        if (priv->board->exit)
                priv->board->exit(pcidev);
 }
 
-static int __maybe_unused exar_suspend(struct device *dev)
+static int exar_suspend(struct device *dev)
 {
-       struct pci_dev *pcidev = to_pci_dev(dev);
-       struct exar8250 *priv = pci_get_drvdata(pcidev);
+       struct exar8250 *priv = dev_get_drvdata(dev);
        unsigned int i;
 
        for (i = 0; i < priv->nr; i++)
                if (priv->line[i] >= 0)
                        serial8250_suspend_port(priv->line[i]);
 
-       /* Ensure that every init quirk is properly torn down */
-       if (priv->board->exit)
-               priv->board->exit(pcidev);
-
        return 0;
 }
 
-static int __maybe_unused exar_resume(struct device *dev)
+static int exar_resume(struct device *dev)
 {
        struct exar8250 *priv = dev_get_drvdata(dev);
        unsigned int i;
@@ -788,7 +789,7 @@ static int __maybe_unused exar_resume(struct device *dev)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
 
 static const struct exar8250_board pbn_fastcom335_2 = {
        .num_ports      = 2,
@@ -938,12 +939,13 @@ static struct pci_driver exar_pci_driver = {
        .probe          = exar_pci_probe,
        .remove         = exar_pci_remove,
        .driver         = {
-               .pm     = &exar_pci_pm,
+               .pm     = pm_sleep_ptr(&exar_pci_pm),
        },
        .id_table       = exar_pci_tbl,
 };
 module_pci_driver(exar_pci_driver);
 
+MODULE_IMPORT_NS(SERIAL_8250_PCI);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Exar Serial Driver");
 MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
index a12f737924c0b79c5d85d13e413f412bb7ed6dd6..a2783e38a2e31641c50667df086ecfad27df34bf 100644 (file)
@@ -234,7 +234,7 @@ static int ingenic_uart_probe(struct platform_device *pdev)
        struct ingenic_uart_data *data;
        const struct ingenic_uart_config *cdata;
        struct resource *regs;
-       int irq, err, line;
+       int err;
 
        cdata = of_device_get_match_data(&pdev->dev);
        if (!cdata) {
@@ -242,10 +242,6 @@ static int ingenic_uart_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
                dev_err(&pdev->dev, "no registers defined\n");
@@ -259,21 +255,19 @@ static int ingenic_uart_probe(struct platform_device *pdev)
        spin_lock_init(&uart.port.lock);
        uart.port.type = PORT_16550A;
        uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
-       uart.port.iotype = UPIO_MEM;
        uart.port.mapbase = regs->start;
-       uart.port.regshift = 2;
        uart.port.serial_out = ingenic_uart_serial_out;
        uart.port.serial_in = ingenic_uart_serial_in;
-       uart.port.irq = irq;
        uart.port.dev = &pdev->dev;
-       uart.port.fifosize = cdata->fifosize;
        uart.tx_loadsz = cdata->tx_loadsz;
        uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
 
-       /* Check for a fixed line number */
-       line = of_alias_get_id(pdev->dev.of_node, "serial");
-       if (line >= 0)
-               uart.port.line = line;
+       err = uart_read_port_properties(&uart.port);
+       if (err)
+               return err;
+
+       uart.port.regshift = 2;
+       uart.port.fifosize = cdata->fifosize;
 
        uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
                                         resource_size(regs));
index 8d728a6a5991412b23298368aa914971ea4b4261..7984ee05af1dada214e275062a5c831d9a66144c 100644 (file)
@@ -92,11 +92,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
        struct lpc18xx_uart_data *data;
        struct uart_8250_port uart;
        struct resource *res;
-       int irq, ret;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
+       int ret;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -139,19 +135,12 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
                goto dis_clk_reg;
        }
 
-       ret = of_alias_get_id(pdev->dev.of_node, "serial");
-       if (ret >= 0)
-               uart.port.line = ret;
-
        data->dma.rx_param = data;
        data->dma.tx_param = data;
 
        spin_lock_init(&uart.port.lock);
        uart.port.dev = &pdev->dev;
-       uart.port.irq = irq;
-       uart.port.iotype = UPIO_MEM32;
        uart.port.mapbase = res->start;
-       uart.port.regshift = 2;
        uart.port.type = PORT_16550A;
        uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
        uart.port.uartclk = clk_get_rate(data->clk_uart);
@@ -160,6 +149,13 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
        uart.port.rs485_supported = lpc18xx_rs485_supported;
        uart.port.serial_out = lpc18xx_uart_serial_out;
 
+       ret = uart_read_port_properties(&uart.port);
+       if (ret)
+               return ret;
+
+       uart.port.iotype = UPIO_MEM32;
+       uart.port.regshift = 2;
+
        uart.dma = &data->dma;
        uart.dma->rxconf.src_maxburst = 1;
        uart.dma->txconf.dst_maxburst = 1;
index 34f17a9785e79e1d26b6fbbbea3441a89f523e44..5d1dd992d8fba0df3d9e9e15d0d0c7b675015ffa 100644 (file)
@@ -4,7 +4,10 @@
  *
  *    Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
  */
+
+#include <linux/bits.h>
 #include <linux/console.h>
+#include <linux/math.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/serial_core.h>
@@ -25,6 +28,36 @@ struct of_serial_info {
        int line;
 };
 
+/* Nuvoton NPCM timeout register */
+#define UART_NPCM_TOR          7
+#define UART_NPCM_TOIE         BIT(7)  /* Timeout Interrupt Enable */
+
+static int npcm_startup(struct uart_port *port)
+{
+       /*
+        * Nuvoton calls the scratch register 'UART_TOR' (timeout
+        * register). Enable it, and set TIOC (timeout interrupt
+        * comparator) to be 0x20 for correct operation.
+        */
+       serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
+
+       return serial8250_do_startup(port);
+}
+
+/* Nuvoton NPCM UARTs have a custom divisor calculation */
+static unsigned int npcm_get_divisor(struct uart_port *port, unsigned int baud,
+                                    unsigned int *frac)
+{
+       return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
+}
+
+static int npcm_setup(struct uart_port *port)
+{
+       port->get_divisor = npcm_get_divisor;
+       port->startup = npcm_startup;
+       return 0;
+}
+
 /*
  * Fill a struct uart_port for a given device node
  */
@@ -36,37 +69,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        struct device *dev = &ofdev->dev;
        struct device_node *np = dev->of_node;
        struct uart_port *port = &up->port;
-       u32 clk, spd, prop;
-       int ret, irq;
+       u32 spd;
+       int ret;
 
        memset(port, 0, sizeof *port);
 
        pm_runtime_enable(&ofdev->dev);
        pm_runtime_get_sync(&ofdev->dev);
 
-       if (of_property_read_u32(np, "clock-frequency", &clk)) {
-
-               /* Get clk rate through clk driver if present */
-               info->clk = devm_clk_get_enabled(dev, NULL);
-               if (IS_ERR(info->clk)) {
-                       ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
-                       goto err_pmruntime;
-               }
-
-               clk = clk_get_rate(info->clk);
-       }
-       /* If current-speed was set, then try not to change it. */
-       if (of_property_read_u32(np, "current-speed", &spd) == 0)
-               port->custom_divisor = clk / (16 * spd);
-
        ret = of_address_to_resource(np, 0, &resource);
        if (ret) {
                dev_err_probe(dev, ret, "invalid address\n");
                goto err_pmruntime;
        }
 
-       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
-                                 UPF_FIXED_TYPE;
+       port->dev = &ofdev->dev;
+       port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
        spin_lock_init(&port->lock);
 
        if (resource_type(&resource) == IORESOURCE_IO) {
@@ -75,70 +93,31 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        } else {
                port->mapbase = resource.start;
                port->mapsize = resource_size(&resource);
+               port->flags |= UPF_IOREMAP;
+       }
 
-               /* Check for shifted address mapping */
-               if (of_property_read_u32(np, "reg-offset", &prop) == 0) {
-                       if (prop >= port->mapsize) {
-                               ret = dev_err_probe(dev, -EINVAL, "reg-offset %u exceeds region size %pa\n",
-                                                   prop, &port->mapsize);
-                               goto err_pmruntime;
-                       }
+       ret = uart_read_and_validate_port_properties(port);
+       if (ret)
+               goto err_pmruntime;
 
-                       port->mapbase += prop;
-                       port->mapsize -= prop;
+       /* Get clk rate through clk driver if present */
+       if (!port->uartclk) {
+               info->clk = devm_clk_get_enabled(dev, NULL);
+               if (IS_ERR(info->clk)) {
+                       ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
+                       goto err_pmruntime;
                }
 
-               port->iotype = UPIO_MEM;
-               if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
-                       switch (prop) {
-                       case 1:
-                               port->iotype = UPIO_MEM;
-                               break;
-                       case 2:
-                               port->iotype = UPIO_MEM16;
-                               break;
-                       case 4:
-                               port->iotype = of_device_is_big_endian(np) ?
-                                              UPIO_MEM32BE : UPIO_MEM32;
-                               break;
-                       default:
-                               ret = dev_err_probe(dev, -EINVAL, "unsupported reg-io-width (%u)\n",
-                                                   prop);
-                               goto err_pmruntime;
-                       }
-               }
-               port->flags |= UPF_IOREMAP;
+               port->uartclk = clk_get_rate(info->clk);
        }
+       /* If current-speed was set, then try not to change it. */
+       if (of_property_read_u32(np, "current-speed", &spd) == 0)
+               port->custom_divisor = port->uartclk / (16 * spd);
 
        /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */
        if (of_device_is_compatible(np, "mrvl,mmp-uart"))
                port->regshift = 2;
 
-       /* Check for registers offset within the devices address range */
-       if (of_property_read_u32(np, "reg-shift", &prop) == 0)
-               port->regshift = prop;
-
-       /* Check for fifo size */
-       if (of_property_read_u32(np, "fifo-size", &prop) == 0)
-               port->fifosize = prop;
-
-       /* Check for a fixed line number */
-       ret = of_alias_get_id(np, "serial");
-       if (ret >= 0)
-               port->line = ret;
-
-       irq = of_irq_get(np, 0);
-       if (irq < 0) {
-               if (irq == -EPROBE_DEFER) {
-                       ret = -EPROBE_DEFER;
-                       goto err_pmruntime;
-               }
-               /* IRQ support not mandatory */
-               irq = 0;
-       }
-
-       port->irq = irq;
-
        info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
        if (IS_ERR(info->rst)) {
                ret = PTR_ERR(info->rst);
@@ -150,12 +129,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                goto err_pmruntime;
 
        port->type = type;
-       port->uartclk = clk;
-
-       if (of_property_read_bool(np, "no-loopback-test"))
-               port->flags |= UPF_SKIP_TEST;
-
-       port->dev = &ofdev->dev;
        port->rs485_config = serial8250_em485_config;
        port->rs485_supported = serial8250_em485_supported;
        up->rs485_start_tx = serial8250_em485_start_tx;
@@ -164,10 +137,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        switch (type) {
        case PORT_RT2880:
                ret = rt288x_setup(port);
-               if (ret)
-                       goto err_pmruntime;
+               break;
+       case PORT_NPCM:
+               ret = npcm_setup(port);
+               break;
+       default:
+               /* Nothing to do */
+               ret = 0;
                break;
        }
+       if (ret)
+               goto err_pmruntime;
 
        if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) &&
            (of_device_is_compatible(np, "fsl,ns16550") ||
@@ -240,7 +220,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
        platform_set_drvdata(ofdev, info);
        return 0;
 err_dispose:
-       irq_dispose_mapping(port8250.port.irq);
        pm_runtime_put_sync(&ofdev->dev);
        pm_runtime_disable(&ofdev->dev);
 err_free:
index 6942990a333c8b6a76520f9d5868e604565034bf..66901d93089a3cbcd3e0f7d16f85936cc859f30c 100644 (file)
@@ -1394,11 +1394,7 @@ static int omap8250_probe(struct platform_device *pdev)
        struct uart_8250_port up;
        struct resource *regs;
        void __iomem *membase;
-       int irq, ret;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
+       int ret;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs) {
@@ -1419,7 +1415,6 @@ static int omap8250_probe(struct platform_device *pdev)
        up.port.dev = &pdev->dev;
        up.port.mapbase = regs->start;
        up.port.membase = membase;
-       up.port.irq = irq;
        /*
         * It claims to be 16C750 compatible however it is a little different.
         * It has EFR and has no FCR7_64byte bit. The AFE (which it claims to
@@ -1429,13 +1424,9 @@ static int omap8250_probe(struct platform_device *pdev)
         * or pm callback.
         */
        up.port.type = PORT_8250;
-       up.port.iotype = UPIO_MEM;
-       up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW |
-               UPF_HARD_FLOW;
+       up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SOFT_FLOW | UPF_HARD_FLOW;
        up.port.private_data = priv;
 
-       up.port.regshift = OMAP_UART_REGSHIFT;
-       up.port.fifosize = 64;
        up.tx_loadsz = 64;
        up.capabilities = UART_CAP_FIFO;
 #ifdef CONFIG_PM
@@ -1461,14 +1452,14 @@ static int omap8250_probe(struct platform_device *pdev)
        up.rs485_stop_tx = serial8250_em485_stop_tx;
        up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
 
-       ret = of_alias_get_id(np, "serial");
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to get alias\n");
+       ret = uart_read_port_properties(&up.port);
+       if (ret)
                return ret;
-       }
-       up.port.line = ret;
 
-       if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) {
+       up.port.regshift = OMAP_UART_REGSHIFT;
+       up.port.fifosize = 64;
+
+       if (!up.port.uartclk) {
                struct clk *clk;
 
                clk = devm_clk_get(&pdev->dev, NULL);
@@ -1560,8 +1551,8 @@ static int omap8250_probe(struct platform_device *pdev)
        }
 #endif
 
-       irq_set_status_flags(irq, IRQ_NOAUTOEN);
-       ret = devm_request_irq(&pdev->dev, irq, omap8250_irq, 0,
+       irq_set_status_flags(up.port.irq, IRQ_NOAUTOEN);
+       ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0,
                               dev_name(&pdev->dev), priv);
        if (ret < 0)
                return ret;
index 2dda737b1660bd7bd6f576d2146440d97e945047..2fbb5851f788b7a45f1002f4d276b4968b067f0e 100644 (file)
@@ -7,23 +7,31 @@
  *  Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
  */
 
+#include <linux/array_size.h>
 #include <linux/bitfield.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
+#include <linux/bits.h>
+#include <linux/circ_buf.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gfp_types.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
-#include <linux/kernel.h>
+#include <linux/minmax.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
 #include <linux/serial_8250.h>
-#include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
-#include <linux/units.h>
+#include <linux/time.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/8250_pci.h>
+#include <linux/types.h>
+#include <linux/units.h>
 
 #include <asm/byteorder.h>
 
@@ -67,6 +75,7 @@
 #define SYSLOCK_RETRY_CNT                      1000
 
 #define UART_RX_BYTE_FIFO                      0x00
+#define UART_TX_BYTE_FIFO                      0x00
 #define UART_FIFO_CTL                          0x02
 
 #define UART_ACTV_REG                          0x11
 #define ADCL_CFG_PIN_SEL                       BIT(1)
 #define ADCL_CFG_EN                            BIT(0)
 
-#define UART_BIT_SAMPLE_CNT                    16
+#define UART_BIT_SAMPLE_CNT_8                  8
+#define UART_BIT_SAMPLE_CNT_16                 16
 #define BAUD_CLOCK_DIV_INT_MSK                 GENMASK(31, 8)
 #define ADCL_CFG_RTS_DELAY_MASK                        GENMASK(11, 8)
-#define UART_CLOCK_DEFAULT                     (62500 * HZ_PER_KHZ)
 
 #define UART_WAKE_REG                          0x8C
 #define UART_WAKE_MASK_REG                     0x90
        (UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
 
 #define UART_BAUD_CLK_DIVISOR_REG              0x54
+#define FRAC_DIV_CFG_REG                       0x58
 
 #define UART_RESET_REG                         0x94
 #define UART_RESET_D3_RESET_DISABLE            BIT(16)
 
 #define UART_BURST_STATUS_REG                  0x9C
+#define UART_TX_BURST_FIFO                     0xA0
 #define UART_RX_BURST_FIFO                     0xA4
 
+#define UART_BIT_DIVISOR_8                     0x26731000
+#define UART_BIT_DIVISOR_16                    0x6ef71000
+#define UART_BAUD_4MBPS                                4000000
+
 #define MAX_PORTS                              4
 #define PORT_OFFSET                            0x100
 #define RX_BUF_SIZE                            512
 #define UART_BURST_SIZE                                4
 
 #define UART_BST_STAT_RX_COUNT_MASK            0x00FF
+#define UART_BST_STAT_TX_COUNT_MASK            0xFF00
 #define UART_BST_STAT_IIR_INT_PEND             0x100000
 #define UART_LSR_OVERRUN_ERR_CLR               0x43
 #define UART_BST_STAT_LSR_RX_MASK              0x9F000000
 #define UART_BST_STAT_LSR_OVERRUN_ERR          0x2000000
 #define UART_BST_STAT_LSR_PARITY_ERR           0x4000000
 #define UART_BST_STAT_LSR_FRAME_ERR            0x8000000
+#define UART_BST_STAT_LSR_THRE                 0x20000000
 
 struct pci1xxxx_8250 {
        unsigned int nr;
@@ -206,15 +223,21 @@ static int pci1xxxx_get_num_ports(struct pci_dev *dev)
 static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
                                         unsigned int baud, unsigned int *frac)
 {
+       unsigned int uart_sample_cnt;
        unsigned int quot;
 
+       if (baud >= UART_BAUD_4MBPS)
+               uart_sample_cnt = UART_BIT_SAMPLE_CNT_8;
+       else
+               uart_sample_cnt = UART_BIT_SAMPLE_CNT_16;
+
        /*
         * Calculate baud rate sampling period in nanoseconds.
         * Fractional part x denotes x/255 parts of a nanosecond.
         */
-       quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
-       *frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
-                 255 / UART_BIT_SAMPLE_CNT / baud;
+       quot = NSEC_PER_SEC / (baud * uart_sample_cnt);
+       *frac = (NSEC_PER_SEC - quot * baud * uart_sample_cnt) *
+                 255 / uart_sample_cnt / baud;
 
        return quot;
 }
@@ -222,6 +245,11 @@ static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
 static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
                                 unsigned int quot, unsigned int frac)
 {
+       if (baud >= UART_BAUD_4MBPS)
+               writel(UART_BIT_DIVISOR_8, port->membase + FRAC_DIV_CFG_REG);
+       else
+               writel(UART_BIT_DIVISOR_16, port->membase + FRAC_DIV_CFG_REG);
+
        writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac,
               port->membase + UART_BAUD_CLK_DIVISOR_REG);
 }
@@ -233,7 +261,16 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
        u32 delay_in_baud_periods;
        u32 baud_period_in_ns;
        u32 mode_cfg = 0;
+       u32 sample_cnt;
        u32 clock_div;
+       u32 frac_div;
+
+       frac_div = readl(port->membase + FRAC_DIV_CFG_REG);
+
+       if (frac_div == UART_BIT_DIVISOR_16)
+               sample_cnt = UART_BIT_SAMPLE_CNT_16;
+       else
+               sample_cnt = UART_BIT_SAMPLE_CNT_8;
 
        /*
         * pci1xxxx's uart hardware supports only RTS delay after
@@ -249,7 +286,7 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
                        clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
                        baud_period_in_ns =
                                FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
-                               UART_BIT_SAMPLE_CNT;
+                               sample_cnt;
                        delay_in_baud_periods =
                                rs485->delay_rts_after_send * NSEC_PER_MSEC /
                                baud_period_in_ns;
@@ -344,6 +381,105 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
        }
 }
 
+static void pci1xxxx_process_write_data(struct uart_port *port,
+                                       struct circ_buf *xmit,
+                                       int *data_empty_count,
+                                       u32 *valid_byte_count)
+{
+       u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
+
+       /*
+        * Each transaction transfers data in DWORDs. If there are less than
+        * four remaining valid_byte_count to transfer or if the circular
+        * buffer has insufficient space for a DWORD, the data is transferred
+        * one byte at a time.
+        */
+       while (valid_burst_count) {
+               if (*data_empty_count - UART_BURST_SIZE < 0)
+                       break;
+               if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE))
+                       break;
+               writel(*(unsigned int *)&xmit->buf[xmit->tail],
+                      port->membase + UART_TX_BURST_FIFO);
+               *valid_byte_count -= UART_BURST_SIZE;
+               *data_empty_count -= UART_BURST_SIZE;
+               valid_burst_count -= UART_BYTE_SIZE;
+
+               xmit->tail = (xmit->tail + UART_BURST_SIZE) &
+                            (UART_XMIT_SIZE - 1);
+       }
+
+       while (*valid_byte_count) {
+               if (*data_empty_count - UART_BYTE_SIZE < 0)
+                       break;
+               writeb(xmit->buf[xmit->tail], port->membase +
+                      UART_TX_BYTE_FIFO);
+               *data_empty_count -= UART_BYTE_SIZE;
+               *valid_byte_count -= UART_BYTE_SIZE;
+
+               /*
+                * When the tail of the circular buffer is reached, the next
+                * byte is transferred to the beginning of the buffer.
+                */
+               xmit->tail = (xmit->tail + UART_BYTE_SIZE) &
+                            (UART_XMIT_SIZE - 1);
+
+               /*
+                * If there are any pending burst count, data is handled by
+                * transmitting DWORDs at a time.
+                */
+               if (valid_burst_count && (xmit->tail <
+                  (UART_XMIT_SIZE - UART_BURST_SIZE)))
+                       break;
+       }
+}
+
+static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
+{
+       struct uart_8250_port *up = up_to_u8250p(port);
+       u32 valid_byte_count;
+       int data_empty_count;
+       struct circ_buf *xmit;
+
+       xmit = &port->state->xmit;
+
+       if (port->x_char) {
+               writeb(port->x_char, port->membase + UART_TX);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) {
+               port->ops->stop_tx(port);
+       } else {
+               data_empty_count = (pci1xxxx_read_burst_status(port) &
+                                   UART_BST_STAT_TX_COUNT_MASK) >> 8;
+               do {
+                       valid_byte_count = uart_circ_chars_pending(xmit);
+
+                       pci1xxxx_process_write_data(port, xmit,
+                                                   &data_empty_count,
+                                                   &valid_byte_count);
+
+                       port->icount.tx++;
+                       if (uart_circ_empty(xmit))
+                               break;
+               } while (data_empty_count && valid_byte_count);
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+        /*
+         * With RPM enabled, we have to wait until the FIFO is empty before
+         * the HW can go idle. So we get here once again with empty FIFO and
+         * disable the interrupt and RPM in __stop_tx()
+         */
+       if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+               port->ops->stop_tx(port);
+}
+
 static int pci1xxxx_handle_irq(struct uart_port *port)
 {
        unsigned long flags;
@@ -359,6 +495,9 @@ static int pci1xxxx_handle_irq(struct uart_port *port)
        if (status & UART_BST_STAT_LSR_RX_MASK)
                pci1xxxx_rx_burst(port, status);
 
+       if (status & UART_BST_STAT_LSR_THRE)
+               pci1xxxx_tx_burst(port, status);
+
        spin_unlock_irqrestore(&port->lock, flags);
 
        return 1;
@@ -481,6 +620,17 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
 
        port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
        port->port.type = PORT_MCHP16550A;
+       /*
+        * 8250 core considers prescaller value to be always 16.
+        * The MCHP ports support downscaled mode and hence the
+        * functional UART clock can be lower, i.e. 62.5MHz, than
+        * software expects in order to support higher baud rates.
+        * Assign here 64MHz to support 4Mbps.
+        *
+        * The value itself is not really used anywhere except baud
+        * rate calculations, so we can mangle it as we wish.
+        */
+       port->port.uartclk = 64 * HZ_PER_MHZ;
        port->port.set_termios = serial8250_do_set_termios;
        port->port.get_divisor = pci1xxxx_get_divisor;
        port->port.set_divisor = pci1xxxx_set_divisor;
@@ -594,7 +744,6 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
 
        memset(&uart, 0, sizeof(uart));
        uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
-       uart.port.uartclk = UART_CLOCK_DEFAULT;
        uart.port.dev = dev;
 
        if (num_vectors == max_vec_reqd)
index 8ca061d3bbb9215d04a4381a84f07b09147f2c8a..fc9dd5d45295da2a526688d442876d5b2c2e18c1 100644 (file)
 
 #include "8250.h"
 
-/* Nuvoton NPCM timeout register */
-#define UART_NPCM_TOR          7
-#define UART_NPCM_TOIE         BIT(7)  /* Timeout Interrupt Enable */
-
 /*
  * Debugging.
  */
@@ -1329,9 +1325,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
                inb_p(ICP);
        }
 
-       if (uart_console(port))
-               console_lock();
-
        /* forget possible initially masked and pending IRQ */
        probe_irq_off(probe_irq_on());
        save_mcr = serial8250_in_MCR(up);
@@ -1371,9 +1364,6 @@ static void autoconfig_irq(struct uart_8250_port *up)
        if (port->flags & UPF_FOURPORT)
                outb_p(save_ICP, ICP);
 
-       if (uart_console(port))
-               console_unlock();
-
        port->irq = (irq > 0) ? irq : 0;
 }
 
@@ -2235,15 +2225,6 @@ int serial8250_do_startup(struct uart_port *port)
                                UART_DA830_PWREMU_MGMT_FREE);
        }
 
-       if (port->type == PORT_NPCM) {
-               /*
-                * Nuvoton calls the scratch register 'UART_TOR' (timeout
-                * register). Enable it, and set TIOC (timeout interrupt
-                * comparator) to be 0x20 for correct operation.
-                */
-               serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);
-       }
-
 #ifdef CONFIG_SERIAL_8250_RSA
        /*
         * If this is an RSA port, see if we can kick it up to the
@@ -2545,15 +2526,6 @@ static void serial8250_shutdown(struct uart_port *port)
                serial8250_do_shutdown(port);
 }
 
-/* Nuvoton NPCM UARTs have a custom divisor calculation */
-static unsigned int npcm_get_divisor(struct uart_8250_port *up,
-               unsigned int baud)
-{
-       struct uart_port *port = &up->port;
-
-       return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
-}
-
 static unsigned int serial8250_do_get_divisor(struct uart_port *port,
                                              unsigned int baud,
                                              unsigned int *frac)
@@ -2598,8 +2570,6 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port,
                quot = 0x8001;
        else if (magic_multiplier && baud >= port->uartclk / 12)
                quot = 0x8002;
-       else if (up->port.type == PORT_NPCM)
-               quot = npcm_get_divisor(up, baud);
        else
                quot = uart_get_divisor(port, baud);
 
@@ -2714,12 +2684,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
  */
 void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
 {
-       struct uart_8250_port *up = up_to_u8250p(port);
        struct tty_port *tport = &port->state->port;
-       unsigned int baud, quot, frac = 0;
-       struct ktermios *termios;
        struct tty_struct *tty;
-       unsigned long flags;
 
        tty = tty_port_tty_get(tport);
        if (!tty) {
@@ -2740,21 +2706,7 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
        if (!tty_port_initialized(tport))
                goto out_unlock;
 
-       termios = &tty->termios;
-
-       baud = serial8250_get_baud_rate(port, termios, NULL);
-       quot = serial8250_get_divisor(port, baud, &frac);
-
-       serial8250_rpm_get(up);
-       uart_port_lock_irqsave(port, &flags);
-
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       serial8250_set_divisor(port, baud, quot, frac);
-       serial_port_out(port, UART_LCR, up->lcr);
-
-       uart_port_unlock_irqrestore(port, flags);
-       serial8250_rpm_put(up);
+       serial8250_do_set_termios(port, &tty->termios, NULL);
 
 out_unlock:
        mutex_unlock(&tport->mutex);
index 77686da42ce8e93ca42d9c00ffde2d4e8bb9c234..f1a51b00b1b9de84307047e3f216694bfa42fb06 100644 (file)
@@ -92,11 +92,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
        struct uart_8250_port uart = {};
        struct pxa8250_data *data;
        struct resource *mmres;
-       int irq, ret;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
+       int ret;
 
        mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mmres)
@@ -114,21 +110,21 @@ static int serial_pxa_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       ret = of_alias_get_id(pdev->dev.of_node, "serial");
-       if (ret >= 0)
-               uart.port.line = ret;
-
        uart.port.type = PORT_XSCALE;
-       uart.port.iotype = UPIO_MEM32;
        uart.port.mapbase = mmres->start;
-       uart.port.regshift = 2;
-       uart.port.irq = irq;
-       uart.port.fifosize = 64;
        uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
        uart.port.dev = &pdev->dev;
        uart.port.uartclk = clk_get_rate(data->clk);
        uart.port.pm = serial_pxa_pm;
        uart.port.private_data = data;
+
+       ret = uart_read_port_properties(&uart.port);
+       if (ret)
+               return ret;
+
+       uart.port.iotype = UPIO_MEM32;
+       uart.port.regshift = 2;
+       uart.port.fifosize = 64;
        uart.dl_write = serial_pxa_dl_write;
 
        ret = serial8250_register_8250_port(&uart);
index ba352262df75a7b32c9fa6401abd012e5ccf0ec8..60a80d00d2519b600dfb4fb635f2f1e33551adad 100644 (file)
@@ -57,25 +57,11 @@ static int tegra_uart_probe(struct platform_device *pdev)
        port = &port8250.port;
        spin_lock_init(&port->lock);
 
-       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
-                     UPF_FIXED_TYPE;
-       port->iotype = UPIO_MEM32;
-       port->regshift = 2;
+       port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
        port->type = PORT_TEGRA;
-       port->irqflags |= IRQF_SHARED;
        port->dev = &pdev->dev;
        port->handle_break = tegra_uart_handle_break;
 
-       ret = of_alias_get_id(pdev->dev.of_node, "serial");
-       if (ret >= 0)
-               port->line = ret;
-
-       ret = platform_get_irq(pdev, 0);
-       if (ret < 0)
-               return ret;
-
-       port->irq = ret;
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                return -ENODEV;
@@ -88,12 +74,18 @@ static int tegra_uart_probe(struct platform_device *pdev)
        port->mapbase = res->start;
        port->mapsize = resource_size(res);
 
+       ret = uart_read_port_properties(port);
+       if (ret)
+               return ret;
+
+       port->iotype = UPIO_MEM32;
+       port->regshift = 2;
+
        uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
        if (IS_ERR(uart->rst))
                return PTR_ERR(uart->rst);
 
-       if (device_property_read_u32(&pdev->dev, "clock-frequency",
-                                    &port->uartclk)) {
+       if (!port->uartclk) {
                uart->clk = devm_clk_get(&pdev->dev, NULL);
                if (IS_ERR(uart->clk)) {
                        dev_err(&pdev->dev, "failed to get clock!\n");
index 6399a38ecce2ada62168872b33b13ae7c7273b49..670d2ca0f7572948384c67a49855cd96464447c1 100644 (file)
@@ -162,7 +162,6 @@ static int uniphier_uart_probe(struct platform_device *pdev)
        struct uniphier8250_priv *priv;
        struct resource *regs;
        void __iomem *membase;
-       int irq;
        int ret;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -175,23 +174,12 @@ static int uniphier_uart_probe(struct platform_device *pdev)
        if (!membase)
                return -ENOMEM;
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        memset(&up, 0, sizeof(up));
 
-       ret = of_alias_get_id(dev->of_node, "serial");
-       if (ret < 0) {
-               dev_err(dev, "failed to get alias id\n");
-               return ret;
-       }
-       up.port.line = ret;
-
        priv->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(priv->clk)) {
                dev_err(dev, "failed to get clock\n");
@@ -211,7 +199,10 @@ static int uniphier_uart_probe(struct platform_device *pdev)
        up.port.mapbase = regs->start;
        up.port.mapsize = resource_size(regs);
        up.port.membase = membase;
-       up.port.irq = irq;
+
+       ret = uart_read_port_properties(&up.port);
+       if (ret)
+               return ret;
 
        up.port.type = PORT_16550A;
        up.port.iotype = UPIO_MEM32;
index 8b9a2c4902e2c31c0897d7daf42a0ffd97c285d7..47ff50763c048c89b19b7c9f13f462bc5368ab43 100644 (file)
@@ -149,6 +149,7 @@ config SERIAL_8250_PCI
 config SERIAL_8250_EXAR
        tristate "8250/16550 Exar/Commtech PCI/PCIe device support"
        depends on SERIAL_8250 && PCI
+       select SERIAL_8250_PCILIB
        default SERIAL_8250
        help
          This builds support for XR17C1xx, XR17V3xx and some Commtech
index cf2c890a560f05204e249b931668deca04b3cb27..2fa3fb30dc6c7552667ea68691b28115569c303e 100644 (file)
@@ -348,10 +348,7 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
                                flag = TTY_FRAME;
                }
 
-               uart_port_unlock(&uap->port);
-               sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
-               uart_port_lock(&uap->port);
-
+               sysrq = uart_prepare_sysrq_char(&uap->port, ch & 255);
                if (!sysrq)
                        uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
        }
@@ -1017,7 +1014,7 @@ static void pl011_dma_rx_callback(void *data)
        ret = pl011_dma_rx_trigger_dma(uap);
 
        pl011_dma_rx_chars(uap, pending, lastbuf, false);
-       uart_port_unlock_irq(&uap->port);
+       uart_unlock_and_check_sysrq(&uap->port);
        /*
         * Do this check after we picked the DMA chars so we don't
         * get some IRQ immediately from RX.
@@ -1540,11 +1537,10 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
 static irqreturn_t pl011_int(int irq, void *dev_id)
 {
        struct uart_amba_port *uap = dev_id;
-       unsigned long flags;
        unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
        int handled = 0;
 
-       uart_port_lock_irqsave(&uap->port, &flags);
+       uart_port_lock(&uap->port);
        status = pl011_read(uap, REG_RIS) & uap->im;
        if (status) {
                do {
@@ -1573,7 +1569,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
                handled = 1;
        }
 
-       uart_port_unlock_irqrestore(&uap->port, flags);
+       uart_unlock_and_check_sysrq(&uap->port);
 
        return IRQ_RETVAL(handled);
 }
@@ -2322,13 +2318,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
 
        clk_enable(uap->clk);
 
-       local_irq_save(flags);
-       if (uap->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&uap->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&uap->port, &flags);
        else
-               uart_port_lock(&uap->port);
+               uart_port_lock_irqsave(&uap->port, &flags);
 
        /*
         *      First save the CR then disable the interrupts
@@ -2354,8 +2347,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
                pl011_write(old_cr, uap, REG_CR);
 
        if (locked)
-               uart_port_unlock(&uap->port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&uap->port, flags);
 
        clk_disable(uap->clk);
 }
index 8d09ace062e5966660e9a077f5b968ff4c8f7b96..7790cbc57391aaafedc70a33cc24fd1f5da5d54d 100644 (file)
@@ -378,7 +378,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
                up->port.icount.rx++;
                ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
 
-               if (uart_handle_sysrq_char(&up->port, ch))
+               if (uart_prepare_sysrq_char(&up->port, ch))
                        continue;
 
                if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0)
@@ -468,7 +468,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
                ar933x_uart_tx_chars(up);
        }
 
-       uart_port_unlock(&up->port);
+       uart_unlock_and_check_sysrq(&up->port);
 
        return IRQ_HANDLED;
 }
@@ -627,14 +627,10 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
        unsigned int int_en;
        int locked = 1;
 
-       local_irq_save(flags);
-
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&up->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&up->port, &flags);
        else
-               uart_port_lock(&up->port);
+               uart_port_lock_irqsave(&up->port, &flags);
 
        /*
         * First save the IER then disable the interrupts
@@ -654,9 +650,7 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
        ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS);
 
        if (locked)
-               uart_port_unlock(&up->port);
-
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&up->port, flags);
 }
 
 static int ar933x_uart_console_setup(struct console *co, char *options)
index a3cefa153456df4a4d486b3784a03b99e1a4fc6e..34801a6f300b6841464f5195f9399ebd90b654d1 100644 (file)
@@ -285,10 +285,9 @@ static void bcm_uart_do_rx(struct uart_port *port)
                                flag = TTY_PARITY;
                }
 
-               if (uart_handle_sysrq_char(port, c))
+               if (uart_prepare_sysrq_char(port, c))
                        continue;
 
-
                if ((cstat & port->ignore_status_mask) == 0)
                        tty_insert_flip_char(tty_port, c, flag);
 
@@ -353,7 +352,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
                                               estat & UART_EXTINP_DCD_MASK);
        }
 
-       uart_port_unlock(port);
+       uart_unlock_and_check_sysrq(port);
        return IRQ_HANDLED;
 }
 
@@ -703,20 +702,14 @@ static void bcm_console_write(struct console *co, const char *s,
 {
        struct uart_port *port;
        unsigned long flags;
-       int locked;
+       int locked = 1;
 
        port = &ports[co->index];
 
-       local_irq_save(flags);
-       if (port->sysrq) {
-               /* bcm_uart_interrupt() already took the lock */
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = uart_port_trylock(port);
-       } else {
-               uart_port_lock(port);
-               locked = 1;
-       }
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(port, &flags);
+       else
+               uart_port_lock_irqsave(port, &flags);
 
        /* call helper to deal with \r\n */
        uart_console_write(port, s, count, bcm_console_putchar);
@@ -725,8 +718,7 @@ static void bcm_console_write(struct console *co, const char *s,
        wait_for_xmitr(port);
 
        if (locked)
-               uart_port_unlock(port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(port, flags);
 }
 
 /*
index 52c87876a88de6b7e43969029947744a91f0e3cf..5426322b5f0ca3f8580880bd9bb86131e676b573 100644 (file)
@@ -837,7 +837,6 @@ static int linflex_probe(struct platform_device *pdev)
                return ret;
 
        sport->dev = &pdev->dev;
-       sport->type = PORT_LINFLEXUART;
        sport->iotype = UPIO_MEM;
        sport->irq = ret;
        sport->ops = &linflex_pops;
index 1eda48964c0b6539f0e6281d121d7b17344549b7..ddbd42c09637cdc9bcc2438367b53e2b4fb8f551 100644 (file)
@@ -395,7 +395,6 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
                 * which in this case is the break signal.
                 */
                if (linestatus & error_mask)  {
-                       linestatus = 0;
                        readb(&ch->ch_cls_uart->txrx);
                        continue;
                }
index ec20329f06036d066c00056a39588dc502e9977d..3e4ac46de1bc3786173c72754e0240965aec183c 100644 (file)
@@ -136,20 +136,16 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
        int locked = 1;
 
        touch_nmi_watchdog();
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&up->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&up->port, &flags);
        else
-               uart_port_lock(&up->port);
+               uart_port_lock_irqsave(&up->port, &flags);
 
        uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
        wait_for_xmit_empty(&up->port);
 
        if (locked)
-               uart_port_unlock(&up->port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&up->port, flags);
 }
 
 static int __init lpc32xx_hsuart_console_setup(struct console *co,
@@ -233,8 +229,6 @@ static unsigned int __serial_get_clock_div(unsigned long uartclk,
 
                hsu_rate++;
        }
-       if (hsu_rate > 0xFF)
-               hsu_rate = 0xFF;
 
        return goodrate;
 }
@@ -268,7 +262,8 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
                        tty_insert_flip_char(tport, 0, TTY_FRAME);
                }
 
-               tty_insert_flip_char(tport, (tmp & 0xFF), flag);
+               if (!uart_prepare_sysrq_char(port, tmp & 0xff))
+                       tty_insert_flip_char(tport, (tmp & 0xFF), flag);
 
                tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
        }
@@ -333,7 +328,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
                __serial_lpc32xx_tx(port);
        }
 
-       uart_port_unlock(port);
+       uart_unlock_and_check_sysrq(port);
 
        return IRQ_HANDLED;
 }
index 10bf6d75bf9ee7f9ee13a36796a8af5439ac5eb9..14dd9cfaa9f76fc388500a637d171e90739291ea 100644 (file)
@@ -30,6 +30,7 @@
 #define MAX310X_MAJOR                  204
 #define MAX310X_MINOR                  209
 #define MAX310X_UART_NRMAX             16
+#define MAX310X_MAX_PORTS              4 /* Maximum number of UART ports per IC. */
 
 /* MAX310X register definitions */
 #define MAX310X_RHR_REG                        (0x00) /* RX FIFO */
@@ -66,6 +67,7 @@
 #define MAX310X_BRGDIVMSB_REG          (0x1d) /* Baud rate divisor MSB */
 #define MAX310X_CLKSRC_REG             (0x1e) /* Clock source */
 #define MAX310X_REG_1F                 (0x1f)
+#define MAX310X_EXTREG_START           (0x20) /* Only relevant in SPI mode. */
 
 #define MAX310X_REVID_REG              MAX310X_REG_1F /* Revision ID */
 
@@ -73,9 +75,9 @@
 #define MAX310X_GLOBALCMD_REG          MAX310X_REG_1F /* Global Command (WO) */
 
 /* Extended registers */
-#define MAX310X_SPI_REVID_EXTREG       MAX310X_REG_05 /* Revision ID */
-#define MAX310X_I2C_REVID_EXTREG       (0x25) /* Revision ID */
-
+#define MAX310X_REVID_EXTREG           (0x25) /* Revision ID
+                                               * (extended addressing space)
+                                               */
 /* IRQ register bits */
 #define MAX310X_IRQ_LSR_BIT            (1 << 0) /* LSR interrupt */
 #define MAX310X_IRQ_SPCHR_BIT          (1 << 1) /* Special char interrupt */
 #define MAX310X_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
 
 /* Flow control trigger level register masks */
-#define MAX310X_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
-#define MAX310X_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
+#define MAX310X_FLOWLVL_HALT_MASK      GENMASK(3, 0) /* Flow control halt level */
+#define MAX310X_FLOWLVL_RES_MASK       GENMASK(7, 4) /* Flow control resume level */
 #define MAX310X_FLOWLVL_HALT(words)    ((words / 8) & 0x0f)
 #define MAX310X_FLOWLVL_RES(words)     (((words / 8) & 0x0f) << 4)
 
 /* FIFO interrupt trigger level register masks */
-#define MAX310X_FIFOTRIGLVL_TX_MASK    (0x0f) /* TX FIFO trigger level */
-#define MAX310X_FIFOTRIGLVL_RX_MASK    (0xf0) /* RX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_TX_MASK    GENMASK(3, 0) /* TX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_RX_MASK    GENMASK(7, 4) /* RX FIFO trigger level */
 #define MAX310X_FIFOTRIGLVL_TX(words)  ((words / 8) & 0x0f)
 #define MAX310X_FIFOTRIGLVL_RX(words)  (((words / 8) & 0x0f) << 4)
 
 #define MAX310X_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
                                                  * are used in conjunction with
                                                  * XOFF2 for definition of
-                                                 * special character */
+                                                 * special character
+                                                 */
 #define MAX310X_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
 #define MAX310X_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
 #define MAX310X_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
                                                  */
 
 /* PLL configuration register masks */
-#define MAX310X_PLLCFG_PREDIV_MASK     (0x3f) /* PLL predivision value */
-#define MAX310X_PLLCFG_PLLFACTOR_MASK  (0xc0) /* PLL multiplication factor */
+#define MAX310X_PLLCFG_PREDIV_MASK     GENMASK(5, 0) /* PLL predivision value */
+#define MAX310X_PLLCFG_PLLFACTOR_MASK  GENMASK(7, 6) /* PLL multiplication factor */
 
 /* Baud rate generator configuration register bits */
 #define MAX310X_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
 
 /* Misc definitions */
 #define MAX310X_FIFO_SIZE              (128)
-#define MAX310x_REV_MASK               (0xf8)
+#define MAX310x_REV_MASK               GENMASK(7, 3)
 #define MAX310X_WRITE_BIT              0x80
 
 /* Port startup definitions */
 
 struct max310x_if_cfg {
        int (*extended_reg_enable)(struct device *dev, bool enable);
-
-       unsigned int rev_id_reg;
+       u8 rev_id_offset;
 };
 
 struct max310x_devtype {
        struct {
                unsigned short min;
                unsigned short max;
-       } slave_addr;
-       char    name[9];
+       } slave_addr; /* Relevant only in I2C mode. */
        int     nr;
+       char    name[9];
        u8      mode1;
-       int     (*detect)(struct device *);
-       void    (*power)(struct uart_port *, int);
+       u8      rev_id_val;
+       u8      rev_id_reg; /* Relevant only if rev_id_val is defined. */
+       u8      power_reg; /* Register address for power/sleep control. */
+       u8      power_bit; /* Bit for sleep or power-off mode (active high). */
 };
 
 struct max310x_one {
@@ -331,62 +335,52 @@ static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)
        regmap_update_bits(one->regmap, reg, mask, val);
 }
 
-static int max3107_detect(struct device *dev)
+static int max310x_detect(struct device *dev)
 {
        struct max310x_port *s = dev_get_drvdata(dev);
        unsigned int val = 0;
        int ret;
 
-       ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
-       if (ret)
-               return ret;
+       /* Check if variant supports REV ID register: */
+       if (s->devtype->rev_id_val) {
+               u8 rev_id_reg = s->devtype->rev_id_reg;
 
-       if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) {
-               dev_err(dev,
-                       "%s ID 0x%02x does not match\n", s->devtype->name, val);
-               return -ENODEV;
-       }
-
-       return 0;
-}
+               /* Check if REV ID is in extended addressing space: */
+               if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) {
+                       ret = s->if_cfg->extended_reg_enable(dev, true);
+                       if (ret)
+                               return ret;
 
-static int max3108_detect(struct device *dev)
-{
-       struct max310x_port *s = dev_get_drvdata(dev);
-       unsigned int val = 0;
-       int ret;
-
-       /* MAX3108 have not REV ID register, we just check default value
-        * from clocksource register to make sure everything works.
-        */
-       ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
-       if (ret)
-               return ret;
-
-       if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) {
-               dev_err(dev, "%s not present\n", s->devtype->name);
-               return -ENODEV;
-       }
+                       /* Adjust REV ID extended addressing space address: */
+                       if (s->if_cfg->rev_id_offset)
+                               rev_id_reg -= s->if_cfg->rev_id_offset;
+               }
 
-       return 0;
-}
+               regmap_read(s->regmap, rev_id_reg, &val);
 
-static int max3109_detect(struct device *dev)
-{
-       struct max310x_port *s = dev_get_drvdata(dev);
-       unsigned int val = 0;
-       int ret;
-
-       ret = s->if_cfg->extended_reg_enable(dev, true);
-       if (ret)
-               return ret;
+               if (s->devtype->rev_id_reg >= MAX310X_EXTREG_START) {
+                       ret = s->if_cfg->extended_reg_enable(dev, false);
+                       if (ret)
+                               return ret;
+               }
 
-       regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
-       s->if_cfg->extended_reg_enable(dev, false);
-       if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
-               dev_err(dev,
-                       "%s ID 0x%02x does not match\n", s->devtype->name, val);
-               return -ENODEV;
+               if (((val & MAX310x_REV_MASK) != s->devtype->rev_id_val))
+                       return dev_err_probe(dev, -ENODEV,
+                                            "%s ID 0x%02x does not match\n",
+                                            s->devtype->name, val);
+       } else {
+               /*
+                * For variant without REV ID register, just check default value
+                * from clocksource register to make sure everything works.
+                */
+               ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
+               if (ret)
+                       return ret;
+
+               if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT))
+                       return dev_err_probe(dev, -ENODEV,
+                                            "%s not present\n",
+                                            s->devtype->name);
        }
 
        return 0;
@@ -394,39 +388,10 @@ static int max3109_detect(struct device *dev)
 
 static void max310x_power(struct uart_port *port, int on)
 {
-       max310x_port_update(port, MAX310X_MODE1_REG,
-                           MAX310X_MODE1_FORCESLEEP_BIT,
-                           on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT);
-       if (on)
-               msleep(50);
-}
-
-static int max14830_detect(struct device *dev)
-{
-       struct max310x_port *s = dev_get_drvdata(dev);
-       unsigned int val = 0;
-       int ret;
-
-       ret = s->if_cfg->extended_reg_enable(dev, true);
-       if (ret)
-               return ret;
-
-       regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
-       s->if_cfg->extended_reg_enable(dev, false);
-       if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) {
-               dev_err(dev,
-                       "%s ID 0x%02x does not match\n", s->devtype->name, val);
-               return -ENODEV;
-       }
-
-       return 0;
-}
+       struct max310x_port *s = dev_get_drvdata(port->dev);
 
-static void max14830_power(struct uart_port *port, int on)
-{
-       max310x_port_update(port, MAX310X_BRGCFG_REG,
-                           MAX14830_BRGCFG_CLKDIS_BIT,
-                           on ? 0 : MAX14830_BRGCFG_CLKDIS_BIT);
+       max310x_port_update(port, s->devtype->power_reg, s->devtype->power_bit,
+                           on ? 0 : s->devtype->power_bit);
        if (on)
                msleep(50);
 }
@@ -435,8 +400,10 @@ static const struct max310x_devtype max3107_devtype = {
        .name   = "MAX3107",
        .nr     = 1,
        .mode1  = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT,
-       .detect = max3107_detect,
-       .power  = max310x_power,
+       .rev_id_val = MAX3107_REV_ID,
+       .rev_id_reg = MAX310X_REVID_REG,
+       .power_reg = MAX310X_MODE1_REG,
+       .power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
        .slave_addr     = {
                .min = 0x2c,
                .max = 0x2f,
@@ -447,8 +414,10 @@ static const struct max310x_devtype max3108_devtype = {
        .name   = "MAX3108",
        .nr     = 1,
        .mode1  = MAX310X_MODE1_AUTOSLEEP_BIT,
-       .detect = max3108_detect,
-       .power  = max310x_power,
+       .rev_id_val = 0, /* Unsupported. */
+       .rev_id_reg = 0, /* Irrelevant when rev_id_val is not defined. */
+       .power_reg = MAX310X_MODE1_REG,
+       .power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
        .slave_addr     = {
                .min = 0x60,
                .max = 0x6f,
@@ -459,8 +428,10 @@ static const struct max310x_devtype max3109_devtype = {
        .name   = "MAX3109",
        .nr     = 2,
        .mode1  = MAX310X_MODE1_AUTOSLEEP_BIT,
-       .detect = max3109_detect,
-       .power  = max310x_power,
+       .rev_id_val = MAX3109_REV_ID,
+       .rev_id_reg = MAX310X_REVID_EXTREG,
+       .power_reg = MAX310X_MODE1_REG,
+       .power_bit = MAX310X_MODE1_FORCESLEEP_BIT,
        .slave_addr     = {
                .min = 0x60,
                .max = 0x6f,
@@ -471,8 +442,10 @@ static const struct max310x_devtype max14830_devtype = {
        .name   = "MAX14830",
        .nr     = 4,
        .mode1  = MAX310X_MODE1_IRQSEL_BIT,
-       .detect = max14830_detect,
-       .power  = max14830_power,
+       .rev_id_val = MAX14830_REV_ID,
+       .rev_id_reg = MAX310X_REVID_EXTREG,
+       .power_reg = MAX310X_BRGCFG_REG,
+       .power_bit = MAX14830_BRGCFG_CLKDIS_BIT,
        .slave_addr     = {
                .min = 0x60,
                .max = 0x6f,
@@ -490,10 +463,8 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
        case MAX310X_RXFIFOLVL_REG:
                return false;
        default:
-               break;
+               return true;
        }
-
-       return true;
 }
 
 static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
@@ -512,10 +483,8 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
        case MAX310X_REG_1F:
                return true;
        default:
-               break;
+               return false;
        }
-
-       return false;
 }
 
 static bool max310x_reg_precious(struct device *dev, unsigned int reg)
@@ -527,10 +496,8 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
        case MAX310X_STS_IRQSTS_REG:
                return true;
        default:
-               break;
+               return false;
        }
-
-       return false;
 }
 
 static bool max310x_reg_noinc(struct device *dev, unsigned int reg)
@@ -689,7 +656,8 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
        u8 ch, flag;
 
        if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) {
-               /* We are just reading, happily ignoring any error conditions.
+               /*
+                * We are just reading, happily ignoring any error conditions.
                 * Break condition, parity checking, framing errors -- they
                 * are all ignored. That means that we can do a batch-read.
                 *
@@ -698,7 +666,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
                 * that the LSR register applies to the "current" character.
                 * That's also the reason why we cannot do batched reads when
                 * asked to check the individual statuses.
-                * */
+                */
 
                sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
                max310x_batch_read(port, one->rx_buf, rxlen);
@@ -802,8 +770,10 @@ static void max310x_handle_tx(struct uart_port *port)
                to_send = (to_send > txlen) ? txlen : to_send;
 
                if (until_end < to_send) {
-                       /* It's a circ buffer -- wrap around.
-                        * We could do that in one SPI transaction, but meh. */
+                       /*
+                        * It's a circ buffer -- wrap around.
+                        * We could do that in one SPI transaction, but meh.
+                        */
                        max310x_batch_write(port, xmit->buf + xmit->tail, until_end);
                        max310x_batch_write(port, xmit->buf, to_send - until_end);
                } else {
@@ -848,6 +818,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
                if (ists & MAX310X_IRQ_TXEMPTY_BIT)
                        max310x_start_tx(port);
        } while (1);
+
        return res;
 }
 
@@ -892,7 +863,8 @@ static unsigned int max310x_tx_empty(struct uart_port *port)
 
 static unsigned int max310x_get_mctrl(struct uart_port *port)
 {
-       /* DCD and DSR are not wired and CTS/RTS is handled automatically
+       /*
+        * DCD and DSR are not wired and CTS/RTS is handled automatically
         * so just indicate DSR and CAR asserted
         */
        return TIOCM_DSR | TIOCM_CAR;
@@ -984,7 +956,8 @@ static void max310x_set_termios(struct uart_port *port,
        max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]);
        max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
 
-       /* Disable transmitter before enabling AutoCTS or auto transmitter
+       /*
+        * Disable transmitter before enabling AutoCTS or auto transmitter
         * flow control
         */
        if (termios->c_cflag & CRTSCTS || termios->c_iflag & IXOFF) {
@@ -1011,7 +984,8 @@ static void max310x_set_termios(struct uart_port *port,
        }
        max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow);
 
-       /* Enable transmitter after disabling AutoCTS and auto transmitter
+       /*
+        * Enable transmitter after disabling AutoCTS and auto transmitter
         * flow control
         */
        if (!(termios->c_cflag & CRTSCTS) && !(termios->c_iflag & IXOFF)) {
@@ -1072,10 +1046,9 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios
 
 static int max310x_startup(struct uart_port *port)
 {
-       struct max310x_port *s = dev_get_drvdata(port->dev);
        unsigned int val;
 
-       s->devtype->power(port, 1);
+       max310x_power(port, 1);
 
        /* Configure MODE1 register */
        max310x_port_update(port, MAX310X_MODE1_REG,
@@ -1103,8 +1076,11 @@ static int max310x_startup(struct uart_port *port)
                                            MAX310X_MODE2_ECHOSUPR_BIT);
        }
 
-       /* Configure flow control levels */
-       /* Flow control halt level 96, resume level 48 */
+       /*
+        * Configure flow control levels:
+        *   resume: 48
+        *   halt:   96
+        */
        max310x_port_write(port, MAX310X_FLOWLVL_REG,
                           MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96));
 
@@ -1120,12 +1096,10 @@ static int max310x_startup(struct uart_port *port)
 
 static void max310x_shutdown(struct uart_port *port)
 {
-       struct max310x_port *s = dev_get_drvdata(port->dev);
-
        /* Disable all interrupts */
        max310x_port_write(port, MAX310X_IRQEN_REG, 0);
 
-       s->devtype->power(port, 0);
+       max310x_power(port, 0);
 }
 
 static const char *max310x_type(struct uart_port *port)
@@ -1187,7 +1161,7 @@ static int __maybe_unused max310x_suspend(struct device *dev)
 
        for (i = 0; i < s->devtype->nr; i++) {
                uart_suspend_port(&max310x_uart, &s->p[i].port);
-               s->devtype->power(&s->p[i].port, 0);
+               max310x_power(&s->p[i].port, 0);
        }
 
        return 0;
@@ -1199,7 +1173,7 @@ static int __maybe_unused max310x_resume(struct device *dev)
        int i;
 
        for (i = 0; i < s->devtype->nr; i++) {
-               s->devtype->power(&s->p[i].port, 1);
+               max310x_power(&s->p[i].port, 1);
                uart_resume_port(&max310x_uart, &s->p[i].port);
        }
 
@@ -1209,7 +1183,7 @@ static int __maybe_unused max310x_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
 
 #ifdef CONFIG_GPIOLIB
-static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
        unsigned int val;
        struct max310x_port *s = gpiochip_get_data(chip);
@@ -1220,7 +1194,7 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
        return !!((val >> 4) & (1 << (offset % 4)));
 }
 
-static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
 {
        struct max310x_port *s = gpiochip_get_data(chip);
        struct uart_port *port = &s->p[offset / 4].port;
@@ -1229,7 +1203,7 @@ static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                            value ? 1 << (offset % 4) : 0);
 }
 
-static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
 {
        struct max310x_port *s = gpiochip_get_data(chip);
        struct uart_port *port = &s->p[offset / 4].port;
@@ -1240,7 +1214,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 }
 
 static int max310x_gpio_direction_output(struct gpio_chip *chip,
-                                        unsigned offset, int value)
+                                        unsigned int offset, int value)
 {
        struct max310x_port *s = gpiochip_get_data(chip);
        struct uart_port *port = &s->p[offset / 4].port;
@@ -1296,10 +1270,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
 
        /* Alloc port structure */
        s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
-       if (!s) {
-               dev_err(dev, "Error allocating port structure\n");
-               return -ENOMEM;
-       }
+       if (!s)
+               return dev_err_probe(dev, -ENOMEM,
+                                    "Error allocating port structure\n");
 
        /* Always ask for fixed clock rate from a property. */
        device_property_read_u32(dev, "clock-frequency", &uartclk);
@@ -1320,8 +1293,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
        if (freq == 0)
                freq = uartclk;
        if (freq == 0) {
-               dev_err(dev, "Cannot get clock rate\n");
-               ret = -EINVAL;
+               ret = dev_err_probe(dev, -EINVAL, "Cannot get clock rate\n");
                goto out_clk;
        }
 
@@ -1345,7 +1317,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
        dev_set_drvdata(dev, s);
 
        /* Check device to ensure we are talking to what we expect */
-       ret = devtype->detect(dev);
+       ret = max310x_detect(dev);
        if (ret)
                goto out_clk;
 
@@ -1427,14 +1399,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
 
                /* Register port */
                ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
-               if (ret) {
-                       s->p[i].port.dev = NULL;
+               if (ret)
                        goto out_uart;
-               }
+
                set_bit(line, max310x_lines);
 
                /* Go to suspend mode */
-               devtype->power(&s->p[i].port, 0);
+               max310x_power(&s->p[i].port, 0);
        }
 
 #ifdef CONFIG_GPIOLIB
@@ -1461,14 +1432,12 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
        if (!ret)
                return 0;
 
-       dev_err(dev, "Unable to reguest IRQ %i\n", irq);
+       dev_err(dev, "Unable to request IRQ %i\n", irq);
 
 out_uart:
        for (i = 0; i < devtype->nr; i++) {
-               if (s->p[i].port.dev) {
+               if (test_and_clear_bit(s->p[i].port.line, max310x_lines))
                        uart_remove_one_port(&max310x_uart, &s->p[i].port);
-                       clear_bit(s->p[i].port.line, max310x_lines);
-               }
        }
 
 out_clk:
@@ -1486,9 +1455,11 @@ static void max310x_remove(struct device *dev)
                cancel_work_sync(&s->p[i].tx_work);
                cancel_work_sync(&s->p[i].md_work);
                cancel_work_sync(&s->p[i].rs_work);
-               uart_remove_one_port(&max310x_uart, &s->p[i].port);
-               clear_bit(s->p[i].port.line, max310x_lines);
-               s->devtype->power(&s->p[i].port, 0);
+
+               if (test_and_clear_bit(s->p[i].port.line, max310x_lines))
+                       uart_remove_one_port(&max310x_uart, &s->p[i].port);
+
+               max310x_power(&s->p[i].port, 0);
        }
 
        clk_disable_unprepare(s->clk);
@@ -1518,6 +1489,19 @@ static struct regmap_config regcfg = {
        .max_raw_write = MAX310X_FIFO_SIZE,
 };
 
+static const char *max310x_regmap_name(u8 port_id)
+{
+       switch (port_id) {
+       case 0: return "port0";
+       case 1: return "port1";
+       case 2: return "port2";
+       case 3: return "port3";
+       default:
+               WARN_ON(true);
+               return NULL;
+       }
+}
+
 #ifdef CONFIG_SPI_MASTER
 static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
 {
@@ -1529,13 +1513,13 @@ static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
 
 static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = {
        .extended_reg_enable = max310x_spi_extended_reg_enable,
-       .rev_id_reg = MAX310X_SPI_REVID_EXTREG,
+       .rev_id_offset = MAX310X_EXTREG_START,
 };
 
 static int max310x_spi_probe(struct spi_device *spi)
 {
        const struct max310x_devtype *devtype;
-       struct regmap *regmaps[4];
+       struct regmap *regmaps[MAX310X_MAX_PORTS];
        unsigned int i;
        int ret;
 
@@ -1547,12 +1531,14 @@ static int max310x_spi_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       devtype = device_get_match_data(&spi->dev);
+       devtype = spi_get_device_match_data(spi);
        if (!devtype)
-               devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
+               return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
 
        for (i = 0; i < devtype->nr; i++) {
                u8 port_mask = i * 0x20;
+
+               regcfg.name = max310x_regmap_name(i);
                regcfg.read_flag_mask = port_mask;
                regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT;
                regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
@@ -1600,7 +1586,7 @@ static struct regmap_config regcfg_i2c = {
        .writeable_reg = max310x_reg_writeable,
        .volatile_reg = max310x_reg_volatile,
        .precious_reg = max310x_reg_precious,
-       .max_register = MAX310X_I2C_REVID_EXTREG,
+       .max_register = MAX310X_REVID_EXTREG,
        .writeable_noinc_reg = max310x_reg_noinc,
        .readable_noinc_reg = max310x_reg_noinc,
        .max_raw_read = MAX310X_FIFO_SIZE,
@@ -1609,7 +1595,7 @@ static struct regmap_config regcfg_i2c = {
 
 static const struct max310x_if_cfg max310x_i2c_if_cfg = {
        .extended_reg_enable = max310x_i2c_extended_reg_enable,
-       .rev_id_reg = MAX310X_I2C_REVID_EXTREG,
+       .rev_id_offset = 0, /* No offset in I2C mode. */
 };
 
 static unsigned short max310x_i2c_slave_addr(unsigned short addr,
@@ -1619,10 +1605,10 @@ static unsigned short max310x_i2c_slave_addr(unsigned short addr,
         * For MAX14830 and MAX3109, the slave address depends on what the
         * A0 and A1 pins are tied to.
         * See Table I2C Address Map of the datasheet.
-        * Based on that table, the following formulas were determined.
-        * UART1 - UART0 = 0x10
-        * UART2 - UART1 = 0x20 + 0x10
-        * UART3 - UART2 = 0x10
+        * Based on that table, the following formulas were determined:
+        *   UART1 - UART0 = 0x10
+        *   UART2 - UART1 = 0x20 + 0x10
+        *   UART3 - UART2 = 0x10
         */
 
        addr -= nr * 0x10;
@@ -1635,20 +1621,24 @@ static unsigned short max310x_i2c_slave_addr(unsigned short addr,
 
 static int max310x_i2c_probe(struct i2c_client *client)
 {
-       const struct max310x_devtype *devtype =
-                       device_get_match_data(&client->dev);
+       const struct max310x_devtype *devtype;
        struct i2c_client *port_client;
-       struct regmap *regmaps[4];
+       struct regmap *regmaps[MAX310X_MAX_PORTS];
        unsigned int i;
        u8 port_addr;
 
+       devtype = i2c_get_match_data(client);
+       if (!devtype)
+               return dev_err_probe(&client->dev, -ENODEV, "Failed to match device\n");
+
        if (client->addr < devtype->slave_addr.min ||
-               client->addr > devtype->slave_addr.max)
+           client->addr > devtype->slave_addr.max)
                return dev_err_probe(&client->dev, -EINVAL,
                                     "Slave addr 0x%x outside of range [0x%x, 0x%x]\n",
                                     client->addr, devtype->slave_addr.min,
                                     devtype->slave_addr.max);
 
+       regcfg_i2c.name = max310x_regmap_name(0);
        regmaps[0] = devm_regmap_init_i2c(client, &regcfg_i2c);
 
        for (i = 1; i < devtype->nr; i++) {
@@ -1657,6 +1647,7 @@ static int max310x_i2c_probe(struct i2c_client *client)
                                                        client->adapter,
                                                        port_addr);
 
+               regcfg_i2c.name = max310x_regmap_name(i);
                regmaps[i] = devm_regmap_init_i2c(port_client, &regcfg_i2c);
        }
 
@@ -1669,6 +1660,15 @@ static void max310x_i2c_remove(struct i2c_client *client)
        max310x_remove(&client->dev);
 }
 
+static const struct i2c_device_id max310x_i2c_id_table[] = {
+       { "max3107",    (kernel_ulong_t)&max3107_devtype, },
+       { "max3108",    (kernel_ulong_t)&max3108_devtype, },
+       { "max3109",    (kernel_ulong_t)&max3109_devtype, },
+       { "max14830",   (kernel_ulong_t)&max14830_devtype, },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max310x_i2c_id_table);
+
 static struct i2c_driver max310x_i2c_driver = {
        .driver = {
                .name           = MAX310X_NAME,
@@ -1677,6 +1677,7 @@ static struct i2c_driver max310x_i2c_driver = {
        },
        .probe          = max310x_i2c_probe,
        .remove         = max310x_i2c_remove,
+       .id_table       = max310x_i2c_id_table,
 };
 #endif
 
index 8690a45239e096a14bfa4d4cc6a5cea16c0a9cdd..b0604d6da0257934581368033d4b3b88cb92a4b4 100644 (file)
@@ -470,33 +470,6 @@ static struct mcf_uart mcf_ports[4];
 #if defined(CONFIG_SERIAL_MCF_CONSOLE)
 /****************************************************************************/
 
-int __init early_mcf_setup(struct mcf_platform_uart *platp)
-{
-       struct uart_port *port;
-       int i;
-
-       for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
-               port = &mcf_ports[i].port;
-
-               port->line = i;
-               port->type = PORT_MCF;
-               port->mapbase = platp[i].mapbase;
-               port->membase = (platp[i].membase) ? platp[i].membase :
-                       (unsigned char __iomem *) port->mapbase;
-               port->iotype = SERIAL_IO_MEM;
-               port->irq = platp[i].irq;
-               port->uartclk = MCF_BUSCLK;
-               port->flags = UPF_BOOT_AUTOCONF;
-               port->rs485_config = mcf_config_rs485;
-               port->rs485_supported = mcf_rs485_supported;
-               port->ops = &mcf_uart_ops;
-       }
-
-       return 0;
-}
-
-/****************************************************************************/
-
 static void mcf_console_putc(struct console *co, const char c)
 {
        struct uart_port *port = &(mcf_ports + co->index)->port;
index 8395688f5ee926f92a2345ab1735c2b9058d7a06..6feac459c0cf4f7a2b6fff658023205d9fa81d78 100644 (file)
@@ -220,7 +220,7 @@ static void meson_receive_chars(struct uart_port *port)
                                continue;
                }
 
-               if (uart_handle_sysrq_char(port, ch))
+               if (uart_prepare_sysrq_char(port, ch))
                        continue;
 
                if ((status & port->ignore_status_mask) == 0)
@@ -248,7 +248,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
                        meson_uart_start_tx(port);
        }
 
-       uart_port_unlock(port);
+       uart_unlock_and_check_sysrq(port);
 
        return IRQ_HANDLED;
 }
@@ -556,18 +556,13 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
                                    u_int count)
 {
        unsigned long flags;
-       int locked;
+       int locked = 1;
        u32 val, tmp;
 
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = uart_port_trylock(port);
-       } else {
-               uart_port_lock(port);
-               locked = 1;
-       }
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(port, &flags);
+       else
+               uart_port_lock_irqsave(port, &flags);
 
        val = readl(port->membase + AML_UART_CONTROL);
        tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
@@ -577,8 +572,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
        writel(val, port->membase + AML_UART_CONTROL);
 
        if (locked)
-               uart_port_unlock(port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(port, flags);
 }
 
 static void meson_serial_console_write(struct console *co, const char *s,
index e24204ad35deff4b2911f4e247071aae90c615d9..d27c4c8c84e130c3336cd3b5f3e5dd9a9536afed 100644 (file)
@@ -588,16 +588,14 @@ static void msm_complete_rx_dma(void *args)
                if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
                        flag = TTY_NORMAL;
 
-               uart_port_unlock_irqrestore(port, flags);
-               sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
-               uart_port_lock_irqsave(port, &flags);
+               sysrq = uart_prepare_sysrq_char(port, dma->virt[i]);
                if (!sysrq)
                        tty_insert_flip_char(tport, dma->virt[i], flag);
        }
 
        msm_start_rx_dma(msm_port);
 done:
-       uart_port_unlock_irqrestore(port, flags);
+       uart_unlock_and_check_sysrq_irqrestore(port, flags);
 
        if (count)
                tty_flip_buffer_push(tport);
@@ -763,9 +761,7 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
                        if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
                                flag = TTY_NORMAL;
 
-                       uart_port_unlock(port);
-                       sysrq = uart_handle_sysrq_char(port, buf[i]);
-                       uart_port_lock(port);
+                       sysrq = uart_prepare_sysrq_char(port, buf[i]);
                        if (!sysrq)
                                tty_insert_flip_char(tport, buf[i], flag);
                }
@@ -825,9 +821,7 @@ static void msm_handle_rx(struct uart_port *port)
                else if (sr & MSM_UART_SR_PAR_FRAME_ERR)
                        flag = TTY_FRAME;
 
-               uart_port_unlock(port);
-               sysrq = uart_handle_sysrq_char(port, c);
-               uart_port_lock(port);
+               sysrq = uart_prepare_sysrq_char(port, c);
                if (!sysrq)
                        tty_insert_flip_char(tport, c, flag);
        }
@@ -948,11 +942,10 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
        struct uart_port *port = dev_id;
        struct msm_port *msm_port = to_msm_port(port);
        struct msm_dma *dma = &msm_port->rx_dma;
-       unsigned long flags;
        unsigned int misr;
        u32 val;
 
-       uart_port_lock_irqsave(port, &flags);
+       uart_port_lock(port);
        misr = msm_read(port, MSM_UART_MISR);
        msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */
 
@@ -984,7 +977,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
                msm_handle_delta_cts(port);
 
        msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */
-       uart_port_unlock_irqrestore(port, flags);
+       uart_unlock_and_check_sysrq(port);
 
        return IRQ_HANDLED;
 }
@@ -1621,14 +1614,10 @@ static void __msm_console_write(struct uart_port *port, const char *s,
                        num_newlines++;
        count += num_newlines;
 
-       local_irq_save(flags);
-
-       if (port->sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(port, &flags);
        else
-               uart_port_lock(port);
+               uart_port_lock_irqsave(port, &flags);
 
        if (is_uartdm)
                msm_reset_dm_count(port, count);
@@ -1667,9 +1656,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
        }
 
        if (locked)
-               uart_port_unlock(port);
-
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(port, flags);
 }
 
 static void msm_console_write(struct console *co, const char *s,
index f5a0b401af63b15c5c8a8d49ec2742a6ce58e263..9be1c871cf116dc43f150a130d8d2777b3f02454 100644 (file)
@@ -508,7 +508,7 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr)
 
        up->port.icount.rx++;
 
-       if (uart_handle_sysrq_char(&up->port, ch))
+       if (uart_prepare_sysrq_char(&up->port, ch))
                return;
 
        uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, TTY_NORMAL);
@@ -563,7 +563,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
                }
        } while (max_count--);
 
-       uart_port_unlock(&up->port);
+       uart_unlock_and_check_sysrq(&up->port);
 
        tty_flip_buffer_push(&up->port.state->port);
 
@@ -1212,13 +1212,10 @@ serial_omap_console_write(struct console *co, const char *s,
        unsigned int ier;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&up->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&up->port, &flags);
        else
-               uart_port_lock(&up->port);
+               uart_port_lock_irqsave(&up->port, &flags);
 
        /*
         * First save the IER then disable the interrupts
@@ -1245,8 +1242,7 @@ serial_omap_console_write(struct console *co, const char *s,
                check_modem_status(up);
 
        if (locked)
-               uart_port_unlock(&up->port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&up->port, flags);
 }
 
 static int __init
index d9fe85397741dd7813571133ad85d928566f0783..8b60ac0ad7cd341f0415fab558f3d5d2892d68e5 100644 (file)
@@ -199,6 +199,7 @@ static void owl_uart_receive_chars(struct uart_port *port)
        stat = owl_uart_read(port, OWL_UART_STAT);
        while (!(stat & OWL_UART_STAT_RFEM)) {
                char flag = TTY_NORMAL;
+               bool sysrq;
 
                if (stat & OWL_UART_STAT_RXER)
                        port->icount.overrun++;
@@ -217,7 +218,9 @@ static void owl_uart_receive_chars(struct uart_port *port)
                val = owl_uart_read(port, OWL_UART_RXDAT);
                val &= 0xff;
 
-               if ((stat & port->ignore_status_mask) == 0)
+               sysrq = uart_prepare_sysrq_char(port, val);
+
+               if (!sysrq && (stat & port->ignore_status_mask) == 0)
                        tty_insert_flip_char(&port->state->port, val, flag);
 
                stat = owl_uart_read(port, OWL_UART_STAT);
@@ -229,10 +232,9 @@ static void owl_uart_receive_chars(struct uart_port *port)
 static irqreturn_t owl_uart_irq(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
-       unsigned long flags;
        u32 stat;
 
-       uart_port_lock_irqsave(port, &flags);
+       uart_port_lock(port);
 
        stat = owl_uart_read(port, OWL_UART_STAT);
 
@@ -246,7 +248,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id)
        stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP;
        owl_uart_write(port, stat, OWL_UART_STAT);
 
-       uart_port_unlock_irqrestore(port, flags);
+       uart_unlock_and_check_sysrq(port);
 
        return IRQ_HANDLED;
 }
@@ -508,18 +510,12 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
 {
        u32 old_ctl, val;
        unsigned long flags;
-       int locked;
+       int locked = 1;
 
-       local_irq_save(flags);
-
-       if (port->sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(port);
-       else {
-               uart_port_lock(port);
-               locked = 1;
-       }
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(port, &flags);
+       else
+               uart_port_lock_irqsave(port, &flags);
 
        old_ctl = owl_uart_read(port, OWL_UART_CTL);
        val = old_ctl | OWL_UART_CTL_TRFS_TX;
@@ -541,9 +537,7 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
        owl_uart_write(port, old_ctl, OWL_UART_CTL);
 
        if (locked)
-               uart_port_unlock(port);
-
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(port, flags);
 }
 
 static void owl_uart_console_write(struct console *co, const char *s,
index 436cc6d52a11bfa53eeb4db1b22ed5cea57eecdf..89257cddf540503d3d41a3d2de74f35e81486192 100644 (file)
@@ -237,9 +237,6 @@ struct eg20t_port {
 
 #define IRQ_NAME_SIZE 17
        char                            irq_name[IRQ_NAME_SIZE];
-
-       /* protect the eg20t_port private structure and io access to membase */
-       spinlock_t lock;
 };
 
 /**
@@ -567,7 +564,7 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
                        if (uart_handle_break(port))
                                continue;
                }
-               if (uart_handle_sysrq_char(port, rbr))
+               if (uart_prepare_sysrq_char(port, rbr))
                        continue;
 
                buf[i++] = rbr;
@@ -599,16 +596,14 @@ static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
        iowrite8(lcr, priv->membase + UART_LCR);
 }
 
-static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
-                  int size)
+static void push_rx(struct eg20t_port *priv, const unsigned char *buf,
+                   int size)
 {
        struct uart_port *port = &priv->port;
        struct tty_port *tport = &port->state->port;
 
        tty_insert_flip_string(tport, buf, size);
        tty_flip_buffer_push(tport);
-
-       return 0;
 }
 
 static int dma_push_rx(struct eg20t_port *priv, int size)
@@ -761,7 +756,7 @@ static int handle_rx_to(struct eg20t_port *priv)
 {
        struct pch_uart_buffer *buf;
        int rx_size;
-       int ret;
+
        if (!priv->start_rx) {
                pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
                                                     PCH_UART_HAL_RX_ERR_INT);
@@ -770,19 +765,12 @@ static int handle_rx_to(struct eg20t_port *priv)
        buf = &priv->rxbuf;
        do {
                rx_size = pch_uart_hal_read(priv, buf->buf, buf->size);
-               ret = push_rx(priv, buf->buf, rx_size);
-               if (ret)
-                       return 0;
+               push_rx(priv, buf->buf, rx_size);
        } while (rx_size == buf->size);
 
        return PCH_UART_HANDLED_RX_INT;
 }
 
-static int handle_rx(struct eg20t_port *priv)
-{
-       return handle_rx_to(priv);
-}
-
 static int dma_handle_rx(struct eg20t_port *priv)
 {
        struct uart_port *port = &priv->port;
@@ -1019,11 +1007,10 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
        u8 lsr;
        int ret = 0;
        unsigned char iid;
-       unsigned long flags;
        int next = 1;
        u8 msr;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       uart_port_lock(&priv->port);
        handled = 0;
        while (next) {
                iid = pch_uart_hal_get_iid(priv);
@@ -1051,7 +1038,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
                                                PCH_UART_HAL_RX_INT |
                                                PCH_UART_HAL_RX_ERR_INT);
                        } else {
-                               ret = handle_rx(priv);
+                               ret = handle_rx_to(priv);
                        }
                        break;
                case PCH_UART_IID_RDR_TO:       /* Received Data Ready
@@ -1083,7 +1070,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
                handled |= (unsigned int)ret;
        }
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       uart_unlock_and_check_sysrq(&priv->port);
        return IRQ_RETVAL(handled);
 }
 
@@ -1194,9 +1181,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl)
        unsigned long flags;
 
        priv = container_of(port, struct eg20t_port, port);
-       spin_lock_irqsave(&priv->lock, flags);
+       uart_port_lock_irqsave(&priv->port, &flags);
        pch_uart_hal_set_break(priv, ctl);
-       spin_unlock_irqrestore(&priv->lock, flags);
+       uart_port_unlock_irqrestore(&priv->port, flags);
 }
 
 /* Grab any interrupt resources and initialise any low level driver state. */
@@ -1346,8 +1333,7 @@ static void pch_uart_set_termios(struct uart_port *port,
 
        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
 
-       spin_lock_irqsave(&priv->lock, flags);
-       uart_port_lock(port);
+       uart_port_lock_irqsave(port, &flags);
 
        uart_update_timeout(port, termios->c_cflag, baud);
        rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
@@ -1360,8 +1346,7 @@ static void pch_uart_set_termios(struct uart_port *port,
                tty_termios_encode_baud_rate(termios, baud, baud);
 
 out:
-       uart_port_unlock(port);
-       spin_unlock_irqrestore(&priv->lock, flags);
+       uart_port_unlock_irqrestore(port, flags);
 }
 
 static const char *pch_uart_type(struct uart_port *port)
@@ -1565,27 +1550,17 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct eg20t_port *priv;
        unsigned long flags;
-       int priv_locked = 1;
-       int port_locked = 1;
+       int locked = 1;
        u8 ier;
 
        priv = pch_uart_ports[co->index];
 
        touch_nmi_watchdog();
 
-       local_irq_save(flags);
-       if (priv->port.sysrq) {
-               /* call to uart_handle_sysrq_char already took the priv lock */
-               priv_locked = 0;
-               /* serial8250_handle_port() already took the port lock */
-               port_locked = 0;
-       } else if (oops_in_progress) {
-               priv_locked = spin_trylock(&priv->lock);
-               port_locked = uart_port_trylock(&priv->port);
-       } else {
-               spin_lock(&priv->lock);
-               uart_port_lock(&priv->port);
-       }
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&priv->port, &flags);
+       else
+               uart_port_lock_irqsave(&priv->port, &flags);
 
        /*
         *      First save the IER then disable the interrupts
@@ -1603,11 +1578,8 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
        wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY);
        iowrite8(ier, priv->membase + UART_IER);
 
-       if (port_locked)
-               uart_port_unlock(&priv->port);
-       if (priv_locked)
-               spin_unlock(&priv->lock);
-       local_irq_restore(flags);
+       if (locked)
+               uart_port_unlock_irqrestore(&priv->port, flags);
 }
 
 static int __init pch_console_setup(struct console *co, char *options)
@@ -1704,8 +1676,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        pci_enable_msi(pdev);
        pci_set_master(pdev);
 
-       spin_lock_init(&priv->lock);
-
        iobase = pci_resource_start(pdev, 0);
        mapbase = pci_resource_start(pdev, 1);
        priv->mapbase = mapbase;
@@ -1735,8 +1705,6 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
                 KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d",
                 priv->port.line);
 
-       spin_lock_init(&priv->port.lock);
-
        pci_set_drvdata(pdev, priv);
        priv->trigger_level = 1;
        priv->fcr = 0;
index 732d821db4f805d539e732367b9ef9df1afb7cc9..05d97e89511e698bee73698edd0a98a58893bb7b 100644 (file)
@@ -1714,18 +1714,13 @@ static int __init pmz_attach(struct platform_device *pdev)
        return uart_add_one_port(&pmz_uart_reg, &uap->port);
 }
 
-static int __exit pmz_detach(struct platform_device *pdev)
+static void __exit pmz_detach(struct platform_device *pdev)
 {
        struct uart_pmac_port *uap = platform_get_drvdata(pdev);
 
-       if (!uap)
-               return -ENODEV;
-
        uart_remove_one_port(&pmz_uart_reg, &uap->port);
 
        uap->port.dev = NULL;
-
-       return 0;
 }
 
 #endif /* !CONFIG_PPC_PMAC */
@@ -1794,7 +1789,7 @@ static struct macio_driver pmz_driver = {
 #else
 
 static struct platform_driver pmz_driver = {
-       .remove         = __exit_p(pmz_detach),
+       .remove_new     = __exit_p(pmz_detach),
        .driver         = {
                .name           = "scc",
        },
index 46e70e155aab210d577ed3df21321df5d0bee823..e395ff29c1a2cfbb3742b2ebeb1545ac850b840d 100644 (file)
@@ -151,7 +151,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
                                flag = TTY_FRAME;
                }
 
-               if (uart_handle_sysrq_char(&up->port, ch))
+               if (uart_prepare_sysrq_char(&up->port, ch))
                        goto ignore_char;
 
                uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
@@ -232,7 +232,7 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
        check_modem_status(up);
        if (lsr & UART_LSR_THRE)
                transmit_chars(up);
-       uart_port_unlock(&up->port);
+       uart_unlock_and_check_sysrq(&up->port);
        return IRQ_HANDLED;
 }
 
@@ -604,13 +604,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
        int locked = 1;
 
        clk_enable(up->clk);
-       local_irq_save(flags);
-       if (up->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&up->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&up->port, &flags);
        else
-               uart_port_lock(&up->port);
+               uart_port_lock_irqsave(&up->port, &flags);
 
        /*
         *      First save the IER then disable the interrupts
@@ -628,10 +625,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
        serial_out(up, UART_IER, ier);
 
        if (locked)
-               uart_port_unlock(&up->port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&up->port, flags);
        clk_disable(up->clk);
-
 }
 
 #ifdef CONFIG_CONSOLE_POLL
index 99e08737f293c6868e56d2de80f31bf0e3345ca3..f9f7ac1a10df3d668d41506075359c7601b12185 100644 (file)
@@ -488,18 +488,16 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
 
        geni_status = readl(uport->membase + SE_GENI_STATUS);
 
-       /* Cancel the current write to log the fault */
        if (!locked) {
-               geni_se_cancel_m_cmd(&port->se);
-               if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
-                                               M_CMD_CANCEL_EN, true)) {
-                       geni_se_abort_m_cmd(&port->se);
-                       qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
-                                                       M_CMD_ABORT_EN, true);
-                       writel(M_CMD_ABORT_EN, uport->membase +
-                                                       SE_GENI_M_IRQ_CLEAR);
-               }
-               writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+               /*
+                * We can only get here if an oops is in progress then we were
+                * unable to get the lock. This means we can't safely access
+                * our state variables like tx_remaining. About the best we
+                * can do is wait for the FIFO to be empty before we start our
+                * transfer, so we'll do that.
+                */
+               qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
+                                         M_TX_FIFO_NOT_EMPTY_EN, false);
        } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
                /*
                 * It seems we can't interrupt existing transfers if all data
@@ -516,11 +514,12 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
 
        __qcom_geni_serial_console_write(uport, s, count);
 
-       if (port->tx_remaining)
-               qcom_geni_serial_setup_tx(uport, port->tx_remaining);
 
-       if (locked)
+       if (locked) {
+               if (port->tx_remaining)
+                       qcom_geni_serial_setup_tx(uport, port->tx_remaining);
                uart_port_unlock_irqrestore(uport, flags);
+       }
 }
 
 static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
index 13deb355cf1bc36509a3c8676bb3aa8eaa11f437..82def9b8632a56102470d3f45f170a4750f3541a 100644 (file)
@@ -394,7 +394,8 @@ static void rda_uart_receive_chars(struct uart_port *port)
                val &= 0xff;
 
                port->icount.rx++;
-               tty_insert_flip_char(&port->state->port, val, flag);
+               if (!uart_prepare_sysrq_char(port, val))
+                       tty_insert_flip_char(&port->state->port, val, flag);
 
                status = rda_uart_read(port, RDA_UART_STATUS);
        }
@@ -405,10 +406,9 @@ static void rda_uart_receive_chars(struct uart_port *port)
 static irqreturn_t rda_interrupt(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
-       unsigned long flags;
        u32 val, irq_mask;
 
-       uart_port_lock_irqsave(port, &flags);
+       uart_port_lock(port);
 
        /* Clear IRQ cause */
        val = rda_uart_read(port, RDA_UART_IRQ_CAUSE);
@@ -425,7 +425,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id)
                rda_uart_send_chars(port);
        }
 
-       uart_port_unlock_irqrestore(port, flags);
+       uart_unlock_and_check_sysrq(port);
 
        return IRQ_HANDLED;
 }
@@ -590,18 +590,12 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
 {
        u32 old_irq_mask;
        unsigned long flags;
-       int locked;
-
-       local_irq_save(flags);
+       int locked = 1;
 
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = uart_port_trylock(port);
-       } else {
-               uart_port_lock(port);
-               locked = 1;
-       }
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(port, &flags);
+       else
+               uart_port_lock_irqsave(port, &flags);
 
        old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
        rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
@@ -615,9 +609,7 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
        rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK);
 
        if (locked)
-               uart_port_unlock(port);
-
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(port, flags);
 }
 
 static void rda_uart_console_write(struct console *co, const char *s,
index 71d17d804fdabb85779a28d866100bbb0325b29e..a2d07e05c50264063983be7e0fe9e0fea80678ca 100644 (file)
  * BJD, 04-Nov-2004
  */
 
-#include <linux/dmaengine.h>
+#include <linux/console.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
 #include <linux/math.h>
 #include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_s3c.h>
+#include <linux/slab.h>
 #include <linux/sysrq.h>
-#include <linux/console.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/serial_s3c.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/of.h>
+#include <linux/types.h>
+
 #include <asm/irq.h>
 
 /* UART name and device definitions */
@@ -73,21 +75,21 @@ struct s3c24xx_uart_info {
        enum s3c24xx_port_type  type;
        unsigned int            port_type;
        unsigned int            fifosize;
-       unsigned long           rx_fifomask;
-       unsigned long           rx_fifoshift;
-       unsigned long           rx_fifofull;
-       unsigned long           tx_fifomask;
-       unsigned long           tx_fifoshift;
-       unsigned long           tx_fifofull;
-       unsigned int            def_clk_sel;
-       unsigned long           num_clks;
-       unsigned long           clksel_mask;
-       unsigned long           clksel_shift;
-       unsigned long           ucon_mask;
+       u32                     rx_fifomask;
+       u32                     rx_fifoshift;
+       u32                     rx_fifofull;
+       u32                     tx_fifomask;
+       u32                     tx_fifoshift;
+       u32                     tx_fifofull;
+       u32                     clksel_mask;
+       u32                     clksel_shift;
+       u32                     ucon_mask;
+       u8                      def_clk_sel;
+       u8                      num_clks;
+       u8                      iotype;
 
        /* uart port features */
-
-       unsigned int            has_divslot:1;
+       bool                    has_divslot;
 };
 
 struct s3c24xx_serial_drv_data {
@@ -196,7 +198,7 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
 /* Byte-order aware bit setting/clearing functions. */
 
 static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
-                                  unsigned int reg)
+                                  u32 reg)
 {
        unsigned long flags;
        u32 val;
@@ -209,7 +211,7 @@ static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
 }
 
 static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx,
-                                    unsigned int reg)
+                                    u32 reg)
 {
        unsigned long flags;
        u32 val;
@@ -233,7 +235,7 @@ static inline const char *s3c24xx_serial_portname(const struct uart_port *port)
        return to_platform_device(port->dev)->name;
 }
 
-static int s3c24xx_serial_txempty_nofifo(const struct uart_port *port)
+static bool s3c24xx_serial_txempty_nofifo(const struct uart_port *port)
 {
        return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
 }
@@ -242,8 +244,8 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        unsigned long flags;
-       unsigned int ucon, ufcon;
        int count = 10000;
+       u32 ucon, ufcon;
 
        uart_port_lock_irqsave(port, &flags);
 
@@ -266,7 +268,7 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        unsigned long flags;
-       unsigned int ucon;
+       u32 ucon;
 
        uart_port_lock_irqsave(port, &flags);
 
@@ -587,8 +589,8 @@ static inline const struct s3c2410_uartcfg
        return ourport->cfg;
 }
 
-static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport,
-                                    unsigned long ufstat)
+static unsigned int
+s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport, u32 ufstat)
 {
        const struct s3c24xx_uart_info *info = ourport->info;
 
@@ -660,7 +662,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
 static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
 {
        struct uart_port *port = &ourport->port;
-       unsigned int ucon;
+       u32 ucon;
 
        /* set Rx mode to DMA mode */
        ucon = rd_regl(port, S3C2410_UCON);
@@ -683,7 +685,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
 static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
 {
        struct uart_port *port = &ourport->port;
-       unsigned int ucon;
+       u32 ucon;
 
        /* set Rx mode to DMA mode */
        ucon = rd_regl(port, S3C2410_UCON);
@@ -708,13 +710,14 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
 
 static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
 {
-       unsigned int utrstat, received;
        struct s3c24xx_uart_port *ourport = dev_id;
        struct uart_port *port = &ourport->port;
        struct s3c24xx_uart_dma *dma = ourport->dma;
        struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
        struct tty_port *t = &port->state->port;
        struct dma_tx_state state;
+       unsigned int received;
+       u32 utrstat;
 
        utrstat = rd_regl(port, S3C2410_UTRSTAT);
        rd_regl(port, S3C2410_UFSTAT);
@@ -756,9 +759,9 @@ finish:
 static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
 {
        struct uart_port *port = &ourport->port;
-       unsigned int ufcon, ufstat, uerstat;
+       unsigned int max_count = port->fifosize;
        unsigned int fifocnt = 0;
-       int max_count = port->fifosize;
+       u32 ufcon, ufstat, uerstat;
        u8 ch, flag;
 
        while (max_count-- > 0) {
@@ -778,7 +781,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
                ch = rd_reg(port, S3C2410_URXH);
 
                if (port->flags & UPF_CONS_FLOW) {
-                       int txe = s3c24xx_serial_txempty_nofifo(port);
+                       bool txe = s3c24xx_serial_txempty_nofifo(port);
 
                        if (ourport->rx_enabled) {
                                if (!txe) {
@@ -942,7 +945,7 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
 {
        const struct s3c24xx_uart_port *ourport = id;
        const struct uart_port *port = &ourport->port;
-       unsigned int pend = rd_regl(port, S3C64XX_UINTP);
+       u32 pend = rd_regl(port, S3C64XX_UINTP);
        irqreturn_t ret = IRQ_HANDLED;
 
        if (pend & S3C64XX_UINTM_RXD_MSK) {
@@ -961,7 +964,7 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id)
 {
        const struct s3c24xx_uart_port *ourport = id;
        const struct uart_port *port = &ourport->port;
-       unsigned int pend = rd_regl(port, S3C2410_UTRSTAT);
+       u32 pend = rd_regl(port, S3C2410_UTRSTAT);
        irqreturn_t ret = IRQ_NONE;
 
        if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) {
@@ -980,24 +983,23 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id)
 static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
 {
        const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
-       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
+       u32 ufstat = rd_regl(port, S3C2410_UFSTAT);
+       u32 ufcon = rd_regl(port, S3C2410_UFCON);
 
        if (ufcon & S3C2410_UFCON_FIFOMODE) {
-               if ((ufstat & info->tx_fifomask) != 0 ||
+               if ((ufstat & info->tx_fifomask) ||
                    (ufstat & info->tx_fifofull))
                        return 0;
-
-               return 1;
+               return TIOCSER_TEMT;
        }
 
-       return s3c24xx_serial_txempty_nofifo(port);
+       return s3c24xx_serial_txempty_nofifo(port) ? TIOCSER_TEMT : 0;
 }
 
 /* no modem control lines */
 static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
 {
-       unsigned int umstat = rd_reg(port, S3C2410_UMSTAT);
+       u32 umstat = rd_reg(port, S3C2410_UMSTAT);
 
        if (umstat & S3C2410_UMSTAT_CTS)
                return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
@@ -1007,8 +1009,8 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
 
 static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       unsigned int umcon = rd_regl(port, S3C2410_UMCON);
-       unsigned int ucon = rd_regl(port, S3C2410_UCON);
+       u32 umcon = rd_regl(port, S3C2410_UMCON);
+       u32 ucon = rd_regl(port, S3C2410_UCON);
 
        if (mctrl & TIOCM_RTS)
                umcon |= S3C2410_UMCOM_RTS_LOW;
@@ -1028,7 +1030,7 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
 static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
 {
        unsigned long flags;
-       unsigned int ucon;
+       u32 ucon;
 
        uart_port_lock_irqsave(port, &flags);
 
@@ -1186,7 +1188,7 @@ static void apple_s5l_serial_shutdown(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
-       unsigned int ucon;
+       u32 ucon;
 
        ucon = rd_regl(port, S3C2410_UCON);
        ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
@@ -1212,7 +1214,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        unsigned long flags;
-       unsigned int ufcon;
+       u32 ufcon;
        int ret;
 
        wr_regl(port, S3C64XX_UINTM, 0xf);
@@ -1257,7 +1259,7 @@ static int apple_s5l_serial_startup(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        unsigned long flags;
-       unsigned int ufcon;
+       u32 ufcon;
        int ret;
 
        wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS);
@@ -1292,8 +1294,6 @@ static int apple_s5l_serial_startup(struct uart_port *port)
        return ret;
 }
 
-/* power power management control */
-
 static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
                              unsigned int old)
 {
@@ -1339,10 +1339,10 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
 
 #define MAX_CLK_NAME_LENGTH 15
 
-static inline int s3c24xx_serial_getsource(struct uart_port *port)
+static inline u8 s3c24xx_serial_getsource(struct uart_port *port)
 {
        const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned int ucon;
+       u32 ucon;
 
        if (info->num_clks == 1)
                return 0;
@@ -1352,11 +1352,10 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port)
        return ucon >> info->clksel_shift;
 }
 
-static void s3c24xx_serial_setsource(struct uart_port *port,
-                       unsigned int clk_sel)
+static void s3c24xx_serial_setsource(struct uart_port *port, u8 clk_sel)
 {
        const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned int ucon;
+       u32 ucon;
 
        if (info->num_clks == 1)
                return;
@@ -1372,14 +1371,15 @@ static void s3c24xx_serial_setsource(struct uart_port *port,
 
 static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
                        unsigned int req_baud, struct clk **best_clk,
-                       unsigned int *clk_num)
+                       u8 *clk_num)
 {
        const struct s3c24xx_uart_info *info = ourport->info;
        struct clk *clk;
        unsigned long rate;
-       unsigned int cnt, baud, quot, best_quot = 0;
+       unsigned int baud, quot, best_quot = 0;
        char clkname[MAX_CLK_NAME_LENGTH];
        int calc_deviation, deviation = (1 << 30) - 1;
+       u8 cnt;
 
        for (cnt = 0; cnt < info->num_clks; cnt++) {
                /* Keep selected clock if provided */
@@ -1472,10 +1472,10 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        struct clk *clk = ERR_PTR(-EINVAL);
        unsigned long flags;
-       unsigned int baud, quot, clk_sel = 0;
-       unsigned int ulcon;
-       unsigned int umcon;
+       unsigned int baud, quot;
        unsigned int udivslot = 0;
+       u32 ulcon, umcon;
+       u8 clk_sel = 0;
 
        /*
         * We don't support modem control lines.
@@ -1737,12 +1737,12 @@ static struct uart_driver s3c24xx_uart_drv = {
 
 static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR];
 
-static void s3c24xx_serial_init_port_default(int index) {
+static void s3c24xx_serial_init_port_default(int index)
+{
        struct uart_port *port = &s3c24xx_serial_ports[index].port;
 
        spin_lock_init(&port->lock);
 
-       port->iotype = UPIO_MEM;
        port->uartclk = 0;
        port->fifosize = 16;
        port->flags = UPF_BOOT_AUTOCONF;
@@ -1758,7 +1758,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
                                     const struct s3c2410_uartcfg *cfg)
 {
        const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+       u32 ucon = rd_regl(port, S3C2410_UCON);
 
        ucon &= (info->clksel_mask | info->ucon_mask);
        wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
@@ -1776,10 +1776,9 @@ static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport)
        struct device *dev = ourport->port.dev;
        const struct s3c24xx_uart_info *info = ourport->info;
        char clk_name[MAX_CLK_NAME_LENGTH];
-       unsigned int clk_sel;
        struct clk *clk;
-       int clk_num;
        int ret;
+       u8 clk_sel, clk_num;
 
        clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel;
        for (clk_num = 0; clk_num < info->num_clks; clk_num++) {
@@ -1904,7 +1903,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
                wr_regl(port, S3C64XX_UINTSP, 0xf);
                break;
        case TYPE_APPLE_S5L: {
-               unsigned int ucon;
+               u32 ucon;
 
                ucon = rd_regl(port, S3C2410_UCON);
                ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
@@ -1952,7 +1951,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct s3c24xx_uart_port *ourport;
        int index = probe_index;
-       int ret, prop = 0;
+       int ret, prop = 0, fifosize_prop = 1;
 
        if (np) {
                ret = of_alias_get_id(np, "serial");
@@ -1989,9 +1988,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
                break;
        }
 
+       ourport->port.iotype = ourport->info->iotype;
+
        if (np) {
-               of_property_read_u32(np,
-                       "samsung,uart-fifosize", &ourport->port.fifosize);
+               fifosize_prop = of_property_read_u32(np, "samsung,uart-fifosize",
+                               &ourport->port.fifosize);
 
                if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
                        switch (prop) {
@@ -2009,10 +2010,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
                }
        }
 
-       if (ourport->drv_data->fifosize[index])
-               ourport->port.fifosize = ourport->drv_data->fifosize[index];
-       else if (ourport->info->fifosize)
-               ourport->port.fifosize = ourport->info->fifosize;
+       if (fifosize_prop) {
+               if (ourport->drv_data->fifosize[index])
+                       ourport->port.fifosize = ourport->drv_data->fifosize[index];
+               else if (ourport->info->fifosize)
+                       ourport->port.fifosize = ourport->info->fifosize;
+       }
+
        ourport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_SAMSUNG_CONSOLE);
 
        /*
@@ -2058,9 +2062,8 @@ static void s3c24xx_serial_remove(struct platform_device *dev)
 {
        struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 
-       if (port) {
+       if (port)
                uart_remove_one_port(&s3c24xx_uart_drv, port);
-       }
 
        uart_unregister_driver(&s3c24xx_uart_drv);
 }
@@ -2106,7 +2109,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
                /* restore IRQ mask */
                switch (ourport->info->type) {
                case TYPE_S3C6400: {
-                       unsigned int uintm = 0xf;
+                       u32 uintm = 0xf;
 
                        if (ourport->tx_enabled)
                                uintm &= ~S3C64XX_UINTM_TXD_MSK;
@@ -2122,7 +2125,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
                        break;
                }
                case TYPE_APPLE_S5L: {
-                       unsigned int ucon;
+                       u32 ucon;
                        int ret;
 
                        ret = clk_prepare_enable(ourport->clk);
@@ -2183,27 +2186,27 @@ static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
 
 static struct uart_port *cons_uart;
 
-static int
-s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
+static bool
+s3c24xx_serial_console_txrdy(struct uart_port *port, u32 ufcon)
 {
        const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
-       unsigned long ufstat, utrstat;
+       u32 ufstat, utrstat;
 
        if (ufcon & S3C2410_UFCON_FIFOMODE) {
                /* fifo mode - check amount of data in fifo registers... */
 
                ufstat = rd_regl(port, S3C2410_UFSTAT);
-               return (ufstat & info->tx_fifofull) ? 0 : 1;
+               return !(ufstat & info->tx_fifofull);
        }
 
        /* in non-fifo mode, we go and use the tx buffer empty */
 
        utrstat = rd_regl(port, S3C2410_UTRSTAT);
-       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
+       return utrstat & S3C2410_UTRSTAT_TXE;
 }
 
 static bool
-s3c24xx_port_configured(unsigned int ucon)
+s3c24xx_port_configured(u32 ucon)
 {
        /* consider the serial port configured if the tx/rx mode set */
        return (ucon & 0xf) != 0;
@@ -2218,7 +2221,7 @@ s3c24xx_port_configured(unsigned int ucon)
 static int s3c24xx_serial_get_poll_char(struct uart_port *port)
 {
        const struct s3c24xx_uart_port *ourport = to_ourport(port);
-       unsigned int ufstat;
+       u32 ufstat;
 
        ufstat = rd_regl(port, S3C2410_UFSTAT);
        if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
@@ -2230,8 +2233,8 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port)
 static void s3c24xx_serial_put_poll_char(struct uart_port *port,
                unsigned char c)
 {
-       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
-       unsigned int ucon = rd_regl(port, S3C2410_UCON);
+       u32 ufcon = rd_regl(port, S3C2410_UFCON);
+       u32 ucon = rd_regl(port, S3C2410_UCON);
 
        /* not possible to xmit on unconfigured port */
        if (!s3c24xx_port_configured(ucon))
@@ -2247,7 +2250,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
 static void
 s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch)
 {
-       unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
+       u32 ufcon = rd_regl(port, S3C2410_UFCON);
 
        while (!s3c24xx_serial_console_txrdy(port, ufcon))
                cpu_relax();
@@ -2258,7 +2261,7 @@ static void
 s3c24xx_serial_console_write(struct console *co, const char *s,
                             unsigned int count)
 {
-       unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
+       u32 ucon = rd_regl(cons_uart, S3C2410_UCON);
        unsigned long flags;
        bool locked = true;
 
@@ -2285,12 +2288,10 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
                           int *parity, int *bits)
 {
        struct clk *clk;
-       unsigned int ulcon;
-       unsigned int ucon;
-       unsigned int ubrdiv;
        unsigned long rate;
-       unsigned int clk_sel;
+       u32 ulcon, ucon, ubrdiv;
        char clk_name[MAX_CLK_NAME_LENGTH];
+       u8 clk_sel;
 
        ulcon  = rd_regl(port, S3C2410_ULCON);
        ucon   = rd_regl(port, S3C2410_UCON);
@@ -2399,8 +2400,9 @@ static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
                .name           = "Samsung S3C6400 UART",
                .type           = TYPE_S3C6400,
                .port_type      = PORT_S3C6400,
+               .iotype         = UPIO_MEM,
                .fifosize       = 64,
-               .has_divslot    = 1,
+               .has_divslot    = true,
                .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
                .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
                .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
@@ -2428,7 +2430,8 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
                .name           = "Samsung S5PV210 UART",
                .type           = TYPE_S3C6400,
                .port_type      = PORT_S3C6400,
-               .has_divslot    = 1,
+               .iotype         = UPIO_MEM,
+               .has_divslot    = true,
                .rx_fifomask    = S5PV210_UFSTAT_RXMASK,
                .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,
                .rx_fifofull    = S5PV210_UFSTAT_RXFULL,
@@ -2452,12 +2455,13 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
 #endif
 
 #if defined(CONFIG_ARCH_EXYNOS)
-#define EXYNOS_COMMON_SERIAL_DRV_DATA()                                \
+#define EXYNOS_COMMON_SERIAL_DRV_DATA                          \
        .info = {                                               \
                .name           = "Samsung Exynos UART",        \
                .type           = TYPE_S3C6400,                 \
                .port_type      = PORT_S3C6400,                 \
-               .has_divslot    = 1,                            \
+               .iotype         = UPIO_MEM,                     \
+               .has_divslot    = true,                         \
                .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
                .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
                .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
@@ -2476,39 +2480,57 @@ static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
        }                                                       \
 
 static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
-       EXYNOS_COMMON_SERIAL_DRV_DATA(),
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
        .fifosize = { 256, 64, 16, 16 },
 };
 
 static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
-       EXYNOS_COMMON_SERIAL_DRV_DATA(),
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
        .fifosize = { 64, 256, 16, 256 },
 };
 
 static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
-       EXYNOS_COMMON_SERIAL_DRV_DATA(),
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
        .fifosize = { 256, 64, 64, 64 },
 };
 
-/*
- * Common drv_data struct for platforms that specify samsung,uart-fifosize in
- * device tree.
- */
-static const struct s3c24xx_serial_drv_data exynos_fifoszdt_serial_drv_data = {
-       EXYNOS_COMMON_SERIAL_DRV_DATA(),
+static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = {
+       .info = {
+               .name           = "Google GS101 UART",
+               .type           = TYPE_S3C6400,
+               .port_type      = PORT_S3C6400,
+               .iotype         = UPIO_MEM32,
+               .has_divslot    = true,
+               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,
+               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,
+               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,
+               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,
+               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,
+               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,
+               .def_clk_sel    = S3C2410_UCON_CLKSEL0,
+               .num_clks       = 1,
+               .clksel_mask    = 0,
+               .clksel_shift   = 0,
+       },
+       .def_cfg = {
+               .ucon           = S5PV210_UCON_DEFAULT,
+               .ufcon          = S5PV210_UFCON_DEFAULT,
+               .has_fracval    = 1,
+       },
+       /* samsung,uart-fifosize must be specified in the device tree. */
        .fifosize = { 0 },
 };
 
 #define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data)
 #define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data)
 #define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data)
-#define EXYNOS_FIFOSZDT_DRV_DATA (&exynos_fifoszdt_serial_drv_data)
+#define GS101_SERIAL_DRV_DATA (&gs101_serial_drv_data)
 
 #else
 #define EXYNOS4210_SERIAL_DRV_DATA NULL
 #define EXYNOS5433_SERIAL_DRV_DATA NULL
 #define EXYNOS850_SERIAL_DRV_DATA NULL
-#define EXYNOS_FIFOSZDT_DRV_DATA NULL
+#define GS101_SERIAL_DRV_DATA NULL
 #endif
 
 #ifdef CONFIG_ARCH_APPLE
@@ -2517,6 +2539,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
                .name           = "Apple S5L UART",
                .type           = TYPE_APPLE_S5L,
                .port_type      = PORT_8250,
+               .iotype         = UPIO_MEM,
                .fifosize       = 16,
                .rx_fifomask    = S3C2410_UFSTAT_RXMASK,
                .rx_fifoshift   = S3C2410_UFSTAT_RXSHIFT,
@@ -2546,8 +2569,9 @@ static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = {
                .name           = "Axis ARTPEC-8 UART",
                .type           = TYPE_S3C6400,
                .port_type      = PORT_S3C6400,
+               .iotype         = UPIO_MEM,
                .fifosize       = 64,
-               .has_divslot    = 1,
+               .has_divslot    = true,
                .rx_fifomask    = S5PV210_UFSTAT_RXMASK,
                .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,
                .rx_fifofull    = S5PV210_UFSTAT_RXFULL,
@@ -2594,7 +2618,7 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
                .driver_data    = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA,
        }, {
                .name           = "gs101-uart",
-               .driver_data    = (kernel_ulong_t)EXYNOS_FIFOSZDT_DRV_DATA,
+               .driver_data    = (kernel_ulong_t)GS101_SERIAL_DRV_DATA,
        },
        { },
 };
@@ -2617,7 +2641,7 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
        { .compatible = "axis,artpec8-uart",
                .data = ARTPEC8_SERIAL_DRV_DATA },
        { .compatible = "google,gs101-uart",
-               .data = EXYNOS_FIFOSZDT_DRV_DATA },
+               .data = GS101_SERIAL_DRV_DATA },
        {},
 };
 MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
@@ -2716,7 +2740,8 @@ static int samsung_early_read(struct console *con, char *s, unsigned int n)
 {
        struct earlycon_device *dev = con->data;
        const struct samsung_early_console_data *data = dev->port.private_data;
-       int ch, ufstat, num_read = 0;
+       int num_read = 0;
+       u32 ch, ufstat;
 
        while (num_read < n) {
                ufstat = rd_regl(&dev->port, S3C2410_UFSTAT);
@@ -2785,6 +2810,17 @@ OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
 OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart",
                        s5pv210_early_console_setup);
 
+static int __init gs101_early_console_setup(struct earlycon_device *device,
+                                           const char *opt)
+{
+       /* gs101 always expects MMIO32 register accesses. */
+       device->port.iotype = UPIO_MEM32;
+
+       return s5pv210_early_console_setup(device, opt);
+}
+
+OF_EARLYCON_DECLARE(gs101, "google,gs101-uart", gs101_early_console_setup);
+
 /* Apple S5L */
 static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
                                                const char *opt)
index 3dfcf20c4eb68c99b71ab06e7c1c1c8925f4261a..4df2a4b10445adde43e83d4b8bd8543a132a1872 100644 (file)
@@ -41,7 +41,7 @@ static int serial_base_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
-static struct bus_type serial_base_bus_type = {
+static const struct bus_type serial_base_bus_type = {
        .name = "serial-base",
        .match = serial_base_match,
 };
index d6a58a9e072a1dad7938fbb53627f4d5e5374adc..ff85ebd3a007dba0105e38d732efc0f6a6f8ab5b 100644 (file)
@@ -2608,7 +2608,12 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
                        port->type = PORT_UNKNOWN;
                        flags |= UART_CONFIG_TYPE;
                }
+               /* Synchronize with possible boot console. */
+               if (uart_console(port))
+                       console_lock();
                port->ops->config_port(port, flags);
+               if (uart_console(port))
+                       console_unlock();
        }
 
        if (port->type != PORT_UNKNOWN) {
@@ -2616,6 +2621,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 
                uart_report_port(drv, port);
 
+               /* Synchronize with possible boot console. */
+               if (uart_console(port))
+                       console_lock();
+
                /* Power up port for set_mctrl() */
                uart_change_pm(state, UART_PM_STATE_ON);
 
@@ -2632,6 +2641,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
 
                uart_rs485_config(port);
 
+               if (uart_console(port))
+                       console_unlock();
+
                /*
                 * If this driver supports console, and it hasn't been
                 * successfully registered yet, try to re-register it.
index 72b6f4f326e2b04953875062f8ebc6e56f324e45..22b9eeb23e68adb2cfd949ff20c18816bb78b1cb 100644 (file)
@@ -8,7 +8,10 @@
 
 #include <linux/device.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/serial_core.h>
 #include <linux/spinlock.h>
 
@@ -105,6 +108,148 @@ void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
 }
 EXPORT_SYMBOL(uart_remove_one_port);
 
+/**
+ * __uart_read_properties - read firmware properties of the given UART port
+ * @port: corresponding port
+ * @use_defaults: apply defaults (when %true) or validate the values (when %false)
+ *
+ * The following device properties are supported:
+ *   - clock-frequency (optional)
+ *   - fifo-size (optional)
+ *   - no-loopback-test (optional)
+ *   - reg-shift (defaults may apply)
+ *   - reg-offset (value may be validated)
+ *   - reg-io-width (defaults may apply or value may be validated)
+ *   - interrupts (OF only)
+ *   - serial [alias ID] (OF only)
+ *
+ * If the port->dev is of struct platform_device type the interrupt line
+ * will be retrieved via platform_get_irq() call against that device.
+ * Otherwise it will be assigned by fwnode_irq_get() call. In both cases
+ * the index 0 of the resource is used.
+ *
+ * The caller is responsible to initialize the following fields of the @port
+ *   ->dev (must be valid)
+ *   ->flags
+ *   ->mapbase
+ *   ->mapsize
+ *   ->regshift (if @use_defaults is false)
+ * before calling this function. Alternatively the above mentioned fields
+ * may be zeroed, in such case the only ones, that have associated properties
+ * found, will be set to the respective values.
+ *
+ * If no error happened, the ->irq, ->mapbase, ->mapsize will be altered.
+ * The ->iotype is always altered.
+ *
+ * When @use_defaults is true and the respective property is not found
+ * the following values will be applied:
+ *   ->regshift = 0
+ * In this case IRQ must be provided, otherwise an error will be returned.
+ *
+ * When @use_defaults is false and the respective property is found
+ * the following values will be validated:
+ *   - reg-io-width (->iotype)
+ *   - reg-offset (->mapsize against ->mapbase)
+ *
+ * Returns: 0 on success or negative errno on failure
+ */
+static int __uart_read_properties(struct uart_port *port, bool use_defaults)
+{
+       struct device *dev = port->dev;
+       u32 value;
+       int ret;
+
+       /* Read optional UART functional clock frequency */
+       device_property_read_u32(dev, "clock-frequency", &port->uartclk);
+
+       /* Read the registers alignment (default: 8-bit) */
+       ret = device_property_read_u32(dev, "reg-shift", &value);
+       if (ret)
+               port->regshift = use_defaults ? 0 : port->regshift;
+       else
+               port->regshift = value;
+
+       /* Read the registers I/O access type (default: MMIO 8-bit) */
+       ret = device_property_read_u32(dev, "reg-io-width", &value);
+       if (ret) {
+               port->iotype = UPIO_MEM;
+       } else {
+               switch (value) {
+               case 1:
+                       port->iotype = UPIO_MEM;
+                       break;
+               case 2:
+                       port->iotype = UPIO_MEM16;
+                       break;
+               case 4:
+                       port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
+                       break;
+               default:
+                       if (!use_defaults) {
+                               dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
+                               return -EINVAL;
+                       }
+                       port->iotype = UPIO_UNKNOWN;
+                       break;
+               }
+       }
+
+       /* Read the address mapping base offset (default: no offset) */
+       ret = device_property_read_u32(dev, "reg-offset", &value);
+       if (ret)
+               value = 0;
+
+       /* Check for shifted address mapping overflow */
+       if (!use_defaults && port->mapsize < value) {
+               dev_err(dev, "reg-offset %u exceeds region size %pa\n", value, &port->mapsize);
+               return -EINVAL;
+       }
+
+       port->mapbase += value;
+       port->mapsize -= value;
+
+       /* Read optional FIFO size */
+       device_property_read_u32(dev, "fifo-size", &port->fifosize);
+
+       if (device_property_read_bool(dev, "no-loopback-test"))
+               port->flags |= UPF_SKIP_TEST;
+
+       /* Get index of serial line, if found in DT aliases */
+       ret = of_alias_get_id(dev_of_node(dev), "serial");
+       if (ret >= 0)
+               port->line = ret;
+
+       if (dev_is_platform(dev))
+               ret = platform_get_irq(to_platform_device(dev), 0);
+       else
+               ret = fwnode_irq_get(dev_fwnode(dev), 0);
+       if (ret == -EPROBE_DEFER)
+               return ret;
+       if (ret > 0)
+               port->irq = ret;
+       else if (use_defaults)
+               /* By default IRQ support is mandatory */
+               return ret;
+       else
+               port->irq = 0;
+
+       port->flags |= UPF_SHARE_IRQ;
+
+       return 0;
+}
+
+int uart_read_port_properties(struct uart_port *port)
+{
+       return __uart_read_properties(port, true);
+}
+EXPORT_SYMBOL_GPL(uart_read_port_properties);
+
+int uart_read_and_validate_port_properties(struct uart_port *port)
+{
+       return __uart_read_properties(port, false);
+}
+EXPORT_SYMBOL_GPL(uart_read_and_validate_port_properties);
+
 static struct device_driver serial_port_driver = {
        .name = "port",
        .suppress_bind_attrs = true,
index e1897894a4ef58cb69f8bb9edef43ed17786cb34..abba397229581851d05cd09ab393865f4509204d 100644 (file)
 #include <linux/serial.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-
 #include <linux/io.h>
 
+#include <asm/txx9/generic.h>
+
 #define PASS_LIMIT     256
 
 #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
index a85e7b9a2e492391ae7a5c6560bc4b2d31ed96fb..e512eaa57ed562eb758d8da2ca34010ca753c022 100644 (file)
@@ -576,13 +576,13 @@ static void sci_start_tx(struct uart_port *port)
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 new, scr = serial_port_in(port, SCSCR);
+               u16 new, scr = sci_serial_in(port, SCSCR);
                if (s->chan_tx)
                        new = scr | SCSCR_TDRQE;
                else
                        new = scr & ~SCSCR_TDRQE;
                if (new != scr)
-                       serial_port_out(port, SCSCR, new);
+                       sci_serial_out(port, SCSCR, new);
        }
 
        if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
@@ -599,7 +599,7 @@ static void sci_start_tx(struct uart_port *port)
        if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE ||
            port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
                /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-               ctrl = serial_port_in(port, SCSCR);
+               ctrl = sci_serial_in(port, SCSCR);
 
                /*
                 * For SCI, TE (transmit enable) must be set after setting TIE
@@ -609,7 +609,7 @@ static void sci_start_tx(struct uart_port *port)
                if (port->type == PORT_SCI)
                        ctrl |= SCSCR_TE;
 
-               serial_port_out(port, SCSCR, ctrl | SCSCR_TIE);
+               sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE);
        }
 }
 
@@ -618,14 +618,14 @@ static void sci_stop_tx(struct uart_port *port)
        unsigned short ctrl;
 
        /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
-       ctrl = serial_port_in(port, SCSCR);
+       ctrl = sci_serial_in(port, SCSCR);
 
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
                ctrl &= ~SCSCR_TDRQE;
 
        ctrl &= ~SCSCR_TIE;
 
-       serial_port_out(port, SCSCR, ctrl);
+       sci_serial_out(port, SCSCR, ctrl);
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
        if (to_sci_port(port)->chan_tx &&
@@ -640,41 +640,40 @@ static void sci_start_rx(struct uart_port *port)
 {
        unsigned short ctrl;
 
-       ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
+       ctrl = sci_serial_in(port, SCSCR) | port_rx_irq_mask(port);
 
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
                ctrl &= ~SCSCR_RDRQE;
 
-       serial_port_out(port, SCSCR, ctrl);
+       sci_serial_out(port, SCSCR, ctrl);
 }
 
 static void sci_stop_rx(struct uart_port *port)
 {
        unsigned short ctrl;
 
-       ctrl = serial_port_in(port, SCSCR);
+       ctrl = sci_serial_in(port, SCSCR);
 
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
                ctrl &= ~SCSCR_RDRQE;
 
        ctrl &= ~port_rx_irq_mask(port);
 
-       serial_port_out(port, SCSCR, ctrl);
+       sci_serial_out(port, SCSCR, ctrl);
 }
 
 static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
 {
        if (port->type == PORT_SCI) {
                /* Just store the mask */
-               serial_port_out(port, SCxSR, mask);
+               sci_serial_out(port, SCxSR, mask);
        } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) {
                /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
                /* Only clear the status bits we want to clear */
-               serial_port_out(port, SCxSR,
-                               serial_port_in(port, SCxSR) & mask);
+               sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask);
        } else {
                /* Store the mask, clear parity/framing errors */
-               serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
+               sci_serial_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
        }
 }
 
@@ -688,7 +687,7 @@ static int sci_poll_get_char(struct uart_port *port)
        int c;
 
        do {
-               status = serial_port_in(port, SCxSR);
+               status = sci_serial_in(port, SCxSR);
                if (status & SCxSR_ERRORS(port)) {
                        sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
                        continue;
@@ -699,10 +698,10 @@ static int sci_poll_get_char(struct uart_port *port)
        if (!(status & SCxSR_RDxF(port)))
                return NO_POLL_CHAR;
 
-       c = serial_port_in(port, SCxRDR);
+       c = sci_serial_in(port, SCxRDR);
 
        /* Dummy read */
-       serial_port_in(port, SCxSR);
+       sci_serial_in(port, SCxSR);
        sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 
        return c;
@@ -714,10 +713,10 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
        unsigned short status;
 
        do {
-               status = serial_port_in(port, SCxSR);
+               status = sci_serial_in(port, SCxSR);
        } while (!(status & SCxSR_TDxE(port)));
 
-       serial_port_out(port, SCxTDR, c);
+       sci_serial_out(port, SCxTDR, c);
        sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
@@ -736,8 +735,8 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
        }
 
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 data = serial_port_in(port, SCPDR);
-               u16 ctrl = serial_port_in(port, SCPCR);
+               u16 data = sci_serial_in(port, SCPDR);
+               u16 ctrl = sci_serial_in(port, SCPCR);
 
                /* Enable RXD and TXD pin functions */
                ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
@@ -756,10 +755,10 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
                        /* Enable CTS# pin function */
                        ctrl &= ~SCPCR_CTSC;
                }
-               serial_port_out(port, SCPDR, data);
-               serial_port_out(port, SCPCR, ctrl);
+               sci_serial_out(port, SCPDR, data);
+               sci_serial_out(port, SCPCR, ctrl);
        } else if (sci_getreg(port, SCSPTR)->size) {
-               u16 status = serial_port_in(port, SCSPTR);
+               u16 status = sci_serial_in(port, SCSPTR);
 
                /* RTS# is always output; and active low, unless autorts */
                status |= SCSPTR_RTSIO;
@@ -769,7 +768,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
                        status &= ~SCSPTR_RTSDT;
                /* CTS# and SCK are inputs */
                status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
-               serial_port_out(port, SCSPTR, status);
+               sci_serial_out(port, SCSPTR, status);
        }
 }
 
@@ -781,13 +780,13 @@ static int sci_txfill(struct uart_port *port)
 
        reg = sci_getreg(port, SCTFDR);
        if (reg->size)
-               return serial_port_in(port, SCTFDR) & fifo_mask;
+               return sci_serial_in(port, SCTFDR) & fifo_mask;
 
        reg = sci_getreg(port, SCFDR);
        if (reg->size)
-               return serial_port_in(port, SCFDR) >> 8;
+               return sci_serial_in(port, SCFDR) >> 8;
 
-       return !(serial_port_in(port, SCxSR) & SCI_TDRE);
+       return !(sci_serial_in(port, SCxSR) & SCI_TDRE);
 }
 
 static int sci_txroom(struct uart_port *port)
@@ -803,13 +802,13 @@ static int sci_rxfill(struct uart_port *port)
 
        reg = sci_getreg(port, SCRFDR);
        if (reg->size)
-               return serial_port_in(port, SCRFDR) & fifo_mask;
+               return sci_serial_in(port, SCRFDR) & fifo_mask;
 
        reg = sci_getreg(port, SCFDR);
        if (reg->size)
-               return serial_port_in(port, SCFDR) & fifo_mask;
+               return sci_serial_in(port, SCFDR) & fifo_mask;
 
-       return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+       return (sci_serial_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
 }
 
 /* ********************************************************************** *
@@ -824,14 +823,14 @@ static void sci_transmit_chars(struct uart_port *port)
        unsigned short ctrl;
        int count;
 
-       status = serial_port_in(port, SCxSR);
+       status = sci_serial_in(port, SCxSR);
        if (!(status & SCxSR_TDxE(port))) {
-               ctrl = serial_port_in(port, SCSCR);
+               ctrl = sci_serial_in(port, SCSCR);
                if (uart_circ_empty(xmit))
                        ctrl &= ~SCSCR_TIE;
                else
                        ctrl |= SCSCR_TIE;
-               serial_port_out(port, SCSCR, ctrl);
+               sci_serial_out(port, SCSCR, ctrl);
                return;
        }
 
@@ -847,15 +846,15 @@ static void sci_transmit_chars(struct uart_port *port)
                        c = xmit->buf[xmit->tail];
                        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) {
-                       ctrl = serial_port_in(port, SCSCR);
+                       ctrl = sci_serial_in(port, SCSCR);
                        ctrl &= ~SCSCR_TE;
-                       serial_port_out(port, SCSCR, ctrl);
+                       sci_serial_out(port, SCSCR, ctrl);
                        return;
                } else {
                        break;
                }
 
-               serial_port_out(port, SCxTDR, c);
+               sci_serial_out(port, SCxTDR, c);
 
                port->icount.tx++;
        } while (--count > 0);
@@ -866,10 +865,10 @@ static void sci_transmit_chars(struct uart_port *port)
                uart_write_wakeup(port);
        if (uart_circ_empty(xmit)) {
                if (port->type == PORT_SCI) {
-                       ctrl = serial_port_in(port, SCSCR);
+                       ctrl = sci_serial_in(port, SCSCR);
                        ctrl &= ~SCSCR_TIE;
                        ctrl |= SCSCR_TEIE;
-                       serial_port_out(port, SCSCR, ctrl);
+                       sci_serial_out(port, SCSCR, ctrl);
                }
 
                sci_stop_tx(port);
@@ -883,7 +882,7 @@ static void sci_receive_chars(struct uart_port *port)
        unsigned short status;
        unsigned char flag;
 
-       status = serial_port_in(port, SCxSR);
+       status = sci_serial_in(port, SCxSR);
        if (!(status & SCxSR_RDxF(port)))
                return;
 
@@ -896,7 +895,7 @@ static void sci_receive_chars(struct uart_port *port)
                        break;
 
                if (port->type == PORT_SCI) {
-                       char c = serial_port_in(port, SCxRDR);
+                       char c = sci_serial_in(port, SCxRDR);
                        if (uart_handle_sysrq_char(port, c))
                                count = 0;
                        else
@@ -907,11 +906,11 @@ static void sci_receive_chars(struct uart_port *port)
 
                                if (port->type == PORT_SCIF ||
                                    port->type == PORT_HSCIF) {
-                                       status = serial_port_in(port, SCxSR);
-                                       c = serial_port_in(port, SCxRDR);
+                                       status = sci_serial_in(port, SCxSR);
+                                       c = sci_serial_in(port, SCxRDR);
                                } else {
-                                       c = serial_port_in(port, SCxRDR);
-                                       status = serial_port_in(port, SCxSR);
+                                       c = sci_serial_in(port, SCxRDR);
+                                       status = sci_serial_in(port, SCxSR);
                                }
                                if (uart_handle_sysrq_char(port, c)) {
                                        count--; i--;
@@ -932,7 +931,7 @@ static void sci_receive_chars(struct uart_port *port)
                        }
                }
 
-               serial_port_in(port, SCxSR); /* dummy read */
+               sci_serial_in(port, SCxSR); /* dummy read */
                sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 
                copied += count;
@@ -944,8 +943,8 @@ static void sci_receive_chars(struct uart_port *port)
                tty_flip_buffer_push(tport);
        } else {
                /* TTY buffers full; read from RX reg to prevent lockup */
-               serial_port_in(port, SCxRDR);
-               serial_port_in(port, SCxSR); /* dummy read */
+               sci_serial_in(port, SCxRDR);
+               sci_serial_in(port, SCxSR); /* dummy read */
                sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
        }
 }
@@ -953,7 +952,7 @@ static void sci_receive_chars(struct uart_port *port)
 static int sci_handle_errors(struct uart_port *port)
 {
        int copied = 0;
-       unsigned short status = serial_port_in(port, SCxSR);
+       unsigned short status = sci_serial_in(port, SCxSR);
        struct tty_port *tport = &port->state->port;
        struct sci_port *s = to_sci_port(port);
 
@@ -1000,10 +999,10 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
        if (!reg->size)
                return 0;
 
-       status = serial_port_in(port, s->params->overrun_reg);
+       status = sci_serial_in(port, s->params->overrun_reg);
        if (status & s->params->overrun_mask) {
                status &= ~s->params->overrun_mask;
-               serial_port_out(port, s->params->overrun_reg, status);
+               sci_serial_out(port, s->params->overrun_reg, status);
 
                port->icount.overrun++;
 
@@ -1018,7 +1017,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
 static int sci_handle_breaks(struct uart_port *port)
 {
        int copied = 0;
-       unsigned short status = serial_port_in(port, SCxSR);
+       unsigned short status = sci_serial_in(port, SCxSR);
        struct tty_port *tport = &port->state->port;
 
        if (uart_handle_break(port))
@@ -1051,7 +1050,7 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
 
        /* HSCIF can be set to an arbitrary level. */
        if (sci_getreg(port, HSRTRGR)->size) {
-               serial_port_out(port, HSRTRGR, rx_trig);
+               sci_serial_out(port, HSRTRGR, rx_trig);
                return rx_trig;
        }
 
@@ -1092,9 +1091,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
                return 1;
        }
 
-       serial_port_out(port, SCFCR,
-               (serial_port_in(port, SCFCR) &
-               ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
+       sci_serial_out(port, SCFCR,
+                      (sci_serial_in(port, SCFCR) &
+                       ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
 
        return rx_trig;
 }
@@ -1102,9 +1101,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
 static int scif_rtrg_enabled(struct uart_port *port)
 {
        if (sci_getreg(port, HSRTRGR)->size)
-               return serial_port_in(port, HSRTRGR) != 0;
+               return sci_serial_in(port, HSRTRGR) != 0;
        else
-               return (serial_port_in(port, SCFCR) &
+               return (sci_serial_in(port, SCFCR) &
                        (SCFCR_RTRG0 | SCFCR_RTRG1)) != 0;
 }
 
@@ -1219,8 +1218,8 @@ static void sci_dma_tx_complete(void *arg)
                s->cookie_tx = -EINVAL;
                if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
                    s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
-                       u16 ctrl = serial_port_in(port, SCSCR);
-                       serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+                       u16 ctrl = sci_serial_in(port, SCSCR);
+                       sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE);
                        if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
                                /* Switch irq from DMA to SCIF */
                                dmaengine_pause(s->chan_tx_saved);
@@ -1296,7 +1295,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
        u16 scr;
 
        /* Direct new serial port interrupts back to CPU */
-       scr = serial_port_in(port, SCSCR);
+       scr = sci_serial_in(port, SCSCR);
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
            s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
                enable_irq(s->irqs[SCIx_RXI_IRQ]);
@@ -1305,7 +1304,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
                else
                        scr &= ~SCSCR_RDRQE;
        }
-       serial_port_out(port, SCSCR, scr | SCSCR_RIE);
+       sci_serial_out(port, SCSCR, scr | SCSCR_RIE);
 }
 
 static void sci_dma_rx_complete(void *arg)
@@ -1714,8 +1713,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
        if (s->chan_rx) {
-               u16 scr = serial_port_in(port, SCSCR);
-               u16 ssr = serial_port_in(port, SCxSR);
+               u16 scr = sci_serial_in(port, SCSCR);
+               u16 ssr = sci_serial_in(port, SCxSR);
 
                /* Disable future Rx interrupts */
                if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
@@ -1733,10 +1732,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
 
                        scr &= ~SCSCR_RIE;
                }
-               serial_port_out(port, SCSCR, scr);
+               sci_serial_out(port, SCSCR, scr);
                /* Clear current interrupt */
-               serial_port_out(port, SCxSR,
-                               ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
+               sci_serial_out(port, SCxSR,
+                              ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
                dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n",
                        jiffies, s->rx_timeout);
                start_hrtimer_us(&s->rx_timer, s->rx_timeout);
@@ -1786,9 +1785,9 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
                return sci_tx_interrupt(irq, ptr);
 
        uart_port_lock_irqsave(port, &flags);
-       ctrl = serial_port_in(port, SCSCR);
+       ctrl = sci_serial_in(port, SCSCR);
        ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
-       serial_port_out(port, SCSCR, ctrl);
+       sci_serial_out(port, SCSCR, ctrl);
        uart_port_unlock_irqrestore(port, flags);
 
        return IRQ_HANDLED;
@@ -1802,7 +1801,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
        sci_handle_breaks(port);
 
        /* drop invalid character received before break was detected */
-       serial_port_in(port, SCxRDR);
+       sci_serial_in(port, SCxRDR);
 
        sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
 
@@ -1816,7 +1815,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
 
        if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) {
                /* Break and Error interrupts are muxed */
-               unsigned short ssr_status = serial_port_in(port, SCxSR);
+               unsigned short ssr_status = sci_serial_in(port, SCxSR);
 
                /* Break Interrupt */
                if (ssr_status & SCxSR_BRK(port))
@@ -1831,7 +1830,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
        if (port->type == PORT_SCI) {
                if (sci_handle_errors(port)) {
                        /* discard character in rx buffer */
-                       serial_port_in(port, SCxSR);
+                       sci_serial_in(port, SCxSR);
                        sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
                }
        } else {
@@ -1856,12 +1855,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
        struct sci_port *s = to_sci_port(port);
        irqreturn_t ret = IRQ_NONE;
 
-       ssr_status = serial_port_in(port, SCxSR);
-       scr_status = serial_port_in(port, SCSCR);
+       ssr_status = sci_serial_in(port, SCxSR);
+       scr_status = sci_serial_in(port, SCSCR);
        if (s->params->overrun_reg == SCxSR)
                orer_status = ssr_status;
        else if (sci_getreg(port, s->params->overrun_reg)->size)
-               orer_status = serial_port_in(port, s->params->overrun_reg);
+               orer_status = sci_serial_in(port, s->params->overrun_reg);
 
        err_enabled = scr_status & port_rx_irq_mask(port);
 
@@ -2038,7 +2037,7 @@ static void sci_free_irq(struct sci_port *port)
 
 static unsigned int sci_tx_empty(struct uart_port *port)
 {
-       unsigned short status = serial_port_in(port, SCxSR);
+       unsigned short status = sci_serial_in(port, SCxSR);
        unsigned short in_tx_fifo = sci_txfill(port);
 
        return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
@@ -2047,27 +2046,27 @@ static unsigned int sci_tx_empty(struct uart_port *port)
 static void sci_set_rts(struct uart_port *port, bool state)
 {
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 data = serial_port_in(port, SCPDR);
+               u16 data = sci_serial_in(port, SCPDR);
 
                /* Active low */
                if (state)
                        data &= ~SCPDR_RTSD;
                else
                        data |= SCPDR_RTSD;
-               serial_port_out(port, SCPDR, data);
+               sci_serial_out(port, SCPDR, data);
 
                /* RTS# is output */
-               serial_port_out(port, SCPCR,
-                               serial_port_in(port, SCPCR) | SCPCR_RTSC);
+               sci_serial_out(port, SCPCR,
+                              sci_serial_in(port, SCPCR) | SCPCR_RTSC);
        } else if (sci_getreg(port, SCSPTR)->size) {
-               u16 ctrl = serial_port_in(port, SCSPTR);
+               u16 ctrl = sci_serial_in(port, SCSPTR);
 
                /* Active low */
                if (state)
                        ctrl &= ~SCSPTR_RTSDT;
                else
                        ctrl |= SCSPTR_RTSDT;
-               serial_port_out(port, SCSPTR, ctrl);
+               sci_serial_out(port, SCSPTR, ctrl);
        }
 }
 
@@ -2075,10 +2074,10 @@ static bool sci_get_cts(struct uart_port *port)
 {
        if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
                /* Active low */
-               return !(serial_port_in(port, SCPDR) & SCPDR_CTSD);
+               return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD);
        } else if (sci_getreg(port, SCSPTR)->size) {
                /* Active low */
-               return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT);
+               return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT);
        }
 
        return true;
@@ -2108,9 +2107,8 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
                 */
                reg = sci_getreg(port, SCFCR);
                if (reg->size)
-                       serial_port_out(port, SCFCR,
-                                       serial_port_in(port, SCFCR) |
-                                       SCFCR_LOOP);
+                       sci_serial_out(port, SCFCR,
+                                      sci_serial_in(port, SCFCR) | SCFCR_LOOP);
        }
 
        mctrl_gpio_set(s->gpios, mctrl);
@@ -2120,21 +2118,21 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
        if (!(mctrl & TIOCM_RTS)) {
                /* Disable Auto RTS */
-               serial_port_out(port, SCFCR,
-                               serial_port_in(port, SCFCR) & ~SCFCR_MCE);
+               sci_serial_out(port, SCFCR,
+                              sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
 
                /* Clear RTS */
                sci_set_rts(port, 0);
        } else if (s->autorts) {
                if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
                        /* Enable RTS# pin function */
-                       serial_port_out(port, SCPCR,
-                               serial_port_in(port, SCPCR) & ~SCPCR_RTSC);
+                       sci_serial_out(port, SCPCR,
+                               sci_serial_in(port, SCPCR) & ~SCPCR_RTSC);
                }
 
                /* Enable Auto RTS */
-               serial_port_out(port, SCFCR,
-                               serial_port_in(port, SCFCR) | SCFCR_MCE);
+               sci_serial_out(port, SCFCR,
+                              sci_serial_in(port, SCFCR) | SCFCR_MCE);
        } else {
                /* Set RTS */
                sci_set_rts(port, 1);
@@ -2187,8 +2185,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
        }
 
        uart_port_lock_irqsave(port, &flags);
-       scsptr = serial_port_in(port, SCSPTR);
-       scscr = serial_port_in(port, SCSCR);
+       scsptr = sci_serial_in(port, SCSPTR);
+       scscr = sci_serial_in(port, SCSCR);
 
        if (break_state == -1) {
                scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
@@ -2198,8 +2196,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
                scscr |= SCSCR_TE;
        }
 
-       serial_port_out(port, SCSPTR, scsptr);
-       serial_port_out(port, SCSCR, scscr);
+       sci_serial_out(port, SCSPTR, scsptr);
+       sci_serial_out(port, SCSCR, scscr);
        uart_port_unlock_irqrestore(port, flags);
 }
 
@@ -2239,9 +2237,9 @@ static void sci_shutdown(struct uart_port *port)
         * Stop RX and TX, disable related interrupts, keep clock source
         * and HSCIF TOT bits
         */
-       scr = serial_port_in(port, SCSCR);
-       serial_port_out(port, SCSCR, scr &
-                       (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+       scr = sci_serial_in(port, SCSCR);
+       sci_serial_out(port, SCSCR,
+                      scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
        uart_port_unlock_irqrestore(port, flags);
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2390,19 +2388,19 @@ static void sci_reset(struct uart_port *port)
        unsigned int status;
        struct sci_port *s = to_sci_port(port);
 
-       serial_port_out(port, SCSCR, s->hscif_tot);     /* TE=0, RE=0, CKE1=0 */
+       sci_serial_out(port, SCSCR, s->hscif_tot);      /* TE=0, RE=0, CKE1=0 */
 
        reg = sci_getreg(port, SCFCR);
        if (reg->size)
-               serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+               sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
 
        sci_clear_SCxSR(port,
                        SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
                        SCxSR_BREAK_CLEAR(port));
        if (sci_getreg(port, SCLSR)->size) {
-               status = serial_port_in(port, SCLSR);
+               status = sci_serial_in(port, SCLSR);
                status &= ~(SCLSR_TO | SCLSR_ORER);
-               serial_port_out(port, SCLSR, status);
+               sci_serial_out(port, SCLSR, status);
        }
 
        if (s->rx_trigger > 1) {
@@ -2540,8 +2538,8 @@ done:
         * It controls the mux to select (H)SCK or frequency divided clock.
         */
        if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
-               serial_port_out(port, SCDL, dl);
-               serial_port_out(port, SCCKS, sccks);
+               sci_serial_out(port, SCDL, dl);
+               sci_serial_out(port, SCCKS, sccks);
        }
 
        uart_port_lock_irqsave(port, &flags);
@@ -2554,7 +2552,7 @@ done:
        bits = tty_get_frame_size(termios->c_cflag);
 
        if (sci_getreg(port, SEMR)->size)
-               serial_port_out(port, SEMR, 0);
+               sci_serial_out(port, SEMR, 0);
 
        if (best_clk >= 0) {
                if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
@@ -2569,9 +2567,9 @@ done:
                        case 27: smr_val |= SCSMR_SRC_27; break;
                        }
                smr_val |= cks;
-               serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
-               serial_port_out(port, SCSMR, smr_val);
-               serial_port_out(port, SCBRR, brr);
+               sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
+               sci_serial_out(port, SCSMR, smr_val);
+               sci_serial_out(port, SCBRR, brr);
                if (sci_getreg(port, HSSRR)->size) {
                        unsigned int hssrr = srr | HSCIF_SRE;
                        /* Calculate deviation from intended rate at the
@@ -2593,7 +2591,7 @@ done:
                                         HSCIF_SRHP_MASK;
                                hssrr |= HSCIF_SRDE;
                        }
-                       serial_port_out(port, HSSRR, hssrr);
+                       sci_serial_out(port, HSSRR, hssrr);
                }
 
                /* Wait one bit interval */
@@ -2601,10 +2599,10 @@ done:
        } else {
                /* Don't touch the bit rate configuration */
                scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
-               smr_val |= serial_port_in(port, SCSMR) &
+               smr_val |= sci_serial_in(port, SCSMR) &
                           (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
-               serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
-               serial_port_out(port, SCSMR, smr_val);
+               sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
+               sci_serial_out(port, SCSMR, smr_val);
        }
 
        sci_init_pins(port, termios->c_cflag);
@@ -2613,7 +2611,7 @@ done:
        s->autorts = false;
        reg = sci_getreg(port, SCFCR);
        if (reg->size) {
-               unsigned short ctrl = serial_port_in(port, SCFCR);
+               unsigned short ctrl = sci_serial_in(port, SCFCR);
 
                if ((port->flags & UPF_HARD_FLOW) &&
                    (termios->c_cflag & CRTSCTS)) {
@@ -2630,7 +2628,7 @@ done:
                 */
                ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
 
-               serial_port_out(port, SCFCR, ctrl);
+               sci_serial_out(port, SCFCR, ctrl);
        }
        if (port->flags & UPF_HARD_FLOW) {
                /* Refresh (Auto) RTS */
@@ -2645,7 +2643,7 @@ done:
        if (port->type != PORT_SCI)
                scr_val |= SCSCR_TE;
        scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0));
-       serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
+       sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
        if ((srr + 1 == 5) &&
            (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
                /*
@@ -3017,9 +3015,6 @@ static int sci_init_single(struct platform_device *dev,
        port->irq               = sci_port->irqs[SCIx_RXI_IRQ];
        port->irqflags          = 0;
 
-       port->serial_in         = sci_serial_in;
-       port->serial_out        = sci_serial_out;
-
        return 0;
 }
 
@@ -3056,21 +3051,21 @@ static void serial_console_write(struct console *co, const char *s,
                uart_port_lock_irqsave(port, &flags);
 
        /* first save SCSCR then disable interrupts, keep clock source */
-       ctrl = serial_port_in(port, SCSCR);
+       ctrl = sci_serial_in(port, SCSCR);
        ctrl_temp = SCSCR_RE | SCSCR_TE |
                    (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
                    (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
-       serial_port_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
+       sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
 
        uart_console_write(port, s, count, serial_console_putchar);
 
        /* wait until fifo is empty and last bit has been transmitted */
        bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
-       while ((serial_port_in(port, SCxSR) & bits) != bits)
+       while ((sci_serial_in(port, SCxSR) & bits) != bits)
                cpu_relax();
 
        /* restore the SCSCR */
-       serial_port_out(port, SCSCR, ctrl);
+       sci_serial_out(port, SCSCR, ctrl);
 
        if (locked)
                uart_port_unlock_irqrestore(port, flags);
@@ -3503,8 +3498,6 @@ static int __init early_console_setup(struct earlycon_device *device,
        if (!device->port.membase)
                return -ENODEV;
 
-       device->port.serial_in = sci_serial_in;
-       device->port.serial_out = sci_serial_out;
        device->port.type = type;
        memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
        port_cfg.type = type;
index a4cc569a78a256746e0e4cc262fc2abfe8ad5214..0670fd9f84967a151ebb2a3fbae6add7f918d003 100644 (file)
@@ -412,7 +412,8 @@ static void __ssp_receive_chars(struct sifive_serial_port *ssp)
                        break;
 
                ssp->port.icount.rx++;
-               uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL);
+               if (!uart_prepare_sysrq_char(&ssp->port, ch))
+                       uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL);
        }
 
        tty_flip_buffer_push(&ssp->port.state->port);
@@ -534,7 +535,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
        if (ip & SIFIVE_SERIAL_IP_TXWM_MASK)
                __ssp_transmit_chars(ssp);
 
-       uart_port_unlock(&ssp->port);
+       uart_unlock_and_check_sysrq(&ssp->port);
 
        return IRQ_HANDLED;
 }
@@ -791,13 +792,10 @@ static void sifive_serial_console_write(struct console *co, const char *s,
        if (!ssp)
                return;
 
-       local_irq_save(flags);
-       if (ssp->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&ssp->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&ssp->port, &flags);
        else
-               uart_port_lock(&ssp->port);
+               uart_port_lock_irqsave(&ssp->port, &flags);
 
        ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
        __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
@@ -807,8 +805,7 @@ static void sifive_serial_console_write(struct console *co, const char *s,
        __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
 
        if (locked)
-               uart_port_unlock(&ssp->port);
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&ssp->port, flags);
 }
 
 static int sifive_serial_console_setup(struct console *co, char *options)
index bbb5595d7e24cc22a195e7520366ac0e43e94e3c..a23e5955184885fa51dbdf302b9b39968561aaa2 100644 (file)
@@ -465,6 +465,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
                            const struct ktermios *old)
 {
        struct asc_port *ascport = to_asc_port(port);
+       bool manual_rts, toggle_rts = false;
        struct gpio_desc *gpiod;
        unsigned int baud;
        u32 ctrl_val;
@@ -518,25 +519,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
 
                /* If flow-control selected, stop handling RTS manually */
                if (ascport->rts) {
-                       devm_gpiod_put(port->dev, ascport->rts);
-                       ascport->rts = NULL;
-
-                       pinctrl_select_state(ascport->pinctrl,
-                                            ascport->states[DEFAULT]);
+                       toggle_rts = true;
+                       manual_rts = false;
                }
        } else {
                /* If flow-control disabled, it's safe to handle RTS manually */
-               if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL]) {
-                       pinctrl_select_state(ascport->pinctrl,
-                                            ascport->states[NO_HW_FLOWCTRL]);
-
-                       gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW);
-                       if (!IS_ERR(gpiod)) {
-                               gpiod_set_consumer_name(gpiod,
-                                               port->dev->of_node->name);
-                               ascport->rts = gpiod;
-                       }
-               }
+               if (!ascport->rts && ascport->states[NO_HW_FLOWCTRL])
+                       manual_rts = toggle_rts = true;
        }
 
        if ((baud < 19200) && !ascport->force_m1) {
@@ -595,6 +584,25 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
        asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN));
 
        uart_port_unlock_irqrestore(port, flags);
+
+       if (toggle_rts) {
+               if (manual_rts) {
+                       pinctrl_select_state(ascport->pinctrl,
+                                            ascport->states[NO_HW_FLOWCTRL]);
+
+                       gpiod = devm_gpiod_get(port->dev, "rts", GPIOD_OUT_LOW);
+                       if (!IS_ERR(gpiod)) {
+                               gpiod_set_consumer_name(gpiod,
+                                                       port->dev->of_node->name);
+                               ascport->rts = gpiod;
+                       }
+               } else {
+                               devm_gpiod_put(port->dev, ascport->rts);
+                               ascport->rts = NULL;
+                               pinctrl_select_state(ascport->pinctrl,
+                                                    ascport->states[DEFAULT]);
+               }
+       }
 }
 
 static const char *asc_type(struct uart_port *port)
index 693e932d6feb5842467d1408e04c8d574342cb1f..58d169e5c1db03b910686ac2a229116644f0d6e9 100644 (file)
@@ -9,6 +9,7 @@
  * Inspired by st-asc.c from STMicroelectronics (c)
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 /* Register offsets */
 static struct stm32_usart_info __maybe_unused stm32f4_info = {
        .ofs = {
-               .isr    = 0x00,
-               .rdr    = 0x04,
-               .tdr    = 0x04,
-               .brr    = 0x08,
-               .cr1    = 0x0c,
-               .cr2    = 0x10,
-               .cr3    = 0x14,
-               .gtpr   = 0x18,
-               .rtor   = UNDEF_REG,
-               .rqr    = UNDEF_REG,
-               .icr    = UNDEF_REG,
+               .isr            = 0x00,
+               .rdr            = 0x04,
+               .tdr            = 0x04,
+               .brr            = 0x08,
+               .cr1            = 0x0c,
+               .cr2            = 0x10,
+               .cr3            = 0x14,
+               .gtpr           = 0x18,
+               .rtor           = UNDEF_REG,
+               .rqr            = UNDEF_REG,
+               .icr            = UNDEF_REG,
+               .presc          = UNDEF_REG,
+               .hwcfgr1        = UNDEF_REG,
        },
        .cfg = {
                .uart_enable_bit = 13,
                .has_7bits_data = false,
-               .fifosize = 1,
        }
 };
 
 static struct stm32_usart_info __maybe_unused stm32f7_info = {
        .ofs = {
-               .cr1    = 0x00,
-               .cr2    = 0x04,
-               .cr3    = 0x08,
-               .brr    = 0x0c,
-               .gtpr   = 0x10,
-               .rtor   = 0x14,
-               .rqr    = 0x18,
-               .isr    = 0x1c,
-               .icr    = 0x20,
-               .rdr    = 0x24,
-               .tdr    = 0x28,
+               .cr1            = 0x00,
+               .cr2            = 0x04,
+               .cr3            = 0x08,
+               .brr            = 0x0c,
+               .gtpr           = 0x10,
+               .rtor           = 0x14,
+               .rqr            = 0x18,
+               .isr            = 0x1c,
+               .icr            = 0x20,
+               .rdr            = 0x24,
+               .tdr            = 0x28,
+               .presc          = UNDEF_REG,
+               .hwcfgr1        = UNDEF_REG,
        },
        .cfg = {
                .uart_enable_bit = 0,
                .has_7bits_data = true,
                .has_swap = true,
-               .fifosize = 1,
        }
 };
 
 static struct stm32_usart_info __maybe_unused stm32h7_info = {
        .ofs = {
-               .cr1    = 0x00,
-               .cr2    = 0x04,
-               .cr3    = 0x08,
-               .brr    = 0x0c,
-               .gtpr   = 0x10,
-               .rtor   = 0x14,
-               .rqr    = 0x18,
-               .isr    = 0x1c,
-               .icr    = 0x20,
-               .rdr    = 0x24,
-               .tdr    = 0x28,
+               .cr1            = 0x00,
+               .cr2            = 0x04,
+               .cr3            = 0x08,
+               .brr            = 0x0c,
+               .gtpr           = 0x10,
+               .rtor           = 0x14,
+               .rqr            = 0x18,
+               .isr            = 0x1c,
+               .icr            = 0x20,
+               .rdr            = 0x24,
+               .tdr            = 0x28,
+               .presc          = 0x2c,
+               .hwcfgr1        = 0x3f0,
        },
        .cfg = {
                .uart_enable_bit = 0,
@@ -100,7 +105,6 @@ static struct stm32_usart_info __maybe_unused stm32h7_info = {
                .has_swap = true,
                .has_wakeup = true,
                .has_fifo = true,
-               .fifosize = 16,
        }
 };
 
@@ -1147,6 +1151,8 @@ static void stm32_usart_shutdown(struct uart_port *port)
        free_irq(port->irq, port);
 }
 
+static const unsigned int stm32_usart_presc_val[] = {1, 2, 4, 6, 8, 10, 12, 16, 32, 64, 128, 256};
+
 static void stm32_usart_set_termios(struct uart_port *port,
                                    struct ktermios *termios,
                                    const struct ktermios *old)
@@ -1155,17 +1161,19 @@ static void stm32_usart_set_termios(struct uart_port *port,
        const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
        const struct stm32_usart_config *cfg = &stm32_port->info->cfg;
        struct serial_rs485 *rs485conf = &port->rs485;
-       unsigned int baud, bits;
+       unsigned int baud, bits, uart_clk, uart_clk_pres;
        u32 usartdiv, mantissa, fraction, oversampling;
        tcflag_t cflag = termios->c_cflag;
-       u32 cr1, cr2, cr3, isr;
+       u32 cr1, cr2, cr3, isr, brr, presc;
        unsigned long flags;
        int ret;
 
        if (!stm32_port->hw_flow_control)
                cflag &= ~CRTSCTS;
 
-       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
+       uart_clk = clk_get_rate(stm32_port->clk);
+
+       baud = uart_get_baud_rate(port, termios, old, 0, uart_clk / 8);
 
        uart_port_lock_irqsave(port, &flags);
 
@@ -1267,27 +1275,48 @@ static void stm32_usart_set_termios(struct uart_port *port,
                cr3 |= USART_CR3_CTSE | USART_CR3_RTSE;
        }
 
-       usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
+       for (presc = 0; presc <= USART_PRESC_MAX; presc++) {
+               uart_clk_pres = DIV_ROUND_CLOSEST(uart_clk, stm32_usart_presc_val[presc]);
+               usartdiv = DIV_ROUND_CLOSEST(uart_clk_pres, baud);
 
-       /*
-        * The USART supports 16 or 8 times oversampling.
-        * By default we prefer 16 times oversampling, so that the receiver
-        * has a better tolerance to clock deviations.
-        * 8 times oversampling is only used to achieve higher speeds.
-        */
-       if (usartdiv < 16) {
-               oversampling = 8;
-               cr1 |= USART_CR1_OVER8;
-               stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8);
-       } else {
-               oversampling = 16;
-               cr1 &= ~USART_CR1_OVER8;
-               stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
+               /*
+                * The USART supports 16 or 8 times oversampling.
+                * By default we prefer 16 times oversampling, so that the receiver
+                * has a better tolerance to clock deviations.
+                * 8 times oversampling is only used to achieve higher speeds.
+                */
+               if (usartdiv < 16) {
+                       oversampling = 8;
+                       cr1 |= USART_CR1_OVER8;
+                       stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8);
+               } else {
+                       oversampling = 16;
+                       cr1 &= ~USART_CR1_OVER8;
+                       stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
+               }
+
+               mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
+               fraction = usartdiv % oversampling;
+               brr = mantissa | fraction;
+
+               if (FIELD_FIT(USART_BRR_MASK, brr)) {
+                       if (ofs->presc != UNDEF_REG) {
+                               port->uartclk = uart_clk_pres;
+                               writel_relaxed(presc, port->membase + ofs->presc);
+                       } else if (presc) {
+                               /* We need a prescaler but we don't have it (STM32F4, STM32F7) */
+                               dev_err(port->dev,
+                                       "unable to set baudrate, input clock is too high");
+                       }
+                       break;
+               } else if (presc == USART_PRESC_MAX) {
+                       /* Even with prescaler and brr at max value we can't set baudrate */
+                       dev_err(port->dev, "unable to set baudrate, input clock is too high");
+                       break;
+               }
        }
 
-       mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
-       fraction = usartdiv % oversampling;
-       writel_relaxed(mantissa | fraction, port->membase + ofs->brr);
+       writel_relaxed(brr, port->membase + ofs->brr);
 
        uart_update_timeout(port, cflag, baud);
 
@@ -1471,37 +1500,57 @@ static const struct uart_ops stm32_uart_ops = {
 #endif /* CONFIG_CONSOLE_POLL */
 };
 
-/*
- * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG)
- * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case,
- * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE.
- * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1.
- */
-static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 };
+struct stm32_usart_thresh_ratio {
+       int mul;
+       int div;
+};
+
+static const struct stm32_usart_thresh_ratio stm32h7_usart_fifo_thresh_cfg[] = {
+       {1, 8}, {1, 4}, {1, 2}, {3, 4}, {7, 8}, {1, 1} };
+
+static int stm32_usart_get_thresh_value(u32 fifo_size, int index)
+{
+       return fifo_size * stm32h7_usart_fifo_thresh_cfg[index].mul /
+               stm32h7_usart_fifo_thresh_cfg[index].div;
+}
 
-static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p,
-                                 int *ftcfg)
+static int stm32_usart_get_ftcfg(struct platform_device *pdev, struct stm32_port *stm32port,
+                                const char *p, int *ftcfg)
 {
-       u32 bytes, i;
+       const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
+       u32 bytes, i, cfg8;
+       int fifo_size;
+
+       if (WARN_ON(ofs->hwcfgr1 == UNDEF_REG))
+               return 1;
+
+       cfg8 = FIELD_GET(USART_HWCFGR1_CFG8,
+                        readl_relaxed(stm32port->port.membase + ofs->hwcfgr1));
+
+       /* On STM32H7, hwcfgr is not present, so returned value will be 0 */
+       fifo_size = cfg8 ? 1 << cfg8 : STM32H7_USART_FIFO_SIZE;
 
-       /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */
+       /* DT option to get RX & TX FIFO threshold (default to half fifo size) */
        if (of_property_read_u32(pdev->dev.of_node, p, &bytes))
-               bytes = 8;
+               bytes = fifo_size / 2;
 
-       for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++)
-               if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes)
+       if (bytes < stm32_usart_get_thresh_value(fifo_size, 0)) {
+               *ftcfg = -EINVAL;
+               return fifo_size;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) {
+               if (stm32_usart_get_thresh_value(fifo_size, i) >= bytes)
                        break;
+       }
        if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg))
                i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1;
 
-       dev_dbg(&pdev->dev, "%s set to %d bytes\n", p,
-               stm32h7_usart_fifo_thresh_cfg[i]);
+       dev_dbg(&pdev->dev, "%s set to %d/%d bytes\n", p,
+               stm32_usart_get_thresh_value(fifo_size, i), fifo_size);
 
-       /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */
-       if (i)
-               *ftcfg = i - 1;
-       else
-               *ftcfg = -EINVAL;
+       *ftcfg = i;
+       return fifo_size;
 }
 
 static void stm32_usart_deinit_port(struct stm32_port *stm32port)
@@ -1531,7 +1580,6 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
        port->flags     = UPF_BOOT_AUTOCONF;
        port->ops       = &stm32_uart_ops;
        port->dev       = &pdev->dev;
-       port->fifosize  = stm32port->info->cfg.fifosize;
        port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
        port->irq = irq;
        port->rs485_config = stm32_usart_config_rs485;
@@ -1547,14 +1595,6 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
        stm32port->swap = stm32port->info->cfg.has_swap &&
                of_property_read_bool(pdev->dev.of_node, "rx-tx-swap");
 
-       stm32port->fifoen = stm32port->info->cfg.has_fifo;
-       if (stm32port->fifoen) {
-               stm32_usart_get_ftcfg(pdev, "rx-threshold",
-                                     &stm32port->rxftcfg);
-               stm32_usart_get_ftcfg(pdev, "tx-threshold",
-                                     &stm32port->txftcfg);
-       }
-
        port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(port->membase))
                return PTR_ERR(port->membase);
@@ -1577,6 +1617,15 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
                goto err_clk;
        }
 
+       stm32port->fifoen = stm32port->info->cfg.has_fifo;
+       if (stm32port->fifoen) {
+               stm32_usart_get_ftcfg(pdev, stm32port, "rx-threshold", &stm32port->rxftcfg);
+               port->fifosize = stm32_usart_get_ftcfg(pdev, stm32port, "tx-threshold",
+                                                      &stm32port->txftcfg);
+       } else {
+               port->fifosize = 1;
+       }
+
        stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0);
        if (IS_ERR(stm32port->gpios)) {
                ret = PTR_ERR(stm32port->gpios);
index f59f831b2a10c4883030acbee52085c64469e23e..af20258ccc7a0fcc57a541b37efcc9848290e141 100644 (file)
@@ -9,17 +9,19 @@
 #define DRIVER_NAME "stm32-usart"
 
 struct stm32_usart_offsets {
-       u8 cr1;
-       u8 cr2;
-       u8 cr3;
-       u8 brr;
-       u8 gtpr;
-       u8 rtor;
-       u8 rqr;
-       u8 isr;
-       u8 icr;
-       u8 rdr;
-       u8 tdr;
+       u16 cr1;
+       u16 cr2;
+       u16 cr3;
+       u16 brr;
+       u16 gtpr;
+       u16 rtor;
+       u16 rqr;
+       u16 isr;
+       u16 icr;
+       u16 rdr;
+       u16 tdr;
+       u16 presc;
+       u16 hwcfgr1;
 };
 
 struct stm32_usart_config {
@@ -28,7 +30,6 @@ struct stm32_usart_config {
        bool has_swap;
        bool has_wakeup;
        bool has_fifo;
-       int fifosize;
 };
 
 struct stm32_usart_info {
@@ -36,7 +37,7 @@ struct stm32_usart_info {
        struct stm32_usart_config cfg;
 };
 
-#define UNDEF_REG 0xff
+#define UNDEF_REG 0xffff
 
 /* USART_SR (F4) / USART_ISR (F7) */
 #define USART_SR_PE            BIT(0)
@@ -71,6 +72,7 @@ struct stm32_usart_info {
 #define USART_BRR_DIV_M_MASK   GENMASK(15, 4)
 #define USART_BRR_DIV_M_SHIFT  4
 #define USART_BRR_04_R_SHIFT   1
+#define USART_BRR_MASK         (USART_BRR_DIV_M_MASK | USART_BRR_DIV_F_MASK)
 
 /* USART_CR1 */
 #define USART_CR1_SBK          BIT(0)
@@ -176,8 +178,16 @@ struct stm32_usart_info {
 #define USART_ICR_CMCF         BIT(17)         /* F7 */
 #define USART_ICR_WUCF         BIT(20)         /* H7 */
 
+/* USART_PRESC */
+#define USART_PRESC            GENMASK(3, 0)   /* H7 */
+#define USART_PRESC_MAX                0b1011
+
+/* USART_HWCFCR1 */
+#define USART_HWCFGR1_CFG8     GENMASK(31, 28) /* MP1 */
+
 #define STM32_SERIAL_NAME "ttySTM"
-#define STM32_MAX_PORTS 8
+#define STM32_MAX_PORTS 9
+#define STM32H7_USART_FIFO_SIZE 16
 
 #define RX_BUF_L 4096           /* dma rx buffer length     */
 #define RX_BUF_P (RX_BUF_L / 2)         /* dma rx buffer period     */
index 99f5285819d4b22645d6e706adfe2be8d69a8ead..f5e29eb4a4ce441911494795aa00fb1221ad17e6 100644 (file)
@@ -260,7 +260,7 @@ static void receive_chars(struct uart_port *port)
                if (port->ignore_status_mask & SUP_DUMMY_READ)
                        goto ignore_char;
 
-               if (uart_handle_sysrq_char(port, ch))
+               if (uart_prepare_sysrq_char(port, ch))
                        goto ignore_char;
 
                uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag);
@@ -287,7 +287,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args)
        if (isc & SUP_UART_ISC_TX)
                transmit_chars(port);
 
-       uart_port_unlock(port);
+       uart_unlock_and_check_sysrq(port);
 
        return IRQ_HANDLED;
 }
@@ -512,22 +512,16 @@ static void sunplus_console_write(struct console *co,
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-
-       if (sunplus_console_ports[co->index]->port.sysrq)
-               locked = 0;
-       else if (oops_in_progress)
-               locked = uart_port_trylock(&sunplus_console_ports[co->index]->port);
+       if (oops_in_progress)
+               locked = uart_port_trylock_irqsave(&sunplus_console_ports[co->index]->port, &flags);
        else
-               uart_port_lock(&sunplus_console_ports[co->index]->port);
+               uart_port_lock_irqsave(&sunplus_console_ports[co->index]->port, &flags);
 
        uart_console_write(&sunplus_console_ports[co->index]->port, s, count,
                           sunplus_uart_console_putchar);
 
        if (locked)
-               uart_port_unlock(&sunplus_console_ports[co->index]->port);
-
-       local_irq_restore(flags);
+               uart_port_unlock_irqrestore(&sunplus_console_ports[co->index]->port, flags);
 }
 
 static int __init sunplus_console_setup(struct console *co, char *options)
index 920762d7b4a4b2607f6ec9b2b7981af803b65361..5f48ec37cb25ff2e9b55950e5a7cfee7d35397bf 100644 (file)
@@ -22,7 +22,9 @@
 #include <linux/of.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
-#include <linux/iopoll.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
 
 #define CDNS_UART_TTY_NAME     "ttyPS"
 #define CDNS_UART_NAME         "xuartps"
@@ -193,6 +195,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
  * @clk_rate_change_nb:        Notifier block for clock changes
  * @quirks:            Flags for RXBS support.
  * @cts_override:      Modem control state override
+ * @gpiod_rts:         Pointer to the gpio descriptor
+ * @rs485_tx_started:  RS485 tx state
+ * @tx_timer:          Timer for tx
  */
 struct cdns_uart {
        struct uart_port        *port;
@@ -203,10 +208,21 @@ struct cdns_uart {
        struct notifier_block   clk_rate_change_nb;
        u32                     quirks;
        bool cts_override;
+       struct gpio_desc        *gpiod_rts;
+       bool                    rs485_tx_started;
+       struct hrtimer          tx_timer;
 };
 struct cdns_platform_data {
        u32 quirks;
 };
+
+struct serial_rs485 cdns_rs485_supported = {
+       .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+                SER_RS485_RTS_AFTER_SEND,
+       .delay_rts_before_send = 1,
+       .delay_rts_after_send = 1,
+};
+
 #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
                clk_rate_change_nb)
 
@@ -306,17 +322,114 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
 }
 
 /**
- * cdns_uart_handle_tx - Handle the bytes to be Txed.
+ * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low
+ * @cdns_uart: Handle to the cdns_uart
+ * @enable: Value to be set to RTS/GPIO
+ */
+static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable)
+{
+       u32 val;
+
+       if (cdns_uart->gpiod_rts) {
+               gpiod_set_value(cdns_uart->gpiod_rts, enable);
+       } else {
+               val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR);
+               if (enable)
+                       val |= CDNS_UART_MODEMCR_RTS;
+               else
+                       val &= ~CDNS_UART_MODEMCR_RTS;
+               writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR);
+       }
+}
+
+/**
+ * cdns_rs485_tx_setup - Tx setup specific to rs485
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
+{
+       bool enable;
+
+       enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_ON_SEND;
+       cdns_rts_gpio_enable(cdns_uart, enable);
+
+       cdns_uart->rs485_tx_started = true;
+}
+
+/**
+ * cdns_rs485_rx_setup - Rx setup specific to rs485
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
+{
+       bool enable;
+
+       enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_AFTER_SEND;
+       cdns_rts_gpio_enable(cdns_uart, enable);
+
+       cdns_uart->rs485_tx_started = false;
+}
+
+/**
+ * cdns_uart_tx_empty -  Check whether TX is empty
+ * @port: Handle to the uart port structure
+ *
+ * Return: TIOCSER_TEMT on success, 0 otherwise
+ */
+static unsigned int cdns_uart_tx_empty(struct uart_port *port)
+{
+       unsigned int status;
+
+       status = readl(port->membase + CDNS_UART_SR);
+       status &= (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE);
+       return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0;
+}
+
+/**
+ * cdns_rs485_rx_callback - Timer rx callback handler for rs485.
+ * @t: Handle to the hrtimer structure
+ */
+static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t)
+{
+       struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer);
+
+       /*
+        * Default Rx should be setup, because Rx signaling path
+        * need to enable to receive data.
+        */
+       cdns_rs485_rx_setup(cdns_uart);
+
+       return HRTIMER_NORESTART;
+}
+
+/**
+ * cdns_calc_after_tx_delay - calculate delay required for after tx.
+ * @cdns_uart: Handle to the cdns_uart
+ */
+static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart)
+{
+       /*
+        * Frame time + stop bit time + rs485.delay_rts_after_send
+        */
+       return cdns_uart->port->frame_time
+              + DIV_ROUND_UP(cdns_uart->port->frame_time, 7)
+              + (u64)cdns_uart->port->rs485.delay_rts_after_send * NSEC_PER_MSEC;
+}
+
+/**
+ * cdns_uart_handle_tx - Handle the bytes to be transmitted.
  * @dev_id: Id of the UART port
  * Return: None
  */
 static void cdns_uart_handle_tx(void *dev_id)
 {
        struct uart_port *port = (struct uart_port *)dev_id;
+       struct cdns_uart *cdns_uart = port->private_data;
        struct circ_buf *xmit = &port->state->xmit;
        unsigned int numbytes;
 
-       if (uart_circ_empty(xmit)) {
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               /* Disable the TX Empty interrupt */
                writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
                return;
        }
@@ -332,6 +445,16 @@ static void cdns_uart_handle_tx(void *dev_id)
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
+
+       /* Enable the TX Empty interrupt */
+       writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
+
+       if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
+           (uart_circ_empty(xmit) || uart_tx_stopped(port))) {
+               cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
+               hrtimer_start(&cdns_uart->tx_timer,
+                             ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
+       }
 }
 
 /**
@@ -564,6 +687,21 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
 }
 #endif
 
+/**
+ * cdns_rs485_tx_callback - Timer tx callback handler for rs485.
+ * @t: Handle to the hrtimer structure
+ */
+static enum hrtimer_restart cdns_rs485_tx_callback(struct hrtimer *t)
+{
+       struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer);
+
+       uart_port_lock(cdns_uart->port);
+       cdns_uart_handle_tx(cdns_uart->port);
+       uart_port_unlock(cdns_uart->port);
+
+       return HRTIMER_NORESTART;
+}
+
 /**
  * cdns_uart_start_tx -  Start transmitting bytes
  * @port: Handle to the uart port structure
@@ -571,6 +709,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
 static void cdns_uart_start_tx(struct uart_port *port)
 {
        unsigned int status;
+       struct cdns_uart *cdns_uart = port->private_data;
 
        if (uart_tx_stopped(port))
                return;
@@ -587,12 +726,19 @@ static void cdns_uart_start_tx(struct uart_port *port)
        if (uart_circ_empty(&port->state->xmit))
                return;
 
+       /* Clear the TX Empty interrupt */
        writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
 
+       if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
+               if (!cdns_uart->rs485_tx_started) {
+                       cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+                       cdns_rs485_tx_setup(cdns_uart);
+                       return hrtimer_start(&cdns_uart->tx_timer,
+                                            ms_to_ktime(port->rs485.delay_rts_before_send),
+                                            HRTIMER_MODE_REL);
+               }
+       }
        cdns_uart_handle_tx(port);
-
-       /* Enable the TX Empty interrupt */
-       writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
 }
 
 /**
@@ -602,6 +748,10 @@ static void cdns_uart_start_tx(struct uart_port *port)
 static void cdns_uart_stop_tx(struct uart_port *port)
 {
        unsigned int regval;
+       struct cdns_uart *cdns_uart = port->private_data;
+
+       if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
+               cdns_rs485_rx_setup(cdns_uart);
 
        regval = readl(port->membase + CDNS_UART_CR);
        regval |= CDNS_UART_CR_TX_DIS;
@@ -626,21 +776,6 @@ static void cdns_uart_stop_rx(struct uart_port *port)
        writel(regval, port->membase + CDNS_UART_CR);
 }
 
-/**
- * cdns_uart_tx_empty -  Check whether TX is empty
- * @port: Handle to the uart port structure
- *
- * Return: TIOCSER_TEMT on success, 0 otherwise
- */
-static unsigned int cdns_uart_tx_empty(struct uart_port *port)
-{
-       unsigned int status;
-
-       status = readl(port->membase + CDNS_UART_SR) &
-                      (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE);
-       return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0;
-}
-
 /**
  * cdns_uart_break_ctl - Based on the input ctl we have to start or stop
  *                     transmitting char breaks
@@ -829,6 +964,9 @@ static int cdns_uart_startup(struct uart_port *port)
                (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
                cpu_relax();
 
+       if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
+               cdns_rs485_rx_setup(cdns_uart);
+
        /*
         * Clear the RX disable bit and then set the RX enable bit to enable
         * the receiver.
@@ -888,6 +1026,10 @@ static void cdns_uart_shutdown(struct uart_port *port)
 {
        int status;
        unsigned long flags;
+       struct cdns_uart *cdns_uart = port->private_data;
+
+       if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED)
+               hrtimer_cancel(&cdns_uart->tx_timer);
 
        uart_port_lock_irqsave(port, &flags);
 
@@ -1033,6 +1175,8 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
        if (mctrl & TIOCM_RTS)
                val |= CDNS_UART_MODEMCR_RTS;
+       if (cdns_uart_data->gpiod_rts)
+               gpiod_set_value(cdns_uart_data->gpiod_rts, !(mctrl & TIOCM_RTS));
        if (mctrl & TIOCM_DTR)
                val |= CDNS_UART_MODEMCR_DTR;
        if (mctrl & TIOCM_LOOP)
@@ -1455,6 +1599,39 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
 /* Temporary variable for storing number of instances */
 static int instances;
 
+/**
+ * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
+ * @port: Pointer to the uart_port structure
+ * @termios: Pointer to the ktermios structure
+ * @rs485: Pointer to the serial_rs485 structure
+ *
+ * Return: 0
+ */
+static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
+                            struct serial_rs485 *rs485)
+{
+       u32 val;
+       struct cdns_uart *cdns_uart = port->private_data;
+
+       if (rs485->flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               /* Make sure auto RTS is disabled */
+               val = readl(port->membase + CDNS_UART_MODEMCR);
+               val &= ~CDNS_UART_MODEMCR_FCM;
+               writel(val, port->membase + CDNS_UART_MODEMCR);
+
+               /* Timer setup */
+               hrtimer_init(&cdns_uart->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+
+               /* Disable transmitter and make Rx setup*/
+               cdns_uart_stop_tx(port);
+       } else {
+               hrtimer_cancel(&cdns_uart->tx_timer);
+       }
+       return 0;
+}
+
 /**
  * cdns_uart_probe - Platform driver probe
  * @pdev: Pointer to the platform device structure
@@ -1597,9 +1774,23 @@ static int cdns_uart_probe(struct platform_device *pdev)
        port->private_data = cdns_uart_data;
        port->read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
                        CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT;
+       port->rs485_config = cdns_rs485_config;
+       port->rs485_supported = cdns_rs485_supported;
        cdns_uart_data->port = port;
        platform_set_drvdata(pdev, port);
 
+       rc = uart_get_rs485_mode(port);
+       if (rc)
+               goto err_out_clk_notifier;
+
+       cdns_uart_data->gpiod_rts = devm_gpiod_get_optional(&pdev->dev, "rts",
+                                                           GPIOD_OUT_LOW);
+       if (IS_ERR(cdns_uart_data->gpiod_rts)) {
+               rc = PTR_ERR(cdns_uart_data->gpiod_rts);
+               dev_err(port->dev, "xuartps: devm_gpiod_get_optional failed\n");
+               goto err_out_clk_notifier;
+       }
+
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
        pm_runtime_set_active(&pdev->dev);
@@ -1618,6 +1809,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
                console_port = port;
        }
 #endif
+       if (cdns_uart_data->port->rs485.flags & SER_RS485_ENABLED)
+               cdns_rs485_rx_setup(cdns_uart_data);
 
        rc = uart_add_one_port(&cdns_uart_uart_driver, port);
        if (rc) {
@@ -1646,6 +1839,7 @@ err_out_pm_disable:
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
        pm_runtime_dont_use_autosuspend(&pdev->dev);
+err_out_clk_notifier:
 #ifdef CONFIG_COMMON_CLK
        clk_notifier_unregister(cdns_uart_data->uartclk,
                        &cdns_uart_data->clk_rate_change_nb);
index f8883afbeeba6d5e305868252864e13692a49341..79f0ff94ce00da1b180d4f01cc26acab7159fdb6 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/errno.h>
 #include <linux/minmax.h>
 #include <linux/tty.h>
+#include <linux/tty_buffer.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/timer.h>
index b3dfe9d5717e3f798dc8b8f4d43e96d535e584d6..2c8ce8b592ed2dc5ae60a5adf72311c058742053 100644 (file)
@@ -5,9 +5,9 @@
 FONTMAPFILE = cp437.uni
 
 obj-$(CONFIG_VT)                       += vt_ioctl.o vc_screen.o \
-                                          selection.o keyboard.o
+                                          selection.o keyboard.o \
+                                          vt.o defkeymap.o
 obj-$(CONFIG_CONSOLE_TRANSLATIONS)     += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE)               += vt.o defkeymap.o
 
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c
index 8967c3a0d9169a40c496a37b0fde281c341af3cd..564341f1a74f3f6b1b553bf8705fe34b62ed3b5a 100644 (file)
@@ -7,7 +7,7 @@
  *     'int set_selection_kernel(struct tiocl_selection *, struct tty_struct *)'
  *     'void clear_selection(void)'
  *     'int paste_selection(struct tty_struct *)'
- *     'int sel_loadlut(char __user *)'
+ *     'int sel_loadlut(u32 __user *)'
  *
  * Now that /dev/vcs exists, most of this can disappear again.
  */
@@ -73,10 +73,12 @@ sel_pos(int n, bool unicode)
 }
 
 /**
- *     clear_selection         -       remove current selection
+ * clear_selection - remove current selection
  *
- *     Remove the current selection highlight, if any from the console
- *     holding the selection. The caller must hold the console lock.
+ * Remove the current selection highlight, if any from the console holding the
+ * selection.
+ *
+ * Locking: The caller must hold the console lock.
  */
 void clear_selection(void)
 {
@@ -88,7 +90,7 @@ void clear_selection(void)
 }
 EXPORT_SYMBOL_GPL(clear_selection);
 
-bool vc_is_sel(struct vc_data *vc)
+bool vc_is_sel(const struct vc_data *vc)
 {
        return vc == vc_sel.cons;
 }
@@ -110,18 +112,25 @@ static inline int inword(const u32 c)
 }
 
 /**
- *     sel_loadlut()           -       load the LUT table
- *     @p: user table
+ * sel_loadlut() - load the LUT table
+ * @lut: user table
+ *
+ * Load the LUT table from user space. Make a temporary copy so a partial
+ * update doesn't make a mess.
  *
- *     Load the LUT table from user space. The caller must hold the console
- *     lock. Make a temporary copy so a partial update doesn't make a mess.
+ * Locking: The console lock is acquired.
  */
-int sel_loadlut(char __user *p)
+int sel_loadlut(u32 __user *lut)
 {
        u32 tmplut[ARRAY_SIZE(inwordLut)];
-       if (copy_from_user(tmplut, (u32 __user *)(p+4), sizeof(inwordLut)))
+
+       if (copy_from_user(tmplut, lut, sizeof(inwordLut)))
                return -EFAULT;
+
+       console_lock();
        memcpy(inwordLut, tmplut, sizeof(inwordLut));
+       console_unlock();
+
        return 0;
 }
 
@@ -166,14 +175,14 @@ static int store_utf8(u32 c, char *p)
 }
 
 /**
- *     set_selection_user      -       set the current selection.
- *     @sel: user selection info
- *     @tty: the console tty
+ * set_selection_user - set the current selection.
+ * @sel: user selection info
+ * @tty: the console tty
  *
- *     Invoked by the ioctl handle for the vt layer.
+ * Invoked by the ioctl handle for the vt layer.
  *
- *     The entire selection process is managed under the console_lock. It's
- *      a lot under the lock but its hardly a performance path
+ * Locking: The entire selection process is managed under the console_lock.
+ * It's a lot under the lock but its hardly a performance path.
  */
 int set_selection_user(const struct tiocl_selection __user *sel,
                       struct tty_struct *tty)
index 38a765eadbe2bc81494f1fbd7a63b50b87101f08..9b5b98dfc8b4017289db11d3a42780760cad38fe 100644 (file)
@@ -145,7 +145,7 @@ static void gotoxy(struct vc_data *vc, int new_x, int new_y);
 static void save_cur(struct vc_data *vc);
 static void reset_terminal(struct vc_data *vc, int do_clear);
 static void con_flush_chars(struct tty_struct *tty);
-static int set_vesa_blanking(char __user *p);
+static int set_vesa_blanking(u8 __user *mode);
 static void set_cursor(struct vc_data *vc);
 static void hide_cursor(struct vc_data *vc);
 static void console_callback(struct work_struct *ignored);
@@ -175,7 +175,7 @@ int do_poke_blanked_console;
 int console_blanked;
 EXPORT_SYMBOL(console_blanked);
 
-static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+static enum vesa_blank_mode vesa_blank_mode;
 static int vesa_off_interval;
 static int blankinterval;
 core_param(consoleblank, blankinterval, int, 0444);
@@ -286,18 +286,20 @@ static inline bool con_should_update(const struct vc_data *vc)
        return con_is_visible(vc) && !console_blanked;
 }
 
-static inline unsigned short *screenpos(const struct vc_data *vc, int offset,
-               bool viewed)
+static inline u16 *screenpos(const struct vc_data *vc, unsigned int offset,
+                            bool viewed)
 {
-       unsigned short *p;
-       
-       if (!viewed)
-               p = (unsigned short *)(vc->vc_origin + offset);
-       else if (!vc->vc_sw->con_screen_pos)
-               p = (unsigned short *)(vc->vc_visible_origin + offset);
+       unsigned long origin = viewed ? vc->vc_visible_origin : vc->vc_origin;
+
+       return (u16 *)(origin + offset);
+}
+
+static void con_putc(struct vc_data *vc, u16 ca, unsigned int y, unsigned int x)
+{
+       if (vc->vc_sw->con_putc)
+               vc->vc_sw->con_putc(vc, ca, y, x);
        else
-               p = vc->vc_sw->con_screen_pos(vc, offset);
-       return p;
+               vc->vc_sw->con_putcs(vc, &ca, 1, y, x);
 }
 
 /* Called  from the keyboard irq path.. */
@@ -591,18 +593,12 @@ static void con_scroll(struct vc_data *vc, unsigned int top,
 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
 {
        unsigned int xx, yy, offset;
-       u16 *p;
+       u16 *p = (u16 *)start;
+
+       offset = (start - vc->vc_origin) / 2;
+       xx = offset % vc->vc_cols;
+       yy = offset / vc->vc_cols;
 
-       p = (u16 *) start;
-       if (!vc->vc_sw->con_getxy) {
-               offset = (start - vc->vc_origin) / 2;
-               xx = offset % vc->vc_cols;
-               yy = offset / vc->vc_cols;
-       } else {
-               int nxx, nyy;
-               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
-               xx = nxx; yy = nyy;
-       }
        for(;;) {
                u16 attrib = scr_readw(p) & 0xff00;
                int startx = xx;
@@ -625,10 +621,6 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
                        break;
                xx = 0;
                yy++;
-               if (vc->vc_sw->con_getxy) {
-                       p = (u16 *)start;
-                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
-               }
        }
 }
 
@@ -703,7 +695,7 @@ static void update_attr(struct vc_data *vc)
 /* Note: inverting the screen twice should revert to the original state */
 void invert_screen(struct vc_data *vc, int offset, int count, bool viewed)
 {
-       unsigned short *p;
+       u16 *p;
 
        WARN_CONSOLE_UNLOCKED();
 
@@ -762,7 +754,7 @@ void complement_pos(struct vc_data *vc, int offset)
            old_offset < vc->vc_screenbuf_size) {
                scr_writew(old, screenpos(vc, old_offset, true));
                if (con_should_update(vc))
-                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
+                       con_putc(vc, old, oldy, oldx);
                notify_update(vc);
        }
 
@@ -771,15 +763,14 @@ void complement_pos(struct vc_data *vc, int offset)
        if (offset != -1 && offset >= 0 &&
            offset < vc->vc_screenbuf_size) {
                unsigned short new;
-               unsigned short *p;
-               p = screenpos(vc, offset, true);
+               u16 *p = screenpos(vc, offset, true);
                old = scr_readw(p);
                new = old ^ vc->vc_complement_mask;
                scr_writew(new, p);
                if (con_should_update(vc)) {
                        oldx = (offset >> 1) % vc->vc_cols;
                        oldy = (offset >> 1) / vc->vc_cols;
-                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
+                       con_putc(vc, new, oldy, oldx);
                }
                notify_update(vc);
        }
@@ -833,7 +824,7 @@ static void add_softcursor(struct vc_data *vc)
                i ^= CUR_FG;
        scr_writew(i, (u16 *)vc->vc_pos);
        if (con_should_update(vc))
-               vc->vc_sw->con_putc(vc, i, vc->state.y, vc->state.x);
+               con_putc(vc, i, vc->state.y, vc->state.x);
 }
 
 static void hide_softcursor(struct vc_data *vc)
@@ -841,8 +832,8 @@ static void hide_softcursor(struct vc_data *vc)
        if (softcursor_original != -1) {
                scr_writew(softcursor_original, (u16 *)vc->vc_pos);
                if (con_should_update(vc))
-                       vc->vc_sw->con_putc(vc, softcursor_original,
-                                       vc->state.y, vc->state.x);
+                       con_putc(vc, softcursor_original, vc->state.y,
+                                vc->state.x);
                softcursor_original = -1;
        }
 }
@@ -852,7 +843,7 @@ static void hide_cursor(struct vc_data *vc)
        if (vc_is_sel(vc))
                clear_selection();
 
-       vc->vc_sw->con_cursor(vc, CM_ERASE);
+       vc->vc_sw->con_cursor(vc, false);
        hide_softcursor(vc);
 }
 
@@ -865,7 +856,7 @@ static void set_cursor(struct vc_data *vc)
                        clear_selection();
                add_softcursor(vc);
                if (CUR_SIZE(vc->vc_cursor_type) != CUR_NONE)
-                       vc->vc_sw->con_cursor(vc, CM_DRAW);
+                       vc->vc_sw->con_cursor(vc, true);
        } else
                hide_cursor(vc);
 }
@@ -897,21 +888,18 @@ static void flush_scrollback(struct vc_data *vc)
        WARN_CONSOLE_UNLOCKED();
 
        set_origin(vc);
-       if (vc->vc_sw->con_flush_scrollback) {
-               vc->vc_sw->con_flush_scrollback(vc);
-       } else if (con_is_visible(vc)) {
-               /*
-                * When no con_flush_scrollback method is provided then the
-                * legacy way for flushing the scrollback buffer is to use
-                * a side effect of the con_switch method. We do it only on
-                * the foreground console as background consoles have no
-                * scrollback buffers in that case and we obviously don't
-                * want to switch to them.
-                */
-               hide_cursor(vc);
-               vc->vc_sw->con_switch(vc);
-               set_cursor(vc);
-       }
+       if (!con_is_visible(vc))
+               return;
+
+       /*
+        * The legacy way for flushing the scrollback buffer is to use a side
+        * effect of the con_switch method. We do it only on the foreground
+        * console as background consoles have no scrollback buffers in that
+        * case and we obviously don't want to switch to them.
+        */
+       hide_cursor(vc);
+       vc->vc_sw->con_switch(vc);
+       set_cursor(vc);
 }
 
 /*
@@ -962,7 +950,7 @@ void redraw_screen(struct vc_data *vc, int is_switch)
        }
 
        if (redraw) {
-               int update;
+               bool update;
                int old_was_color = vc->vc_can_do_color;
 
                set_origin(vc);
@@ -999,7 +987,7 @@ int vc_cons_allocated(unsigned int i)
        return (i < MAX_NR_CONSOLES && vc_cons[i].d);
 }
 
-static void visual_init(struct vc_data *vc, int num, int init)
+static void visual_init(struct vc_data *vc, int num, bool init)
 {
        /* ++Geert: vc->vc_sw->con_init determines console size */
        if (vc->vc_sw)
@@ -1083,7 +1071,7 @@ int vc_allocate(unsigned int currcons)    /* return 0 on success */
        vc->port.ops = &vc_port_ops;
        INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
 
-       visual_init(vc, currcons, 1);
+       visual_init(vc, currcons, true);
 
        if (!*vc->uni_pagedict_loc)
                con_set_default_unimap(vc);
@@ -1115,51 +1103,44 @@ err_free:
 }
 
 static inline int resize_screen(struct vc_data *vc, int width, int height,
-                               int user)
+                               bool from_user)
 {
        /* Resizes the resolution of the display adapater */
        int err = 0;
 
        if (vc->vc_sw->con_resize)
-               err = vc->vc_sw->con_resize(vc, width, height, user);
+               err = vc->vc_sw->con_resize(vc, width, height, from_user);
 
        return err;
 }
 
 /**
- *     vc_do_resize    -       resizing method for the tty
- *     @tty: tty being resized
- *     @vc: virtual console private data
- *     @cols: columns
- *     @lines: lines
+ * vc_do_resize - resizing method for the tty
+ * @tty: tty being resized
+ * @vc: virtual console private data
+ * @cols: columns
+ * @lines: lines
+ * @from_user: invoked by a user?
  *
- *     Resize a virtual console, clipping according to the actual constraints.
- *     If the caller passes a tty structure then update the termios winsize
- *     information and perform any necessary signal handling.
+ * Resize a virtual console, clipping according to the actual constraints. If
+ * the caller passes a tty structure then update the termios winsize
+ * information and perform any necessary signal handling.
  *
- *     Caller must hold the console semaphore. Takes the termios rwsem and
- *     ctrl.lock of the tty IFF a tty is passed.
+ * Locking: Caller must hold the console semaphore. Takes the termios rwsem and
+ * ctrl.lock of the tty IFF a tty is passed.
  */
-
 static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
-                               unsigned int cols, unsigned int lines)
+                       unsigned int cols, unsigned int lines, bool from_user)
 {
        unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
        unsigned long end;
        unsigned int old_rows, old_row_size, first_copied_row;
        unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-       unsigned int user;
        unsigned short *oldscreen, *newscreen;
        u32 **new_uniscr = NULL;
 
        WARN_CONSOLE_UNLOCKED();
 
-       if (!vc)
-               return -ENXIO;
-
-       user = vc->vc_resize_user;
-       vc->vc_resize_user = 0;
-
        if (cols > VC_MAXCOL || lines > VC_MAXROW)
                return -EINVAL;
 
@@ -1185,7 +1166,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
                 * to deal with possible errors from the code below, we call
                 * the resize_screen here as well.
                 */
-               return resize_screen(vc, new_cols, new_rows, user);
+               return resize_screen(vc, new_cols, new_rows, from_user);
        }
 
        if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
@@ -1208,7 +1189,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
        old_rows = vc->vc_rows;
        old_row_size = vc->vc_size_row;
 
-       err = resize_screen(vc, new_cols, new_rows, user);
+       err = resize_screen(vc, new_cols, new_rows, from_user);
        if (err) {
                kfree(newscreen);
                vc_uniscr_free(new_uniscr);
@@ -1295,34 +1276,35 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
 }
 
 /**
- *     vc_resize               -       resize a VT
- *     @vc: virtual console
- *     @cols: columns
- *     @rows: rows
+ * __vc_resize - resize a VT
+ * @vc: virtual console
+ * @cols: columns
+ * @rows: rows
+ * @from_user: invoked by a user?
+ *
+ * Resize a virtual console as seen from the console end of things. We use the
+ * common vc_do_resize() method to update the structures.
  *
- *     Resize a virtual console as seen from the console end of things. We
- *     use the common vc_do_resize methods to update the structures. The
- *     caller must hold the console sem to protect console internals and
- *     vc->port.tty
+ * Locking: The caller must hold the console sem to protect console internals
+ * and @vc->port.tty.
  */
-
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows,
+               bool from_user)
 {
-       return vc_do_resize(vc->port.tty, vc, cols, rows);
+       return vc_do_resize(vc->port.tty, vc, cols, rows, from_user);
 }
-EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(__vc_resize);
 
 /**
- *     vt_resize               -       resize a VT
- *     @tty: tty to resize
- *     @ws: winsize attributes
+ * vt_resize - resize a VT
+ * @tty: tty to resize
+ * @ws: winsize attributes
  *
- *     Resize a virtual terminal. This is called by the tty layer as we
- *     register our own handler for resizing. The mutual helper does all
- *     the actual work.
+ * Resize a virtual terminal. This is called by the tty layer as we register
+ * our own handler for resizing. The mutual helper does all the actual work.
  *
- *     Takes the console sem and the called methods then take the tty
- *     termios_rwsem and the tty ctrl.lock in that order.
+ * Locking: Takes the console sem and the called methods then take the tty
+ * termios_rwsem and the tty ctrl.lock in that order.
  */
 static int vt_resize(struct tty_struct *tty, struct winsize *ws)
 {
@@ -1330,7 +1312,7 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
        int ret;
 
        console_lock();
-       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
+       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row, false);
        console_unlock();
        return ret;
 }
@@ -1503,36 +1485,43 @@ static inline void del(struct vc_data *vc)
        /* ignored */
 }
 
-static void csi_J(struct vc_data *vc, int vpar)
+enum CSI_J {
+       CSI_J_CURSOR_TO_END     = 0,
+       CSI_J_START_TO_CURSOR   = 1,
+       CSI_J_VISIBLE           = 2,
+       CSI_J_FULL              = 3,
+};
+
+static void csi_J(struct vc_data *vc, enum CSI_J vpar)
 {
+       unsigned short *start;
        unsigned int count;
-       unsigned short * start;
 
        switch (vpar) {
-               case 0: /* erase from cursor to end of display */
-                       vc_uniscr_clear_line(vc, vc->state.x,
-                                            vc->vc_cols - vc->state.x);
-                       vc_uniscr_clear_lines(vc, vc->state.y + 1,
-                                             vc->vc_rows - vc->state.y - 1);
-                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
-                       start = (unsigned short *)vc->vc_pos;
-                       break;
-               case 1: /* erase from start to cursor */
-                       vc_uniscr_clear_line(vc, 0, vc->state.x + 1);
-                       vc_uniscr_clear_lines(vc, 0, vc->state.y);
-                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
-                       start = (unsigned short *)vc->vc_origin;
-                       break;
-               case 3: /* include scrollback */
-                       flush_scrollback(vc);
-                       fallthrough;
-               case 2: /* erase whole display */
-                       vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
-                       count = vc->vc_cols * vc->vc_rows;
-                       start = (unsigned short *)vc->vc_origin;
-                       break;
-               default:
-                       return;
+       case CSI_J_CURSOR_TO_END:
+               vc_uniscr_clear_line(vc, vc->state.x,
+                                    vc->vc_cols - vc->state.x);
+               vc_uniscr_clear_lines(vc, vc->state.y + 1,
+                                     vc->vc_rows - vc->state.y - 1);
+               count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+               start = (unsigned short *)vc->vc_pos;
+               break;
+       case CSI_J_START_TO_CURSOR:
+               vc_uniscr_clear_line(vc, 0, vc->state.x + 1);
+               vc_uniscr_clear_lines(vc, 0, vc->state.y);
+               count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+               start = (unsigned short *)vc->vc_origin;
+               break;
+       case CSI_J_FULL:
+               flush_scrollback(vc);
+               fallthrough;
+       case CSI_J_VISIBLE:
+               vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
+               count = vc->vc_cols * vc->vc_rows;
+               start = (unsigned short *)vc->vc_origin;
+               break;
+       default:
+               return;
        }
        scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
        if (con_should_update(vc))
@@ -1540,27 +1529,33 @@ static void csi_J(struct vc_data *vc, int vpar)
        vc->vc_need_wrap = 0;
 }
 
-static void csi_K(struct vc_data *vc, int vpar)
+enum {
+       CSI_K_CURSOR_TO_LINEEND         = 0,
+       CSI_K_LINESTART_TO_CURSOR       = 1,
+       CSI_K_LINE                      = 2,
+};
+
+static void csi_K(struct vc_data *vc)
 {
        unsigned int count;
        unsigned short *start = (unsigned short *)vc->vc_pos;
        int offset;
 
-       switch (vpar) {
-               case 0: /* erase from cursor to end of line */
-                       offset = 0;
-                       count = vc->vc_cols - vc->state.x;
-                       break;
-               case 1: /* erase from start of line to cursor */
-                       offset = -vc->state.x;
-                       count = vc->state.x + 1;
-                       break;
-               case 2: /* erase whole line */
-                       offset = -vc->state.x;
-                       count = vc->vc_cols;
-                       break;
-               default:
-                       return;
+       switch (vc->vc_par[0]) {
+       case CSI_K_CURSOR_TO_LINEEND:
+               offset = 0;
+               count = vc->vc_cols - vc->state.x;
+               break;
+       case CSI_K_LINESTART_TO_CURSOR:
+               offset = -vc->state.x;
+               count = vc->state.x + 1;
+               break;
+       case CSI_K_LINE:
+               offset = -vc->state.x;
+               count = vc->vc_cols;
+               break;
+       default:
+               return;
        }
        vc_uniscr_clear_line(vc, vc->state.x + offset, count);
        scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
@@ -1569,20 +1564,15 @@ static void csi_K(struct vc_data *vc, int vpar)
                do_update_region(vc, (unsigned long)(start + offset), count);
 }
 
-/* erase the following vpar positions */
-static void csi_X(struct vc_data *vc, unsigned int vpar)
+/* erase the following count positions */
+static void csi_X(struct vc_data *vc)
 {                                        /* not vt100? */
-       unsigned int count;
-
-       if (!vpar)
-               vpar++;
-
-       count = min(vpar, vc->vc_cols - vc->state.x);
+       unsigned int count = clamp(vc->vc_par[0], 1, vc->vc_cols - vc->state.x);
 
        vc_uniscr_clear_line(vc, vc->state.x, count);
        scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
        if (con_should_update(vc))
-               vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, 1, count);
+               vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, count);
        vc->vc_need_wrap = 0;
 }
 
@@ -1598,7 +1588,7 @@ static void default_attr(struct vc_data *vc)
 
 struct rgb { u8 r; u8 g; u8 b; };
 
-static void rgb_from_256(int i, struct rgb *c)
+static void rgb_from_256(unsigned int i, struct rgb *c)
 {
        if (i < 8) {            /* Standard colours. */
                c->r = i&1 ? 0xaa : 0x00;
@@ -1609,9 +1599,12 @@ static void rgb_from_256(int i, struct rgb *c)
                c->g = i&2 ? 0xff : 0x55;
                c->b = i&4 ? 0xff : 0x55;
        } else if (i < 232) {   /* 6x6x6 colour cube. */
-               c->r = (i - 16) / 36 * 85 / 2;
-               c->g = (i - 16) / 6 % 6 * 85 / 2;
-               c->b = (i - 16) % 6 * 85 / 2;
+               i -= 16;
+               c->b = i % 6 * 255 / 6;
+               i /= 6;
+               c->g = i % 6 * 255 / 6;
+               i /= 6;
+               c->r = i     * 255 / 6;
        } else                  /* Grayscale ramp. */
                c->r = c->g = c->b = i * 10 - 2312;
 }
@@ -1681,6 +1674,39 @@ static int vc_t416_color(struct vc_data *vc, int i,
        return i;
 }
 
+enum {
+       CSI_m_DEFAULT                   = 0,
+       CSI_m_BOLD                      = 1,
+       CSI_m_HALF_BRIGHT               = 2,
+       CSI_m_ITALIC                    = 3,
+       CSI_m_UNDERLINE                 = 4,
+       CSI_m_BLINK                     = 5,
+       CSI_m_REVERSE                   = 7,
+       CSI_m_PRI_FONT                  = 10,
+       CSI_m_ALT_FONT1                 = 11,
+       CSI_m_ALT_FONT2                 = 12,
+       CSI_m_DOUBLE_UNDERLINE          = 21,
+       CSI_m_NORMAL_INTENSITY          = 22,
+       CSI_m_NO_ITALIC                 = 23,
+       CSI_m_NO_UNDERLINE              = 24,
+       CSI_m_NO_BLINK                  = 25,
+       CSI_m_NO_REVERSE                = 27,
+       CSI_m_FG_COLOR_BEG              = 30,
+       CSI_m_FG_COLOR_END              = 37,
+       CSI_m_FG_COLOR                  = 38,
+       CSI_m_DEFAULT_FG_COLOR          = 39,
+       CSI_m_BG_COLOR_BEG              = 40,
+       CSI_m_BG_COLOR_END              = 47,
+       CSI_m_BG_COLOR                  = 48,
+       CSI_m_DEFAULT_BG_COLOR          = 49,
+       CSI_m_BRIGHT_FG_COLOR_BEG       = 90,
+       CSI_m_BRIGHT_FG_COLOR_END       = 97,
+       CSI_m_BRIGHT_FG_COLOR_OFF       = CSI_m_BRIGHT_FG_COLOR_BEG - CSI_m_FG_COLOR_BEG,
+       CSI_m_BRIGHT_BG_COLOR_BEG       = 100,
+       CSI_m_BRIGHT_BG_COLOR_END       = 107,
+       CSI_m_BRIGHT_BG_COLOR_OFF       = CSI_m_BRIGHT_BG_COLOR_BEG - CSI_m_BG_COLOR_BEG,
+};
+
 /* console_lock is held */
 static void csi_m(struct vc_data *vc)
 {
@@ -1688,33 +1714,33 @@ static void csi_m(struct vc_data *vc)
 
        for (i = 0; i <= vc->vc_npar; i++)
                switch (vc->vc_par[i]) {
-               case 0: /* all attributes off */
+               case CSI_m_DEFAULT:     /* all attributes off */
                        default_attr(vc);
                        break;
-               case 1:
+               case CSI_m_BOLD:
                        vc->state.intensity = VCI_BOLD;
                        break;
-               case 2:
+               case CSI_m_HALF_BRIGHT:
                        vc->state.intensity = VCI_HALF_BRIGHT;
                        break;
-               case 3:
+               case CSI_m_ITALIC:
                        vc->state.italic = true;
                        break;
-               case 21:
+               case CSI_m_DOUBLE_UNDERLINE:
                        /*
                         * No console drivers support double underline, so
                         * convert it to a single underline.
                         */
-               case 4:
+               case CSI_m_UNDERLINE:
                        vc->state.underline = true;
                        break;
-               case 5:
+               case CSI_m_BLINK:
                        vc->state.blink = true;
                        break;
-               case 7:
+               case CSI_m_REVERSE:
                        vc->state.reverse = true;
                        break;
-               case 10: /* ANSI X3.64-1979 (SCO-ish?)
+               case CSI_m_PRI_FONT: /* ANSI X3.64-1979 (SCO-ish?)
                          * Select primary font, don't display control chars if
                          * defined, don't set bit 8 on output.
                          */
@@ -1722,7 +1748,7 @@ static void csi_m(struct vc_data *vc)
                        vc->vc_disp_ctrl = 0;
                        vc->vc_toggle_meta = 0;
                        break;
-               case 11: /* ANSI X3.64-1979 (SCO-ish?)
+               case CSI_m_ALT_FONT1: /* ANSI X3.64-1979 (SCO-ish?)
                          * Select first alternate font, lets chars < 32 be
                          * displayed as ROM chars.
                          */
@@ -1730,7 +1756,7 @@ static void csi_m(struct vc_data *vc)
                        vc->vc_disp_ctrl = 1;
                        vc->vc_toggle_meta = 0;
                        break;
-               case 12: /* ANSI X3.64-1979 (SCO-ish?)
+               case CSI_m_ALT_FONT2: /* ANSI X3.64-1979 (SCO-ish?)
                          * Select second alternate font, toggle high bit
                          * before displaying as ROM char.
                          */
@@ -1738,47 +1764,51 @@ static void csi_m(struct vc_data *vc)
                        vc->vc_disp_ctrl = 1;
                        vc->vc_toggle_meta = 1;
                        break;
-               case 22:
+               case CSI_m_NORMAL_INTENSITY:
                        vc->state.intensity = VCI_NORMAL;
                        break;
-               case 23:
+               case CSI_m_NO_ITALIC:
                        vc->state.italic = false;
                        break;
-               case 24:
+               case CSI_m_NO_UNDERLINE:
                        vc->state.underline = false;
                        break;
-               case 25:
+               case CSI_m_NO_BLINK:
                        vc->state.blink = false;
                        break;
-               case 27:
+               case CSI_m_NO_REVERSE:
                        vc->state.reverse = false;
                        break;
-               case 38:
+               case CSI_m_FG_COLOR:
                        i = vc_t416_color(vc, i, rgb_foreground);
                        break;
-               case 48:
+               case CSI_m_BG_COLOR:
                        i = vc_t416_color(vc, i, rgb_background);
                        break;
-               case 39:
+               case CSI_m_DEFAULT_FG_COLOR:
                        vc->state.color = (vc->vc_def_color & 0x0f) |
                                (vc->state.color & 0xf0);
                        break;
-               case 49:
+               case CSI_m_DEFAULT_BG_COLOR:
                        vc->state.color = (vc->vc_def_color & 0xf0) |
                                (vc->state.color & 0x0f);
                        break;
-               default:
-                       if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
-                               if (vc->vc_par[i] < 100)
-                                       vc->state.intensity = VCI_BOLD;
-                               vc->vc_par[i] -= 60;
-                       }
-                       if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
-                               vc->state.color = color_table[vc->vc_par[i] - 30]
-                                       | (vc->state.color & 0xf0);
-                       else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
-                               vc->state.color = (color_table[vc->vc_par[i] - 40] << 4)
-                                       | (vc->state.color & 0x0f);
+               case CSI_m_BRIGHT_FG_COLOR_BEG ... CSI_m_BRIGHT_FG_COLOR_END:
+                       vc->state.intensity = VCI_BOLD;
+                       vc->vc_par[i] -= CSI_m_BRIGHT_FG_COLOR_OFF;
+                       fallthrough;
+               case CSI_m_FG_COLOR_BEG ... CSI_m_FG_COLOR_END:
+                       vc->vc_par[i] -= CSI_m_FG_COLOR_BEG;
+                       vc->state.color = color_table[vc->vc_par[i]] |
+                               (vc->state.color & 0xf0);
+                       break;
+               case CSI_m_BRIGHT_BG_COLOR_BEG ... CSI_m_BRIGHT_BG_COLOR_END:
+                       vc->vc_par[i] -= CSI_m_BRIGHT_BG_COLOR_OFF;
+                       fallthrough;
+               case CSI_m_BG_COLOR_BEG ... CSI_m_BG_COLOR_END:
+                       vc->vc_par[i] -= CSI_m_BG_COLOR_BEG;
+                       vc->state.color = (color_table[vc->vc_par[i]] << 4) |
+                               (vc->state.color & 0x0f);
                        break;
                }
        update_attr(vc);
@@ -1832,133 +1862,175 @@ int mouse_reporting(void)
        return vc_cons[fg_console].d->vc_report_mouse;
 }
 
+enum {
+       CSI_DEC_hl_CURSOR_KEYS  = 1,    /* CKM: cursor keys send ^[Ox/^[[x */
+       CSI_DEC_hl_132_COLUMNS  = 3,    /* COLM: 80/132 mode switch */
+       CSI_DEC_hl_REVERSE_VIDEO = 5,   /* SCNM */
+       CSI_DEC_hl_ORIGIN_MODE  = 6,    /* OM: origin relative/absolute */
+       CSI_DEC_hl_AUTOWRAP     = 7,    /* AWM */
+       CSI_DEC_hl_AUTOREPEAT   = 8,    /* ARM */
+       CSI_DEC_hl_MOUSE_X10    = 9,
+       CSI_DEC_hl_SHOW_CURSOR  = 25,   /* TCEM */
+       CSI_DEC_hl_MOUSE_VT200  = 1000,
+};
+
 /* console_lock is held */
-static void set_mode(struct vc_data *vc, int on_off)
+static void csi_DEC_hl(struct vc_data *vc, bool on_off)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i <= vc->vc_npar; i++)
-               if (vc->vc_priv == EPdec) {
-                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
-                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
-                               if (on_off)
-                                       set_kbd(vc, decckm);
-                               else
-                                       clr_kbd(vc, decckm);
-                               break;
-                       case 3: /* 80/132 mode switch unimplemented */
+               switch (vc->vc_par[i]) {
+               case CSI_DEC_hl_CURSOR_KEYS:
+                       if (on_off)
+                               set_kbd(vc, decckm);
+                       else
+                               clr_kbd(vc, decckm);
+                       break;
+               case CSI_DEC_hl_132_COLUMNS:    /* unimplemented */
 #if 0
-                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
-                               /* this alone does not suffice; some user mode
-                                  utility has to change the hardware regs */
+                       vc_resize(deccolm ? 132 : 80, vc->vc_rows);
+                       /* this alone does not suffice; some user mode
+                          utility has to change the hardware regs */
 #endif
-                               break;
-                       case 5:                 /* Inverted screen on/off */
-                               if (vc->vc_decscnm != on_off) {
-                                       vc->vc_decscnm = on_off;
-                                       invert_screen(vc, 0,
-                                                       vc->vc_screenbuf_size,
-                                                       false);
-                                       update_attr(vc);
-                               }
-                               break;
-                       case 6:                 /* Origin relative/absolute */
-                               vc->vc_decom = on_off;
-                               gotoxay(vc, 0, 0);
-                               break;
-                       case 7:                 /* Autowrap on/off */
-                               vc->vc_decawm = on_off;
-                               break;
-                       case 8:                 /* Autorepeat on/off */
-                               if (on_off)
-                                       set_kbd(vc, decarm);
-                               else
-                                       clr_kbd(vc, decarm);
-                               break;
-                       case 9:
-                               vc->vc_report_mouse = on_off ? 1 : 0;
-                               break;
-                       case 25:                /* Cursor on/off */
-                               vc->vc_deccm = on_off;
-                               break;
-                       case 1000:
-                               vc->vc_report_mouse = on_off ? 2 : 0;
-                               break;
-                       }
-               } else {
-                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
-                       case 3:                 /* Monitor (display ctrls) */
-                               vc->vc_disp_ctrl = on_off;
-                               break;
-                       case 4:                 /* Insert Mode on/off */
-                               vc->vc_decim = on_off;
-                               break;
-                       case 20:                /* Lf, Enter == CrLf/Lf */
-                               if (on_off)
-                                       set_kbd(vc, lnm);
-                               else
-                                       clr_kbd(vc, lnm);
-                               break;
+                       break;
+               case CSI_DEC_hl_REVERSE_VIDEO:
+                       if (vc->vc_decscnm != on_off) {
+                               vc->vc_decscnm = on_off;
+                               invert_screen(vc, 0, vc->vc_screenbuf_size,
+                                             false);
+                               update_attr(vc);
                        }
+                       break;
+               case CSI_DEC_hl_ORIGIN_MODE:
+                       vc->vc_decom = on_off;
+                       gotoxay(vc, 0, 0);
+                       break;
+               case CSI_DEC_hl_AUTOWRAP:
+                       vc->vc_decawm = on_off;
+                       break;
+               case CSI_DEC_hl_AUTOREPEAT:
+                       if (on_off)
+                               set_kbd(vc, decarm);
+                       else
+                               clr_kbd(vc, decarm);
+                       break;
+               case CSI_DEC_hl_MOUSE_X10:
+                       vc->vc_report_mouse = on_off ? 1 : 0;
+                       break;
+               case CSI_DEC_hl_SHOW_CURSOR:
+                       vc->vc_deccm = on_off;
+                       break;
+               case CSI_DEC_hl_MOUSE_VT200:
+                       vc->vc_report_mouse = on_off ? 2 : 0;
+                       break;
                }
 }
 
+enum {
+       CSI_hl_DISPLAY_CTRL     = 3,    /* handle ansi control chars */
+       CSI_hl_INSERT           = 4,    /* IRM: insert/replace */
+       CSI_hl_AUTO_NL          = 20,   /* LNM: Enter == CrLf/Lf */
+};
+
 /* console_lock is held */
-static void setterm_command(struct vc_data *vc)
+static void csi_hl(struct vc_data *vc, bool on_off)
+{
+       unsigned int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               switch (vc->vc_par[i]) {        /* ANSI modes set/reset */
+               case CSI_hl_DISPLAY_CTRL:
+                       vc->vc_disp_ctrl = on_off;
+                       break;
+               case CSI_hl_INSERT:
+                       vc->vc_decim = on_off;
+                       break;
+               case CSI_hl_AUTO_NL:
+                       if (on_off)
+                               set_kbd(vc, lnm);
+                       else
+                               clr_kbd(vc, lnm);
+                       break;
+               }
+}
+
+enum CSI_right_square_bracket {
+       CSI_RSB_COLOR_FOR_UNDERLINE             = 1,
+       CSI_RSB_COLOR_FOR_HALF_BRIGHT           = 2,
+       CSI_RSB_MAKE_CUR_COLOR_DEFAULT          = 8,
+       CSI_RSB_BLANKING_INTERVAL               = 9,
+       CSI_RSB_BELL_FREQUENCY                  = 10,
+       CSI_RSB_BELL_DURATION                   = 11,
+       CSI_RSB_BRING_CONSOLE_TO_FRONT          = 12,
+       CSI_RSB_UNBLANK                         = 13,
+       CSI_RSB_VESA_OFF_INTERVAL               = 14,
+       CSI_RSB_BRING_PREV_CONSOLE_TO_FRONT     = 15,
+       CSI_RSB_CURSOR_BLINK_INTERVAL           = 16,
+};
+
+/*
+ * csi_RSB - csi+] (Right Square Bracket) handler
+ *
+ * These are linux console private sequences.
+ *
+ * console_lock is held
+ */
+static void csi_RSB(struct vc_data *vc)
 {
        switch (vc->vc_par[0]) {
-       case 1: /* set color for underline mode */
+       case CSI_RSB_COLOR_FOR_UNDERLINE:
                if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
                        vc->vc_ulcolor = color_table[vc->vc_par[1]];
                        if (vc->state.underline)
                                update_attr(vc);
                }
                break;
-       case 2: /* set color for half intensity mode */
+       case CSI_RSB_COLOR_FOR_HALF_BRIGHT:
                if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
                        vc->vc_halfcolor = color_table[vc->vc_par[1]];
                        if (vc->state.intensity == VCI_HALF_BRIGHT)
                                update_attr(vc);
                }
                break;
-       case 8: /* store colors as defaults */
+       case CSI_RSB_MAKE_CUR_COLOR_DEFAULT:
                vc->vc_def_color = vc->vc_attr;
                if (vc->vc_hi_font_mask == 0x100)
                        vc->vc_def_color >>= 1;
                default_attr(vc);
                update_attr(vc);
                break;
-       case 9: /* set blanking interval */
+       case CSI_RSB_BLANKING_INTERVAL:
                blankinterval = min(vc->vc_par[1], 60U) * 60;
                poke_blanked_console();
                break;
-       case 10: /* set bell frequency in Hz */
+       case CSI_RSB_BELL_FREQUENCY:
                if (vc->vc_npar >= 1)
                        vc->vc_bell_pitch = vc->vc_par[1];
                else
                        vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
                break;
-       case 11: /* set bell duration in msec */
+       case CSI_RSB_BELL_DURATION:
                if (vc->vc_npar >= 1)
                        vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
                                msecs_to_jiffies(vc->vc_par[1]) : 0;
                else
                        vc->vc_bell_duration = DEFAULT_BELL_DURATION;
                break;
-       case 12: /* bring specified console to the front */
+       case CSI_RSB_BRING_CONSOLE_TO_FRONT:
                if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
                        set_console(vc->vc_par[1] - 1);
                break;
-       case 13: /* unblank the screen */
+       case CSI_RSB_UNBLANK:
                poke_blanked_console();
                break;
-       case 14: /* set vesa powerdown interval */
+       case CSI_RSB_VESA_OFF_INTERVAL:
                vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ;
                break;
-       case 15: /* activate the previous console */
+       case CSI_RSB_BRING_PREV_CONSOLE_TO_FRONT:
                set_console(last_console);
                break;
-       case 16: /* set cursor blink duration in msec */
+       case CSI_RSB_CURSOR_BLINK_INTERVAL:
                if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
                                vc->vc_par[1] <= USHRT_MAX)
                        vc->vc_cur_blink_ms = vc->vc_par[1];
@@ -1971,41 +2043,32 @@ static void setterm_command(struct vc_data *vc)
 /* console_lock is held */
 static void csi_at(struct vc_data *vc, unsigned int nr)
 {
-       if (nr > vc->vc_cols - vc->state.x)
-               nr = vc->vc_cols - vc->state.x;
-       else if (!nr)
-               nr = 1;
+       nr = clamp(nr, 1, vc->vc_cols - vc->state.x);
        insert_char(vc, nr);
 }
 
 /* console_lock is held */
-static void csi_L(struct vc_data *vc, unsigned int nr)
+static void csi_L(struct vc_data *vc)
 {
-       if (nr > vc->vc_rows - vc->state.y)
-               nr = vc->vc_rows - vc->state.y;
-       else if (!nr)
-               nr = 1;
+       unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_rows - vc->state.y);
+
        con_scroll(vc, vc->state.y, vc->vc_bottom, SM_DOWN, nr);
        vc->vc_need_wrap = 0;
 }
 
 /* console_lock is held */
-static void csi_P(struct vc_data *vc, unsigned int nr)
+static void csi_P(struct vc_data *vc)
 {
-       if (nr > vc->vc_cols - vc->state.x)
-               nr = vc->vc_cols - vc->state.x;
-       else if (!nr)
-               nr = 1;
+       unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_cols - vc->state.x);
+
        delete_char(vc, nr);
 }
 
 /* console_lock is held */
-static void csi_M(struct vc_data *vc, unsigned int nr)
+static void csi_M(struct vc_data *vc)
 {
-       if (nr > vc->vc_rows - vc->state.y)
-               nr = vc->vc_rows - vc->state.y;
-       else if (!nr)
-               nr=1;
+       unsigned int nr = clamp(vc->vc_par[0], 1, vc->vc_rows - vc->state.y);
+
        con_scroll(vc, vc->state.y, vc->vc_bottom, SM_UP, nr);
        vc->vc_need_wrap = 0;
 }
@@ -2028,9 +2091,48 @@ static void restore_cur(struct vc_data *vc)
        vc->vc_need_wrap = 0;
 }
 
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
-       EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
-       ESpalette, ESosc, ESapc, ESpm, ESdcs };
+/**
+ * enum vc_ctl_state - control characters state of a vt
+ *
+ * @ESnormal:          initial state, no control characters parsed
+ * @ESesc:             ESC parsed
+ * @ESsquare:          CSI parsed -- modifiers/parameters/ctrl chars expected
+ * @ESgetpars:         CSI parsed -- parameters/ctrl chars expected
+ * @ESfunckey:         CSI [ parsed
+ * @EShash:            ESC # parsed
+ * @ESsetG0:           ESC ( parsed
+ * @ESsetG1:           ESC ) parsed
+ * @ESpercent:         ESC % parsed
+ * @EScsiignore:       CSI [0x20-0x3f] parsed
+ * @ESnonstd:          OSC parsed
+ * @ESpalette:         OSC P parsed
+ * @ESosc:             OSC [0-9] parsed
+ * @ESANSI_first:      first state for ignoring ansi control sequences
+ * @ESapc:             ESC _ parsed
+ * @ESpm:              ESC ^ parsed
+ * @ESdcs:             ESC P parsed
+ * @ESANSI_last:       last state for ignoring ansi control sequences
+ */
+enum vc_ctl_state {
+       ESnormal,
+       ESesc,
+       ESsquare,
+       ESgetpars,
+       ESfunckey,
+       EShash,
+       ESsetG0,
+       ESsetG1,
+       ESpercent,
+       EScsiignore,
+       ESnonstd,
+       ESpalette,
+       ESosc,
+       ESANSI_first = ESosc,
+       ESapc,
+       ESpm,
+       ESdcs,
+       ESANSI_last = ESdcs,
+};
 
 /* console_lock is held (except via vc_init()) */
 static void reset_terminal(struct vc_data *vc, int do_clear)
@@ -2078,10 +2180,10 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
        gotoxy(vc, 0, 0);
        save_cur(vc);
        if (do_clear)
-           csi_J(vc, 2);
+           csi_J(vc, CSI_J_VISIBLE);
 }
 
-static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
+static void vc_setGx(struct vc_data *vc, unsigned int which, u8 c)
 {
        unsigned char *charset = &vc->state.Gx_charset[which];
 
@@ -2104,36 +2206,54 @@ static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
                vc->vc_translate = set_translate(*charset, vc);
 }
 
-/* is this state an ANSI control string? */
-static bool ansi_control_string(unsigned int state)
+static bool ansi_control_string(enum vc_ctl_state state)
 {
-       if (state == ESosc || state == ESapc || state == ESpm || state == ESdcs)
-               return true;
-       return false;
+       return state >= ESANSI_first && state <= ESANSI_last;
 }
 
-/* console_lock is held */
-static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
+enum {
+       ASCII_NULL              = 0,
+       ASCII_BELL              = 7,
+       ASCII_BACKSPACE         = 8,
+       ASCII_IGNORE_FIRST      = ASCII_BACKSPACE,
+       ASCII_HTAB              = 9,
+       ASCII_LINEFEED          = 10,
+       ASCII_VTAB              = 11,
+       ASCII_FORMFEED          = 12,
+       ASCII_CAR_RET           = 13,
+       ASCII_IGNORE_LAST       = ASCII_CAR_RET,
+       ASCII_SHIFTOUT          = 14,
+       ASCII_SHIFTIN           = 15,
+       ASCII_CANCEL            = 24,
+       ASCII_SUBSTITUTE        = 26,
+       ASCII_ESCAPE            = 27,
+       ASCII_CSI_IGNORE_FIRST  = ' ', /* 0x2x, 0x3a and 0x3c - 0x3f */
+       ASCII_CSI_IGNORE_LAST   = '?',
+       ASCII_DEL               = 127,
+       ASCII_EXT_CSI           = 128 + ASCII_ESCAPE,
+};
+
+/*
+ * Handle ascii characters in control sequences and change states accordingly.
+ * E.g. ESC sets the state of vc to ESesc.
+ *
+ * Returns: true if @c handled.
+ */
+static bool handle_ascii(struct tty_struct *tty, struct vc_data *vc, u8 c)
 {
-       /*
-        *  Control characters can be used in the _middle_
-        *  of an escape sequence, aside from ANSI control strings.
-        */
-       if (ansi_control_string(vc->vc_state) && c >= 8 && c <= 13)
-               return;
        switch (c) {
-       case 0:
-               return;
-       case 7:
+       case ASCII_NULL:
+               return true;
+       case ASCII_BELL:
                if (ansi_control_string(vc->vc_state))
                        vc->vc_state = ESnormal;
                else if (vc->vc_bell_duration)
                        kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
-               return;
-       case 8:
+               return true;
+       case ASCII_BACKSPACE:
                bs(vc);
-               return;
-       case 9:
+               return true;
+       case ASCII_HTAB:
                vc->vc_pos -= (vc->state.x << 1);
 
                vc->state.x = find_next_bit(vc->vc_tab_stop,
@@ -2144,119 +2264,330 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
 
                vc->vc_pos += (vc->state.x << 1);
                notify_write(vc, '\t');
-               return;
-       case 10: case 11: case 12:
+               return true;
+       case ASCII_LINEFEED:
+       case ASCII_VTAB:
+       case ASCII_FORMFEED:
                lf(vc);
                if (!is_kbd(vc, lnm))
-                       return;
+                       return true;
                fallthrough;
-       case 13:
+       case ASCII_CAR_RET:
                cr(vc);
-               return;
-       case 14:
+               return true;
+       case ASCII_SHIFTOUT:
                vc->state.charset = 1;
                vc->vc_translate = set_translate(vc->state.Gx_charset[1], vc);
                vc->vc_disp_ctrl = 1;
-               return;
-       case 15:
+               return true;
+       case ASCII_SHIFTIN:
                vc->state.charset = 0;
                vc->vc_translate = set_translate(vc->state.Gx_charset[0], vc);
                vc->vc_disp_ctrl = 0;
-               return;
-       case 24: case 26:
+               return true;
+       case ASCII_CANCEL:
+       case ASCII_SUBSTITUTE:
                vc->vc_state = ESnormal;
-               return;
-       case 27:
+               return true;
+       case ASCII_ESCAPE:
                vc->vc_state = ESesc;
-               return;
-       case 127:
+               return true;
+       case ASCII_DEL:
                del(vc);
-               return;
-       case 128+27:
+               return true;
+       case ASCII_EXT_CSI:
                vc->vc_state = ESsquare;
-               return;
+               return true;
        }
-       switch(vc->vc_state) {
-       case ESesc:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '[':
-                       vc->vc_state = ESsquare;
-                       return;
-               case ']':
-                       vc->vc_state = ESnonstd;
-                       return;
-               case '_':
-                       vc->vc_state = ESapc;
-                       return;
-               case '^':
-                       vc->vc_state = ESpm;
-                       return;
-               case '%':
-                       vc->vc_state = ESpercent;
-                       return;
-               case 'E':
-                       cr(vc);
-                       lf(vc);
-                       return;
-               case 'M':
-                       ri(vc);
-                       return;
-               case 'D':
-                       lf(vc);
-                       return;
-               case 'H':
-                       if (vc->state.x < VC_TABSTOPS_COUNT)
-                               set_bit(vc->state.x, vc->vc_tab_stop);
-                       return;
-               case 'P':
-                       vc->vc_state = ESdcs;
-                       return;
-               case 'Z':
+
+       return false;
+}
+
+/*
+ * Handle a character (@c) following an ESC (when @vc is in the ESesc state).
+ * E.g. previous ESC with @c == '[' here yields the ESsquare state (that is:
+ * CSI).
+ */
+static void handle_esc(struct tty_struct *tty, struct vc_data *vc, u8 c)
+{
+       vc->vc_state = ESnormal;
+       switch (c) {
+       case '[':
+               vc->vc_state = ESsquare;
+               break;
+       case ']':
+               vc->vc_state = ESnonstd;
+               break;
+       case '_':
+               vc->vc_state = ESapc;
+               break;
+       case '^':
+               vc->vc_state = ESpm;
+               break;
+       case '%':
+               vc->vc_state = ESpercent;
+               break;
+       case 'E':
+               cr(vc);
+               lf(vc);
+               break;
+       case 'M':
+               ri(vc);
+               break;
+       case 'D':
+               lf(vc);
+               break;
+       case 'H':
+               if (vc->state.x < VC_TABSTOPS_COUNT)
+                       set_bit(vc->state.x, vc->vc_tab_stop);
+               break;
+       case 'P':
+               vc->vc_state = ESdcs;
+               break;
+       case 'Z':
+               respond_ID(tty);
+               break;
+       case '7':
+               save_cur(vc);
+               break;
+       case '8':
+               restore_cur(vc);
+               break;
+       case '(':
+               vc->vc_state = ESsetG0;
+               break;
+       case ')':
+               vc->vc_state = ESsetG1;
+               break;
+       case '#':
+               vc->vc_state = EShash;
+               break;
+       case 'c':
+               reset_terminal(vc, 1);
+               break;
+       case '>':  /* Numeric keypad */
+               clr_kbd(vc, kbdapplic);
+               break;
+       case '=':  /* Appl. keypad */
+               set_kbd(vc, kbdapplic);
+               break;
+       }
+}
+
+/*
+ * Handle special DEC control sequences ("ESC [ ? parameters char"). Parameters
+ * are in @vc->vc_par and the char is in @c here.
+ */
+static void csi_DEC(struct tty_struct *tty, struct vc_data *vc, u8 c)
+{
+       switch (c) {
+       case 'h':
+               csi_DEC_hl(vc, true);
+               break;
+       case 'l':
+               csi_DEC_hl(vc, false);
+               break;
+       case 'c':
+               if (vc->vc_par[0])
+                       vc->vc_cursor_type = CUR_MAKE(vc->vc_par[0],
+                                                     vc->vc_par[1],
+                                                     vc->vc_par[2]);
+               else
+                       vc->vc_cursor_type = cur_default;
+               break;
+       case 'm':
+               clear_selection();
+               if (vc->vc_par[0])
+                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
+               else
+                       vc->vc_complement_mask = vc->vc_s_complement_mask;
+               break;
+       case 'n':
+               if (vc->vc_par[0] == 5)
+                       status_report(tty);
+               else if (vc->vc_par[0] == 6)
+                       cursor_report(vc, tty);
+               break;
+       }
+}
+
+/*
+ * Handle Control Sequence Introducer control characters. That is
+ * "ESC [ parameters char". Parameters are in @vc->vc_par and the char is in
+ * @c here.
+ */
+static void csi_ECMA(struct tty_struct *tty, struct vc_data *vc, u8 c)
+{
+       switch (c) {
+       case 'G':
+       case '`':
+               if (vc->vc_par[0])
+                       vc->vc_par[0]--;
+               gotoxy(vc, vc->vc_par[0], vc->state.y);
+               break;
+       case 'A':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]);
+               break;
+       case 'B':
+       case 'e':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]);
+               break;
+       case 'C':
+       case 'a':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y);
+               break;
+       case 'D':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y);
+               break;
+       case 'E':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, 0, vc->state.y + vc->vc_par[0]);
+               break;
+       case 'F':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               gotoxy(vc, 0, vc->state.y - vc->vc_par[0]);
+               break;
+       case 'd':
+               if (vc->vc_par[0])
+                       vc->vc_par[0]--;
+               gotoxay(vc, vc->state.x ,vc->vc_par[0]);
+               break;
+       case 'H':
+       case 'f':
+               if (vc->vc_par[0])
+                       vc->vc_par[0]--;
+               if (vc->vc_par[1])
+                       vc->vc_par[1]--;
+               gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
+               break;
+       case 'J':
+               csi_J(vc, vc->vc_par[0]);
+               break;
+       case 'K':
+               csi_K(vc);
+               break;
+       case 'L':
+               csi_L(vc);
+               break;
+       case 'M':
+               csi_M(vc);
+               break;
+       case 'P':
+               csi_P(vc);
+               break;
+       case 'c':
+               if (!vc->vc_par[0])
                        respond_ID(tty);
-                       return;
-               case '7':
-                       save_cur(vc);
-                       return;
-               case '8':
-                       restore_cur(vc);
-                       return;
-               case '(':
-                       vc->vc_state = ESsetG0;
-                       return;
-               case ')':
-                       vc->vc_state = ESsetG1;
-                       return;
-               case '#':
-                       vc->vc_state = EShash;
-                       return;
-               case 'c':
-                       reset_terminal(vc, 1);
-                       return;
-               case '>':  /* Numeric keypad */
-                       clr_kbd(vc, kbdapplic);
-                       return;
-               case '=':  /* Appl. keypad */
-                       set_kbd(vc, kbdapplic);
-                       return;
+               break;
+       case 'g':
+               if (!vc->vc_par[0] && vc->state.x < VC_TABSTOPS_COUNT)
+                       set_bit(vc->state.x, vc->vc_tab_stop);
+               else if (vc->vc_par[0] == 3)
+                       bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT);
+               break;
+       case 'h':
+               csi_hl(vc, true);
+               break;
+       case 'l':
+               csi_hl(vc, false);
+               break;
+       case 'm':
+               csi_m(vc);
+               break;
+       case 'n':
+               if (vc->vc_par[0] == 5)
+                       status_report(tty);
+               else if (vc->vc_par[0] == 6)
+                       cursor_report(vc, tty);
+               break;
+       case 'q': /* DECLL - but only 3 leds */
+               /* map 0,1,2,3 to 0,1,2,4 */
+               if (vc->vc_par[0] < 4)
+                       vt_set_led_state(vc->vc_num,
+                                   (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
+               break;
+       case 'r':
+               if (!vc->vc_par[0])
+                       vc->vc_par[0]++;
+               if (!vc->vc_par[1])
+                       vc->vc_par[1] = vc->vc_rows;
+               /* Minimum allowed region is 2 lines */
+               if (vc->vc_par[0] < vc->vc_par[1] &&
+                   vc->vc_par[1] <= vc->vc_rows) {
+                       vc->vc_top = vc->vc_par[0] - 1;
+                       vc->vc_bottom = vc->vc_par[1];
+                       gotoxay(vc, 0, 0);
                }
+               break;
+       case 's':
+               save_cur(vc);
+               break;
+       case 'u':
+               restore_cur(vc);
+               break;
+       case 'X':
+               csi_X(vc);
+               break;
+       case '@':
+               csi_at(vc, vc->vc_par[0]);
+               break;
+       case ']':
+               csi_RSB(vc);
+               break;
+       }
+
+}
+
+static void vc_reset_params(struct vc_data *vc)
+{
+       memset(vc->vc_par, 0, sizeof(vc->vc_par));
+       vc->vc_npar = 0;
+}
+
+/* console_lock is held */
+static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c)
+{
+       /*
+        *  Control characters can be used in the _middle_
+        *  of an escape sequence, aside from ANSI control strings.
+        */
+       if (ansi_control_string(vc->vc_state) && c >= ASCII_IGNORE_FIRST &&
+           c <= ASCII_IGNORE_LAST)
+               return;
+
+       if (handle_ascii(tty, vc, c))
+               return;
+
+       switch(vc->vc_state) {
+       case ESesc:     /* ESC */
+               handle_esc(tty, vc, c);
                return;
-       case ESnonstd:
-               if (c=='P') {   /* palette escape sequence */
-                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                               vc->vc_par[vc->vc_npar] = 0;
-                       vc->vc_npar = 0;
+       case ESnonstd:  /* ESC ] aka OSC */
+               switch (c) {
+               case 'P': /* palette escape sequence */
+                       vc_reset_params(vc);
                        vc->vc_state = ESpalette;
                        return;
-               } else if (c=='R') {   /* reset palette */
+               case 'R': /* reset palette */
                        reset_palette(vc);
-                       vc->vc_state = ESnormal;
-               } else if (c>='0' && c<='9')
+                       break;
+               case '0' ... '9':
                        vc->vc_state = ESosc;
-               else
-                       vc->vc_state = ESnormal;
+                       return;
+               }
+               vc->vc_state = ESnormal;
                return;
-       case ESpalette:
+       case ESpalette: /* ESC ] P aka OSC P */
                if (isxdigit(c)) {
                        vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
                        if (vc->vc_npar == 7) {
@@ -2273,16 +2604,14 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                } else
                        vc->vc_state = ESnormal;
                return;
-       case ESsquare:
-               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                       vc->vc_par[vc->vc_npar] = 0;
-               vc->vc_npar = 0;
+       case ESsquare:  /* ESC [ aka CSI, parameters or modifiers expected */
+               vc_reset_params(vc);
+
                vc->vc_state = ESgetpars;
-               if (c == '[') { /* Function key */
-                       vc->vc_state=ESfunckey;
-                       return;
-               }
                switch (c) {
+               case '[': /* Function key */
+                       vc->vc_state = ESfunckey;
+                       return;
                case '?':
                        vc->vc_priv = EPdec;
                        return;
@@ -2298,182 +2627,44 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                }
                vc->vc_priv = EPecma;
                fallthrough;
-       case ESgetpars:
-               if (c == ';' && vc->vc_npar < NPAR - 1) {
-                       vc->vc_npar++;
-                       return;
-               } else if (c>='0' && c<='9') {
+       case ESgetpars: /* ESC [ aka CSI, parameters expected */
+               switch (c) {
+               case ';':
+                       if (vc->vc_npar < NPAR - 1) {
+                               vc->vc_npar++;
+                               return;
+                       }
+                       break;
+               case '0' ... '9':
                        vc->vc_par[vc->vc_npar] *= 10;
                        vc->vc_par[vc->vc_npar] += c - '0';
                        return;
                }
-               if (c >= 0x20 && c <= 0x3f) { /* 0x2x, 0x3a and 0x3c - 0x3f */
+               if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST) {
                        vc->vc_state = EScsiignore;
                        return;
                }
+
+               /* parameters done, handle the control char @c */
+
                vc->vc_state = ESnormal;
-               switch(c) {
-               case 'h':
-                       if (vc->vc_priv <= EPdec)
-                               set_mode(vc, 1);
-                       return;
-               case 'l':
-                       if (vc->vc_priv <= EPdec)
-                               set_mode(vc, 0);
-                       return;
-               case 'c':
-                       if (vc->vc_priv == EPdec) {
-                               if (vc->vc_par[0])
-                                       vc->vc_cursor_type =
-                                               CUR_MAKE(vc->vc_par[0],
-                                                        vc->vc_par[1],
-                                                        vc->vc_par[2]);
-                               else
-                                       vc->vc_cursor_type = cur_default;
-                               return;
-                       }
-                       break;
-               case 'm':
-                       if (vc->vc_priv == EPdec) {
-                               clear_selection();
-                               if (vc->vc_par[0])
-                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
-                               else
-                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
-                               return;
-                       }
-                       break;
-               case 'n':
-                       if (vc->vc_priv == EPecma) {
-                               if (vc->vc_par[0] == 5)
-                                       status_report(tty);
-                               else if (vc->vc_par[0] == 6)
-                                       cursor_report(vc, tty);
-                       }
-                       return;
-               }
-               if (vc->vc_priv != EPecma) {
-                       vc->vc_priv = EPecma;
-                       return;
-               }
-               switch(c) {
-               case 'G': case '`':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxy(vc, vc->vc_par[0], vc->state.y);
-                       return;
-               case 'A':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]);
-                       return;
-               case 'B': case 'e':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]);
-                       return;
-               case 'C': case 'a':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y);
-                       return;
-               case 'D':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y);
-                       return;
-               case 'E':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->state.y + vc->vc_par[0]);
-                       return;
-               case 'F':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->state.y - vc->vc_par[0]);
-                       return;
-               case 'd':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxay(vc, vc->state.x ,vc->vc_par[0]);
-                       return;
-               case 'H': case 'f':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       if (vc->vc_par[1])
-                               vc->vc_par[1]--;
-                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
-                       return;
-               case 'J':
-                       csi_J(vc, vc->vc_par[0]);
-                       return;
-               case 'K':
-                       csi_K(vc, vc->vc_par[0]);
-                       return;
-               case 'L':
-                       csi_L(vc, vc->vc_par[0]);
-                       return;
-               case 'M':
-                       csi_M(vc, vc->vc_par[0]);
-                       return;
-               case 'P':
-                       csi_P(vc, vc->vc_par[0]);
-                       return;
-               case 'c':
-                       if (!vc->vc_par[0])
-                               respond_ID(tty);
-                       return;
-               case 'g':
-                       if (!vc->vc_par[0] && vc->state.x < VC_TABSTOPS_COUNT)
-                               set_bit(vc->state.x, vc->vc_tab_stop);
-                       else if (vc->vc_par[0] == 3)
-                               bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT);
-                       return;
-               case 'm':
-                       csi_m(vc);
-                       return;
-               case 'q': /* DECLL - but only 3 leds */
-                       /* map 0,1,2,3 to 0,1,2,4 */
-                       if (vc->vc_par[0] < 4)
-                               vt_set_led_state(vc->vc_num,
-                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
-                       return;
-               case 'r':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       if (!vc->vc_par[1])
-                               vc->vc_par[1] = vc->vc_rows;
-                       /* Minimum allowed region is 2 lines */
-                       if (vc->vc_par[0] < vc->vc_par[1] &&
-                           vc->vc_par[1] <= vc->vc_rows) {
-                               vc->vc_top = vc->vc_par[0] - 1;
-                               vc->vc_bottom = vc->vc_par[1];
-                               gotoxay(vc, 0, 0);
-                       }
-                       return;
-               case 's':
-                       save_cur(vc);
-                       return;
-               case 'u':
-                       restore_cur(vc);
-                       return;
-               case 'X':
-                       csi_X(vc, vc->vc_par[0]);
+
+               switch (vc->vc_priv) {
+               case EPdec:
+                       csi_DEC(tty, vc, c);
                        return;
-               case '@':
-                       csi_at(vc, vc->vc_par[0]);
+               case EPecma:
+                       csi_ECMA(tty, vc, c);
                        return;
-               case ']': /* setterm functions */
-                       setterm_command(vc);
+               default:
                        return;
                }
-               return;
        case EScsiignore:
-               if (c >= 20 && c <= 0x3f)
+               if (c >= ASCII_CSI_IGNORE_FIRST && c <= ASCII_CSI_IGNORE_LAST)
                        return;
                vc->vc_state = ESnormal;
                return;
-       case ESpercent:
+       case ESpercent: /* ESC % */
                vc->vc_state = ESnormal;
                switch (c) {
                case '@':  /* defined in ISO 2022 */
@@ -2485,36 +2676,36 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        return;
                }
                return;
-       case ESfunckey:
+       case ESfunckey: /* ESC [ [ aka CSI [ */
                vc->vc_state = ESnormal;
                return;
-       case EShash:
+       case EShash:    /* ESC # */
                vc->vc_state = ESnormal;
                if (c == '8') {
                        /* DEC screen alignment test. kludge :-) */
                        vc->vc_video_erase_char =
                                (vc->vc_video_erase_char & 0xff00) | 'E';
-                       csi_J(vc, 2);
+                       csi_J(vc, CSI_J_VISIBLE);
                        vc->vc_video_erase_char =
                                (vc->vc_video_erase_char & 0xff00) | ' ';
                        do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
                }
                return;
-       case ESsetG0:
+       case ESsetG0:   /* ESC ( */
                vc_setGx(vc, 0, c);
                vc->vc_state = ESnormal;
                return;
-       case ESsetG1:
+       case ESsetG1:   /* ESC ) */
                vc_setGx(vc, 1, c);
                vc->vc_state = ESnormal;
                return;
-       case ESapc:
+       case ESapc:     /* ESC _ */
                return;
-       case ESosc:
+       case ESosc:     /* ESC ] [0-9] aka OSC [0-9] */
                return;
-       case ESpm:
+       case ESpm:      /* ESC ^ */
                return;
-       case ESdcs:
+       case ESdcs:     /* ESC P */
                return;
        default:
                vc->vc_state = ESnormal;
@@ -2588,33 +2779,39 @@ static inline int vc_translate_ascii(const struct vc_data *vc, int c)
 
 
 /**
- * vc_sanitize_unicode - Replace invalid Unicode code points with U+FFFD
- * @c: the received character, or U+FFFD for invalid sequences.
+ * vc_sanitize_unicode - Replace invalid Unicode code points with ``U+FFFD``
+ * @c: the received code point
  */
 static inline int vc_sanitize_unicode(const int c)
 {
-       if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+       if (c >= 0xd800 && c <= 0xdfff)
                return 0xfffd;
 
        return c;
 }
 
 /**
- * vc_translate_unicode - Combine UTF-8 into Unicode in @vc_utf_char
+ * vc_translate_unicode - Combine UTF-8 into Unicode in &vc_data.vc_utf_char
  * @vc: virtual console
- * @c: character to translate
- * @rescan: we return true if we need more (continuation) data
+ * @c: UTF-8 byte to translate
+ * @rescan: set to true iff @c wasn't consumed here and needs to be re-processed
+ *
+ * * &vc_data.vc_utf_char is the being-constructed Unicode code point.
+ * * &vc_data.vc_utf_count is the number of continuation bytes still expected to
+ *   arrive.
+ * * &vc_data.vc_npar is the number of continuation bytes arrived so far.
  *
- * @vc_utf_char is the being-constructed unicode character.
- * @vc_utf_count is the number of continuation bytes still expected to arrive.
- * @vc_npar is the number of continuation bytes arrived so far.
+ * Return:
+ * * %-1 - Input OK so far, @c consumed, further bytes expected.
+ * * %0xFFFD - Possibility 1: input invalid, @c may have been consumed (see
+ *             desc. of @rescan). Possibility 2: input OK, @c consumed,
+ *             ``U+FFFD`` is the resulting code point. ``U+FFFD`` is valid,
+ *             ``REPLACEMENT CHARACTER``.
+ * * otherwise - Input OK, @c consumed, resulting code point returned.
  */
 static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
 {
-       static const u32 utf8_length_changes[] = {
-               0x0000007f, 0x000007ff, 0x0000ffff,
-               0x001fffff, 0x03ffffff, 0x7fffffff
-       };
+       static const u32 utf8_length_changes[] = {0x7f, 0x7ff, 0xffff, 0x10ffff};
 
        /* Continuation byte received */
        if ((c & 0xc0) == 0x80) {
@@ -2660,14 +2857,7 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
        } else if ((c & 0xf8) == 0xf0) {
                vc->vc_utf_count = 3;
                vc->vc_utf_char = (c & 0x07);
-       } else if ((c & 0xfc) == 0xf8) {
-               vc->vc_utf_count = 4;
-               vc->vc_utf_char = (c & 0x03);
-       } else if ((c & 0xfe) == 0xfc) {
-               vc->vc_utf_count = 5;
-               vc->vc_utf_char = (c & 0x01);
        } else {
-               /* 254 and 255 are invalid */
                return 0xfffd;
        }
 
@@ -2711,9 +2901,13 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
         * as cursor movement) and should not be displayed as a glyph unless
         * the disp_ctrl mode is explicitly enabled.
         */
-       static const u32 CTRL_ACTION = 0x0d00ff81;
+       static const u32 CTRL_ACTION = BIT(ASCII_NULL) |
+               GENMASK(ASCII_SHIFTIN, ASCII_BELL) | BIT(ASCII_CANCEL) |
+               BIT(ASCII_SUBSTITUTE) | BIT(ASCII_ESCAPE);
        /* Cannot be overridden by disp_ctrl */
-       static const u32 CTRL_ALWAYS = 0x0800f501;
+       static const u32 CTRL_ALWAYS = BIT(ASCII_NULL) | BIT(ASCII_BACKSPACE) |
+               BIT(ASCII_LINEFEED) | BIT(ASCII_SHIFTIN) | BIT(ASCII_SHIFTOUT) |
+               BIT(ASCII_CAR_RET) | BIT(ASCII_FORMFEED) | BIT(ASCII_ESCAPE);
 
        if (vc->vc_state != ESnormal)
                return true;
@@ -2730,17 +2924,17 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
         * useless without them; to display an arbitrary font position use the
         * direct-to-font zone in UTF-8 mode.
         */
-       if (c < 32) {
+       if (c < BITS_PER_TYPE(CTRL_ALWAYS)) {
                if (vc->vc_disp_ctrl)
                        return CTRL_ALWAYS & BIT(c);
                else
                        return vc->vc_utf || (CTRL_ACTION & BIT(c));
        }
 
-       if (c == 127 && !vc->vc_disp_ctrl)
+       if (c == ASCII_DEL && !vc->vc_disp_ctrl)
                return true;
 
-       if (c == 128 + 27)
+       if (c == ASCII_EXT_CSI)
                return true;
 
        return false;
@@ -2852,7 +3046,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
        };
        int c, tc, n = 0;
        unsigned int currcons;
-       struct vc_data *vc;
+       struct vc_data *vc = tty->driver_data;
        struct vt_notifier_param param;
        bool rescan;
 
@@ -2860,13 +3054,6 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
                return count;
 
        console_lock();
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               pr_err("vt: argh, driver_data is NULL !\n");
-               console_unlock();
-               return 0;
-       }
-
        currcons = vc->vc_num;
        if (!vc_cons_allocated(currcons)) {
                /* could this happen? */
@@ -2883,7 +3070,7 @@ static int do_con_write(struct tty_struct *tty, const u8 *buf, int count)
        param.vc = vc;
 
        while (!tty->flow.stopped && count) {
-               int orig = *buf;
+               u8 orig = *buf;
                buf++;
                n++;
                count--;
@@ -2992,16 +3179,16 @@ struct tty_driver *console_driver;
 #ifdef CONFIG_VT_CONSOLE
 
 /**
- * vt_kmsg_redirect() - Sets/gets the kernel message console
- * @new:       The new virtual terminal number or -1 if the console should stay
- *             unchanged
+ * vt_kmsg_redirect() - sets/gets the kernel message console
+ * @new: the new virtual terminal number or -1 if the console should stay
+ *     unchanged
  *
  * By default, the kernel messages are always printed on the current virtual
  * console. However, the user may modify that default with the
- * TIOCL_SETKMSGREDIRECT ioctl call.
+ * %TIOCL_SETKMSGREDIRECT ioctl call.
  *
  * This function sets the kernel message console to be @new. It returns the old
- * virtual console number. The virtual terminal number 0 (both as parameter and
+ * virtual console number. The virtual terminal number %0 (both as parameter and
  * return value) means no redirection (i.e. always printed on the currently
  * active console).
  *
@@ -3009,8 +3196,8 @@ struct tty_driver *console_driver;
  * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
  * case to make the code more understandable.
  *
- * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
- * the parameter and always returns 0.
+ * When the kernel is compiled without %CONFIG_VT_CONSOLE, this function ignores
+ * the parameter and always returns %0.
  */
 int vt_kmsg_redirect(int new)
 {
@@ -3065,22 +3252,23 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
        cnt = 0;
        while (count--) {
                c = *b++;
-               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
+               if (c == ASCII_LINEFEED || c == ASCII_CAR_RET ||
+                   c == ASCII_BACKSPACE || vc->vc_need_wrap) {
                        if (cnt && con_is_visible(vc))
                                vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
                        cnt = 0;
-                       if (c == 8) {           /* backspace */
+                       if (c == ASCII_BACKSPACE) {
                                bs(vc);
                                start = (ushort *)vc->vc_pos;
                                start_x = vc->state.x;
                                continue;
                        }
-                       if (c != 13)
+                       if (c != ASCII_CAR_RET)
                                lf(vc);
                        cr(vc);
                        start = (ushort *)vc->vc_pos;
                        start_x = vc->state.x;
-                       if (c == 10 || c == 13)
+                       if (c == ASCII_LINEFEED || c == ASCII_CAR_RET)
                                continue;
                }
                vc_uniscr_putc(vc, c);
@@ -3144,6 +3332,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
 {
        char type, data;
        char __user *p = (char __user *)arg;
+       void __user *param_aligned32 = (u32 __user *)arg + 1;
+       void __user *param = (void __user *)arg + 1;
        int lines;
        int ret;
 
@@ -3157,8 +3347,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        case TIOCL_SETSEL:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               return set_selection_user((struct tiocl_selection
-                                        __user *)(p+1), tty);
+               return set_selection_user(param, tty);
        case TIOCL_PASTESEL:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
@@ -3171,10 +3360,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        case TIOCL_SELLOADLUT:
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               console_lock();
-               ret = sel_loadlut(p);
-               console_unlock();
-               break;
+               return sel_loadlut(param_aligned32);
        case TIOCL_GETSHIFTSTATE:
                /*
                 * Make it possible to react to Shift+Mousebutton. Note that
@@ -3190,10 +3376,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                console_unlock();
                return put_user(data, p);
        case TIOCL_SETVESABLANK:
-               console_lock();
-               ret = set_vesa_blanking(p);
-               console_unlock();
-               break;
+               return set_vesa_blanking(param);
        case TIOCL_GETKMSGREDIRECT:
                data = vt_get_kmsg_redirect();
                return put_user(data, p);
@@ -3214,7 +3397,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                 */
                return fg_console;
        case TIOCL_SCROLLCONSOLE:
-               if (get_user(lines, (s32 __user *)(p+4)))
+               if (get_user(lines, (s32 __user *)param_aligned32))
                        return -EFAULT;
 
                /*
@@ -3312,16 +3495,13 @@ static void con_start(struct tty_struct *tty)
 
 static void con_flush_chars(struct tty_struct *tty)
 {
-       struct vc_data *vc;
+       struct vc_data *vc = tty->driver_data;
 
        if (in_interrupt())     /* from flush_to_ldisc */
                return;
 
-       /* if we race with con_close(), vt may be null */
        console_lock();
-       vc = tty->driver_data;
-       if (vc)
-               set_cursor(vc);
+       set_cursor(vc);
        console_unlock();
 }
 
@@ -3471,7 +3651,7 @@ static int __init con_init(void)
                vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
                INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
                tty_port_init(&vc->port);
-               visual_init(vc, currcons, 1);
+               visual_init(vc, currcons, true);
                /* Assuming vc->vc_{cols,rows,screenbuf_size} are sane here. */
                vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
                vc_init(vc, currcons || !vc->vc_sw->con_save_screen);
@@ -3481,7 +3661,7 @@ static int __init con_init(void)
        set_origin(vc);
        save_screen(vc);
        gotoxy(vc, vc->state.x, vc->state.y);
-       csi_J(vc, 0);
+       csi_J(vc, CSI_J_CURSOR_TO_END);
        update_screen(vc);
        pr_info("Console: %s %s %dx%d\n",
                vc->vc_can_do_color ? "colour" : "mono",
@@ -3640,7 +3820,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
                old_was_color = vc->vc_can_do_color;
                vc->vc_sw->con_deinit(vc);
                vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-               visual_init(vc, i, 0);
+               visual_init(vc, i, false);
                set_origin(vc);
                update_attr(vc);
 
@@ -3930,7 +4110,7 @@ static void vtconsole_deinit_device(struct con_driver *con)
  * RETURNS: zero if unbound, nonzero if bound
  *
  * Drivers can call this and if zero, they should release
- * all resources allocated on con_startup()
+ * all resources allocated on &consw.con_startup()
  */
 int con_is_bound(const struct consw *csw)
 {
@@ -3970,15 +4150,9 @@ EXPORT_SYMBOL(con_is_visible);
  * Called when the console is taken over by the kernel debugger, this
  * function needs to save the current console state, then put the console
  * into a state suitable for the kernel debugger.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to prepare
- * the console for the debugger.
  */
-int con_debug_enter(struct vc_data *vc)
+void con_debug_enter(struct vc_data *vc)
 {
-       int ret = 0;
-
        saved_fg_console = fg_console;
        saved_last_console = last_console;
        saved_want_console = want_console;
@@ -3987,7 +4161,7 @@ int con_debug_enter(struct vc_data *vc)
        vc->vc_mode = KD_TEXT;
        console_blanked = 0;
        if (vc->vc_sw->con_debug_enter)
-               ret = vc->vc_sw->con_debug_enter(vc);
+               vc->vc_sw->con_debug_enter(vc);
 #ifdef CONFIG_KGDB_KDB
        /* Set the initial LINES variable if it is not already set */
        if (vc->vc_rows < 999) {
@@ -4017,7 +4191,6 @@ int con_debug_enter(struct vc_data *vc)
                }
        }
 #endif /* CONFIG_KGDB_KDB */
-       return ret;
 }
 EXPORT_SYMBOL_GPL(con_debug_enter);
 
@@ -4026,15 +4199,10 @@ EXPORT_SYMBOL_GPL(con_debug_enter);
  *
  * Restore the console state to what it was before the kernel debugger
  * was invoked.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to restore
- * the console.
  */
-int con_debug_leave(void)
+void con_debug_leave(void)
 {
        struct vc_data *vc;
-       int ret = 0;
 
        fg_console = saved_fg_console;
        last_console = saved_last_console;
@@ -4044,8 +4212,7 @@ int con_debug_leave(void)
 
        vc = vc_cons[fg_console].d;
        if (vc->vc_sw->con_debug_leave)
-               ret = vc->vc_sw->con_debug_leave(vc);
-       return ret;
+               vc->vc_sw->con_debug_leave(vc);
 }
 EXPORT_SYMBOL_GPL(con_debug_leave);
 
@@ -4275,14 +4442,17 @@ postcore_initcall(vtconsole_class_init);
  *     Screen blanking
  */
 
-static int set_vesa_blanking(char __user *p)
+static int set_vesa_blanking(u8 __user *mode_user)
 {
-       unsigned int mode;
+       u8 mode;
 
-       if (get_user(mode, p + 1))
+       if (get_user(mode, mode_user))
                return -EFAULT;
 
-       vesa_blank_mode = (mode < 4) ? mode : 0;
+       console_lock();
+       vesa_blank_mode = (mode <= VESA_BLANK_MAX) ? mode : VESA_NO_BLANKING;
+       console_unlock();
+
        return 0;
 }
 
@@ -4307,7 +4477,7 @@ void do_blank_screen(int entering_gfx)
        if (entering_gfx) {
                hide_cursor(vc);
                save_screen(vc);
-               vc->vc_sw->con_blank(vc, -1, 1);
+               vc->vc_sw->con_blank(vc, VESA_VSYNC_SUSPEND, 1);
                console_blanked = fg_console + 1;
                blank_state = blank_off;
                set_origin(vc);
@@ -4328,7 +4498,8 @@ void do_blank_screen(int entering_gfx)
 
        save_screen(vc);
        /* In case we need to reset origin, blanking hook returns 1 */
-       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
+       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? VESA_VSYNC_SUSPEND :
+                                (vesa_blank_mode + 1), 0);
        console_blanked = fg_console + 1;
        if (i)
                set_origin(vc);
@@ -4379,7 +4550,7 @@ void do_unblank_screen(int leaving_gfx)
        }
 
        console_blanked = 0;
-       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
+       if (vc->vc_sw->con_blank(vc, VESA_NO_BLANKING, leaving_gfx))
                /* Low-level driver cannot restore -> do it ourselves */
                update_screen(vc);
        if (console_blank_hook)
@@ -4584,7 +4755,7 @@ out:
        return rc;
 }
 
-static int con_font_set(struct vc_data *vc, struct console_font_op *op)
+static int con_font_set(struct vc_data *vc, const struct console_font_op *op)
 {
        struct console_font font;
        int rc = -EINVAL;
@@ -4748,43 +4919,3 @@ void vcs_scr_updated(struct vc_data *vc)
 {
        notify_update(vc);
 }
-
-void vc_scrolldelta_helper(struct vc_data *c, int lines,
-               unsigned int rolled_over, void *base, unsigned int size)
-{
-       unsigned long ubase = (unsigned long)base;
-       ptrdiff_t scr_end = (void *)c->vc_scr_end - base;
-       ptrdiff_t vorigin = (void *)c->vc_visible_origin - base;
-       ptrdiff_t origin = (void *)c->vc_origin - base;
-       int margin = c->vc_size_row * 4;
-       int from, wrap, from_off, avail;
-
-       /* Turn scrollback off */
-       if (!lines) {
-               c->vc_visible_origin = c->vc_origin;
-               return;
-       }
-
-       /* Do we have already enough to allow jumping from 0 to the end? */
-       if (rolled_over > scr_end + margin) {
-               from = scr_end;
-               wrap = rolled_over + c->vc_size_row;
-       } else {
-               from = 0;
-               wrap = size;
-       }
-
-       from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
-       avail = (origin - from + wrap) % wrap;
-
-       /* Only a little piece would be left? Show all incl. the piece! */
-       if (avail < 2 * margin)
-               margin = 0;
-       if (from_off < margin)
-               from_off = 0;
-       if (from_off > avail - margin)
-               from_off = avail;
-
-       c->vc_visible_origin = ubase + (from + from_off) % wrap;
-}
-EXPORT_SYMBOL_GPL(vc_scrolldelta_helper);
index 8c685b5014044b891c40e1cf00bd4629a661e33f..4b91072f3a4e916a3acd9ef8841764ab4febb0c9 100644 (file)
@@ -714,8 +714,7 @@ static int vt_resizex(struct vc_data *vc, struct vt_consize __user *cs)
                                vcp->vc_scan_lines = v.v_vlin;
                        if (v.v_clin)
                                vcp->vc_cell_height = v.v_clin;
-                       vcp->vc_resize_user = 1;
-                       ret = vc_resize(vcp, v.v_cols, v.v_rows);
+                       ret = __vc_resize(vcp, v.v_cols, v.v_rows, true);
                        if (ret) {
                                vcp->vc_scan_lines = save_scan_lines;
                                vcp->vc_cell_height = save_cell_height;
@@ -923,9 +922,8 @@ int vt_ioctl(struct tty_struct *tty,
                        vc = vc_cons[i].d;
 
                        if (vc) {
-                               vc->vc_resize_user = 1;
                                /* FIXME: review v tty lock */
-                               vc_resize(vc_cons[i].d, cc, ll);
+                               __vc_resize(vc_cons[i].d, cc, ll, true);
                        }
                }
                console_unlock();
index 2d572f6c8ec833023450136e3e2278d46d8937ae..bb77de6fa067efe26280b24b0f62b54ba75bcbca 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kobject.h>
 #include <linux/cdev.h>
 #include <linux/uio_driver.h>
+#include <linux/dma-mapping.h>
 
 #define UIO_MAX_DEVICES                (1U << MINORBITS)
 
@@ -759,6 +760,49 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
                               vma->vm_page_prot);
 }
 
+static int uio_mmap_dma_coherent(struct vm_area_struct *vma)
+{
+       struct uio_device *idev = vma->vm_private_data;
+       struct uio_mem *mem;
+       void *addr;
+       int ret = 0;
+       int mi;
+
+       mi = uio_find_mem_index(vma);
+       if (mi < 0)
+               return -EINVAL;
+
+       mem = idev->info->mem + mi;
+
+       if (mem->addr & ~PAGE_MASK)
+               return -ENODEV;
+       if (mem->dma_addr & ~PAGE_MASK)
+               return -ENODEV;
+       if (!mem->dma_device)
+               return -ENODEV;
+       if (vma->vm_end - vma->vm_start > mem->size)
+               return -EINVAL;
+
+       dev_warn(mem->dma_device,
+                "use of UIO_MEM_DMA_COHERENT is highly discouraged");
+
+       /*
+        * UIO uses offset to index into the maps for a device.
+        * We need to clear vm_pgoff for dma_mmap_coherent.
+        */
+       vma->vm_pgoff = 0;
+
+       addr = (void *)mem->addr;
+       ret = dma_mmap_coherent(mem->dma_device,
+                               vma,
+                               addr,
+                               mem->dma_addr,
+                               vma->vm_end - vma->vm_start);
+       vma->vm_pgoff = mi;
+
+       return ret;
+}
+
 static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
 {
        struct uio_listener *listener = filep->private_data;
@@ -806,6 +850,9 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
        case UIO_MEM_VIRTUAL:
                ret = uio_mmap_logical(vma);
                break;
+       case UIO_MEM_DMA_COHERENT:
+               ret = uio_mmap_dma_coherent(vma);
+               break;
        default:
                ret = -EINVAL;
        }
index 5313307c2754a8c66ee013687acd7e4bf893aed0..d5f9384df1255f241d27c80ae4cd40be8d1d2609 100644 (file)
@@ -36,7 +36,6 @@ struct uio_dmem_genirq_platdata {
        struct platform_device *pdev;
        unsigned int dmem_region_start;
        unsigned int num_dmem_regions;
-       void *dmem_region_vaddr[MAX_UIO_MAPS];
        struct mutex alloc_lock;
        unsigned int refcnt;
 };
@@ -50,7 +49,6 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
 {
        struct uio_dmem_genirq_platdata *priv = info->priv;
        struct uio_mem *uiomem;
-       int dmem_region = priv->dmem_region_start;
 
        uiomem = &priv->uioinfo->mem[priv->dmem_region_start];
 
@@ -61,11 +59,8 @@ static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
                        break;
 
                addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size,
-                               (dma_addr_t *)&uiomem->addr, GFP_KERNEL);
-               if (!addr) {
-                       uiomem->addr = DMEM_MAP_ERROR;
-               }
-               priv->dmem_region_vaddr[dmem_region++] = addr;
+                                         &uiomem->dma_addr, GFP_KERNEL);
+               uiomem->addr = addr ? (phys_addr_t) addr : DMEM_MAP_ERROR;
                ++uiomem;
        }
        priv->refcnt++;
@@ -80,7 +75,6 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
 {
        struct uio_dmem_genirq_platdata *priv = info->priv;
        struct uio_mem *uiomem;
-       int dmem_region = priv->dmem_region_start;
 
        /* Tell the Runtime PM code that the device has become idle */
        pm_runtime_put_sync(&priv->pdev->dev);
@@ -93,13 +87,12 @@ static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
        while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) {
                if (!uiomem->size)
                        break;
-               if (priv->dmem_region_vaddr[dmem_region]) {
-                       dma_free_coherent(&priv->pdev->dev, uiomem->size,
-                                       priv->dmem_region_vaddr[dmem_region],
-                                       uiomem->addr);
+               if (uiomem->addr) {
+                       dma_free_coherent(uiomem->dma_device, uiomem->size,
+                                         (void *) uiomem->addr,
+                                         uiomem->dma_addr);
                }
                uiomem->addr = DMEM_MAP_ERROR;
-               ++dmem_region;
                ++uiomem;
        }
 
@@ -264,7 +257,8 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
                                        " dynamic and fixed memory regions.\n");
                        break;
                }
-               uiomem->memtype = UIO_MEM_PHYS;
+               uiomem->memtype = UIO_MEM_DMA_COHERENT;
+               uiomem->dma_device = &pdev->dev;
                uiomem->addr = DMEM_MAP_ERROR;
                uiomem->size = pdata->dynamic_region_sizes[i];
                ++uiomem;
index 77e2dc40488555b56a1abfe6f01688a01869c7c7..72b33f7d4c40fcc44bce35962a9b1ec6c2fc7701 100644 (file)
@@ -191,9 +191,11 @@ static int pruss_probe(struct platform_device *pdev)
                p->mem[1].size = sram_pool_sz;
                p->mem[1].memtype = UIO_MEM_PHYS;
 
-               p->mem[2].addr = gdev->ddr_paddr;
+               p->mem[2].addr = (phys_addr_t) gdev->ddr_vaddr;
+               p->mem[2].dma_addr = gdev->ddr_paddr;
                p->mem[2].size = extram_pool_sz;
-               p->mem[2].memtype = UIO_MEM_PHYS;
+               p->mem[2].memtype = UIO_MEM_DMA_COHERENT;
+               p->mem[2].dma_device = dev;
 
                p->name = devm_kasprintf(dev, GFP_KERNEL, "pruss_evt%d", cnt);
                p->version = DRV_VERSION;
index ee917f1b091c893ebccad19bd5a62aea9e65c721..8b936a2e93a0d43a775bd76249aeb2d92f8e6542 100644 (file)
@@ -435,7 +435,7 @@ int cdns_drd_init(struct cdns *cdns)
                        writel(1, &cdns->otg_v1_regs->simulate);
                        cdns->version  = CDNS3_CONTROLLER_V1;
                } else {
-                       dev_err(cdns->dev, "not supporte DID=0x%08x\n", state);
+                       dev_err(cdns->dev, "not supported DID=0x%08x\n", state);
                        return -EINVAL;
                }
 
index 351ede4b5de20da9bde2de0f71d81c136511c3e3..58e3ca7e479392112f656384c664efc36bb1151a 100644 (file)
@@ -116,3 +116,30 @@ config USB_AUTOSUSPEND_DELAY
          The default value Linux has always had is 2 seconds.  Change
          this value if you want a different delay and cannot modify
          the command line or module parameter.
+
+config USB_DEFAULT_AUTHORIZATION_MODE
+       int "Default authorization mode for USB devices"
+       range 0 2
+       default 1
+       depends on USB
+       help
+         Select the default USB device authorization mode. Can be overridden
+         with usbcore.authorized_default command line or module parameter.
+
+         This option allows you to choose whether USB devices that are
+         connected to the system can be used by default, or if they are
+         locked down.
+
+         With value 0 all connected USB devices with the exception of root
+         hub require user space authorization before they can be used.
+
+         With value 1 (default) no user space authorization is required to
+         use connected USB devices.
+
+         With value 2 all connected USB devices with exception of internal
+         USB devices require user space authorization before they can be
+         used. Note that in this mode the differentiation between internal
+         and external USB devices relies on ACPI, and on systems without
+         ACPI selecting value 2 is analogous to selecting value 0.
+
+         If unsure, keep the default value.
index e01b1913d02bf68aa3dd3ad4e3a30adb11585c5f..e02ba15f6e34fa7f442e613ab99bac83f792912b 100644 (file)
@@ -1710,9 +1710,7 @@ int usb_autoresume_device(struct usb_device *udev)
 {
        int     status;
 
-       status = pm_runtime_get_sync(&udev->dev);
-       if (status < 0)
-               pm_runtime_put_sync(&udev->dev);
+       status = pm_runtime_resume_and_get(&udev->dev);
        dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
                        __func__, atomic_read(&udev->dev.power.usage_count),
                        status);
@@ -1818,9 +1816,7 @@ int usb_autopm_get_interface(struct usb_interface *intf)
 {
        int     status;
 
-       status = pm_runtime_get_sync(&intf->dev);
-       if (status < 0)
-               pm_runtime_put_sync(&intf->dev);
+       status = pm_runtime_resume_and_get(&intf->dev);
        dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
                        __func__, atomic_read(&intf->dev.power.usage_count),
                        status);
index a2530811cf7ded0656556d35abcc43b302409ce8..4b38b87a13438d382d3bd0d1ace2df069fbb0d00 100644 (file)
@@ -141,7 +141,7 @@ static void ep_device_release(struct device *dev)
        kfree(ep_dev);
 }
 
-struct device_type usb_ep_device_type = {
+const struct device_type usb_ep_device_type = {
        .name =         "usb_endpoint",
        .release = ep_device_release,
 };
index edf74458474a1e7065d3d6c3bd651e9cbba172b8..c0e005670d67d1b9cf0b8cdb03d12635148772d6 100644 (file)
@@ -357,12 +357,10 @@ static const u8 ss_rh_config_descriptor[] = {
 #define USB_AUTHORIZE_ALL      1
 #define USB_AUTHORIZE_INTERNAL 2
 
-static int authorized_default = USB_AUTHORIZE_WIRED;
+static int authorized_default = CONFIG_USB_DEFAULT_AUTHORIZATION_MODE;
 module_param(authorized_default, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(authorized_default,
-               "Default USB device authorization: 0 is not authorized, 1 is "
-               "authorized, 2 is authorized for internal devices, -1 is "
-               "authorized (default, same as 1)");
+               "Default USB device authorization: 0 is not authorized, 1 is authorized (default), 2 is authorized for internal devices, -1 is authorized (same as 1)");
 /*-------------------------------------------------------------------------*/
 
 /**
@@ -2795,10 +2793,16 @@ int usb_add_hcd(struct usb_hcd *hcd,
        struct usb_device *rhdev;
        struct usb_hcd *shared_hcd;
 
-       if (!hcd->skip_phy_initialization && usb_hcd_is_primary_hcd(hcd)) {
-               hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
-               if (IS_ERR(hcd->phy_roothub))
-                       return PTR_ERR(hcd->phy_roothub);
+       if (!hcd->skip_phy_initialization) {
+               if (usb_hcd_is_primary_hcd(hcd)) {
+                       hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev);
+                       if (IS_ERR(hcd->phy_roothub))
+                               return PTR_ERR(hcd->phy_roothub);
+               } else {
+                       hcd->phy_roothub = usb_phy_roothub_alloc_usb3_phy(hcd->self.sysdev);
+                       if (IS_ERR(hcd->phy_roothub))
+                               return PTR_ERR(hcd->phy_roothub);
+               }
 
                retval = usb_phy_roothub_init(hcd->phy_roothub);
                if (retval)
index e38a4124f6102a5ff2a47107a8286815cfc5c8e2..3ee8455585b6be66e2312e17f922b57cc4385801 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/byteorder.h>
 
 #include "hub.h"
+#include "phy.h"
 #include "otg_productlist.h"
 
 #define USB_VENDOR_GENESYS_LOGIC               0x05e3
@@ -634,6 +635,34 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
                ret = 0;
        }
        mutex_unlock(&hub->status_mutex);
+
+       /*
+        * There is no need to lock status_mutex here, because status_mutex
+        * protects hub->status, and the phy driver only checks the port
+        * status without changing the status.
+        */
+       if (!ret) {
+               struct usb_device *hdev = hub->hdev;
+
+               /*
+                * Only roothub will be notified of connection changes,
+                * since the USB PHY only cares about changes at the next
+                * level.
+                */
+               if (is_root_hub(hdev)) {
+                       struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+                       bool connect;
+                       bool connect_change;
+
+                       connect_change = *change & USB_PORT_STAT_C_CONNECTION;
+                       connect = *status & USB_PORT_STAT_CONNECTION;
+                       if (connect_change && connect)
+                               usb_phy_roothub_notify_connect(hcd->phy_roothub, port1 - 1);
+                       else if (connect_change)
+                               usb_phy_roothub_notify_disconnect(hcd->phy_roothub, port1 - 1);
+               }
+       }
+
        return ret;
 }
 
index 077dfe48d01c1cb2ab807197450daae79d56c59a..d2b2787be4092ee25e48d82b9a4db3e934478b1a 100644 (file)
@@ -1198,6 +1198,8 @@ EXPORT_SYMBOL_GPL(usb_get_status);
  * same status code used to report a true stall.
  *
  * This call is synchronous, and may not be used in an interrupt context.
+ * If a thread in your driver uses this call, make sure your disconnect()
+ * method can wait for it to complete.
  *
  * Return: Zero on success, or else the status code returned by the
  * underlying usb_control_msg() call.
@@ -1516,7 +1518,8 @@ void usb_enable_interface(struct usb_device *dev,
  * This call is synchronous, and may not be used in an interrupt context.
  * Also, drivers must not change altsettings while urbs are scheduled for
  * endpoints in that interface; all such urbs must first be completed
- * (perhaps forced by unlinking).
+ * (perhaps forced by unlinking). If a thread in your driver uses this call,
+ * make sure your disconnect() method can wait for it to complete.
  *
  * Return: Zero on success, or else the status code returned by the
  * underlying usb_control_msg() call.
@@ -1849,7 +1852,7 @@ static int usb_if_uevent(const struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-struct device_type usb_if_device_type = {
+const struct device_type usb_if_device_type = {
        .name =         "usb_interface",
        .release =      usb_release_interface,
        .uevent =       usb_if_uevent,
index db4ccf9ce3d9b46b518f050804831ab706adf35c..f1a499ee482c3e9afb0eba256e4401ef33df1390 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/of.h>
+#include <linux/of_graph.h>
 #include <linux/usb/of.h>
 
 /**
@@ -75,6 +76,76 @@ bool usb_of_has_combined_node(struct usb_device *udev)
 }
 EXPORT_SYMBOL_GPL(usb_of_has_combined_node);
 
+static bool usb_of_has_devices_or_graph(const struct usb_device *hub)
+{
+       const struct device_node *np = hub->dev.of_node;
+       struct device_node *child;
+
+       if (of_graph_is_present(np))
+               return true;
+
+       for_each_child_of_node(np, child)
+               if (of_property_present(child, "reg"))
+                       return true;
+
+       return false;
+}
+
+/**
+ * usb_of_get_connect_type() - get a USB hub's port connect_type
+ * @hub: hub to which port is for @port1
+ * @port1: one-based index of port
+ *
+ * Get the connect_type of @port1 based on the device node for @hub. If the
+ * port is described in the OF graph, the connect_type is "hotplug". If the
+ * @hub has a child device has with a 'reg' property equal to @port1 the
+ * connect_type is "hard-wired". If there isn't an OF graph or child node at
+ * all then the connect_type is "unknown". Otherwise, the port is considered
+ * "unused" because it isn't described at all.
+ *
+ * Return: A connect_type for @port1 based on the device node for @hub.
+ */
+enum usb_port_connect_type usb_of_get_connect_type(struct usb_device *hub, int port1)
+{
+       struct device_node *np, *child, *ep, *remote_np;
+       enum usb_port_connect_type connect_type;
+
+       /* Only set connect_type if binding has ports/hardwired devices. */
+       if (!usb_of_has_devices_or_graph(hub))
+               return USB_PORT_CONNECT_TYPE_UNKNOWN;
+
+       /* Assume port is unused if there's a graph or a child node. */
+       connect_type = USB_PORT_NOT_USED;
+
+       np = hub->dev.of_node;
+       /*
+        * Hotplug ports are connected to an available remote node, e.g.
+        * usb-a-connector compatible node, in the OF graph.
+        */
+       if (of_graph_is_present(np)) {
+               ep = of_graph_get_endpoint_by_regs(np, port1, -1);
+               if (ep) {
+                       remote_np = of_graph_get_remote_port_parent(ep);
+                       of_node_put(ep);
+                       if (of_device_is_available(remote_np))
+                               connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG;
+                       of_node_put(remote_np);
+               }
+       }
+
+       /*
+        * Hard-wired ports are child nodes with a reg property corresponding
+        * to the port number, i.e. a usb device.
+        */
+       child = usb_of_get_device_node(hub, port1);
+       if (of_device_is_available(child))
+               connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED;
+       of_node_put(child);
+
+       return connect_type;
+}
+EXPORT_SYMBOL_GPL(usb_of_get_connect_type);
+
 /**
  * usb_of_get_interface_node() - get a USB interface node
  * @udev: USB device of interface
index fb1588e7c28232dc16bc8ad28574f6ec7cefd764..faa20054ad5a1c3f704cb9f70b5049cefdab804e 100644 (file)
@@ -19,6 +19,30 @@ struct usb_phy_roothub {
        struct list_head        list;
 };
 
+/* Allocate the roothub_entry by specific name of phy */
+static int usb_phy_roothub_add_phy_by_name(struct device *dev, const char *name,
+                                          struct list_head *list)
+{
+       struct usb_phy_roothub *roothub_entry;
+       struct phy *phy;
+
+       phy = devm_of_phy_get(dev, dev->of_node, name);
+       if (IS_ERR(phy))
+               return PTR_ERR(phy);
+
+       roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
+       if (!roothub_entry)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&roothub_entry->list);
+
+       roothub_entry->phy = phy;
+
+       list_add_tail(&roothub_entry->list, list);
+
+       return 0;
+}
+
 static int usb_phy_roothub_add_phy(struct device *dev, int index,
                                   struct list_head *list)
 {
@@ -65,6 +89,9 @@ struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
 
        INIT_LIST_HEAD(&phy_roothub->list);
 
+       if (!usb_phy_roothub_add_phy_by_name(dev, "usb2-phy", &phy_roothub->list))
+               return phy_roothub;
+
        for (i = 0; i < num_phys; i++) {
                err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
                if (err)
@@ -75,6 +102,41 @@ struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
 
+/**
+ * usb_phy_roothub_alloc_usb3_phy - alloc the roothub
+ * @dev: the device of the host controller
+ *
+ * Allocate the usb phy roothub if the host use a generic usb3-phy.
+ *
+ * Return: On success, a pointer to the usb_phy_roothub. Otherwise,
+ * %NULL if no use usb3 phy or %-ENOMEM if out of memory.
+ */
+struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev)
+{
+       struct usb_phy_roothub *phy_roothub;
+       int num_phys;
+
+       if (!IS_ENABLED(CONFIG_GENERIC_PHY))
+               return NULL;
+
+       num_phys = of_count_phandle_with_args(dev->of_node, "phys",
+                                             "#phy-cells");
+       if (num_phys <= 0)
+               return NULL;
+
+       phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
+       if (!phy_roothub)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&phy_roothub->list);
+
+       if (!usb_phy_roothub_add_phy_by_name(dev, "usb3-phy", &phy_roothub->list))
+               return phy_roothub;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc_usb3_phy);
+
 int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub)
 {
        struct usb_phy_roothub *roothub_entry;
@@ -172,6 +234,64 @@ int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
 }
 EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
 
+/**
+ * usb_phy_roothub_notify_connect() - connect notification
+ * @phy_roothub: the phy of roothub, if the host use a generic phy.
+ * @port: the port index for connect
+ *
+ * If the phy needs to get connection status, the callback can be used.
+ * Returns: %0 if successful, a negative error code otherwise
+ */
+int usb_phy_roothub_notify_connect(struct usb_phy_roothub *phy_roothub, int port)
+{
+       struct usb_phy_roothub *roothub_entry;
+       struct list_head *head;
+       int err;
+
+       if (!phy_roothub)
+               return 0;
+
+       head = &phy_roothub->list;
+
+       list_for_each_entry(roothub_entry, head, list) {
+               err = phy_notify_connect(roothub_entry->phy, port);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_notify_connect);
+
+/**
+ * usb_phy_roothub_notify_disconnect() - disconnect notification
+ * @phy_roothub: the phy of roothub, if the host use a generic phy.
+ * @port: the port index for disconnect
+ *
+ * If the phy needs to get connection status, the callback can be used.
+ * Returns: %0 if successful, a negative error code otherwise
+ */
+int usb_phy_roothub_notify_disconnect(struct usb_phy_roothub *phy_roothub, int port)
+{
+       struct usb_phy_roothub *roothub_entry;
+       struct list_head *head;
+       int err;
+
+       if (!phy_roothub)
+               return 0;
+
+       head = &phy_roothub->list;
+
+       list_for_each_entry(roothub_entry, head, list) {
+               err = phy_notify_disconnect(roothub_entry->phy, port);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_notify_disconnect);
+
 int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
 {
        struct usb_phy_roothub *roothub_entry;
index 20a267cd986b2c4940e415c821a45fa0a5eb6d85..88b49c0ea6b581bc9f66941e48c0d9ae53a322ca 100644 (file)
@@ -12,6 +12,7 @@ struct device;
 struct usb_phy_roothub;
 
 struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev);
+struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev);
 
 int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub);
 int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub);
@@ -19,6 +20,8 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub);
 int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
                             enum phy_mode mode);
 int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub);
+int usb_phy_roothub_notify_connect(struct usb_phy_roothub *phy_roothub, int port);
+int usb_phy_roothub_notify_disconnect(struct usb_phy_roothub *phy_roothub, int port);
 int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub);
 void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub);
 
index 4d63496f98b6c45074eee270db26c53b4019dac6..5b5e613a11e599bdb05dd121ad073f69a7f5b386 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/pm_qos.h>
 #include <linux/component.h>
+#include <linux/usb/of.h>
 
 #include "hub.h"
 
@@ -429,7 +430,7 @@ static const struct dev_pm_ops usb_port_pm_ops = {
 #endif
 };
 
-struct device_type usb_port_device_type = {
+const struct device_type usb_port_device_type = {
        .name =         "usb_port",
        .release =      usb_port_device_release,
        .pm =           &usb_port_pm_ops,
@@ -709,6 +710,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
                return -ENOMEM;
        }
 
+       port_dev->connect_type = usb_of_get_connect_type(hdev, port1);
        hub->ports[port1 - 1] = port_dev;
        port_dev->portnum = port1;
        set_bit(port1, hub->power_bits);
index 5d21718afb05cff29a985dcd1678849dc706dfe6..f98263e21c2a71104664ad21b33e0a2dc2d612cf 100644 (file)
@@ -273,9 +273,10 @@ static ssize_t avoid_reset_quirk_store(struct device *dev,
                                      const char *buf, size_t count)
 {
        struct usb_device       *udev = to_usb_device(dev);
-       int                     val, rc;
+       bool                    val;
+       int                     rc;
 
-       if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
+       if (kstrtobool(buf, &val) != 0)
                return -EINVAL;
        rc = usb_lock_device_interruptible(udev);
        if (rc < 0)
@@ -322,13 +323,14 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
        struct usb_device *udev = to_usb_device(dev);
-       int value, rc;
+       bool value;
+       int rc;
 
        /* Hubs are always enabled for USB_PERSIST */
        if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
                return -EPERM;
 
-       if (sscanf(buf, "%d", &value) != 1)
+       if (kstrtobool(buf, &value) != 0)
                return -EINVAL;
 
        rc = usb_lock_device_interruptible(udev);
@@ -739,14 +741,14 @@ static ssize_t authorized_store(struct device *dev,
 {
        ssize_t result;
        struct usb_device *usb_dev = to_usb_device(dev);
-       unsigned val;
-       result = sscanf(buf, "%u\n", &val);
-       if (result != 1)
+       bool val;
+
+       if (kstrtobool(buf, &val) != 0)
                result = -EINVAL;
-       else if (val == 0)
-               result = usb_deauthorize_device(usb_dev);
-       else
+       else if (val)
                result = usb_authorize_device(usb_dev);
+       else
+               result = usb_deauthorize_device(usb_dev);
        return result < 0 ? result : size;
 }
 static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,
@@ -847,16 +849,10 @@ static const struct attribute_group dev_string_attr_grp = {
        .is_visible =   dev_string_attrs_are_visible,
 };
 
-const struct attribute_group *usb_device_groups[] = {
-       &dev_attr_grp,
-       &dev_string_attr_grp,
-       NULL
-};
-
 /* Binary descriptors */
 
 static ssize_t
-read_descriptors(struct file *filp, struct kobject *kobj,
+descriptors_read(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t off, size_t count)
 {
@@ -878,7 +874,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
                        srclen = sizeof(struct usb_device_descriptor);
                } else {
                        src = udev->rawdescriptors[cfgno];
-                       srclen = __le16_to_cpu(udev->config[cfgno].desc.
+                       srclen = le16_to_cpu(udev->config[cfgno].desc.
                                        wTotalLength);
                }
                if (off < srclen) {
@@ -893,11 +889,69 @@ read_descriptors(struct file *filp, struct kobject *kobj,
        }
        return count - nleft;
 }
+static BIN_ATTR_RO(descriptors, 18 + 65535); /* dev descr + max-size raw descriptor */
+
+static ssize_t
+bos_descriptors_read(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct usb_device *udev = to_usb_device(dev);
+       struct usb_host_bos *bos = udev->bos;
+       struct usb_bos_descriptor *desc;
+       size_t desclen, n = 0;
+
+       if (bos) {
+               desc = bos->desc;
+               desclen = le16_to_cpu(desc->wTotalLength);
+               if (off < desclen) {
+                       n = min(count, desclen - (size_t) off);
+                       memcpy(buf, (void *) desc + off, n);
+               }
+       }
+       return n;
+}
+static BIN_ATTR_RO(bos_descriptors, 65535); /* max-size BOS */
 
-static struct bin_attribute dev_bin_attr_descriptors = {
-       .attr = {.name = "descriptors", .mode = 0444},
-       .read = read_descriptors,
-       .size = 18 + 65535,     /* dev descr + max-size raw descriptor */
+/* When modifying this list, be sure to modify dev_bin_attrs_are_visible()
+ * accordingly.
+ */
+static struct bin_attribute *dev_bin_attrs[] = {
+       &bin_attr_descriptors,
+       &bin_attr_bos_descriptors,
+       NULL
+};
+
+static umode_t dev_bin_attrs_are_visible(struct kobject *kobj,
+               struct bin_attribute *a, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct usb_device *udev = to_usb_device(dev);
+
+       /*
+        * There's no need to check if the descriptors attribute should
+        * be visible because all devices have a device descriptor. The
+        * bos_descriptors attribute should be visible if and only if
+        * the device has a BOS, so check if it exists here.
+        */
+       if (a == &bin_attr_bos_descriptors) {
+               if (udev->bos == NULL)
+                       return 0;
+       }
+       return a->attr.mode;
+}
+
+static const struct attribute_group dev_bin_attr_grp = {
+       .bin_attrs =            dev_bin_attrs,
+       .is_bin_visible =       dev_bin_attrs_are_visible,
+};
+
+const struct attribute_group *usb_device_groups[] = {
+       &dev_attr_grp,
+       &dev_string_attr_grp,
+       &dev_bin_attr_grp,
+       NULL
 };
 
 /*
@@ -1015,10 +1069,6 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
        struct device *dev = &udev->dev;
        int retval;
 
-       retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
-       if (retval)
-               goto error;
-
        retval = add_persist_attributes(dev);
        if (retval)
                goto error;
@@ -1048,7 +1098,6 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
 
        remove_power_attributes(dev);
        remove_persist_attributes(dev);
-       device_remove_bin_file(dev, &dev_bin_attr_descriptors);
 }
 
 /* Interface Association Descriptor fields */
index a34b22537d7ccfd4810708e756acbd17b8844e50..7f8a912d4fe2a26e8b3a4902254af659982a2fb5 100644 (file)
@@ -142,12 +142,19 @@ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
 }
 EXPORT_SYMBOL_GPL(usb_acpi_set_power_state);
 
-static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
-               struct acpi_pld_info *pld)
+/*
+ * Private to usb-acpi, all the core needs to know is that
+ * port_dev->location is non-zero when it has been set by the firmware.
+ */
+#define USB_ACPI_LOCATION_VALID (1 << 31)
+
+static void
+usb_acpi_get_connect_type(struct usb_port *port_dev, 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 = NULL;
+       struct acpi_pld_info *pld = NULL;
        acpi_status status;
 
        /*
@@ -158,6 +165,12 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
         * a usb device is directly hard-wired to the port. If no visible and
         * no connectable, the port would be not used.
         */
+
+       status = acpi_get_physical_device_location(handle, &pld);
+       if (ACPI_SUCCESS(status) && pld)
+               port_dev->location = USB_ACPI_LOCATION_VALID |
+                       pld->group_token << 8 | pld->group_position;
+
        status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
        if (ACPI_FAILURE(status))
                goto out;
@@ -166,25 +179,22 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
        if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4)
                goto out;
 
+       /* UPC states port is connectable */
        if (upc->package.elements[0].integer.value)
-               if (pld->user_visible)
+               if (!pld)
+                       ; /* keep connect_type as unknown */
+               else if (pld->user_visible)
                        connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG;
                else
                        connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED;
-       else if (!pld->user_visible)
+       else
                connect_type = USB_PORT_NOT_USED;
 out:
+       port_dev->connect_type = connect_type;
        kfree(upc);
-       return connect_type;
+       ACPI_FREE(pld);
 }
 
-
-/*
- * Private to usb-acpi, all the core needs to know is that
- * port_dev->location is non-zero when it has been set by the firmware.
- */
-#define USB_ACPI_LOCATION_VALID (1 << 31)
-
 static struct acpi_device *
 usb_acpi_get_companion_for_port(struct usb_port *port_dev)
 {
@@ -222,22 +232,12 @@ static struct acpi_device *
 usb_acpi_find_companion_for_port(struct usb_port *port_dev)
 {
        struct acpi_device *adev;
-       struct acpi_pld_info *pld;
-       acpi_handle *handle;
-       acpi_status status;
 
        adev = usb_acpi_get_companion_for_port(port_dev);
        if (!adev)
                return NULL;
 
-       handle = adev->handle;
-       status = acpi_get_physical_device_location(handle, &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);
-               ACPI_FREE(pld);
-       }
+       usb_acpi_get_connect_type(port_dev, adev->handle);
 
        return adev;
 }
index dc8d9228a5e759775cc16b0a1bbacf514235b396..a0c432b14b20ba3fd8f1a9b1716988f0c578259c 100644 (file)
@@ -592,7 +592,7 @@ static char *usb_devnode(const struct device *dev,
                         usb_dev->bus->busnum, usb_dev->devnum);
 }
 
-struct device_type usb_device_type = {
+const struct device_type usb_device_type = {
        .name =         "usb_device",
        .release =      usb_release_dev,
        .uevent =       usb_dev_uevent,
index bfecb50773b6b61d04b9d696faaab7350c9644a6..b8324ea05b20fb037cff5ae53ec1ac6d6498f6e2 100644 (file)
@@ -144,10 +144,10 @@ static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
 extern const struct class usbmisc_class;
 extern const struct bus_type usb_bus_type;
 extern struct mutex usb_port_peer_mutex;
-extern struct device_type usb_device_type;
-extern struct device_type usb_if_device_type;
-extern struct device_type usb_ep_device_type;
-extern struct device_type usb_port_device_type;
+extern const struct device_type usb_device_type;
+extern const struct device_type usb_if_device_type;
+extern const struct device_type usb_ep_device_type;
+extern const struct device_type usb_port_device_type;
 extern struct usb_device_driver usb_generic_driver;
 
 static inline int is_usb_device(const struct device *dev)
index 5fc27b20df6301c27b71b9fec2be9353f40776a7..31078f3d41b88d0e2be63ce9c0b7c92c56a7ef23 100644 (file)
@@ -131,7 +131,7 @@ config USB_DWC3_QCOM
        tristate "Qualcomm Platform"
        depends on ARCH_QCOM || COMPILE_TEST
        depends on EXTCON || !EXTCON
-       depends on (OF || ACPI)
+       depends on OF
        default USB_DWC3
        help
          Some Qualcomm SoCs use DesignWare Core IP for USB2/3
index e120611a5174f7589ac124641a7b279654babff6..c07edfc954f72e8bd5bb654a96ae731b1411ecf0 100644 (file)
@@ -755,6 +755,7 @@ struct dwc3_ep {
 #define DWC3_EP_PENDING_CLEAR_STALL    BIT(11)
 #define DWC3_EP_TXFIFO_RESIZED         BIT(12)
 #define DWC3_EP_DELAY_STOP             BIT(13)
+#define DWC3_EP_RESOURCE_ALLOCATED     BIT(14)
 
        /* This last one is specific to EP0 */
 #define DWC3_EP0_DIR_IN                        BIT(31)
@@ -1257,6 +1258,7 @@ struct dwc3 {
 #define DWC31_REVISION_170A    0x3137302a
 #define DWC31_REVISION_180A    0x3138302a
 #define DWC31_REVISION_190A    0x3139302a
+#define DWC31_REVISION_200A    0x3230302a
 
 #define DWC32_REVISION_ANY     0x0
 #define DWC32_REVISION_100A    0x3130302a
index 90a587bc29b74e533212f41e1a25fcda9655d68f..fad151e78fd669f7a136d9217a8124ae88f9473c 100644 (file)
 #define USBSS_VBUS_STAT_SESSVALID      BIT(2)
 #define USBSS_VBUS_STAT_VBUSVALID      BIT(0)
 
-/* Mask for PHY PLL REFCLK */
+/* USB_PHY_CTRL register bits in CTRL_MMR */
+#define PHY_CORE_VOLTAGE_MASK  BIT(31)
 #define PHY_PLL_REFCLK_MASK    GENMASK(3, 0)
 
+/* USB PHY2 register offsets */
+#define        USB_PHY_PLL_REG12               0x130
+#define        USB_PHY_PLL_LDO_REF_EN          BIT(5)
+#define        USB_PHY_PLL_LDO_REF_EN_EN       BIT(4)
+
 #define DWC3_AM62_AUTOSUSPEND_DELAY    100
 
 struct dwc3_am62 {
@@ -162,6 +168,13 @@ static int phy_syscon_pll_refclk(struct dwc3_am62 *am62)
 
        am62->offset = args.args[0];
 
+       /* Core voltage. PHY_CORE_VOLTAGE bit Recommended to be 0 always */
+       ret = regmap_update_bits(am62->syscon, am62->offset, PHY_CORE_VOLTAGE_MASK, 0);
+       if (ret) {
+               dev_err(dev, "failed to set phy core voltage\n");
+               return ret;
+       }
+
        ret = regmap_update_bits(am62->syscon, am62->offset, PHY_PLL_REFCLK_MASK, am62->rate_code);
        if (ret) {
                dev_err(dev, "failed to set phy pll reference clock rate\n");
@@ -176,8 +189,9 @@ static int dwc3_ti_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *node = pdev->dev.of_node;
        struct dwc3_am62 *am62;
-       int i, ret;
        unsigned long rate;
+       void __iomem *phy;
+       int i, ret;
        u32 reg;
 
        am62 = devm_kzalloc(dev, sizeof(*am62), GFP_KERNEL);
@@ -219,6 +233,17 @@ static int dwc3_ti_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       /* Workaround Errata i2409 */
+       phy = devm_platform_ioremap_resource(pdev, 1);
+       if (IS_ERR(phy)) {
+               dev_err(dev, "can't map PHY IOMEM resource. Won't apply i2409 fix.\n");
+               phy = NULL;
+       } else {
+               reg = readl(phy + USB_PHY_PLL_REG12);
+               reg |= USB_PHY_PLL_LDO_REF_EN | USB_PHY_PLL_LDO_REF_EN_EN;
+               writel(reg, phy + USB_PHY_PLL_REG12);
+       }
+
        /* VBUS divider select */
        am62->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
        reg = dwc3_ti_readl(am62, USBSS_PHY_CONFIG);
@@ -267,21 +292,15 @@ err_pm_disable:
        return ret;
 }
 
-static int dwc3_ti_remove_core(struct device *dev, void *c)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-
-       platform_device_unregister(pdev);
-       return 0;
-}
-
 static void dwc3_ti_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct dwc3_am62 *am62 = platform_get_drvdata(pdev);
        u32 reg;
 
-       device_for_each_child(dev, NULL, dwc3_ti_remove_core);
+       pm_runtime_get_sync(dev);
+       device_init_wakeup(dev, false);
+       of_platform_depopulate(dev);
 
        /* Clear mode valid bit */
        reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
@@ -289,7 +308,6 @@ static void dwc3_ti_remove(struct platform_device *pdev)
        dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);
 
        pm_runtime_put_sync(dev);
-       clk_disable_unprepare(am62->usb2_refclk);
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 }
index d1539fc9eabdae5d572ab58986a457f877c0b065..be7be00ecb34911ae170da7f3f8f4796442b2732 100644 (file)
@@ -52,8 +52,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
        if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
                simple->need_reset = true;
 
-       simple->resets = of_reset_control_array_get(np, false, true,
-                                                   true);
+       simple->resets = of_reset_control_array_get_optional_exclusive(np);
        if (IS_ERR(simple->resets)) {
                ret = PTR_ERR(simple->resets);
                dev_err(dev, "failed to get device resets, err=%d\n", ret);
@@ -173,6 +172,7 @@ static const struct of_device_id of_dwc3_simple_match[] = {
        { .compatible = "sprd,sc9860-dwc3" },
        { .compatible = "allwinner,sun50i-h6-dwc3" },
        { .compatible = "hisilicon,hi3670-dwc3" },
+       { .compatible = "hisilicon,hi3798mv200-dwc3" },
        { .compatible = "intel,keembay-dwc3" },
        { /* Sentinel */ }
 };
index dbd6a5b2b2892e50098c1c752a822b8036bdfe98..f6b2fab49d5e6045abc753455dca1f5176f0f9f2 100644 (file)
@@ -4,7 +4,6 @@
  * Inspired by dwc3-of-simple.c
  */
 
-#include <linux/acpi.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/clk.h>
 #define APPS_USB_AVG_BW 0
 #define APPS_USB_PEAK_BW MBps_to_icc(40)
 
-struct dwc3_acpi_pdata {
-       u32                     qscratch_base_offset;
-       u32                     qscratch_base_size;
-       u32                     dwc3_core_base_size;
-       int                     qusb2_phy_irq_index;
-       int                     dp_hs_phy_irq_index;
-       int                     dm_hs_phy_irq_index;
-       int                     ss_phy_irq_index;
-       bool                    is_urs;
-};
-
 struct dwc3_qcom {
        struct device           *dev;
        void __iomem            *qscratch_base;
        struct platform_device  *dwc3;
-       struct platform_device  *urs_usb;
        struct clk              **clks;
        int                     num_clocks;
        struct reset_control    *resets;
@@ -84,8 +71,6 @@ struct dwc3_qcom {
        struct notifier_block   vbus_nb;
        struct notifier_block   host_nb;
 
-       const struct dwc3_acpi_pdata *acpi_pdata;
-
        enum usb_dr_mode        mode;
        bool                    is_suspended;
        bool                    pm_suspended;
@@ -248,9 +233,6 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
        struct device *dev = qcom->dev;
        int ret;
 
-       if (has_acpi_companion(dev))
-               return 0;
-
        qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
        if (IS_ERR(qcom->icc_path_ddr)) {
                return dev_err_probe(dev, PTR_ERR(qcom->icc_path_ddr),
@@ -519,31 +501,13 @@ static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
                          PIPE_UTMI_CLK_DIS);
 }
 
-static int dwc3_qcom_get_irq(struct platform_device *pdev,
-                            const char *name, int num)
-{
-       struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
-       struct platform_device *pdev_irq = qcom->urs_usb ? qcom->urs_usb : pdev;
-       struct device_node *np = pdev->dev.of_node;
-       int ret;
-
-       if (np)
-               ret = platform_get_irq_byname_optional(pdev_irq, name);
-       else
-               ret = platform_get_irq_optional(pdev_irq, num);
-
-       return ret;
-}
-
 static int dwc3_qcom_setup_irq(struct platform_device *pdev)
 {
        struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
-       const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
        int irq;
        int ret;
 
-       irq = dwc3_qcom_get_irq(pdev, "qusb2_phy",
-                               pdata ? pdata->qusb2_phy_irq_index : -1);
+       irq = platform_get_irq_byname_optional(pdev, "qusb2_phy");
        if (irq > 0) {
                /* Keep wakeup interrupts disabled until suspend */
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
@@ -557,8 +521,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
                qcom->qusb2_phy_irq = irq;
        }
 
-       irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
-                               pdata ? pdata->dp_hs_phy_irq_index : -1);
+       irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_irq");
        if (irq > 0) {
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
                                        qcom_dwc3_resume_irq,
@@ -571,8 +534,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
                qcom->dp_hs_phy_irq = irq;
        }
 
-       irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
-                               pdata ? pdata->dm_hs_phy_irq_index : -1);
+       irq = platform_get_irq_byname_optional(pdev, "dm_hs_phy_irq");
        if (irq > 0) {
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
                                        qcom_dwc3_resume_irq,
@@ -585,8 +547,7 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
                qcom->dm_hs_phy_irq = irq;
        }
 
-       irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
-                               pdata ? pdata->ss_phy_irq_index : -1);
+       irq = platform_get_irq_byname_optional(pdev, "ss_phy_irq");
        if (irq > 0) {
                ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
                                        qcom_dwc3_resume_irq,
@@ -649,88 +610,6 @@ static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
        return 0;
 }
 
-static const struct property_entry dwc3_qcom_acpi_properties[] = {
-       PROPERTY_ENTRY_STRING("dr_mode", "host"),
-       {}
-};
-
-static const struct software_node dwc3_qcom_swnode = {
-       .properties = dwc3_qcom_acpi_properties,
-};
-
-static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
-{
-       struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
-       struct device           *dev = &pdev->dev;
-       struct resource         *res, *child_res = NULL;
-       struct platform_device  *pdev_irq = qcom->urs_usb ? qcom->urs_usb :
-                                                           pdev;
-       int                     irq;
-       int                     ret;
-
-       qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
-       if (!qcom->dwc3)
-               return -ENOMEM;
-
-       qcom->dwc3->dev.parent = dev;
-       qcom->dwc3->dev.type = dev->type;
-       qcom->dwc3->dev.dma_mask = dev->dma_mask;
-       qcom->dwc3->dev.dma_parms = dev->dma_parms;
-       qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
-
-       child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
-       if (!child_res) {
-               platform_device_put(qcom->dwc3);
-               return -ENOMEM;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get memory resource\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       child_res[0].flags = res->flags;
-       child_res[0].start = res->start;
-       child_res[0].end = child_res[0].start +
-               qcom->acpi_pdata->dwc3_core_base_size;
-
-       irq = platform_get_irq(pdev_irq, 0);
-       if (irq < 0) {
-               ret = irq;
-               goto out;
-       }
-       child_res[1].flags = IORESOURCE_IRQ;
-       child_res[1].start = child_res[1].end = irq;
-
-       ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add resources\n");
-               goto out;
-       }
-
-       ret = device_add_software_node(&qcom->dwc3->dev, &dwc3_qcom_swnode);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to add properties\n");
-               goto out;
-       }
-
-       ret = platform_device_add(qcom->dwc3);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add device\n");
-               device_remove_software_node(&qcom->dwc3->dev);
-               goto out;
-       }
-       kfree(child_res);
-       return 0;
-
-out:
-       platform_device_put(qcom->dwc3);
-       kfree(child_res);
-       return ret;
-}
-
 static int dwc3_qcom_of_register_core(struct platform_device *pdev)
 {
        struct dwc3_qcom        *qcom = platform_get_drvdata(pdev);
@@ -763,57 +642,12 @@ node_put:
        return ret;
 }
 
-static struct platform_device *dwc3_qcom_create_urs_usb_platdev(struct device *dev)
-{
-       struct platform_device *urs_usb = NULL;
-       struct fwnode_handle *fwh;
-       struct acpi_device *adev;
-       char name[8];
-       int ret;
-       int id;
-
-       /* Figure out device id */
-       ret = sscanf(fwnode_get_name(dev->fwnode), "URS%d", &id);
-       if (!ret)
-               return NULL;
-
-       /* Find the child using name */
-       snprintf(name, sizeof(name), "USB%d", id);
-       fwh = fwnode_get_named_child_node(dev->fwnode, name);
-       if (!fwh)
-               return NULL;
-
-       adev = to_acpi_device_node(fwh);
-       if (!adev)
-               goto err_put_handle;
-
-       urs_usb = acpi_create_platform_device(adev, NULL);
-       if (IS_ERR_OR_NULL(urs_usb))
-               goto err_put_handle;
-
-       return urs_usb;
-
-err_put_handle:
-       fwnode_handle_put(fwh);
-
-       return urs_usb;
-}
-
-static void dwc3_qcom_destroy_urs_usb_platdev(struct platform_device *urs_usb)
-{
-       struct fwnode_handle *fwh = urs_usb->dev.fwnode;
-
-       platform_device_unregister(urs_usb);
-       fwnode_handle_put(fwh);
-}
-
 static int dwc3_qcom_probe(struct platform_device *pdev)
 {
        struct device_node      *np = pdev->dev.of_node;
        struct device           *dev = &pdev->dev;
        struct dwc3_qcom        *qcom;
-       struct resource         *res, *parent_res = NULL;
-       struct resource         local_res;
+       struct resource         *res;
        int                     ret, i;
        bool                    ignore_pipe_clk;
        bool                    wakeup_source;
@@ -825,14 +659,6 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, qcom);
        qcom->dev = &pdev->dev;
 
-       if (has_acpi_companion(dev)) {
-               qcom->acpi_pdata = acpi_device_get_match_data(dev);
-               if (!qcom->acpi_pdata) {
-                       dev_err(&pdev->dev, "no supporting ACPI device data\n");
-                       return -EINVAL;
-               }
-       }
-
        qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
        if (IS_ERR(qcom->resets)) {
                return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets),
@@ -861,40 +687,16 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       if (np) {
-               parent_res = res;
-       } else {
-               memcpy(&local_res, res, sizeof(struct resource));
-               parent_res = &local_res;
-
-               parent_res->start = res->start +
-                       qcom->acpi_pdata->qscratch_base_offset;
-               parent_res->end = parent_res->start +
-                       qcom->acpi_pdata->qscratch_base_size;
-
-               if (qcom->acpi_pdata->is_urs) {
-                       qcom->urs_usb = dwc3_qcom_create_urs_usb_platdev(dev);
-                       if (IS_ERR_OR_NULL(qcom->urs_usb)) {
-                               dev_err(dev, "failed to create URS USB platdev\n");
-                               if (!qcom->urs_usb)
-                                       ret = -ENODEV;
-                               else
-                                       ret = PTR_ERR(qcom->urs_usb);
-                               goto clk_disable;
-                       }
-               }
-       }
-
-       qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
+       qcom->qscratch_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(qcom->qscratch_base)) {
                ret = PTR_ERR(qcom->qscratch_base);
-               goto free_urs;
+               goto clk_disable;
        }
 
        ret = dwc3_qcom_setup_irq(pdev);
        if (ret) {
                dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
-               goto free_urs;
+               goto clk_disable;
        }
 
        /*
@@ -906,14 +708,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        if (ignore_pipe_clk)
                dwc3_qcom_select_utmi_clk(qcom);
 
-       if (np)
-               ret = dwc3_qcom_of_register_core(pdev);
-       else
-               ret = dwc3_qcom_acpi_register_core(pdev);
-
+       ret = dwc3_qcom_of_register_core(pdev);
        if (ret) {
                dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
-               goto free_urs;
+               goto clk_disable;
        }
 
        ret = dwc3_qcom_interconnect_init(qcom);
@@ -945,16 +743,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 interconnect_exit:
        dwc3_qcom_interconnect_exit(qcom);
 depopulate:
-       if (np) {
-               of_platform_depopulate(&pdev->dev);
-       } else {
-               device_remove_software_node(&qcom->dwc3->dev);
-               platform_device_del(qcom->dwc3);
-       }
+       of_platform_depopulate(&pdev->dev);
        platform_device_put(qcom->dwc3);
-free_urs:
-       if (qcom->urs_usb)
-               dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb);
 clk_disable:
        for (i = qcom->num_clocks - 1; i >= 0; i--) {
                clk_disable_unprepare(qcom->clks[i]);
@@ -969,21 +759,12 @@ reset_assert:
 static void dwc3_qcom_remove(struct platform_device *pdev)
 {
        struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
-       struct device_node *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
        int i;
 
-       if (np) {
-               of_platform_depopulate(&pdev->dev);
-       } else {
-               device_remove_software_node(&qcom->dwc3->dev);
-               platform_device_del(qcom->dwc3);
-       }
+       of_platform_depopulate(&pdev->dev);
        platform_device_put(qcom->dwc3);
 
-       if (qcom->urs_usb)
-               dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb);
-
        for (i = qcom->num_clocks - 1; i >= 0; i--) {
                clk_disable_unprepare(qcom->clks[i]);
                clk_put(qcom->clks[i]);
@@ -1053,38 +834,6 @@ static const struct of_device_id dwc3_qcom_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
 
-#ifdef CONFIG_ACPI
-static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
-       .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
-       .qscratch_base_size = SDM845_QSCRATCH_SIZE,
-       .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
-       .qusb2_phy_irq_index = 1,
-       .dp_hs_phy_irq_index = 4,
-       .dm_hs_phy_irq_index = 3,
-       .ss_phy_irq_index = 2
-};
-
-static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
-       .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
-       .qscratch_base_size = SDM845_QSCRATCH_SIZE,
-       .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
-       .qusb2_phy_irq_index = 1,
-       .dp_hs_phy_irq_index = 4,
-       .dm_hs_phy_irq_index = 3,
-       .ss_phy_irq_index = 2,
-       .is_urs = true,
-};
-
-static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
-       { "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
-       { "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata },
-       { "QCOM0497", (unsigned long)&sdm845_acpi_urs_pdata },
-       { "QCOM04A6", (unsigned long)&sdm845_acpi_pdata },
-       { },
-};
-MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
-#endif
-
 static struct platform_driver dwc3_qcom_driver = {
        .probe          = dwc3_qcom_probe,
        .remove_new     = dwc3_qcom_remove,
@@ -1092,7 +841,6 @@ static struct platform_driver dwc3_qcom_driver = {
                .name   = "dwc3-qcom",
                .pm     = &dwc3_qcom_dev_pm_ops,
                .of_match_table = dwc3_qcom_of_match,
-               .acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
        },
 };
 
index 6ae8a36f21cf687fa6eaff07bf37f8faa96bf7f9..72bb722da2f258fb07fa7701bbe07b7509f1c15a 100644 (file)
@@ -646,6 +646,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                return -EINVAL;
 
        case USB_STATE_ADDRESS:
+               dwc3_gadget_start_config(dwc, 2);
                dwc3_gadget_clear_tx_fifos(dwc);
 
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
index 28f49400f3e8b178e23c881120577da461178c35..40c52dbc28d3b4a1b2ff9580dc183e0db1152bdd 100644 (file)
@@ -519,77 +519,56 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
 static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep)
 {
        struct dwc3_gadget_ep_cmd_params params;
+       int ret;
+
+       if (dep->flags & DWC3_EP_RESOURCE_ALLOCATED)
+               return 0;
 
        memset(&params, 0x00, sizeof(params));
 
        params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
 
-       return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
+       ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETTRANSFRESOURCE,
                        &params);
+       if (ret)
+               return ret;
+
+       dep->flags |= DWC3_EP_RESOURCE_ALLOCATED;
+       return 0;
 }
 
 /**
- * dwc3_gadget_start_config - configure ep resources
- * @dep: endpoint that is being enabled
- *
- * Issue a %DWC3_DEPCMD_DEPSTARTCFG command to @dep. After the command's
- * completion, it will set Transfer Resource for all available endpoints.
- *
- * The assignment of transfer resources cannot perfectly follow the data book
- * due to the fact that the controller driver does not have all knowledge of the
- * configuration in advance. It is given this information piecemeal by the
- * composite gadget framework after every SET_CONFIGURATION and
- * SET_INTERFACE. Trying to follow the databook programming model in this
- * scenario can cause errors. For two reasons:
- *
- * 1) The databook says to do %DWC3_DEPCMD_DEPSTARTCFG for every
- * %USB_REQ_SET_CONFIGURATION and %USB_REQ_SET_INTERFACE (8.1.5). This is
- * incorrect in the scenario of multiple interfaces.
- *
- * 2) The databook does not mention doing more %DWC3_DEPCMD_DEPXFERCFG for new
- * endpoint on alt setting (8.1.6).
- *
- * The following simplified method is used instead:
+ * dwc3_gadget_start_config - reset endpoint resources
+ * @dwc: pointer to the DWC3 context
+ * @resource_index: DEPSTARTCFG.XferRscIdx value (must be 0 or 2)
  *
- * All hardware endpoints can be assigned a transfer resource and this setting
- * will stay persistent until either a core reset or hibernation. So whenever we
- * do a %DWC3_DEPCMD_DEPSTARTCFG(0) we can go ahead and do
- * %DWC3_DEPCMD_DEPXFERCFG for every hardware endpoint as well. We are
- * guaranteed that there are as many transfer resources as endpoints.
+ * Set resource_index=0 to reset all endpoints' resources allocation. Do this as
+ * part of the power-on/soft-reset initialization.
  *
- * This function is called for each endpoint when it is being enabled but is
- * triggered only when called for EP0-out, which always happens first, and which
- * should only happen in one of the above conditions.
+ * Set resource_index=2 to reset only non-control endpoints' resources. Do this
+ * on receiving the SET_CONFIGURATION request or hibernation resume.
  */
-static int dwc3_gadget_start_config(struct dwc3_ep *dep)
+int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index)
 {
        struct dwc3_gadget_ep_cmd_params params;
-       struct dwc3             *dwc;
        u32                     cmd;
        int                     i;
        int                     ret;
 
-       if (dep->number)
-               return 0;
+       if (resource_index != 0 && resource_index != 2)
+               return -EINVAL;
 
        memset(&params, 0x00, sizeof(params));
        cmd = DWC3_DEPCMD_DEPSTARTCFG;
-       dwc = dep->dwc;
+       cmd |= DWC3_DEPCMD_PARAM(resource_index);
 
-       ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
+       ret = dwc3_send_gadget_ep_cmd(dwc->eps[0], cmd, &params);
        if (ret)
                return ret;
 
-       for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
-               struct dwc3_ep *dep = dwc->eps[i];
-
-               if (!dep)
-                       continue;
-
-               ret = dwc3_gadget_set_xfer_resource(dep);
-               if (ret)
-                       return ret;
-       }
+       /* Reset resource allocation flags */
+       for (i = resource_index; i < dwc->num_eps && dwc->eps[i]; i++)
+               dwc->eps[i]->flags &= ~DWC3_EP_RESOURCE_ALLOCATED;
 
        return 0;
 }
@@ -884,16 +863,18 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
                ret = dwc3_gadget_resize_tx_fifos(dep);
                if (ret)
                        return ret;
-
-               ret = dwc3_gadget_start_config(dep);
-               if (ret)
-                       return ret;
        }
 
        ret = dwc3_gadget_set_ep_config(dep, action);
        if (ret)
                return ret;
 
+       if (!(dep->flags & DWC3_EP_RESOURCE_ALLOCATED)) {
+               ret = dwc3_gadget_set_xfer_resource(dep);
+               if (ret)
+                       return ret;
+       }
+
        if (!(dep->flags & DWC3_EP_ENABLED)) {
                struct dwc3_trb *trb_st_hw;
                struct dwc3_trb *trb_link;
@@ -1047,7 +1028,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
        dep->stream_capable = false;
        dep->type = 0;
-       mask = DWC3_EP_TXFIFO_RESIZED;
+       mask = DWC3_EP_TXFIFO_RESIZED | DWC3_EP_RESOURCE_ALLOCATED;
        /*
         * dwc3_remove_requests() can exit early if DWC3 EP delayed stop is
         * set.  Do not clear DEP flags, so that the end transfer command will
@@ -2913,6 +2894,12 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
        /* Start with SuperSpeed Default */
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
+       ret = dwc3_gadget_start_config(dwc, 0);
+       if (ret) {
+               dev_err(dwc->dev, "failed to config endpoints\n");
+               return ret;
+       }
+
        dep = dwc->eps[0];
        dep->flags = 0;
        ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
@@ -3428,7 +3415,7 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep,
                struct dwc3_request *req, const struct dwc3_event_depevt *event,
                int status)
 {
-       struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue];
+       struct dwc3_trb *trb;
        struct scatterlist *sg = req->sg;
        struct scatterlist *s;
        unsigned int num_queued = req->num_queued_sgs;
index 55a56cf67d7364998f9f4a42fd95e5d856cd105c..d73e735e40810807e5a09750aafb36ed318eee48 100644 (file)
@@ -119,6 +119,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
 void dwc3_ep0_send_delayed_status(struct dwc3 *dwc);
 void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt);
+int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index);
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
index 43230915323c7dfa6625bfbbe67b1f8df238dcd4..5a5cb6ce9946d36e8b3de702fec7b3ab102f0779 100644 (file)
 #include <linux/of.h>
 #include <linux/platform_device.h>
 
+#include "../host/xhci-port.h"
+#include "../host/xhci-ext-caps.h"
+#include "../host/xhci-caps.h"
 #include "core.h"
 
+#define XHCI_HCSPARAMS1                0x4
+#define XHCI_PORTSC_BASE       0x400
+
+/**
+ * dwc3_power_off_all_roothub_ports - Power off all Root hub ports
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
+{
+       void __iomem *xhci_regs;
+       u32 op_regs_base;
+       int port_num;
+       u32 offset;
+       u32 reg;
+       int i;
+
+       /* xhci regs is not mapped yet, do it temperary here */
+       if (dwc->xhci_resources[0].start) {
+               xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END);
+               if (!xhci_regs) {
+                       dev_err(dwc->dev, "Failed to ioremap xhci_regs\n");
+                       return;
+               }
+
+               op_regs_base = HC_LENGTH(readl(xhci_regs));
+               reg = readl(xhci_regs + XHCI_HCSPARAMS1);
+               port_num = HCS_MAX_PORTS(reg);
+
+               for (i = 1; i <= port_num; i++) {
+                       offset = op_regs_base + XHCI_PORTSC_BASE + 0x10 * (i - 1);
+                       reg = readl(xhci_regs + offset);
+                       reg &= ~PORT_POWER;
+                       writel(reg, xhci_regs + offset);
+               }
+
+               iounmap(xhci_regs);
+       } else {
+               dev_err(dwc->dev, "xhci base reg invalid\n");
+       }
+}
+
 static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
                                        int irq, char *name)
 {
@@ -66,6 +110,12 @@ int dwc3_host_init(struct dwc3 *dwc)
        int                     ret, irq;
        int                     prop_idx = 0;
 
+       /*
+        * Some platforms need to power off all Root hub ports immediately after DWC3 set to host
+        * mode to avoid VBUS glitch happen when xhci get reset later.
+        */
+       dwc3_power_off_all_roothub_ports(dwc);
+
        irq = dwc3_host_get_irq(dwc);
        if (irq < 0)
                return irq;
index b3592bcb0f96684ef41edec3d73997aba3b92fe8..566ff0b1282a82950b0af3c020261d83a6d21579 100644 (file)
@@ -190,6 +190,7 @@ config USB_F_MASS_STORAGE
        tristate
 
 config USB_F_FS
+       select DMA_SHARED_BUFFER
        tristate
 
 config USB_F_UAC1
index 6bff6cb93789167b7de9d2b939d5e4e6255078db..bffbc1dc651f9ecdead7e3398004ca2e77355cef 100644 (file)
@@ -15,6 +15,9 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/blkdev.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-fence.h>
+#include <linux/dma-resv.h>
 #include <linux/pagemap.h>
 #include <linux/export.h>
 #include <linux/fs_parser.h>
@@ -43,6 +46,8 @@
 
 #define FUNCTIONFS_MAGIC       0xa647361 /* Chosen by a honest dice roll ;) */
 
+MODULE_IMPORT_NS(DMA_BUF);
+
 /* Reference counter handling */
 static void ffs_data_get(struct ffs_data *ffs);
 static void ffs_data_put(struct ffs_data *ffs);
@@ -124,6 +129,25 @@ struct ffs_ep {
        u8                              num;
 };
 
+struct ffs_dmabuf_priv {
+       struct list_head entry;
+       struct kref ref;
+       struct ffs_data *ffs;
+       struct dma_buf_attachment *attach;
+       struct sg_table *sgt;
+       enum dma_data_direction dir;
+       spinlock_t lock;
+       u64 context;
+       struct usb_request *req;        /* P: ffs->eps_lock */
+       struct usb_ep *ep;              /* P: ffs->eps_lock */
+};
+
+struct ffs_dma_fence {
+       struct dma_fence base;
+       struct ffs_dmabuf_priv *priv;
+       struct work_struct work;
+};
+
 struct ffs_epfile {
        /* Protects ep->ep and ep->req. */
        struct mutex                    mutex;
@@ -197,6 +221,11 @@ struct ffs_epfile {
        unsigned char                   isoc;   /* P: ffs->eps_lock */
 
        unsigned char                   _pad;
+
+       /* Protects dmabufs */
+       struct mutex                    dmabufs_mutex;
+       struct list_head                dmabufs; /* P: dmabufs_mutex */
+       atomic_t                        seqno;
 };
 
 struct ffs_buffer {
@@ -934,31 +963,44 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
        return ret;
 }
 
-static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
+static struct ffs_ep *ffs_epfile_wait_ep(struct file *file)
 {
        struct ffs_epfile *epfile = file->private_data;
-       struct usb_request *req;
        struct ffs_ep *ep;
-       char *data = NULL;
-       ssize_t ret, data_len = -EINVAL;
-       int halt;
-
-       /* Are we still active? */
-       if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
-               return -ENODEV;
+       int ret;
 
        /* Wait for endpoint to be enabled */
        ep = epfile->ep;
        if (!ep) {
                if (file->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
+                       return ERR_PTR(-EAGAIN);
 
                ret = wait_event_interruptible(
                                epfile->ffs->wait, (ep = epfile->ep));
                if (ret)
-                       return -EINTR;
+                       return ERR_PTR(-EINTR);
        }
 
+       return ep;
+}
+
+static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
+{
+       struct ffs_epfile *epfile = file->private_data;
+       struct usb_request *req;
+       struct ffs_ep *ep;
+       char *data = NULL;
+       ssize_t ret, data_len = -EINVAL;
+       int halt;
+
+       /* Are we still active? */
+       if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
+               return -ENODEV;
+
+       ep = ffs_epfile_wait_ep(file);
+       if (IS_ERR(ep))
+               return PTR_ERR(ep);
+
        /* Do we halt? */
        halt = (!io_data->read == !epfile->in);
        if (halt && epfile->isoc)
@@ -1258,10 +1300,58 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
        return res;
 }
 
+static void ffs_dmabuf_release(struct kref *ref)
+{
+       struct ffs_dmabuf_priv *priv = container_of(ref, struct ffs_dmabuf_priv, ref);
+       struct dma_buf_attachment *attach = priv->attach;
+       struct dma_buf *dmabuf = attach->dmabuf;
+
+       pr_vdebug("FFS DMABUF release\n");
+       dma_resv_lock(dmabuf->resv, NULL);
+       dma_buf_unmap_attachment(attach, priv->sgt, priv->dir);
+       dma_resv_unlock(dmabuf->resv);
+
+       dma_buf_detach(attach->dmabuf, attach);
+       dma_buf_put(dmabuf);
+       kfree(priv);
+}
+
+static void ffs_dmabuf_get(struct dma_buf_attachment *attach)
+{
+       struct ffs_dmabuf_priv *priv = attach->importer_priv;
+
+       kref_get(&priv->ref);
+}
+
+static void ffs_dmabuf_put(struct dma_buf_attachment *attach)
+{
+       struct ffs_dmabuf_priv *priv = attach->importer_priv;
+
+       kref_put(&priv->ref, ffs_dmabuf_release);
+}
+
 static int
 ffs_epfile_release(struct inode *inode, struct file *file)
 {
        struct ffs_epfile *epfile = inode->i_private;
+       struct ffs_dmabuf_priv *priv, *tmp;
+       struct ffs_data *ffs = epfile->ffs;
+
+       mutex_lock(&epfile->dmabufs_mutex);
+
+       /* Close all attached DMABUFs */
+       list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) {
+               /* Cancel any pending transfer */
+               spin_lock_irq(&ffs->eps_lock);
+               if (priv->ep && priv->req)
+                       usb_ep_dequeue(priv->ep, priv->req);
+               spin_unlock_irq(&ffs->eps_lock);
+
+               list_del(&priv->entry);
+               ffs_dmabuf_put(priv->attach);
+       }
+
+       mutex_unlock(&epfile->dmabufs_mutex);
 
        __ffs_epfile_read_buffer_free(epfile);
        ffs_data_closed(epfile->ffs);
@@ -1269,6 +1359,356 @@ ffs_epfile_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static void ffs_dmabuf_cleanup(struct work_struct *work)
+{
+       struct ffs_dma_fence *dma_fence =
+               container_of(work, struct ffs_dma_fence, work);
+       struct ffs_dmabuf_priv *priv = dma_fence->priv;
+       struct dma_buf_attachment *attach = priv->attach;
+       struct dma_fence *fence = &dma_fence->base;
+
+       ffs_dmabuf_put(attach);
+       dma_fence_put(fence);
+}
+
+static void ffs_dmabuf_signal_done(struct ffs_dma_fence *dma_fence, int ret)
+{
+       struct ffs_dmabuf_priv *priv = dma_fence->priv;
+       struct dma_fence *fence = &dma_fence->base;
+       bool cookie = dma_fence_begin_signalling();
+
+       dma_fence_get(fence);
+       fence->error = ret;
+       dma_fence_signal(fence);
+       dma_fence_end_signalling(cookie);
+
+       /*
+        * The fence will be unref'd in ffs_dmabuf_cleanup.
+        * It can't be done here, as the unref functions might try to lock
+        * the resv object, which would deadlock.
+        */
+       INIT_WORK(&dma_fence->work, ffs_dmabuf_cleanup);
+       queue_work(priv->ffs->io_completion_wq, &dma_fence->work);
+}
+
+static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep,
+                                         struct usb_request *req)
+{
+       pr_vdebug("FFS: DMABUF transfer complete, status=%d\n", req->status);
+       ffs_dmabuf_signal_done(req->context, req->status);
+       usb_ep_free_request(ep, req);
+}
+
+static const char *ffs_dmabuf_get_driver_name(struct dma_fence *fence)
+{
+       return "functionfs";
+}
+
+static const char *ffs_dmabuf_get_timeline_name(struct dma_fence *fence)
+{
+       return "";
+}
+
+static void ffs_dmabuf_fence_release(struct dma_fence *fence)
+{
+       struct ffs_dma_fence *dma_fence =
+               container_of(fence, struct ffs_dma_fence, base);
+
+       kfree(dma_fence);
+}
+
+static const struct dma_fence_ops ffs_dmabuf_fence_ops = {
+       .get_driver_name        = ffs_dmabuf_get_driver_name,
+       .get_timeline_name      = ffs_dmabuf_get_timeline_name,
+       .release                = ffs_dmabuf_fence_release,
+};
+
+static int ffs_dma_resv_lock(struct dma_buf *dmabuf, bool nonblock)
+{
+       if (!nonblock)
+               return dma_resv_lock_interruptible(dmabuf->resv, NULL);
+
+       if (!dma_resv_trylock(dmabuf->resv))
+               return -EBUSY;
+
+       return 0;
+}
+
+static struct dma_buf_attachment *
+ffs_dmabuf_find_attachment(struct ffs_epfile *epfile, struct dma_buf *dmabuf)
+{
+       struct device *dev = epfile->ffs->gadget->dev.parent;
+       struct dma_buf_attachment *attach = NULL;
+       struct ffs_dmabuf_priv *priv;
+
+       mutex_lock(&epfile->dmabufs_mutex);
+
+       list_for_each_entry(priv, &epfile->dmabufs, entry) {
+               if (priv->attach->dev == dev
+                   && priv->attach->dmabuf == dmabuf) {
+                       attach = priv->attach;
+                       break;
+               }
+       }
+
+       if (attach)
+               ffs_dmabuf_get(attach);
+
+       mutex_unlock(&epfile->dmabufs_mutex);
+
+       return attach ?: ERR_PTR(-EPERM);
+}
+
+static int ffs_dmabuf_attach(struct file *file, int fd)
+{
+       bool nonblock = file->f_flags & O_NONBLOCK;
+       struct ffs_epfile *epfile = file->private_data;
+       struct usb_gadget *gadget = epfile->ffs->gadget;
+       struct dma_buf_attachment *attach;
+       struct ffs_dmabuf_priv *priv;
+       enum dma_data_direction dir;
+       struct sg_table *sg_table;
+       struct dma_buf *dmabuf;
+       int err;
+
+       if (!gadget || !gadget->sg_supported)
+               return -EPERM;
+
+       dmabuf = dma_buf_get(fd);
+       if (IS_ERR(dmabuf))
+               return PTR_ERR(dmabuf);
+
+       attach = dma_buf_attach(dmabuf, gadget->dev.parent);
+       if (IS_ERR(attach)) {
+               err = PTR_ERR(attach);
+               goto err_dmabuf_put;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               err = -ENOMEM;
+               goto err_dmabuf_detach;
+       }
+
+       dir = epfile->in ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       err = ffs_dma_resv_lock(dmabuf, nonblock);
+       if (err)
+               goto err_free_priv;
+
+       sg_table = dma_buf_map_attachment(attach, dir);
+       dma_resv_unlock(dmabuf->resv);
+
+       if (IS_ERR(sg_table)) {
+               err = PTR_ERR(sg_table);
+               goto err_free_priv;
+       }
+
+       attach->importer_priv = priv;
+
+       priv->sgt = sg_table;
+       priv->dir = dir;
+       priv->ffs = epfile->ffs;
+       priv->attach = attach;
+       spin_lock_init(&priv->lock);
+       kref_init(&priv->ref);
+       priv->context = dma_fence_context_alloc(1);
+
+       mutex_lock(&epfile->dmabufs_mutex);
+       list_add(&priv->entry, &epfile->dmabufs);
+       mutex_unlock(&epfile->dmabufs_mutex);
+
+       return 0;
+
+err_free_priv:
+       kfree(priv);
+err_dmabuf_detach:
+       dma_buf_detach(dmabuf, attach);
+err_dmabuf_put:
+       dma_buf_put(dmabuf);
+
+       return err;
+}
+
+static int ffs_dmabuf_detach(struct file *file, int fd)
+{
+       struct ffs_epfile *epfile = file->private_data;
+       struct ffs_data *ffs = epfile->ffs;
+       struct device *dev = ffs->gadget->dev.parent;
+       struct ffs_dmabuf_priv *priv, *tmp;
+       struct dma_buf *dmabuf;
+       int ret = -EPERM;
+
+       dmabuf = dma_buf_get(fd);
+       if (IS_ERR(dmabuf))
+               return PTR_ERR(dmabuf);
+
+       mutex_lock(&epfile->dmabufs_mutex);
+
+       list_for_each_entry_safe(priv, tmp, &epfile->dmabufs, entry) {
+               if (priv->attach->dev == dev
+                   && priv->attach->dmabuf == dmabuf) {
+                       /* Cancel any pending transfer */
+                       spin_lock_irq(&ffs->eps_lock);
+                       if (priv->ep && priv->req)
+                               usb_ep_dequeue(priv->ep, priv->req);
+                       spin_unlock_irq(&ffs->eps_lock);
+
+                       list_del(&priv->entry);
+
+                       /* Unref the reference from ffs_dmabuf_attach() */
+                       ffs_dmabuf_put(priv->attach);
+                       ret = 0;
+                       break;
+               }
+       }
+
+       mutex_unlock(&epfile->dmabufs_mutex);
+       dma_buf_put(dmabuf);
+
+       return ret;
+}
+
+static int ffs_dmabuf_transfer(struct file *file,
+                              const struct usb_ffs_dmabuf_transfer_req *req)
+{
+       bool nonblock = file->f_flags & O_NONBLOCK;
+       struct ffs_epfile *epfile = file->private_data;
+       struct dma_buf_attachment *attach;
+       struct ffs_dmabuf_priv *priv;
+       struct ffs_dma_fence *fence;
+       struct usb_request *usb_req;
+       struct dma_buf *dmabuf;
+       struct ffs_ep *ep;
+       bool cookie;
+       u32 seqno;
+       int ret;
+
+       if (req->flags & ~USB_FFS_DMABUF_TRANSFER_MASK)
+               return -EINVAL;
+
+       dmabuf = dma_buf_get(req->fd);
+       if (IS_ERR(dmabuf))
+               return PTR_ERR(dmabuf);
+
+       if (req->length > dmabuf->size || req->length == 0) {
+               ret = -EINVAL;
+               goto err_dmabuf_put;
+       }
+
+       attach = ffs_dmabuf_find_attachment(epfile, dmabuf);
+       if (IS_ERR(attach)) {
+               ret = PTR_ERR(attach);
+               goto err_dmabuf_put;
+       }
+
+       priv = attach->importer_priv;
+
+       ep = ffs_epfile_wait_ep(file);
+       if (IS_ERR(ep)) {
+               ret = PTR_ERR(ep);
+               goto err_attachment_put;
+       }
+
+       ret = ffs_dma_resv_lock(dmabuf, nonblock);
+       if (ret)
+               goto err_attachment_put;
+
+       /* Make sure we don't have writers */
+       if (!dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_WRITE)) {
+               pr_vdebug("FFS WRITE fence is not signaled\n");
+               ret = -EBUSY;
+               goto err_resv_unlock;
+       }
+
+       /* If we're writing to the DMABUF, make sure we don't have readers */
+       if (epfile->in &&
+           !dma_resv_test_signaled(dmabuf->resv, DMA_RESV_USAGE_READ)) {
+               pr_vdebug("FFS READ fence is not signaled\n");
+               ret = -EBUSY;
+               goto err_resv_unlock;
+       }
+
+       ret = dma_resv_reserve_fences(dmabuf->resv, 1);
+       if (ret)
+               goto err_resv_unlock;
+
+       fence = kmalloc(sizeof(*fence), GFP_KERNEL);
+       if (!fence) {
+               ret = -ENOMEM;
+               goto err_resv_unlock;
+       }
+
+       fence->priv = priv;
+
+       spin_lock_irq(&epfile->ffs->eps_lock);
+
+       /* In the meantime, endpoint got disabled or changed. */
+       if (epfile->ep != ep) {
+               ret = -ESHUTDOWN;
+               goto err_fence_put;
+       }
+
+       usb_req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
+       if (!usb_req) {
+               ret = -ENOMEM;
+               goto err_fence_put;
+       }
+
+       /*
+        * usb_ep_queue() guarantees that all transfers are processed in the
+        * order they are enqueued, so we can use a simple incrementing
+        * sequence number for the dma_fence.
+        */
+       seqno = atomic_add_return(1, &epfile->seqno);
+
+       dma_fence_init(&fence->base, &ffs_dmabuf_fence_ops,
+                      &priv->lock, priv->context, seqno);
+
+       dma_resv_add_fence(dmabuf->resv, &fence->base,
+                          dma_resv_usage_rw(epfile->in));
+       dma_resv_unlock(dmabuf->resv);
+
+       /* Now that the dma_fence is in place, queue the transfer. */
+
+       usb_req->length = req->length;
+       usb_req->buf = NULL;
+       usb_req->sg = priv->sgt->sgl;
+       usb_req->num_sgs = sg_nents_for_len(priv->sgt->sgl, req->length);
+       usb_req->sg_was_mapped = true;
+       usb_req->context  = fence;
+       usb_req->complete = ffs_epfile_dmabuf_io_complete;
+
+       cookie = dma_fence_begin_signalling();
+       ret = usb_ep_queue(ep->ep, usb_req, GFP_ATOMIC);
+       dma_fence_end_signalling(cookie);
+       if (!ret) {
+               priv->req = usb_req;
+               priv->ep = ep->ep;
+       } else {
+               pr_warn("FFS: Failed to queue DMABUF: %d\n", ret);
+               ffs_dmabuf_signal_done(fence, ret);
+               usb_ep_free_request(ep->ep, usb_req);
+       }
+
+       spin_unlock_irq(&epfile->ffs->eps_lock);
+       dma_buf_put(dmabuf);
+
+       return ret;
+
+err_fence_put:
+       spin_unlock_irq(&epfile->ffs->eps_lock);
+       dma_fence_put(&fence->base);
+err_resv_unlock:
+       dma_resv_unlock(dmabuf->resv);
+err_attachment_put:
+       ffs_dmabuf_put(attach);
+err_dmabuf_put:
+       dma_buf_put(dmabuf);
+
+       return ret;
+}
+
 static long ffs_epfile_ioctl(struct file *file, unsigned code,
                             unsigned long value)
 {
@@ -1279,18 +1719,49 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
        if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
                return -ENODEV;
 
-       /* Wait for endpoint to be enabled */
-       ep = epfile->ep;
-       if (!ep) {
-               if (file->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
+       switch (code) {
+       case FUNCTIONFS_DMABUF_ATTACH:
+       {
+               int fd;
 
-               ret = wait_event_interruptible(
-                               epfile->ffs->wait, (ep = epfile->ep));
-               if (ret)
-                       return -EINTR;
+               if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               return ffs_dmabuf_attach(file, fd);
+       }
+       case FUNCTIONFS_DMABUF_DETACH:
+       {
+               int fd;
+
+               if (copy_from_user(&fd, (void __user *)value, sizeof(fd))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               return ffs_dmabuf_detach(file, fd);
+       }
+       case FUNCTIONFS_DMABUF_TRANSFER:
+       {
+               struct usb_ffs_dmabuf_transfer_req req;
+
+               if (copy_from_user(&req, (void __user *)value, sizeof(req))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               return ffs_dmabuf_transfer(file, &req);
+       }
+       default:
+               break;
        }
 
+       /* Wait for endpoint to be enabled */
+       ep = ffs_epfile_wait_ep(file);
+       if (IS_ERR(ep))
+               return PTR_ERR(ep);
+
        spin_lock_irq(&epfile->ffs->eps_lock);
 
        /* In the meantime, endpoint got disabled or changed. */
@@ -1863,6 +2334,8 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
        for (i = 1; i <= count; ++i, ++epfile) {
                epfile->ffs = ffs;
                mutex_init(&epfile->mutex);
+               mutex_init(&epfile->dmabufs_mutex);
+               INIT_LIST_HEAD(&epfile->dmabufs);
                if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
                        sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
                else
@@ -3445,6 +3918,25 @@ static inline struct f_fs_opts *to_ffs_opts(struct config_item *item)
                            func_inst.group);
 }
 
+static ssize_t f_fs_opts_ready_show(struct config_item *item, char *page)
+{
+       struct f_fs_opts *opts = to_ffs_opts(item);
+       int ready;
+
+       ffs_dev_lock();
+       ready = opts->dev->desc_ready;
+       ffs_dev_unlock();
+
+       return sprintf(page, "%d\n", ready);
+}
+
+CONFIGFS_ATTR_RO(f_fs_opts_, ready);
+
+static struct configfs_attribute *ffs_attrs[] = {
+       &f_fs_opts_attr_ready,
+       NULL,
+};
+
 static void ffs_attr_release(struct config_item *item)
 {
        struct f_fs_opts *opts = to_ffs_opts(item);
@@ -3458,6 +3950,7 @@ static struct configfs_item_operations ffs_item_ops = {
 
 static const struct config_item_type ffs_func_type = {
        .ct_item_ops    = &ffs_item_ops,
+       .ct_attrs       = ffs_attrs,
        .ct_owner       = THIS_MODULE,
 };
 
index 3c5a6f6ac3414c965519a23d00650c77c9793a4e..444212c0b5a98cc38b3795d9368b648f01754949 100644 (file)
@@ -718,7 +718,7 @@ static const struct net_device_ops eth_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-static struct device_type gadget_type = {
+static const struct device_type gadget_type = {
        .name   = "gadget",
 };
 
index dd3241fc6939d6fa0e0a23a36469e5f137164e3a..d41f5f31dadd583e44a7823a7a89e5b4dafcb78f 100644 (file)
@@ -35,6 +35,9 @@ uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
 
        data[1] = UVC_STREAM_EOH | video->fid;
 
+       if (video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE)
+               data[1] |= UVC_STREAM_ERR;
+
        if (video->queue.buf_used == 0 && ts.tv_sec) {
                /* dwClockFrequency is 48 MHz */
                u32 pts = ((u64)ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC) * 48;
@@ -370,6 +373,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
        struct uvc_video *video = ureq->video;
        struct uvc_video_queue *queue = &video->queue;
        struct uvc_buffer *last_buf;
+       struct usb_request *to_queue = req;
        unsigned long flags;
        bool is_bulk = video->max_payload_size;
        int ret = 0;
@@ -397,7 +401,8 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
 
        case -EXDEV:
                uvcg_dbg(&video->uvc->func, "VS request missed xfer.\n");
-               queue->flags |= UVC_QUEUE_DROP_INCOMPLETE;
+               if (req->length != 0)
+                       queue->flags |= UVC_QUEUE_DROP_INCOMPLETE;
                break;
 
        case -ESHUTDOWN:        /* disconnect from host. */
@@ -425,59 +430,59 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
         * we're still streaming before queueing the usb_request
         * back to req_free
         */
-       if (video->is_enabled) {
+       if (!video->is_enabled) {
+               uvc_video_free_request(ureq, ep);
+               spin_unlock_irqrestore(&video->req_lock, flags);
+               uvcg_queue_cancel(queue, 0);
+
+               return;
+       }
+
+       /*
+        * Here we check whether any request is available in the ready
+        * list. If it is, queue it to the ep and add the current
+        * usb_request to the req_free list - for video_pump to fill in.
+        * Otherwise, just use the current usb_request to queue a 0
+        * length request to the ep. Since we always add to the req_free
+        * list if we dequeue from the ready list, there will never
+        * be a situation where the req_free list is completely out of
+        * requests and cannot recover.
+        */
+       to_queue->length = 0;
+       if (!list_empty(&video->req_ready)) {
+               to_queue = list_first_entry(&video->req_ready,
+                       struct usb_request, list);
+               list_del(&to_queue->list);
+               list_add_tail(&req->list, &video->req_free);
                /*
-                * Here we check whether any request is available in the ready
-                * list. If it is, queue it to the ep and add the current
-                * usb_request to the req_free list - for video_pump to fill in.
-                * Otherwise, just use the current usb_request to queue a 0
-                * length request to the ep. Since we always add to the req_free
-                * list if we dequeue from the ready list, there will never
-                * be a situation where the req_free list is completely out of
-                * requests and cannot recover.
+                * Queue work to the wq as well since it is possible that a
+                * buffer may not have been completely encoded with the set of
+                * in-flight usb requests for whih the complete callbacks are
+                * firing.
+                * In that case, if we do not queue work to the worker thread,
+                * the buffer will never be marked as complete - and therefore
+                * not be returned to userpsace. As a result,
+                * dequeue -> queue -> dequeue flow of uvc buffers will not
+                * happen.
                 */
-               struct usb_request *to_queue = req;
-
-               to_queue->length = 0;
-               if (!list_empty(&video->req_ready)) {
-                       to_queue = list_first_entry(&video->req_ready,
-                               struct usb_request, list);
-                       list_del(&to_queue->list);
-                       list_add_tail(&req->list, &video->req_free);
-                       /*
-                        * Queue work to the wq as well since it is possible that a
-                        * buffer may not have been completely encoded with the set of
-                        * in-flight usb requests for whih the complete callbacks are
-                        * firing.
-                        * In that case, if we do not queue work to the worker thread,
-                        * the buffer will never be marked as complete - and therefore
-                        * not be returned to userpsace. As a result,
-                        * dequeue -> queue -> dequeue flow of uvc buffers will not
-                        * happen.
-                        */
-                       queue_work(video->async_wq, &video->pump);
-               }
+               queue_work(video->async_wq, &video->pump);
+       }
+       /*
+        * Queue to the endpoint. The actual queueing to ep will
+        * only happen on one thread - the async_wq for bulk endpoints
+        * and this thread for isoc endpoints.
+        */
+       ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
+       if (ret < 0) {
                /*
-                * Queue to the endpoint. The actual queueing to ep will
-                * only happen on one thread - the async_wq for bulk endpoints
-                * and this thread for isoc endpoints.
+                * Endpoint error, but the stream is still enabled.
+                * Put request back in req_free for it to be cleaned
+                * up later.
                 */
-               ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
-               if (ret < 0) {
-                       /*
-                        * Endpoint error, but the stream is still enabled.
-                        * Put request back in req_free for it to be cleaned
-                        * up later.
-                        */
-                       list_add_tail(&to_queue->list, &video->req_free);
-               }
-       } else {
-               uvc_video_free_request(ureq, ep);
-               ret = 0;
+               list_add_tail(&to_queue->list, &video->req_free);
        }
+
        spin_unlock_irqrestore(&video->req_lock, flags);
-       if (ret < 0)
-               uvcg_queue_cancel(queue, 0);
 }
 
 static int
@@ -594,10 +599,7 @@ static void uvcg_video_pump(struct work_struct *work)
                 */
                spin_lock_irqsave(&queue->irqlock, flags);
                buf = uvcg_queue_head(queue);
-
-               if (buf != NULL) {
-                       video->encode(req, video, buf);
-               } else {
+               if (!buf) {
                        /*
                         * Either the queue has been disconnected or no video buffer
                         * available for bulk transfer. Either way, stop processing
@@ -607,6 +609,8 @@ static void uvcg_video_pump(struct work_struct *work)
                        break;
                }
 
+               video->encode(req, video, buf);
+
                spin_unlock_irqrestore(&queue->irqlock, flags);
 
                spin_lock_irqsave(&video->req_lock, flags);
@@ -623,14 +627,7 @@ static void uvcg_video_pump(struct work_struct *work)
                        uvcg_queue_cancel(queue, 0);
                        break;
                }
-
-               /* The request is owned by  the endpoint / ready list. */
-               req = NULL;
        }
-
-       if (!req)
-               return;
-
        spin_lock_irqsave(&video->req_lock, flags);
        if (video->is_enabled)
                list_add_tail(&req->list, &video->req_free);
index d59f94464b870b76c21a5b0380460479fdd1e8ed..9d4150124fdb82b91dcbddc3e8ee9dc24abee7ba 100644 (file)
@@ -903,6 +903,11 @@ int usb_gadget_map_request_by_dev(struct device *dev,
        if (req->length == 0)
                return 0;
 
+       if (req->sg_was_mapped) {
+               req->num_mapped_sgs = req->num_sgs;
+               return 0;
+       }
+
        if (req->num_sgs) {
                int     mapped;
 
@@ -948,7 +953,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_map_request);
 void usb_gadget_unmap_request_by_dev(struct device *dev,
                struct usb_request *req, int is_in)
 {
-       if (req->length == 0)
+       if (req->length == 0 || req->sg_was_mapped)
                return;
 
        if (req->num_mapped_sgs) {
index e8042c158f6dcd4d65858238ff36c8acd9a1c68d..e82d03224f940f9a98f978f7b46241f98f1c8e3e 100644 (file)
@@ -13,7 +13,7 @@
  * code from Dave Liu and Shlomi Gridish.
  */
 
-#undef VERBOSE
+#define pr_fmt(x) "udc: " x
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -183,9 +183,9 @@ __acquires(ep->udc->lock)
        usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
 
        if (status && (status != -ESHUTDOWN))
-               VDBG("complete %s req %p stat %d len %u/%u",
-                       ep->ep.name, &req->req, status,
-                       req->req.actual, req->req.length);
+               dev_vdbg(&udc->gadget.dev, "complete %s req %p stat %d len %u/%u\n",
+                        ep->ep.name, &req->req, status,
+                        req->req.actual, req->req.length);
 
        ep->stopped = 1;
 
@@ -285,7 +285,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
        timeout = jiffies + FSL_UDC_RESET_TIMEOUT;
        while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) {
                if (time_after(jiffies, timeout)) {
-                       ERR("udc reset timeout!\n");
+                       dev_err(&udc->gadget.dev, "udc reset timeout!\n");
                        return -ETIMEDOUT;
                }
                cpu_relax();
@@ -308,9 +308,10 @@ static int dr_controller_setup(struct fsl_udc *udc)
        tmp &= USB_EP_LIST_ADDRESS_MASK;
        fsl_writel(tmp, &dr_regs->endpointlistaddr);
 
-       VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
-               udc->ep_qh, (int)tmp,
-               fsl_readl(&dr_regs->endpointlistaddr));
+       dev_vdbg(&udc->gadget.dev,
+                "vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x\n",
+                udc->ep_qh, (int)tmp,
+                fsl_readl(&dr_regs->endpointlistaddr));
 
        max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams));
        for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) {
@@ -498,7 +499,7 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
                tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
                break;
        default:
-               VDBG("error ep type is %d", ep_type);
+               dev_vdbg(&udc->gadget.dev, "error ep type is %d\n", ep_type);
                return;
        }
        if (zlt)
@@ -611,10 +612,10 @@ static int fsl_ep_enable(struct usb_ep *_ep,
        spin_unlock_irqrestore(&udc->lock, flags);
        retval = 0;
 
-       VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
-                       ep->ep.desc->bEndpointAddress & 0x0f,
-                       (desc->bEndpointAddress & USB_DIR_IN)
-                               ? "in" : "out", max);
+       dev_vdbg(&udc->gadget.dev, "enabled %s (ep%d%s) maxpacket %d\n",
+                ep->ep.name, ep->ep.desc->bEndpointAddress & 0x0f,
+                (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+                max);
 en_done:
        return retval;
 }
@@ -633,7 +634,10 @@ static int fsl_ep_disable(struct usb_ep *_ep)
 
        ep = container_of(_ep, struct fsl_ep, ep);
        if (!_ep || !ep->ep.desc) {
-               VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+               /*
+                * dev_vdbg(&udc->gadget.dev, "%s not enabled\n",
+                *       _ep ? ep->ep.name : NULL);
+                */
                return -EINVAL;
        }
 
@@ -659,7 +663,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
        ep->stopped = 1;
        spin_unlock_irqrestore(&udc->lock, flags);
 
-       VDBG("disabled %s OK", _ep->name);
+       dev_vdbg(&udc->gadget.dev, "disabled %s OK\n", _ep->name);
        return 0;
 }
 
@@ -719,8 +723,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
 {
        u32 temp, bitmask, tmp_stat;
 
-       /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
-       VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
+       /* dev_vdbg(&udc->gadget.dev, "QH addr Register 0x%8x\n", dr_regs->endpointlistaddr);
+       dev_vdbg(&udc->gadget.dev, "ep_qh[%d] addr is 0x%8x\n", i, (u32)&(ep->udc->ep_qh[i])); */
 
        bitmask = ep_is_in(ep)
                ? (1 << (ep_index(ep) + 16))
@@ -808,7 +812,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
                *is_last = 0;
 
        if ((*is_last) == 0)
-               VDBG("multi-dtd request!");
+               dev_vdbg(&udc_controller->gadget.dev, "multi-dtd request!\n");
        /* Fill in the transfer size; set active bit */
        swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
 
@@ -820,7 +824,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
 
        mb();
 
-       VDBG("length = %d address= 0x%x", *length, (int)*dma);
+       dev_vdbg(&udc_controller->gadget.dev, "length = %d address= 0x%x\n", *length, (int)*dma);
 
        return dtd;
 }
@@ -871,11 +875,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        /* catch various bogus parameters */
        if (!_req || !req->req.complete || !req->req.buf
                        || !list_empty(&req->queue)) {
-               VDBG("%s, bad params", __func__);
+               dev_vdbg(&udc->gadget.dev, "%s, bad params\n", __func__);
                return -EINVAL;
        }
        if (unlikely(!_ep || !ep->ep.desc)) {
-               VDBG("%s, bad ep", __func__);
+               dev_vdbg(&udc->gadget.dev, "%s, bad ep\n", __func__);
                return -EINVAL;
        }
        if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
@@ -1036,8 +1040,8 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
                udc->ep0_dir = 0;
        }
 out:
-       VDBG(" %s %s halt stat %d", ep->ep.name,
-                       value ?  "set" : "clear", status);
+       dev_vdbg(&udc->gadget.dev, "%s %s halt stat %d\n", ep->ep.name,
+                value ?  "set" : "clear", status);
 
        return status;
 }
@@ -1105,7 +1109,8 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep)
                /* Wait until flush complete */
                while (fsl_readl(&dr_regs->endptflush)) {
                        if (time_after(jiffies, timeout)) {
-                               ERR("ep flush timeout\n");
+                               dev_err(&udc_controller->gadget.dev,
+                                       "ep flush timeout\n");
                                return;
                        }
                        cpu_relax();
@@ -1177,7 +1182,7 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
 
        udc = container_of(gadget, struct fsl_udc, gadget);
        spin_lock_irqsave(&udc->lock, flags);
-       VDBG("VBUS %s", is_active ? "on" : "off");
+       dev_vdbg(&gadget->dev, "VBUS %s\n", is_active ? "on" : "off");
        udc->vbus_active = (is_active != 0);
        if (can_pullup(udc))
                fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP),
@@ -1543,7 +1548,7 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
                udc->ep0_state = WAIT_FOR_SETUP;
                break;
        case WAIT_FOR_SETUP:
-               ERR("Unexpected ep0 packets\n");
+               dev_err(&udc->gadget.dev, "Unexpected ep0 packets\n");
                break;
        default:
                ep0stall(udc);
@@ -1612,7 +1617,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
                errors = hc32_to_cpu(curr_td->size_ioc_sts);
                if (errors & DTD_ERROR_MASK) {
                        if (errors & DTD_STATUS_HALTED) {
-                               ERR("dTD error %08x QH=%d\n", errors, pipe);
+                               dev_err(&udc->gadget.dev, "dTD error %08x QH=%d\n", errors, pipe);
                                /* Clear the errors and Halt condition */
                                tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts);
                                tmp &= ~errors;
@@ -1623,32 +1628,35 @@ static int process_ep_req(struct fsl_udc *udc, int pipe,
                                break;
                        }
                        if (errors & DTD_STATUS_DATA_BUFF_ERR) {
-                               VDBG("Transfer overflow");
+                               dev_vdbg(&udc->gadget.dev, "Transfer overflow\n");
                                status = -EPROTO;
                                break;
                        } else if (errors & DTD_STATUS_TRANSACTION_ERR) {
-                               VDBG("ISO error");
+                               dev_vdbg(&udc->gadget.dev, "ISO error\n");
                                status = -EILSEQ;
                                break;
                        } else
-                               ERR("Unknown error has occurred (0x%x)!\n",
+                               dev_err(&udc->gadget.dev,
+                                       "Unknown error has occurred (0x%x)!\n",
                                        errors);
 
                } else if (hc32_to_cpu(curr_td->size_ioc_sts)
                                & DTD_STATUS_ACTIVE) {
-                       VDBG("Request not complete");
+                       dev_vdbg(&udc->gadget.dev, "Request not complete\n");
                        status = REQ_UNCOMPLETE;
                        return status;
                } else if (remaining_length) {
                        if (direction) {
-                               VDBG("Transmit dTD remaining length not zero");
+                               dev_vdbg(&udc->gadget.dev,
+                                        "Transmit dTD remaining length not zero\n");
                                status = -EPROTO;
                                break;
                        } else {
                                break;
                        }
                } else {
-                       VDBG("dTD transmitted successful");
+                       dev_vdbg(&udc->gadget.dev,
+                                "dTD transmitted successful\n");
                }
 
                if (j != curr_req->dtd_count - 1)
@@ -1691,7 +1699,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
 
                /* If the ep is configured */
                if (!curr_ep->ep.name) {
-                       WARNING("Invalid EP?");
+                       dev_warn(&udc->gadget.dev, "Invalid EP?\n");
                        continue;
                }
 
@@ -1700,8 +1708,9 @@ static void dtd_complete_irq(struct fsl_udc *udc)
                                queue) {
                        status = process_ep_req(udc, i, curr_req);
 
-                       VDBG("status of process_ep_req= %d, ep = %d",
-                                       status, ep_num);
+                       dev_vdbg(&udc->gadget.dev,
+                                "status of process_ep_req= %d, ep = %d\n",
+                                status, ep_num);
                        if (status == REQ_UNCOMPLETE)
                                break;
                        /* write back status to req */
@@ -1820,7 +1829,7 @@ static void reset_irq(struct fsl_udc *udc)
        while (fsl_readl(&dr_regs->endpointprime)) {
                /* Wait until all endptprime bits cleared */
                if (time_after(jiffies, timeout)) {
-                       ERR("Timeout for reset\n");
+                       dev_err(&udc->gadget.dev, "Timeout for reset\n");
                        break;
                }
                cpu_relax();
@@ -1830,7 +1839,7 @@ static void reset_irq(struct fsl_udc *udc)
        fsl_writel(0xffffffff, &dr_regs->endptflush);
 
        if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
-               VDBG("Bus reset");
+               dev_vdbg(&udc->gadget.dev, "Bus reset\n");
                /* Bus is reseting */
                udc->bus_reset = 1;
                /* Reset all the queues, include XD, dTD, EP queue
@@ -1838,7 +1847,7 @@ static void reset_irq(struct fsl_udc *udc)
                reset_queues(udc, true);
                udc->usb_state = USB_STATE_DEFAULT;
        } else {
-               VDBG("Controller reset");
+               dev_vdbg(&udc->gadget.dev, "Controller reset\n");
                /* initialize usb hw reg except for regs for EP, not
                 * touch usbintr reg */
                dr_controller_setup(udc);
@@ -1872,7 +1881,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
        /* Clear notification bits */
        fsl_writel(irq_src, &dr_regs->usbsts);
 
-       /* VDBG("irq_src [0x%8x]", irq_src); */
+       /* dev_vdbg(&udc->gadget.dev, "irq_src [0x%8x]", irq_src); */
 
        /* Need to resume? */
        if (udc->usb_state == USB_STATE_SUSPENDED)
@@ -1881,7 +1890,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
 
        /* USB Interrupt */
        if (irq_src & USB_STS_INT) {
-               VDBG("Packet int");
+               dev_vdbg(&udc->gadget.dev, "Packet int\n");
                /* Setup package, we only support ep0 as control ep */
                if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) {
                        tripwire_handler(udc, 0,
@@ -1910,7 +1919,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
 
        /* Reset Received */
        if (irq_src & USB_STS_RESET) {
-               VDBG("reset int");
+               dev_vdbg(&udc->gadget.dev, "reset int\n");
                reset_irq(udc);
                status = IRQ_HANDLED;
        }
@@ -1922,7 +1931,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
        }
 
        if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
-               VDBG("Error IRQ %x", irq_src);
+               dev_vdbg(&udc->gadget.dev, "Error IRQ %x\n", irq_src);
        }
 
        spin_unlock_irqrestore(&udc->lock, flags);
@@ -1958,7 +1967,7 @@ static int fsl_udc_start(struct usb_gadget *g,
                                        udc_controller->transceiver->otg,
                                                    &udc_controller->gadget);
                        if (retval < 0) {
-                               ERR("can't bind to transceiver\n");
+                               dev_err(&udc_controller->gadget.dev, "can't bind to transceiver\n");
                                udc_controller->driver = NULL;
                                return retval;
                        }
@@ -2243,7 +2252,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
 
        udc->eps = kcalloc(udc->max_ep, sizeof(struct fsl_ep), GFP_KERNEL);
        if (!udc->eps) {
-               ERR("kmalloc udc endpoint status failed\n");
+               dev_err(&udc->gadget.dev, "kmalloc udc endpoint status failed\n");
                goto eps_alloc_failed;
        }
 
@@ -2258,7 +2267,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
        udc->ep_qh = dma_alloc_coherent(&pdev->dev, size,
                                        &udc->ep_qh_dma, GFP_KERNEL);
        if (!udc->ep_qh) {
-               ERR("malloc QHs for udc failed\n");
+               dev_err(&udc->gadget.dev, "malloc QHs for udc failed\n");
                goto ep_queue_alloc_failed;
        }
 
@@ -2269,14 +2278,14 @@ static int struct_udc_setup(struct fsl_udc *udc,
        udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL),
                        struct fsl_req, req);
        if (!udc->status_req) {
-               ERR("kzalloc for udc status request failed\n");
+               dev_err(&udc->gadget.dev, "kzalloc for udc status request failed\n");
                goto udc_status_alloc_failed;
        }
 
        /* allocate a small amount of memory to get valid address */
        udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
        if (!udc->status_req->req.buf) {
-               ERR("kzalloc for udc request buffer failed\n");
+               dev_err(&udc->gadget.dev, "kzalloc for udc request buffer failed\n");
                goto udc_req_buf_alloc_failed;
        }
 
@@ -2373,7 +2382,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
        if (pdata->operating_mode == FSL_USB2_DR_OTG) {
                udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
                if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
-                       ERR("Can't find OTG driver!\n");
+                       dev_err(&udc_controller->gadget.dev, "Can't find OTG driver!\n");
                        ret = -ENODEV;
                        goto err_kfree;
                }
@@ -2389,7 +2398,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
        if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
                if (!request_mem_region(res->start, resource_size(res),
                                        driver_name)) {
-                       ERR("request mem region for %s failed\n", pdev->name);
+                       dev_err(&udc_controller->gadget.dev, "request mem region for %s failed\n", pdev->name);
                        ret = -EBUSY;
                        goto err_kfree;
                }
@@ -2420,7 +2429,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
        /* Read Device Controller Capability Parameters register */
        dccparams = fsl_readl(&dr_regs->dccparams);
        if (!(dccparams & DCCPARAMS_DC)) {
-               ERR("This SOC doesn't support device role\n");
+               dev_err(&udc_controller->gadget.dev, "This SOC doesn't support device role\n");
                ret = -ENODEV;
                goto err_exit;
        }
@@ -2438,14 +2447,14 @@ static int fsl_udc_probe(struct platform_device *pdev)
        ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
                        driver_name, udc_controller);
        if (ret != 0) {
-               ERR("cannot request irq %d err %d\n",
+               dev_err(&udc_controller->gadget.dev, "cannot request irq %d err %d\n",
                                udc_controller->irq, ret);
                goto err_exit;
        }
 
        /* Initialize the udc structure including QH member and other member */
        if (struct_udc_setup(udc_controller, pdev)) {
-               ERR("Can't initialize udc data structure\n");
+               dev_err(&udc_controller->gadget.dev, "Can't initialize udc data structure\n");
                ret = -ENOMEM;
                goto err_free_irq;
        }
@@ -2486,7 +2495,7 @@ static int fsl_udc_probe(struct platform_device *pdev)
        /* setup the udc->eps[] for non-control endpoints and link
         * to gadget.ep_list */
        for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) {
-               char name[14];
+               char name[16];
 
                sprintf(name, "ep%dout", i);
                struct_ep_setup(udc_controller, i * 2, name, 1);
@@ -2666,6 +2675,15 @@ static const struct platform_device_id fsl_udc_devtype[] = {
        }
 };
 MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
+
+static const struct of_device_id fsl_udc_dt_ids[] = {
+       { .compatible = "fsl-usb2-dr" },
+       { .compatible = "fsl-usb2-mph" },
+       { .compatible = "fsl,mpc5121-usb2-dr" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_udc_dt_ids);
+
 static struct platform_driver udc_driver = {
        .probe          = fsl_udc_probe,
        .remove_new     = fsl_udc_remove,
@@ -2675,6 +2693,7 @@ static struct platform_driver udc_driver = {
        .resume         = fsl_udc_resume,
        .driver         = {
                        .name = driver_name,
+                       .of_match_table = fsl_udc_dt_ids,
                        /* udc suspend/resume called from OTG driver */
                        .suspend = fsl_udc_otg_suspend,
                        .resume  = fsl_udc_otg_resume,
index 2efc5a930b48e32d2dbc60c6424b0451991f077a..cc1756f3e89d1399df91d63fe7b58e0e6d8a27e6 100644 (file)
@@ -508,53 +508,6 @@ struct fsl_udc {
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(fmt, args...)      printk(KERN_DEBUG "[%s]  " fmt "\n", \
-                               __func__, ## args)
-#else
-#define DBG(fmt, args...)      do{}while(0)
-#endif
-
-#if 0
-static void dump_msg(const char *label, const u8 * buf, unsigned int length)
-{
-       unsigned int start, num, i;
-       char line[52], *p;
-
-       if (length >= 512)
-               return;
-       DBG("%s, length %u:\n", label, length);
-       start = 0;
-       while (length > 0) {
-               num = min(length, 16u);
-               p = line;
-               for (i = 0; i < num; ++i) {
-                       if (i == 8)
-                               *p++ = ' ';
-                       sprintf(p, " %02x", buf[i]);
-                       p += 3;
-               }
-               *p = 0;
-               printk(KERN_DEBUG "%6x: %s\n", start, line);
-               buf += num;
-               start += num;
-               length -= num;
-       }
-}
-#endif
-
-#ifdef VERBOSE
-#define VDBG           DBG
-#else
-#define VDBG(stuff...) do{}while(0)
-#endif
-
-#define ERR(stuff...)          pr_err("udc: " stuff)
-#define WARNING(stuff...)      pr_warn("udc: " stuff)
-#define INFO(stuff...)         pr_info("udc: " stuff)
-
-/*-------------------------------------------------------------------------*/
-
 /* ### Add board specific defines here
  */
 
index 12e76bb62c20944f902ab33b04691d266e9365a7..19bbc38f3d35dc7977dde74d67eec7e5908834e5 100644 (file)
@@ -2650,7 +2650,7 @@ net2272_plat_probe(struct platform_device *pdev)
                goto err_req;
        }
 
-       ret = net2272_probe_fin(dev, IRQF_TRIGGER_LOW);
+       ret = net2272_probe_fin(dev, irqflags);
        if (ret)
                goto err_io;
 
index 61424cfd2e1cb4e6783b4a39c851c9527ca40ae0..1a6317e4b2a323d7b484107bbc87ccd2d7a15ac8 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/byteorder/generic.h>
 #include <linux/platform_data/pxa2xx_udc.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
index 547af2ed9e5e02c2f1326df9688667d749c00bbe..ba5a06690507797b91a92f06b115e776c82f3a97 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/extcon.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
 #include <linux/module.h>
index cb85168fd00c2895a70066d998169320524ccbe0..7aa46d426f31b26a1ee4e650f28871db1e3d4de4 100644 (file)
@@ -3491,8 +3491,8 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc)
 
 static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
 {
-       int err = 0, usb3;
-       unsigned int i;
+       int err = 0, usb3_companion_port;
+       unsigned int i, j;
 
        xudc->utmi_phy = devm_kcalloc(xudc->dev, xudc->soc->num_phys,
                                           sizeof(*xudc->utmi_phy), GFP_KERNEL);
@@ -3520,7 +3520,7 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
                if (IS_ERR(xudc->utmi_phy[i])) {
                        err = PTR_ERR(xudc->utmi_phy[i]);
                        dev_err_probe(xudc->dev, err,
-                                     "failed to get usb2-%d PHY\n", i);
+                               "failed to get PHY for phy-name usb2-%d\n", i);
                        goto clean_up;
                } else if (xudc->utmi_phy[i]) {
                        /* Get usb-phy, if utmi phy is available */
@@ -3539,19 +3539,30 @@ static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
                }
 
                /* Get USB3 phy */
-               usb3 = tegra_xusb_padctl_get_usb3_companion(xudc->padctl, i);
-               if (usb3 < 0)
+               usb3_companion_port = tegra_xusb_padctl_get_usb3_companion(xudc->padctl, i);
+               if (usb3_companion_port < 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]);
-                       dev_err_probe(xudc->dev, err,
-                                     "failed to get usb3-%d PHY\n", usb3);
-                       goto clean_up;
-               } else if (xudc->usb3_phy[i])
-                       dev_dbg(xudc->dev, "usb3-%d PHY registered", usb3);
+               for (j = 0; j < xudc->soc->num_phys; j++) {
+                       snprintf(phy_name, sizeof(phy_name), "usb3-%d", j);
+                       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]);
+                               dev_err_probe(xudc->dev, err,
+                                       "failed to get PHY for phy-name usb3-%d\n", j);
+                               goto clean_up;
+                       } else if (xudc->usb3_phy[i]) {
+                               int usb2_port =
+                                       tegra_xusb_padctl_get_port_number(xudc->utmi_phy[i]);
+                               int usb3_port =
+                                       tegra_xusb_padctl_get_port_number(xudc->usb3_phy[i]);
+                               if (usb3_port == usb3_companion_port) {
+                                       dev_dbg(xudc->dev, "USB2 port %d is paired with USB3 port %d for device mode port %d\n",
+                                        usb2_port, usb3_port, i);
+                                       break;
+                               }
+                       }
+               }
        }
 
        return err;
index 6c47ab0a491d5133c59539c93b4a33e39c9262ca..ad145a54ca74e4003ceadee7f1defc171ddee124 100644 (file)
@@ -65,6 +65,15 @@ struct orion_ehci_hcd {
 
 static struct hc_driver __read_mostly ehci_orion_hc_driver;
 
+/*
+ * Legacy DMA mask is 32 bit.
+ * AC5 has the DDR starting at 8GB, hence it requires
+ * a larger (34-bit) DMA mask, in order for DMA allocations
+ * to succeed:
+ */
+static const u64 dma_mask_orion =      DMA_BIT_MASK(32);
+static const u64 dma_mask_ac5 =                DMA_BIT_MASK(34);
+
 /*
  * Implement Orion USB controller specification guidelines
  */
@@ -211,6 +220,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
        int irq, err;
        enum orion_ehci_phy_ver phy_version;
        struct orion_ehci_hcd *priv;
+       u64 *dma_mask_ptr;
 
        if (usb_disabled())
                return -ENODEV;
@@ -228,7 +238,8 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
         * set. Since shared usb code relies on it, set it here for
         * now. Once we have dma capability bindings this can go away.
         */
-       err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       dma_mask_ptr = (u64 *)of_device_get_match_data(&pdev->dev);
+       err = dma_coerce_mask_and_coherent(&pdev->dev, *dma_mask_ptr);
        if (err)
                goto err;
 
@@ -332,8 +343,9 @@ static void ehci_orion_drv_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id ehci_orion_dt_ids[] = {
-       { .compatible = "marvell,orion-ehci", },
-       { .compatible = "marvell,armada-3700-ehci", },
+       { .compatible = "marvell,orion-ehci", .data = &dma_mask_orion},
+       { .compatible = "marvell,armada-3700-ehci", .data = &dma_mask_orion},
+       { .compatible = "marvell,ac5-ehci", .data = &dma_mask_ac5},
        {},
 };
 MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);
index 357d9aee38a3799abef70942971c42f265f70287..3348c25ddb18d2c2564a7c9511dc72921107db1f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_platform.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_data/usb-ohci-pxa27x.h>
 #include <linux/platform_data/pxa2xx_udc.h>
 #include <linux/platform_device.h>
index 0956495bba57574e58b0323617d92ea931d0d014..2b871540bb50025f53c814da0fa544e2176fd760 100644 (file)
@@ -585,6 +585,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
                finish_request(sl811, ep, urb, urbstat);
 }
 
+#ifdef QUIRK2
 static inline u8 checkdone(struct sl811 *sl811)
 {
        u8      ctl;
@@ -616,6 +617,7 @@ static inline u8 checkdone(struct sl811 *sl811)
 #endif
        return irqstat;
 }
+#endif
 
 static irqreturn_t sl811h_irq(struct usb_hcd *hcd)
 {
diff --git a/drivers/usb/host/xhci-caps.h b/drivers/usb/host/xhci-caps.h
new file mode 100644 (file)
index 0000000..9e94ceb
--- /dev/null
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* hc_capbase bitmasks */
+/* bits 7:0 - how long is the Capabilities register */
+#define HC_LENGTH(p)           XHCI_HC_LENGTH(p)
+/* bits 31:16  */
+#define HC_VERSION(p)          (((p) >> 16) & 0xffff)
+
+/* HCSPARAMS1 - hcs_params1 - bitmasks */
+/* bits 0:7, Max Device Slots */
+#define HCS_MAX_SLOTS(p)       (((p) >> 0) & 0xff)
+#define HCS_SLOTS_MASK         0xff
+/* bits 8:18, Max Interrupters */
+#define HCS_MAX_INTRS(p)       (((p) >> 8) & 0x7ff)
+/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
+#define HCS_MAX_PORTS(p)       (((p) >> 24) & 0x7f)
+
+/* HCSPARAMS2 - hcs_params2 - bitmasks */
+/* bits 0:3, frames or uframes that SW needs to queue transactions
+ * ahead of the HW to meet periodic deadlines */
+#define HCS_IST(p)             (((p) >> 0) & 0xf)
+/* bits 4:7, max number of Event Ring segments */
+#define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
+/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
+/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
+/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
+#define HCS_MAX_SCRATCHPAD(p)   ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
+
+/* HCSPARAMS3 - hcs_params3 - bitmasks */
+/* bits 0:7, Max U1 to U0 latency for the roothub ports */
+#define HCS_U1_LATENCY(p)      (((p) >> 0) & 0xff)
+/* bits 16:31, Max U2 to U0 latency for the roothub ports */
+#define HCS_U2_LATENCY(p)      (((p) >> 16) & 0xffff)
+
+/* HCCPARAMS - hcc_params - bitmasks */
+/* true: HC can use 64-bit address pointers */
+#define HCC_64BIT_ADDR(p)      ((p) & (1 << 0))
+/* true: HC can do bandwidth negotiation */
+#define HCC_BANDWIDTH_NEG(p)   ((p) & (1 << 1))
+/* true: HC uses 64-byte Device Context structures
+ * FIXME 64-byte context structures aren't supported yet.
+ */
+#define HCC_64BYTE_CONTEXT(p)  ((p) & (1 << 2))
+/* true: HC has port power switches */
+#define HCC_PPC(p)             ((p) & (1 << 3))
+/* true: HC has port indicators */
+#define HCS_INDICATOR(p)       ((p) & (1 << 4))
+/* true: HC has Light HC Reset Capability */
+#define HCC_LIGHT_RESET(p)     ((p) & (1 << 5))
+/* true: HC supports latency tolerance messaging */
+#define HCC_LTC(p)             ((p) & (1 << 6))
+/* true: no secondary Stream ID Support */
+#define HCC_NSS(p)             ((p) & (1 << 7))
+/* true: HC supports Stopped - Short Packet */
+#define HCC_SPC(p)             ((p) & (1 << 9))
+/* true: HC has Contiguous Frame ID Capability */
+#define HCC_CFC(p)             ((p) & (1 << 11))
+/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
+#define HCC_MAX_PSA(p)         (1 << ((((p) >> 12) & 0xf) + 1))
+/* Extended Capabilities pointer from PCI base - section 5.3.6 */
+#define HCC_EXT_CAPS(p)                XHCI_HCC_EXT_CAPS(p)
+
+#define CTX_SIZE(_hcc)         (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
+
+/* db_off bitmask - bits 0:1 reserved */
+#define        DBOFF_MASK      (~0x3)
+
+/* run_regs_off bitmask - bits 0:4 reserved */
+#define        RTSOFF_MASK     (~0x1f)
+
+/* HCCPARAMS2 - hcc_params2 - bitmasks */
+/* true: HC supports U3 entry Capability */
+#define        HCC2_U3C(p)             ((p) & (1 << 0))
+/* true: HC supports Configure endpoint command Max exit latency too large */
+#define        HCC2_CMC(p)             ((p) & (1 << 1))
+/* true: HC supports Force Save context Capability */
+#define        HCC2_FSC(p)             ((p) & (1 << 2))
+/* true: HC supports Compliance Transition Capability */
+#define        HCC2_CTC(p)             ((p) & (1 << 3))
+/* true: HC support Large ESIT payload Capability > 48k */
+#define        HCC2_LEC(p)             ((p) & (1 << 4))
+/* true: HC support Configuration Information Capability */
+#define        HCC2_CIC(p)             ((p) & (1 << 5))
+/* true: HC support Extended TBC Capability, Isoc burst count > 65535 */
+#define        HCC2_ETC(p)             ((p) & (1 << 6))
index d82935d31126dd020d941b7a7cd8c78a93f3392f..8a9869ef0db66a5df132a71c66f19f5fdcee14c4 100644 (file)
@@ -634,7 +634,8 @@ static int xhci_dbc_start(struct xhci_dbc *dbc)
                return ret;
        }
 
-       return mod_delayed_work(system_wq, &dbc->event_work, 1);
+       return mod_delayed_work(system_wq, &dbc->event_work,
+                               msecs_to_jiffies(dbc->poll_interval));
 }
 
 static void xhci_dbc_stop(struct xhci_dbc *dbc)
@@ -899,8 +900,10 @@ static void xhci_dbc_handle_events(struct work_struct *work)
        enum evtreturn          evtr;
        struct xhci_dbc         *dbc;
        unsigned long           flags;
+       unsigned int            poll_interval;
 
        dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
+       poll_interval = dbc->poll_interval;
 
        spin_lock_irqsave(&dbc->lock, flags);
        evtr = xhci_dbc_do_handle_events(dbc);
@@ -916,13 +919,18 @@ static void xhci_dbc_handle_events(struct work_struct *work)
                        dbc->driver->disconnect(dbc);
                break;
        case EVT_DONE:
+               /* set fast poll rate if there are pending data transfers */
+               if (!list_empty(&dbc->eps[BULK_OUT].list_pending) ||
+                   !list_empty(&dbc->eps[BULK_IN].list_pending))
+                       poll_interval = 1;
                break;
        default:
                dev_info(dbc->dev, "stop handling dbc events\n");
                return;
        }
 
-       mod_delayed_work(system_wq, &dbc->event_work, 1);
+       mod_delayed_work(system_wq, &dbc->event_work,
+                        msecs_to_jiffies(poll_interval));
 }
 
 static const char * const dbc_state_strings[DS_MAX] = {
@@ -1175,6 +1183,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
        dbc->idVendor = DBC_VENDOR_ID;
        dbc->bcdDevice = DBC_DEVICE_REV;
        dbc->bInterfaceProtocol = DBC_PROTOCOL;
+       dbc->poll_interval = DBC_POLL_INTERVAL_DEFAULT;
 
        if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE)
                goto err;
index e39e3ae1677aeb48bfc00ad8f32d9157901b1dc1..92661b555c2a29db77b78ac75f593f71fe8cc689 100644 (file)
@@ -94,6 +94,7 @@ struct dbc_ep {
 
 #define DBC_QUEUE_SIZE                 16
 #define DBC_WRITE_BUF_SIZE             8192
+#define DBC_POLL_INTERVAL_DEFAULT      64      /* milliseconds */
 
 /*
  * Private structure for DbC hardware state:
@@ -140,6 +141,7 @@ struct xhci_dbc {
 
        enum dbc_state                  state;
        struct delayed_work             event_work;
+       unsigned int                    poll_interval;  /* ms */
        unsigned                        resume_required:1;
        struct dbc_ep                   eps[2];
 
index 0980ade2a234a38ee6b8d25e674e1da12b624224..61f083de6e196744ea3e6655a86c83581ce34d10 100644 (file)
@@ -448,38 +448,6 @@ u32 xhci_port_state_to_neutral(u32 state)
 }
 EXPORT_SYMBOL_GPL(xhci_port_state_to_neutral);
 
-/**
- * xhci_find_slot_id_by_port() - Find slot id of a usb device on a roothub port
- * @hcd: pointer to hcd of the roothub
- * @xhci: pointer to xhci structure
- * @port: one-based port number of the port in this roothub.
- *
- * Return: Slot id of the usb device connected to the root port, 0 if not found
- */
-
-int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
-               u16 port)
-{
-       int slot_id;
-       int i;
-       enum usb_device_speed speed;
-
-       slot_id = 0;
-       for (i = 0; i < MAX_HC_SLOTS; i++) {
-               if (!xhci->devs[i] || !xhci->devs[i]->udev)
-                       continue;
-               speed = xhci->devs[i]->udev->speed;
-               if (((speed >= USB_SPEED_SUPER) == (hcd->speed >= HCD_USB3))
-                               && xhci->devs[i]->fake_port == port) {
-                       slot_id = i;
-                       break;
-               }
-       }
-
-       return slot_id;
-}
-EXPORT_SYMBOL_GPL(xhci_find_slot_id_by_port);
-
 /*
  * Stop device
  * It issues stop endpoint command for EP 0 to 30. And wait the last command
@@ -930,7 +898,6 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
        struct xhci_bus_state *bus_state;
        struct xhci_hcd *xhci;
        struct usb_hcd *hcd;
-       int slot_id;
        u32 wIndex;
 
        hcd = port->rhub->hcd;
@@ -986,13 +953,11 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port,
                spin_lock_irqsave(&xhci->lock, *flags);
 
                if (time_left) {
-                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                                           wIndex + 1);
-                       if (!slot_id) {
+                       if (!port->slot_id) {
                                xhci_dbg(xhci, "slot_id is zero\n");
                                return -ENODEV;
                        }
-                       xhci_ring_device(xhci, slot_id);
+                       xhci_ring_device(xhci, port->slot_id);
                } else {
                        int port_status = readl(port->addr);
 
@@ -1202,7 +1167,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        unsigned long flags;
        u32 temp, status;
        int retval = 0;
-       int slot_id;
        struct xhci_bus_state *bus_state;
        u16 link_state = 0;
        u16 wake_mask = 0;
@@ -1332,15 +1296,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                goto error;
                        }
 
-                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                                           portnum1);
-                       if (!slot_id) {
+                       if (!port->slot_id) {
                                xhci_warn(xhci, "slot_id is zero\n");
                                goto error;
                        }
                        /* unlock to execute stop endpoint commands */
                        spin_unlock_irqrestore(&xhci->lock, flags);
-                       xhci_stop_device(xhci, slot_id, 1);
+                       xhci_stop_device(xhci, port->slot_id, 1);
                        spin_lock_irqsave(&xhci->lock, flags);
 
                        xhci_set_link_state(xhci, port, XDEV_U3);
@@ -1463,14 +1425,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
                        if (link_state == USB_SS_PORT_LS_U3) {
                                int retries = 16;
-                               slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                                                   portnum1);
-                               if (slot_id) {
+                               if (port->slot_id) {
                                        /* unlock to execute stop endpoint
                                         * commands */
                                        spin_unlock_irqrestore(&xhci->lock,
                                                                flags);
-                                       xhci_stop_device(xhci, slot_id, 1);
+                                       xhci_stop_device(xhci, port->slot_id, 1);
                                        spin_lock_irqsave(&xhci->lock, flags);
                                }
                                xhci_set_link_state(xhci, port, USB_SS_PORT_LS_U3);
@@ -1584,13 +1544,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        }
                        bus_state->port_c_suspend |= 1 << wIndex;
 
-                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                       portnum1);
-                       if (!slot_id) {
+                       if (!port->slot_id) {
                                xhci_dbg(xhci, "slot_id is zero\n");
                                goto error;
                        }
-                       xhci_ring_device(xhci, slot_id);
+                       xhci_ring_device(xhci, port->slot_id);
                        break;
                case USB_PORT_FEAT_C_SUSPEND:
                        bus_state->port_c_suspend &= ~(1 << wIndex);
@@ -1821,10 +1779,7 @@ retry:
                if (!portsc_buf[port_index])
                        continue;
                if (test_bit(port_index, &bus_state->bus_suspended)) {
-                       int slot_id;
-
-                       slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-                                                           port_index + 1);
+                       int slot_id = ports[port_index]->slot_id;
                        if (slot_id) {
                                spin_unlock_irqrestore(&xhci->lock, flags);
                                xhci_stop_device(xhci, slot_id, 1);
@@ -1877,7 +1832,6 @@ int xhci_bus_resume(struct usb_hcd *hcd)
        struct xhci_bus_state *bus_state;
        unsigned long flags;
        int max_ports, port_index;
-       int slot_id;
        int sret;
        u32 next_state;
        u32 temp, portsc;
@@ -1970,9 +1924,8 @@ int xhci_bus_resume(struct usb_hcd *hcd)
                        continue;
                }
                xhci_test_and_clear_bit(xhci, ports[port_index], PORT_PLC);
-               slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1);
-               if (slot_id)
-                       xhci_ring_device(xhci, slot_id);
+               if (ports[port_index]->slot_id)
+                       xhci_ring_device(xhci, ports[port_index]->slot_id);
        }
        (void) readl(&xhci->op_regs->command);
 
index a7716202a8dd58d74f3d31fd48d0833de89db2be..69dd866698833e990bf22097f89d165af65d2ba2 100644 (file)
@@ -84,7 +84,7 @@ static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
        struct xhci_segment *seg;
 
        seg = first->next;
-       while (seg != first) {
+       while (seg && seg != first) {
                struct xhci_segment *next = seg->next;
                xhci_segment_free(xhci, seg);
                seg = next;
@@ -351,17 +351,10 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
 
                next = xhci_segment_alloc(xhci, cycle_state, max_packet, num,
                                          flags);
-               if (!next) {
-                       prev = *first;
-                       while (prev) {
-                               next = prev->next;
-                               xhci_segment_free(xhci, prev);
-                               prev = next;
-                       }
-                       return -ENOMEM;
-               }
-               xhci_link_segments(prev, next, type, chain_links);
+               if (!next)
+                       goto free_segments;
 
+               xhci_link_segments(prev, next, type, chain_links);
                prev = next;
                num++;
        }
@@ -369,6 +362,10 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
        *last = prev;
 
        return 0;
+
+free_segments:
+       xhci_free_segments_for_ring(xhci, *first);
+       return -ENOMEM;
 }
 
 /*
@@ -444,19 +441,11 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
        if (ret)
                return -ENOMEM;
 
-       if (ring->type == TYPE_STREAM)
+       if (ring->type == TYPE_STREAM) {
                ret = xhci_update_stream_segment_mapping(ring->trb_address_map,
                                                ring, first, last, flags);
-       if (ret) {
-               struct xhci_segment *next;
-               do {
-                       next = first->next;
-                       xhci_segment_free(xhci, first);
-                       if (first == last)
-                               break;
-                       first = next;
-               } while (true);
-               return ret;
+               if (ret)
+                       goto free_segments;
        }
 
        xhci_link_rings(xhci, ring, first, last, num_new_segs);
@@ -466,6 +455,10 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
                        ring->num_segs);
 
        return 0;
+
+free_segments:
+       xhci_free_segments_for_ring(xhci, first);
+       return ret;
 }
 
 struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
@@ -789,15 +782,14 @@ static void xhci_free_tt_info(struct xhci_hcd *xhci,
        bool slot_found = false;
 
        /* If the device never made it past the Set Address stage,
-        * it may not have the real_port set correctly.
+        * it may not have the root hub port pointer set correctly.
         */
-       if (virt_dev->real_port == 0 ||
-                       virt_dev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) {
-               xhci_dbg(xhci, "Bad real port.\n");
+       if (!virt_dev->rhub_port) {
+               xhci_dbg(xhci, "Bad rhub port.\n");
                return;
        }
 
-       tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts);
+       tt_list_head = &(xhci->rh_bw[virt_dev->rhub_port->hw_portnum].tts);
        list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) {
                /* Multi-TT hubs will have more than one entry */
                if (tt_info->slot_id == slot_id) {
@@ -834,7 +826,7 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
                        goto free_tts;
                INIT_LIST_HEAD(&tt_info->tt_list);
                list_add(&tt_info->tt_list,
-                               &xhci->rh_bw[virt_dev->real_port - 1].tts);
+                               &xhci->rh_bw[virt_dev->rhub_port->hw_portnum].tts);
                tt_info->slot_id = virt_dev->udev->slot_id;
                if (tt->multi)
                        tt_info->ttport = i+1;
@@ -908,6 +900,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
 
        if (dev->udev && dev->udev->slot_id)
                dev->udev->slot_id = 0;
+       if (dev->rhub_port && dev->rhub_port->slot_id == slot_id)
+               dev->rhub_port->slot_id = 0;
        kfree(xhci->devs[slot_id]);
        xhci->devs[slot_id] = NULL;
 }
@@ -929,13 +923,12 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i
        if (!vdev)
                return;
 
-       if (vdev->real_port == 0 ||
-                       vdev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) {
-               xhci_dbg(xhci, "Bad vdev->real_port.\n");
+       if (!vdev->rhub_port) {
+               xhci_dbg(xhci, "Bad rhub port.\n");
                goto out;
        }
 
-       tt_list_head = &(xhci->rh_bw[vdev->real_port - 1].tts);
+       tt_list_head = &(xhci->rh_bw[vdev->rhub_port->hw_portnum].tts);
        list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) {
                /* is this a hub device that added a tt_info to the tts list */
                if (tt_info->slot_id == slot_id) {
@@ -1051,16 +1044,16 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
  * The xHCI roothub may have ports of differing speeds in any order in the port
  * status registers.
  *
- * The xHCI hardware wants to know the roothub port number that the USB device
+ * The xHCI hardware wants to know the roothub port that the USB device
  * is attached to (or the roothub port its ancestor hub is attached to).  All we
  * know is the index of that port under either the USB 2.0 or the USB 3.0
  * roothub, but that doesn't give us the real index into the HW port status
- * registers. Call xhci_find_raw_port_number() to get real index.
+ * registers.
  */
-static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
-               struct usb_device *udev)
+static struct xhci_port *xhci_find_rhub_port(struct xhci_hcd *xhci, struct usb_device *udev)
 {
        struct usb_device *top_dev;
+       struct xhci_hub *rhub;
        struct usb_hcd *hcd;
 
        if (udev->speed >= USB_SPEED_SUPER)
@@ -1072,7 +1065,8 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
                        top_dev = top_dev->parent)
                /* Found device below root hub */;
 
-       return  xhci_find_raw_port_number(hcd, top_dev->portnum);
+       rhub = xhci_get_rhub(hcd);
+       return rhub->ports[top_dev->portnum - 1];
 }
 
 /* Setup an xHCI virtual device for a Set Address command */
@@ -1081,9 +1075,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        struct xhci_virt_device *dev;
        struct xhci_ep_ctx      *ep0_ctx;
        struct xhci_slot_ctx    *slot_ctx;
-       u32                     port_num;
        u32                     max_packets;
-       struct usb_device *top_dev;
 
        dev = xhci->devs[udev->slot_id];
        /* Slot ID 0 is reserved */
@@ -1124,18 +1116,15 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
                return -EINVAL;
        }
        /* Find the root hub port this device is under */
-       port_num = xhci_find_real_port_number(xhci, udev);
-       if (!port_num)
+       dev->rhub_port = xhci_find_rhub_port(xhci, udev);
+       if (!dev->rhub_port)
                return -EINVAL;
-       slot_ctx->dev_info2 |= cpu_to_le32(ROOT_HUB_PORT(port_num));
-       /* Set the port number in the virtual_device to the faked port number */
-       for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
-                       top_dev = top_dev->parent)
-               /* Found device below root hub */;
-       dev->fake_port = top_dev->portnum;
-       dev->real_port = port_num;
-       xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num);
-       xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->fake_port);
+       /* Slot ID is set to the device directly below the root hub */
+       if (!udev->parent->parent)
+               dev->rhub_port->slot_id = udev->slot_id;
+       slot_ctx->dev_info2 |= cpu_to_le32(ROOT_HUB_PORT(dev->rhub_port->hw_portnum + 1));
+       xhci_dbg(xhci, "Slot ID %d: HW portnum %d, hcd portnum %d\n",
+                udev->slot_id, dev->rhub_port->hw_portnum, dev->rhub_port->hcd_portnum);
 
        /* Find the right bandwidth table that this device will be a part of.
         * If this is a full speed device attached directly to a root port (or a
@@ -1144,12 +1133,12 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
         * will never be created for the HS root hub.
         */
        if (!udev->tt || !udev->tt->hub->parent) {
-               dev->bw_table = &xhci->rh_bw[port_num - 1].bw_table;
+               dev->bw_table = &xhci->rh_bw[dev->rhub_port->hw_portnum].bw_table;
        } else {
                struct xhci_root_port_bw_info *rh_bw;
                struct xhci_tt_bw_info *tt_bw;
 
-               rh_bw = &xhci->rh_bw[port_num - 1];
+               rh_bw = &xhci->rh_bw[dev->rhub_port->hw_portnum];
                /* Find the right TT. */
                list_for_each_entry(tt_bw, &rh_bw->tts, tt_list) {
                        if (tt_bw->slot_id != udev->tt->hub->slot_id)
@@ -2533,7 +2522,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        if (xhci_add_interrupter(xhci, ir, 0))
                goto fail;
 
-       xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
+       ir->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
 
        /*
         * XXX: Might need to set the Interrupter Moderation Register to
index 61f3f8bbdcead3f325b60128c8bf648acf32dc2b..27eb384a3963421402ca6e16ffa21908831fa689 100644 (file)
@@ -122,10 +122,6 @@ static u32 get_bw_boundary(enum usb_device_speed speed)
 * each HS root port is treated as a single bandwidth domain,
 * but each SS root port is treated as two bandwidth domains, one for IN eps,
 * one for OUT eps.
-* @real_port value is defined as follow according to xHCI spec:
-* 1 for SSport0, ..., N+1 for SSportN, N+2 for HSport0, N+3 for HSport1, etc
-* so the bandwidth domain array is organized as follow for simplification:
-* SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY
 */
 static struct mu3h_sch_bw_info *
 get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
@@ -136,19 +132,19 @@ get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
        int bw_index;
 
        virt_dev = xhci->devs[udev->slot_id];
-       if (!virt_dev->real_port) {
-               WARN_ONCE(1, "%s invalid real_port\n", dev_name(&udev->dev));
+       if (!virt_dev->rhub_port) {
+               WARN_ONCE(1, "%s invalid rhub port\n", dev_name(&udev->dev));
                return NULL;
        }
 
        if (udev->speed >= USB_SPEED_SUPER) {
                if (usb_endpoint_dir_out(&ep->desc))
-                       bw_index = (virt_dev->real_port - 1) * 2;
+                       bw_index = (virt_dev->rhub_port->hw_portnum) * 2;
                else
-                       bw_index = (virt_dev->real_port - 1) * 2 + 1;
+                       bw_index = (virt_dev->rhub_port->hw_portnum) * 2 + 1;
        } else {
                /* add one more for each SS port */
-               bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1;
+               bw_index = virt_dev->rhub_port->hw_portnum + xhci->usb3_rhub.num_ports;
        }
 
        return &mtk->sch_array[bw_index];
index b534ca9752be43cb304f69c94b70b1fef5bc75c8..93b6976480188c6b32fa8b8e7f6617caedb65ca7 100644 (file)
@@ -307,8 +307,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_RESET_ON_RESUME;
        }
 
-       if (pdev->vendor == PCI_VENDOR_ID_AMD)
+       if (pdev->vendor == PCI_VENDOR_ID_AMD) {
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+               if (pdev->device == 0x43f7)
+                       xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+       }
 
        if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
                ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
@@ -820,7 +823,6 @@ static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
        struct xhci_hcd         *xhci = hcd_to_xhci(hcd);
        struct xhci_port        *port;
        struct usb_device       *udev;
-       unsigned int            slot_id;
        u32                     portsc;
        int                     i;
 
@@ -843,15 +845,14 @@ static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)
                if ((portsc & PORT_PLS_MASK) != XDEV_U3)
                        continue;
 
-               slot_id = xhci_find_slot_id_by_port(port->rhub->hcd, xhci,
-                                                   port->hcd_portnum + 1);
-               if (!slot_id || !xhci->devs[slot_id]) {
+               if (!port->slot_id || !xhci->devs[port->slot_id]) {
                        xhci_err(xhci, "No dev for slot_id %d for port %d-%d in U3\n",
-                                slot_id, port->rhub->hcd->self.busnum, port->hcd_portnum + 1);
+                                port->slot_id, port->rhub->hcd->self.busnum,
+                                port->hcd_portnum + 1);
                        continue;
                }
 
-               udev = xhci->devs[slot_id]->udev;
+               udev = xhci->devs[port->slot_id]->udev;
 
                /* if wakeup is enabled then don't disable the port */
                if (udev->do_remote_wakeup && do_wakeup)
diff --git a/drivers/usb/host/xhci-port.h b/drivers/usb/host/xhci-port.h
new file mode 100644 (file)
index 0000000..f19efb9
--- /dev/null
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
+/* true: device connected */
+#define PORT_CONNECT   (1 << 0)
+/* true: port enabled */
+#define PORT_PE                (1 << 1)
+/* bit 2 reserved and zeroed */
+/* true: port has an over-current condition */
+#define PORT_OC                (1 << 3)
+/* true: port reset signaling asserted */
+#define PORT_RESET     (1 << 4)
+/* Port Link State - bits 5:8
+ * A read gives the current link PM state of the port,
+ * a write with Link State Write Strobe set sets the link state.
+ */
+#define PORT_PLS_MASK  (0xf << 5)
+#define XDEV_U0                (0x0 << 5)
+#define XDEV_U1                (0x1 << 5)
+#define XDEV_U2                (0x2 << 5)
+#define XDEV_U3                (0x3 << 5)
+#define XDEV_DISABLED  (0x4 << 5)
+#define XDEV_RXDETECT  (0x5 << 5)
+#define XDEV_INACTIVE  (0x6 << 5)
+#define XDEV_POLLING   (0x7 << 5)
+#define XDEV_RECOVERY  (0x8 << 5)
+#define XDEV_HOT_RESET (0x9 << 5)
+#define XDEV_COMP_MODE (0xa << 5)
+#define XDEV_TEST_MODE (0xb << 5)
+#define XDEV_RESUME    (0xf << 5)
+
+/* true: port has power (see HCC_PPC) */
+#define PORT_POWER     (1 << 9)
+/* bits 10:13 indicate device speed:
+ * 0 - undefined speed - port hasn't be initialized by a reset yet
+ * 1 - full speed
+ * 2 - low speed
+ * 3 - high speed
+ * 4 - super speed
+ * 5-15 reserved
+ */
+#define DEV_SPEED_MASK         (0xf << 10)
+#define        XDEV_FS                 (0x1 << 10)
+#define        XDEV_LS                 (0x2 << 10)
+#define        XDEV_HS                 (0x3 << 10)
+#define        XDEV_SS                 (0x4 << 10)
+#define        XDEV_SSP                (0x5 << 10)
+#define DEV_UNDEFSPEED(p)      (((p) & DEV_SPEED_MASK) == (0x0<<10))
+#define DEV_FULLSPEED(p)       (((p) & DEV_SPEED_MASK) == XDEV_FS)
+#define DEV_LOWSPEED(p)                (((p) & DEV_SPEED_MASK) == XDEV_LS)
+#define DEV_HIGHSPEED(p)       (((p) & DEV_SPEED_MASK) == XDEV_HS)
+#define DEV_SUPERSPEED(p)      (((p) & DEV_SPEED_MASK) == XDEV_SS)
+#define DEV_SUPERSPEEDPLUS(p)  (((p) & DEV_SPEED_MASK) == XDEV_SSP)
+#define DEV_SUPERSPEED_ANY(p)  (((p) & DEV_SPEED_MASK) >= XDEV_SS)
+#define DEV_PORT_SPEED(p)      (((p) >> 10) & 0x0f)
+
+/* Bits 20:23 in the Slot Context are the speed for the device */
+#define        SLOT_SPEED_FS           (XDEV_FS << 10)
+#define        SLOT_SPEED_LS           (XDEV_LS << 10)
+#define        SLOT_SPEED_HS           (XDEV_HS << 10)
+#define        SLOT_SPEED_SS           (XDEV_SS << 10)
+#define        SLOT_SPEED_SSP          (XDEV_SSP << 10)
+/* Port Indicator Control */
+#define PORT_LED_OFF   (0 << 14)
+#define PORT_LED_AMBER (1 << 14)
+#define PORT_LED_GREEN (2 << 14)
+#define PORT_LED_MASK  (3 << 14)
+/* Port Link State Write Strobe - set this when changing link state */
+#define PORT_LINK_STROBE       (1 << 16)
+/* true: connect status change */
+#define PORT_CSC       (1 << 17)
+/* true: port enable change */
+#define PORT_PEC       (1 << 18)
+/* true: warm reset for a USB 3.0 device is done.  A "hot" reset puts the port
+ * into an enabled state, and the device into the default state.  A "warm" reset
+ * also resets the link, forcing the device through the link training sequence.
+ * SW can also look at the Port Reset register to see when warm reset is done.
+ */
+#define PORT_WRC       (1 << 19)
+/* true: over-current change */
+#define PORT_OCC       (1 << 20)
+/* true: reset change - 1 to 0 transition of PORT_RESET */
+#define PORT_RC                (1 << 21)
+/* port link status change - set on some port link state transitions:
+ *  Transition                         Reason
+ *  ------------------------------------------------------------------------------
+ *  - U3 to Resume                     Wakeup signaling from a device
+ *  - Resume to Recovery to U0         USB 3.0 device resume
+ *  - Resume to U0                     USB 2.0 device resume
+ *  - U3 to Recovery to U0             Software resume of USB 3.0 device complete
+ *  - U3 to U0                         Software resume of USB 2.0 device complete
+ *  - U2 to U0                         L1 resume of USB 2.1 device complete
+ *  - U0 to U0 (???)                   L1 entry rejection by USB 2.1 device
+ *  - U0 to disabled                   L1 entry error with USB 2.1 device
+ *  - Any state to inactive            Error on USB 3.0 port
+ */
+#define PORT_PLC       (1 << 22)
+/* port configure error change - port failed to configure its link partner */
+#define PORT_CEC       (1 << 23)
+#define PORT_CHANGE_MASK       (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
+                                PORT_RC | PORT_PLC | PORT_CEC)
+
+
+/* Cold Attach Status - xHC can set this bit to report device attached during
+ * Sx state. Warm port reset should be perfomed to clear this bit and move port
+ * to connected state.
+ */
+#define PORT_CAS       (1 << 24)
+/* wake on connect (enable) */
+#define PORT_WKCONN_E  (1 << 25)
+/* wake on disconnect (enable) */
+#define PORT_WKDISC_E  (1 << 26)
+/* wake on over-current (enable) */
+#define PORT_WKOC_E    (1 << 27)
+/* bits 28:29 reserved */
+/* true: device is non-removable - for USB 3.0 roothub emulation */
+#define PORT_DEV_REMOVE        (1 << 30)
+/* Initiate a warm port reset - complete when PORT_WRC is '1' */
+#define PORT_WR                (1 << 31)
+
+/* We mark duplicate entries with -1 */
+#define DUPLICATE_ENTRY ((u8)(-1))
+
+/* Port Power Management Status and Control - port_power_base bitmasks */
+/* Inactivity timer value for transitions into U1, in microseconds.
+ * Timeout can be up to 127us.  0xFF means an infinite timeout.
+ */
+#define PORT_U1_TIMEOUT(p)     ((p) & 0xff)
+#define PORT_U1_TIMEOUT_MASK   0xff
+/* Inactivity timer value for transitions into U2 */
+#define PORT_U2_TIMEOUT(p)     (((p) & 0xff) << 8)
+#define PORT_U2_TIMEOUT_MASK   (0xff << 8)
+/* Bits 24:31 for port testing */
+
+/* USB2 Protocol PORTSPMSC */
+#define        PORT_L1S_MASK           7
+#define        PORT_L1S_SUCCESS        1
+#define        PORT_RWE                (1 << 3)
+#define        PORT_HIRD(p)            (((p) & 0xf) << 4)
+#define        PORT_HIRD_MASK          (0xf << 4)
+#define        PORT_L1DS_MASK          (0xff << 8)
+#define        PORT_L1DS(p)            (((p) & 0xff) << 8)
+#define        PORT_HLE                (1 << 16)
+#define PORT_TEST_MODE_SHIFT   28
+
+/* USB3 Protocol PORTLI  Port Link Information */
+#define PORT_RX_LANES(p)       (((p) >> 16) & 0xf)
+#define PORT_TX_LANES(p)       (((p) >> 20) & 0xf)
+
+/* USB2 Protocol PORTHLPMC */
+#define PORT_HIRDM(p)((p) & 3)
+#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2)
+#define PORT_BESLD(p)(((p) & 0xf) << 10)
+
+/* use 512 microseconds as USB2 LPM L1 default timeout. */
+#define XHCI_L1_TIMEOUT                512
+
+/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency.
+ * Safe to use with mixed HIRD and BESL systems (host and device) and is used
+ * by other operating systems.
+ *
+ * XHCI 1.0 errata 8/14/12 Table 13 notes:
+ * "Software should choose xHC BESL/BESLD field values that do not violate a
+ * device's resume latency requirements,
+ * e.g. not program values > '4' if BLC = '1' and a HIRD device is attached,
+ * or not program values < '4' if BLC = '0' and a BESL device is attached.
+ */
+#define XHCI_DEFAULT_BESL      4
+
+/*
+ * USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports
+ * to complete link training. usually link trainig completes much faster
+ * so check status 10 times with 36ms sleep in places we need to wait for
+ * polling to complete.
+ */
+#define XHCI_PORT_POLLING_LFPS_TIME  36
index 4f64b814d4aa20fdd08e349e5c07324b3e105c5e..52278afea94be01b9f05c71fffaca9d3da98c936 100644 (file)
@@ -113,6 +113,12 @@ static bool last_td_in_urb(struct xhci_td *td)
        return urb_priv->num_tds_done == urb_priv->num_tds;
 }
 
+static bool unhandled_event_trb(struct xhci_ring *ring)
+{
+       return ((le32_to_cpu(ring->dequeue->event_cmd.flags) & TRB_CYCLE) ==
+               ring->cycle_state);
+}
+
 static void inc_td_cnt(struct urb *urb)
 {
        struct urb_priv *urb_priv = urb->hcpriv;
@@ -1154,6 +1160,15 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
                                break;
                        ep->ep_state &= ~EP_STOP_CMD_PENDING;
                        return;
+               case EP_STATE_STOPPED:
+                       /*
+                        * NEC uPD720200 sometimes sets this state and fails with
+                        * Context Error while continuing to process TRBs.
+                        * Be conservative and trust EP_CTX_STATE on other chips.
+                        */
+                       if (!(xhci->quirks & XHCI_NEC_HOST))
+                               break;
+                       fallthrough;
                case EP_STATE_RUNNING:
                        /* Race, HW handled stop ep cmd before ep was running */
                        xhci_dbg(xhci, "Stop ep completion ctx error, ep is running\n");
@@ -1870,7 +1885,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
        u32 port_id;
        u32 portsc, cmd_reg;
        int max_ports;
-       int slot_id;
        unsigned int hcd_portnum;
        struct xhci_bus_state *bus_state;
        bool bogus_port_status = false;
@@ -1922,9 +1936,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
 
        if (hcd->speed >= HCD_USB3 &&
            (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
-               slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
-               if (slot_id && xhci->devs[slot_id])
-                       xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR;
+               if (port->slot_id && xhci->devs[port->slot_id])
+                       xhci->devs[port->slot_id]->flags |= VDEV_PORT_ERROR;
        }
 
        if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
@@ -1982,9 +1995,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
                 * so the roothub behavior is consistent with external
                 * USB 3.0 hub behavior.
                 */
-               slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
-               if (slot_id && xhci->devs[slot_id])
-                       xhci_ring_device(xhci, slot_id);
+               if (port->slot_id && xhci->devs[port->slot_id])
+                       xhci_ring_device(xhci, port->slot_id);
                if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
                        xhci_test_and_clear_bit(xhci, port, PORT_PLC);
                        usb_wakeup_notification(hcd->self.root_hub,
@@ -2816,7 +2828,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                        td_num--;
 
                /* Is this a TRB in the currently executing TD? */
-               ep_seg = trb_in_td(xhci, ep_ring->deq_seg, ep_ring->dequeue,
+               ep_seg = trb_in_td(xhci, td->start_seg, td->first_trb,
                                td->last_trb, ep_trb_dma, false);
 
                /*
@@ -2884,9 +2896,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                                        "part of current TD ep_index %d "
                                        "comp_code %u\n", ep_index,
                                        trb_comp_code);
-                               trb_in_td(xhci, ep_ring->deq_seg,
-                                         ep_ring->dequeue, td->last_trb,
-                                         ep_trb_dma, true);
+                               trb_in_td(xhci, td->start_seg, td->first_trb,
+                                         td->last_trb, ep_trb_dma, true);
                                return -ESHUTDOWN;
                        }
                }
@@ -2962,32 +2973,18 @@ err_out:
 }
 
 /*
- * This function handles all OS-owned events on the event ring.  It may drop
+ * This function handles one OS-owned event on the event ring. It may drop
  * xhci->lock between event processing (e.g. to pass up port status changes).
- * Returns >0 for "possibly more events to process" (caller should call again),
- * otherwise 0 if done.  In future, <0 returns should indicate error code.
  */
-static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+                                union xhci_trb *event)
 {
-       union xhci_trb *event;
        u32 trb_type;
 
-       /* Event ring hasn't been allocated yet. */
-       if (!ir || !ir->event_ring || !ir->event_ring->dequeue) {
-               xhci_err(xhci, "ERROR interrupter not ready\n");
-               return -ENOMEM;
-       }
-
-       event = ir->event_ring->dequeue;
-       /* Does the HC or OS own the TRB? */
-       if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) !=
-           ir->event_ring->cycle_state)
-               return 0;
-
        trace_xhci_handle_event(ir->event_ring, &event->generic);
 
        /*
-        * Barrier between reading the TRB_CYCLE (valid) flag above and any
+        * Barrier between reading the TRB_CYCLE (valid) flag before, and any
         * speculative reads of the event's flags/data below.
         */
        rmb();
@@ -3017,18 +3014,11 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
         * to make sure a watchdog timer didn't mark the host as non-responsive.
         */
        if (xhci->xhc_state & XHCI_STATE_DYING) {
-               xhci_dbg(xhci, "xHCI host dying, returning from "
-                               "event handler.\n");
-               return 0;
+               xhci_dbg(xhci, "xHCI host dying, returning from event handler.\n");
+               return -ENODEV;
        }
 
-       /* Update SW event ring dequeue pointer */
-       inc_deq(xhci, ir->event_ring);
-
-       /* Are there more items on the event ring?  Caller will call us again to
-        * check.
-        */
-       return 1;
+       return 0;
 }
 
 /*
@@ -3038,30 +3028,26 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
  */
 static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
                                     struct xhci_interrupter *ir,
-                                    union xhci_trb *event_ring_deq,
                                     bool clear_ehb)
 {
        u64 temp_64;
        dma_addr_t deq;
 
        temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
-       /* If necessary, update the HW's version of the event ring deq ptr. */
-       if (event_ring_deq != ir->event_ring->dequeue) {
-               deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
-                               ir->event_ring->dequeue);
-               if (deq == 0)
-                       xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
-               /*
-                * Per 4.9.4, Software writes to the ERDP register shall
-                * always advance the Event Ring Dequeue Pointer value.
-                */
-               if ((temp_64 & ERST_PTR_MASK) == (deq & ERST_PTR_MASK))
-                       return;
+       deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg,
+                                  ir->event_ring->dequeue);
+       if (deq == 0)
+               xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
+       /*
+        * Per 4.9.4, Software writes to the ERDP register shall always advance
+        * the Event Ring Dequeue Pointer value.
+        */
+       if ((temp_64 & ERST_PTR_MASK) == (deq & ERST_PTR_MASK) && !clear_ehb)
+               return;
 
-               /* Update HC event ring dequeue pointer */
-               temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK;
-               temp_64 |= deq & ERST_PTR_MASK;
-       }
+       /* Update HC event ring dequeue pointer */
+       temp_64 = ir->event_ring->deq_seg->num & ERST_DESI_MASK;
+       temp_64 |= deq & ERST_PTR_MASK;
 
        /* Clear the event handler busy flag (RW1C) */
        if (clear_ehb)
@@ -3069,6 +3055,76 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
        xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
 }
 
+/* Clear the interrupt pending bit for a specific interrupter. */
+static void xhci_clear_interrupt_pending(struct xhci_hcd *xhci,
+                                        struct xhci_interrupter *ir)
+{
+       if (!ir->ip_autoclear) {
+               u32 irq_pending;
+
+               irq_pending = readl(&ir->ir_set->irq_pending);
+               irq_pending |= IMAN_IP;
+               writel(irq_pending, &ir->ir_set->irq_pending);
+       }
+}
+
+/*
+ * Handle all OS-owned events on an interrupter event ring. It may drop
+ * and reaquire xhci->lock between event processing.
+ */
+static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
+{
+       int event_loop = 0;
+       int err;
+       u64 temp;
+
+       xhci_clear_interrupt_pending(xhci, ir);
+
+       /* Event ring hasn't been allocated yet. */
+       if (!ir->event_ring || !ir->event_ring->dequeue) {
+               xhci_err(xhci, "ERROR interrupter event ring not ready\n");
+               return -ENOMEM;
+       }
+
+       if (xhci->xhc_state & XHCI_STATE_DYING ||
+           xhci->xhc_state & XHCI_STATE_HALTED) {
+               xhci_dbg(xhci, "xHCI dying, ignoring interrupt. Shouldn't IRQs be disabled?\n");
+
+               /* Clear the event handler busy flag (RW1C) */
+               temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+               xhci_write_64(xhci, temp | ERST_EHB, &ir->ir_set->erst_dequeue);
+               return -ENODEV;
+       }
+
+       /* Process all OS owned event TRBs on this event ring */
+       while (unhandled_event_trb(ir->event_ring)) {
+               err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue);
+
+               /*
+                * If half a segment of events have been handled in one go then
+                * update ERDP, and force isoc trbs to interrupt more often
+                */
+               if (event_loop++ > TRBS_PER_SEGMENT / 2) {
+                       xhci_update_erst_dequeue(xhci, ir, false);
+
+                       if (ir->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
+                               ir->isoc_bei_interval = ir->isoc_bei_interval / 2;
+
+                       event_loop = 0;
+               }
+
+               /* Update SW event ring dequeue pointer */
+               inc_deq(xhci, ir->event_ring);
+
+               if (err)
+                       break;
+       }
+
+       xhci_update_erst_dequeue(xhci, ir, true);
+
+       return 0;
+}
+
 /*
  * xHCI spec says we can get an interrupt, and if the HC has an error condition,
  * we might get bad data out of the event ring.  Section 4.10.2.7 has a list of
@@ -3077,12 +3133,8 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
 irqreturn_t xhci_irq(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-       union xhci_trb *event_ring_deq;
-       struct xhci_interrupter *ir;
        irqreturn_t ret = IRQ_NONE;
-       u64 temp_64;
        u32 status;
-       int event_loop = 0;
 
        spin_lock(&xhci->lock);
        /* Check if the xHC generated the interrupt, or the irq is shared */
@@ -3115,50 +3167,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
         */
        status |= STS_EINT;
        writel(status, &xhci->op_regs->status);
-
-       /* This is the handler of the primary interrupter */
-       ir = xhci->interrupters[0];
-       if (!hcd->msi_enabled) {
-               u32 irq_pending;
-               irq_pending = readl(&ir->ir_set->irq_pending);
-               irq_pending |= IMAN_IP;
-               writel(irq_pending, &ir->ir_set->irq_pending);
-       }
-
-       if (xhci->xhc_state & XHCI_STATE_DYING ||
-           xhci->xhc_state & XHCI_STATE_HALTED) {
-               xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
-                               "Shouldn't IRQs be disabled?\n");
-               /* Clear the event handler busy flag (RW1C);
-                * the event ring should be empty.
-                */
-               temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
-               xhci_write_64(xhci, temp_64 | ERST_EHB,
-                               &ir->ir_set->erst_dequeue);
-               ret = IRQ_HANDLED;
-               goto out;
-       }
-
-       event_ring_deq = ir->event_ring->dequeue;
-       /* FIXME this should be a delayed service routine
-        * that clears the EHB.
-        */
-       while (xhci_handle_event(xhci, ir) > 0) {
-               if (event_loop++ < TRBS_PER_SEGMENT / 2)
-                       continue;
-               xhci_update_erst_dequeue(xhci, ir, event_ring_deq, false);
-               event_ring_deq = ir->event_ring->dequeue;
-
-               /* ring is half-full, force isoc trbs to interrupt more often */
-               if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN)
-                       xhci->isoc_bei_interval = xhci->isoc_bei_interval / 2;
-
-               event_loop = 0;
-       }
-
-       xhci_update_erst_dequeue(xhci, ir, event_ring_deq, true);
        ret = IRQ_HANDLED;
 
+       /* This is the handler of the primary interrupter */
+       xhci_handle_events(xhci, xhci->interrupters[0]);
 out:
        spin_unlock(&xhci->lock);
 
@@ -4019,7 +4031,8 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci,
 }
 
 /* Check if we should generate event interrupt for a TD in an isoc URB */
-static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i)
+static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i,
+                                struct xhci_interrupter *ir)
 {
        if (xhci->hci_version < 0x100)
                return false;
@@ -4030,8 +4043,8 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i)
         * If AVOID_BEI is set the host handles full event rings poorly,
         * generate an event at least every 8th TD to clear the event ring
         */
-       if (i && xhci->quirks & XHCI_AVOID_BEI)
-               return !!(i % xhci->isoc_bei_interval);
+       if (i && ir->isoc_bei_interval && xhci->quirks & XHCI_AVOID_BEI)
+               return !!(i % ir->isoc_bei_interval);
 
        return true;
 }
@@ -4040,6 +4053,7 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i)
 static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                struct urb *urb, int slot_id, unsigned int ep_index)
 {
+       struct xhci_interrupter *ir;
        struct xhci_ring *ep_ring;
        struct urb_priv *urb_priv;
        struct xhci_td *td;
@@ -4057,6 +4071,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        xep = &xhci->devs[slot_id]->eps[ep_index];
        ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
+       ir = xhci->interrupters[0];
 
        num_tds = urb->number_of_packets;
        if (num_tds < 1) {
@@ -4144,7 +4159,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                td->last_trb = ep_ring->enqueue;
                                td->last_trb_seg = ep_ring->enq_seg;
                                field |= TRB_IOC;
-                               if (trb_block_event_intr(xhci, num_tds, i))
+                               if (trb_block_event_intr(xhci, num_tds, i, ir))
                                        field |= TRB_BEI;
                        }
                        /* Calculate TRB length */
index ac47b1c0544a6836882970add7a7cb50ed54678f..1740000d54c295d4d8884910fc3f3ae04e6a4d6b 100644 (file)
@@ -172,8 +172,8 @@ DECLARE_EVENT_CLASS(xhci_log_free_virt_dev,
                __field(void *, vdev)
                __field(unsigned long long, out_ctx)
                __field(unsigned long long, in_ctx)
-               __field(u8, fake_port)
-               __field(u8, real_port)
+               __field(int, hcd_portnum)
+               __field(int, hw_portnum)
                __field(u16, current_mel)
 
        ),
@@ -181,13 +181,13 @@ DECLARE_EVENT_CLASS(xhci_log_free_virt_dev,
                __entry->vdev = vdev;
                __entry->in_ctx = (unsigned long long) vdev->in_ctx->dma;
                __entry->out_ctx = (unsigned long long) vdev->out_ctx->dma;
-               __entry->fake_port = (u8) vdev->fake_port;
-               __entry->real_port = (u8) vdev->real_port;
+               __entry->hcd_portnum = (int) vdev->rhub_port->hcd_portnum;
+               __entry->hw_portnum = (int) vdev->rhub_port->hw_portnum;
                __entry->current_mel = (u16) vdev->current_mel;
                ),
-       TP_printk("vdev %p ctx %llx | %llx fake_port %d real_port %d current_mel %d",
+       TP_printk("vdev %p ctx %llx | %llx hcd_portnum %d hw_portnum %d current_mel %d",
                __entry->vdev, __entry->in_ctx, __entry->out_ctx,
-               __entry->fake_port, __entry->real_port, __entry->current_mel
+               __entry->hcd_portnum, __entry->hw_portnum, __entry->current_mel
        )
 );
 
index c057c42c36f4cc9385af591c2921f77dac62c21f..8579603edaff17e629f137bd4fe21fcbb90377c1 100644 (file)
@@ -346,6 +346,23 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir)
        return 0;
 }
 
+/* interrupt moderation interval imod_interval in nanoseconds */
+static int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
+                                          u32 imod_interval)
+{
+       u32 imod;
+
+       if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250)
+               return -EINVAL;
+
+       imod = readl(&ir->ir_set->irq_control);
+       imod &= ~ER_IRQ_INTERVAL_MASK;
+       imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
+       writel(imod, &ir->ir_set->irq_control);
+
+       return 0;
+}
+
 static void compliance_mode_recovery(struct timer_list *t)
 {
        struct xhci_hcd *xhci;
@@ -528,7 +545,6 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
  */
 int xhci_run(struct usb_hcd *hcd)
 {
-       u32 temp;
        u64 temp_64;
        int ret;
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -538,6 +554,9 @@ int xhci_run(struct usb_hcd *hcd)
         */
 
        hcd->uses_new_polling = 1;
+       if (hcd->msi_enabled)
+               ir->ip_autoclear = true;
+
        if (!usb_hcd_is_primary_hcd(hcd))
                return xhci_run_finished(xhci);
 
@@ -548,12 +567,7 @@ int xhci_run(struct usb_hcd *hcd)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
 
-       xhci_dbg_trace(xhci, trace_xhci_dbg_init,
-                       "// Set the interrupt modulation register");
-       temp = readl(&ir->ir_set->irq_control);
-       temp &= ~ER_IRQ_INTERVAL_MASK;
-       temp |= (xhci->imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
-       writel(temp, &ir->ir_set->irq_control);
+       xhci_set_interrupter_moderation(ir, xhci->imod_interval);
 
        if (xhci->quirks & XHCI_NEC_HOST) {
                struct xhci_command *command;
@@ -780,19 +794,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
                seg = seg->next;
        } while (seg != ring->deq_seg);
 
-       /* Reset the software enqueue and dequeue pointers */
-       ring->deq_seg = ring->first_seg;
-       ring->dequeue = ring->first_seg->trbs;
-       ring->enq_seg = ring->deq_seg;
-       ring->enqueue = ring->dequeue;
-
-       ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
-       /*
-        * Ring is now zeroed, so the HW should look for change of ownership
-        * when the cycle bit is set to 1.
-        */
-       ring->cycle_state = 1;
-
+       xhci_initialize_ring_info(ring, 1);
        /*
         * Reset the hardware dequeue pointer.
         * Yes, this will need to be re-written after resume, but we're paranoid
@@ -1217,6 +1219,8 @@ static int xhci_map_temp_buffer(struct usb_hcd *hcd, struct urb *urb)
 
        temp = kzalloc_node(buf_len, GFP_ATOMIC,
                            dev_to_node(hcd->self.sysdev));
+       if (!temp)
+               return -ENOMEM;
 
        if (usb_urb_dir_out(urb))
                sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
@@ -2259,7 +2263,7 @@ static int xhci_check_tt_bw_table(struct xhci_hcd *xhci,
        struct xhci_tt_bw_info *tt_info;
 
        /* Find the bandwidth table for the root port this TT is attached to. */
-       bw_table = &xhci->rh_bw[virt_dev->real_port - 1].bw_table;
+       bw_table = &xhci->rh_bw[virt_dev->rhub_port->hw_portnum].bw_table;
        tt_info = virt_dev->tt_info;
        /* If this TT already had active endpoints, the bandwidth for this TT
         * has already been added.  Removing all periodic endpoints (and thus
@@ -2377,7 +2381,7 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
        if (virt_dev->tt_info) {
                xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
                                "Recalculating BW for rootport %u",
-                               virt_dev->real_port);
+                               virt_dev->rhub_port->hw_portnum + 1);
                if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) {
                        xhci_warn(xhci, "Not enough bandwidth on HS bus for "
                                        "newly activated TT.\n");
@@ -2390,7 +2394,7 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
        } else {
                xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
                                "Recalculating BW for rootport %u",
-                               virt_dev->real_port);
+                               virt_dev->rhub_port->hw_portnum + 1);
        }
 
        /* Add in how much bandwidth will be used for interval zero, or the
@@ -2487,14 +2491,12 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
                bw_used += overhead + packet_size;
 
        if (!virt_dev->tt_info && virt_dev->udev->speed == USB_SPEED_HIGH) {
-               unsigned int port_index = virt_dev->real_port - 1;
-
                /* OK, we're manipulating a HS device attached to a
                 * root port bandwidth domain.  Include the number of active TTs
                 * in the bandwidth used.
                 */
                bw_used += TT_HS_OVERHEAD *
-                       xhci->rh_bw[port_index].num_active_tts;
+                       xhci->rh_bw[virt_dev->rhub_port->hw_portnum].num_active_tts;
        }
 
        xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
@@ -2681,7 +2683,7 @@ void xhci_update_tt_active_eps(struct xhci_hcd *xhci,
        if (!virt_dev->tt_info)
                return;
 
-       rh_bw_info = &xhci->rh_bw[virt_dev->real_port - 1];
+       rh_bw_info = &xhci->rh_bw[virt_dev->rhub_port->hw_portnum];
        if (old_active_eps == 0 &&
                                virt_dev->tt_info->active_eps != 0) {
                rh_bw_info->num_active_tts += 1;
index 6f82d404883f9accf627c057a96702a7d8d65a80..6f4bf98a628245818c11e32ae355e596efb4c23c 100644 (file)
@@ -22,6 +22,9 @@
 #include       "xhci-ext-caps.h"
 #include "pci-quirks.h"
 
+#include "xhci-port.h"
+#include "xhci-caps.h"
+
 /* max buffer size for trace and debug messages */
 #define XHCI_MSG_MAX           500
 
@@ -62,90 +65,6 @@ struct xhci_cap_regs {
        /* Reserved up to (CAPLENGTH - 0x1C) */
 };
 
-/* hc_capbase bitmasks */
-/* bits 7:0 - how long is the Capabilities register */
-#define HC_LENGTH(p)           XHCI_HC_LENGTH(p)
-/* bits 31:16  */
-#define HC_VERSION(p)          (((p) >> 16) & 0xffff)
-
-/* HCSPARAMS1 - hcs_params1 - bitmasks */
-/* bits 0:7, Max Device Slots */
-#define HCS_MAX_SLOTS(p)       (((p) >> 0) & 0xff)
-#define HCS_SLOTS_MASK         0xff
-/* bits 8:18, Max Interrupters */
-#define HCS_MAX_INTRS(p)       (((p) >> 8) & 0x7ff)
-/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
-#define HCS_MAX_PORTS(p)       (((p) >> 24) & 0x7f)
-
-/* HCSPARAMS2 - hcs_params2 - bitmasks */
-/* bits 0:3, frames or uframes that SW needs to queue transactions
- * ahead of the HW to meet periodic deadlines */
-#define HCS_IST(p)             (((p) >> 0) & 0xf)
-/* bits 4:7, max number of Event Ring segments */
-#define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
-/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */
-/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
-/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */
-#define HCS_MAX_SCRATCHPAD(p)   ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f))
-
-/* HCSPARAMS3 - hcs_params3 - bitmasks */
-/* bits 0:7, Max U1 to U0 latency for the roothub ports */
-#define HCS_U1_LATENCY(p)      (((p) >> 0) & 0xff)
-/* bits 16:31, Max U2 to U0 latency for the roothub ports */
-#define HCS_U2_LATENCY(p)      (((p) >> 16) & 0xffff)
-
-/* HCCPARAMS - hcc_params - bitmasks */
-/* true: HC can use 64-bit address pointers */
-#define HCC_64BIT_ADDR(p)      ((p) & (1 << 0))
-/* true: HC can do bandwidth negotiation */
-#define HCC_BANDWIDTH_NEG(p)   ((p) & (1 << 1))
-/* true: HC uses 64-byte Device Context structures
- * FIXME 64-byte context structures aren't supported yet.
- */
-#define HCC_64BYTE_CONTEXT(p)  ((p) & (1 << 2))
-/* true: HC has port power switches */
-#define HCC_PPC(p)             ((p) & (1 << 3))
-/* true: HC has port indicators */
-#define HCS_INDICATOR(p)       ((p) & (1 << 4))
-/* true: HC has Light HC Reset Capability */
-#define HCC_LIGHT_RESET(p)     ((p) & (1 << 5))
-/* true: HC supports latency tolerance messaging */
-#define HCC_LTC(p)             ((p) & (1 << 6))
-/* true: no secondary Stream ID Support */
-#define HCC_NSS(p)             ((p) & (1 << 7))
-/* true: HC supports Stopped - Short Packet */
-#define HCC_SPC(p)             ((p) & (1 << 9))
-/* true: HC has Contiguous Frame ID Capability */
-#define HCC_CFC(p)             ((p) & (1 << 11))
-/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
-#define HCC_MAX_PSA(p)         (1 << ((((p) >> 12) & 0xf) + 1))
-/* Extended Capabilities pointer from PCI base - section 5.3.6 */
-#define HCC_EXT_CAPS(p)                XHCI_HCC_EXT_CAPS(p)
-
-#define CTX_SIZE(_hcc)         (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
-
-/* db_off bitmask - bits 0:1 reserved */
-#define        DBOFF_MASK      (~0x3)
-
-/* run_regs_off bitmask - bits 0:4 reserved */
-#define        RTSOFF_MASK     (~0x1f)
-
-/* HCCPARAMS2 - hcc_params2 - bitmasks */
-/* true: HC supports U3 entry Capability */
-#define        HCC2_U3C(p)             ((p) & (1 << 0))
-/* true: HC supports Configure endpoint command Max exit latency too large */
-#define        HCC2_CMC(p)             ((p) & (1 << 1))
-/* true: HC supports Force Save context Capability */
-#define        HCC2_FSC(p)             ((p) & (1 << 2))
-/* true: HC supports Compliance Transition Capability */
-#define        HCC2_CTC(p)             ((p) & (1 << 3))
-/* true: HC support Large ESIT payload Capability > 48k */
-#define        HCC2_LEC(p)             ((p) & (1 << 4))
-/* true: HC support Configuration Information Capability */
-#define        HCC2_CIC(p)             ((p) & (1 << 5))
-/* true: HC support Extended TBC Capability, Isoc burst count > 65535 */
-#define        HCC2_ETC(p)             ((p) & (1 << 6))
-
 /* Number of registers per port */
 #define        NUM_PORT_REGS   4
 
@@ -291,181 +210,6 @@ struct xhci_op_regs {
 #define CONFIG_CIE             (1 << 9)
 /* bits 10:31 - reserved and should be preserved */
 
-/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
-/* true: device connected */
-#define PORT_CONNECT   (1 << 0)
-/* true: port enabled */
-#define PORT_PE                (1 << 1)
-/* bit 2 reserved and zeroed */
-/* true: port has an over-current condition */
-#define PORT_OC                (1 << 3)
-/* true: port reset signaling asserted */
-#define PORT_RESET     (1 << 4)
-/* Port Link State - bits 5:8
- * A read gives the current link PM state of the port,
- * a write with Link State Write Strobe set sets the link state.
- */
-#define PORT_PLS_MASK  (0xf << 5)
-#define XDEV_U0                (0x0 << 5)
-#define XDEV_U1                (0x1 << 5)
-#define XDEV_U2                (0x2 << 5)
-#define XDEV_U3                (0x3 << 5)
-#define XDEV_DISABLED  (0x4 << 5)
-#define XDEV_RXDETECT  (0x5 << 5)
-#define XDEV_INACTIVE  (0x6 << 5)
-#define XDEV_POLLING   (0x7 << 5)
-#define XDEV_RECOVERY  (0x8 << 5)
-#define XDEV_HOT_RESET (0x9 << 5)
-#define XDEV_COMP_MODE (0xa << 5)
-#define XDEV_TEST_MODE (0xb << 5)
-#define XDEV_RESUME    (0xf << 5)
-
-/* true: port has power (see HCC_PPC) */
-#define PORT_POWER     (1 << 9)
-/* bits 10:13 indicate device speed:
- * 0 - undefined speed - port hasn't be initialized by a reset yet
- * 1 - full speed
- * 2 - low speed
- * 3 - high speed
- * 4 - super speed
- * 5-15 reserved
- */
-#define DEV_SPEED_MASK         (0xf << 10)
-#define        XDEV_FS                 (0x1 << 10)
-#define        XDEV_LS                 (0x2 << 10)
-#define        XDEV_HS                 (0x3 << 10)
-#define        XDEV_SS                 (0x4 << 10)
-#define        XDEV_SSP                (0x5 << 10)
-#define DEV_UNDEFSPEED(p)      (((p) & DEV_SPEED_MASK) == (0x0<<10))
-#define DEV_FULLSPEED(p)       (((p) & DEV_SPEED_MASK) == XDEV_FS)
-#define DEV_LOWSPEED(p)                (((p) & DEV_SPEED_MASK) == XDEV_LS)
-#define DEV_HIGHSPEED(p)       (((p) & DEV_SPEED_MASK) == XDEV_HS)
-#define DEV_SUPERSPEED(p)      (((p) & DEV_SPEED_MASK) == XDEV_SS)
-#define DEV_SUPERSPEEDPLUS(p)  (((p) & DEV_SPEED_MASK) == XDEV_SSP)
-#define DEV_SUPERSPEED_ANY(p)  (((p) & DEV_SPEED_MASK) >= XDEV_SS)
-#define DEV_PORT_SPEED(p)      (((p) >> 10) & 0x0f)
-
-/* Bits 20:23 in the Slot Context are the speed for the device */
-#define        SLOT_SPEED_FS           (XDEV_FS << 10)
-#define        SLOT_SPEED_LS           (XDEV_LS << 10)
-#define        SLOT_SPEED_HS           (XDEV_HS << 10)
-#define        SLOT_SPEED_SS           (XDEV_SS << 10)
-#define        SLOT_SPEED_SSP          (XDEV_SSP << 10)
-/* Port Indicator Control */
-#define PORT_LED_OFF   (0 << 14)
-#define PORT_LED_AMBER (1 << 14)
-#define PORT_LED_GREEN (2 << 14)
-#define PORT_LED_MASK  (3 << 14)
-/* Port Link State Write Strobe - set this when changing link state */
-#define PORT_LINK_STROBE       (1 << 16)
-/* true: connect status change */
-#define PORT_CSC       (1 << 17)
-/* true: port enable change */
-#define PORT_PEC       (1 << 18)
-/* true: warm reset for a USB 3.0 device is done.  A "hot" reset puts the port
- * into an enabled state, and the device into the default state.  A "warm" reset
- * also resets the link, forcing the device through the link training sequence.
- * SW can also look at the Port Reset register to see when warm reset is done.
- */
-#define PORT_WRC       (1 << 19)
-/* true: over-current change */
-#define PORT_OCC       (1 << 20)
-/* true: reset change - 1 to 0 transition of PORT_RESET */
-#define PORT_RC                (1 << 21)
-/* port link status change - set on some port link state transitions:
- *  Transition                         Reason
- *  ------------------------------------------------------------------------------
- *  - U3 to Resume                     Wakeup signaling from a device
- *  - Resume to Recovery to U0         USB 3.0 device resume
- *  - Resume to U0                     USB 2.0 device resume
- *  - U3 to Recovery to U0             Software resume of USB 3.0 device complete
- *  - U3 to U0                         Software resume of USB 2.0 device complete
- *  - U2 to U0                         L1 resume of USB 2.1 device complete
- *  - U0 to U0 (???)                   L1 entry rejection by USB 2.1 device
- *  - U0 to disabled                   L1 entry error with USB 2.1 device
- *  - Any state to inactive            Error on USB 3.0 port
- */
-#define PORT_PLC       (1 << 22)
-/* port configure error change - port failed to configure its link partner */
-#define PORT_CEC       (1 << 23)
-#define PORT_CHANGE_MASK       (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
-                                PORT_RC | PORT_PLC | PORT_CEC)
-
-
-/* Cold Attach Status - xHC can set this bit to report device attached during
- * Sx state. Warm port reset should be perfomed to clear this bit and move port
- * to connected state.
- */
-#define PORT_CAS       (1 << 24)
-/* wake on connect (enable) */
-#define PORT_WKCONN_E  (1 << 25)
-/* wake on disconnect (enable) */
-#define PORT_WKDISC_E  (1 << 26)
-/* wake on over-current (enable) */
-#define PORT_WKOC_E    (1 << 27)
-/* bits 28:29 reserved */
-/* true: device is non-removable - for USB 3.0 roothub emulation */
-#define PORT_DEV_REMOVE        (1 << 30)
-/* Initiate a warm port reset - complete when PORT_WRC is '1' */
-#define PORT_WR                (1 << 31)
-
-/* We mark duplicate entries with -1 */
-#define DUPLICATE_ENTRY ((u8)(-1))
-
-/* Port Power Management Status and Control - port_power_base bitmasks */
-/* Inactivity timer value for transitions into U1, in microseconds.
- * Timeout can be up to 127us.  0xFF means an infinite timeout.
- */
-#define PORT_U1_TIMEOUT(p)     ((p) & 0xff)
-#define PORT_U1_TIMEOUT_MASK   0xff
-/* Inactivity timer value for transitions into U2 */
-#define PORT_U2_TIMEOUT(p)     (((p) & 0xff) << 8)
-#define PORT_U2_TIMEOUT_MASK   (0xff << 8)
-/* Bits 24:31 for port testing */
-
-/* USB2 Protocol PORTSPMSC */
-#define        PORT_L1S_MASK           7
-#define        PORT_L1S_SUCCESS        1
-#define        PORT_RWE                (1 << 3)
-#define        PORT_HIRD(p)            (((p) & 0xf) << 4)
-#define        PORT_HIRD_MASK          (0xf << 4)
-#define        PORT_L1DS_MASK          (0xff << 8)
-#define        PORT_L1DS(p)            (((p) & 0xff) << 8)
-#define        PORT_HLE                (1 << 16)
-#define PORT_TEST_MODE_SHIFT   28
-
-/* USB3 Protocol PORTLI  Port Link Information */
-#define PORT_RX_LANES(p)       (((p) >> 16) & 0xf)
-#define PORT_TX_LANES(p)       (((p) >> 20) & 0xf)
-
-/* USB2 Protocol PORTHLPMC */
-#define PORT_HIRDM(p)((p) & 3)
-#define PORT_L1_TIMEOUT(p)(((p) & 0xff) << 2)
-#define PORT_BESLD(p)(((p) & 0xf) << 10)
-
-/* use 512 microseconds as USB2 LPM L1 default timeout. */
-#define XHCI_L1_TIMEOUT                512
-
-/* Set default HIRD/BESL value to 4 (350/400us) for USB2 L1 LPM resume latency.
- * Safe to use with mixed HIRD and BESL systems (host and device) and is used
- * by other operating systems.
- *
- * XHCI 1.0 errata 8/14/12 Table 13 notes:
- * "Software should choose xHC BESL/BESLD field values that do not violate a
- * device's resume latency requirements,
- * e.g. not program values > '4' if BLC = '1' and a HIRD device is attached,
- * or not program values < '4' if BLC = '0' and a BESL device is attached.
- */
-#define XHCI_DEFAULT_BESL      4
-
-/*
- * USB3 specification define a 360ms tPollingLFPSTiemout for USB3 ports
- * to complete link training. usually link trainig completes much faster
- * so check status 10 times with 36ms sleep in places we need to wait for
- * polling to complete.
- */
-#define XHCI_PORT_POLLING_LFPS_TIME  36
-
 /**
  * struct xhci_intr_reg - Interrupt Register Set
  * @irq_pending:       IMAN - Interrupt Management Register.  Used to enable
@@ -995,8 +739,7 @@ struct xhci_virt_device {
        /* Used for addressing devices and configuration changes */
        struct xhci_container_ctx       *in_ctx;
        struct xhci_virt_ep             eps[EP_CTX_PER_DEV];
-       u8                              fake_port;
-       u8                              real_port;
+       struct xhci_port                *rhub_port;
        struct xhci_interval_bw_table   *bw_table;
        struct xhci_tt_bw_info          *tt_info;
        /*
@@ -1688,6 +1431,8 @@ struct xhci_interrupter {
        struct xhci_erst        erst;
        struct xhci_intr_reg __iomem *ir_set;
        unsigned int            intr_num;
+       bool                    ip_autoclear;
+       u32                     isoc_bei_interval;
        /* For interrupter registers save and restore over suspend/resume */
        u32     s3_irq_pending;
        u32     s3_irq_control;
@@ -1717,6 +1462,8 @@ struct xhci_port {
        unsigned int            lpm_incapable:1;
        unsigned long           resume_timestamp;
        bool                    rexit_active;
+       /* Slot ID is the index of the device directly connected to the port */
+       int                     slot_id;
        struct completion       rexit_done;
        struct completion       u3exit_done;
 };
@@ -1760,7 +1507,6 @@ struct xhci_hcd {
        u8              isoc_threshold;
        /* imod_interval in ns (I * 250ns) */
        u32             imod_interval;
-       u32             isoc_bei_interval;
        int             event_ring_max;
        /* 4KB min, 128MB max */
        int             page_size;
@@ -2200,8 +1946,6 @@ unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd);
 #endif /* CONFIG_PM */
 
 u32 xhci_port_state_to_neutral(u32 state);
-int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
-               u16 port);
 void xhci_ring_device(struct xhci_hcd *xhci, int slot_id);
 
 /* xHCI contexts */
index 67f098579fb456976c2ff36e8c751efe4e0dc277..7b7e1554ea20e223a7461561c88f272a838a1888 100644 (file)
@@ -631,7 +631,6 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
        mdc800->camera_busy=0;
        mdc800->camera_request_ready=0;
 
-       retval=0;
        mdc800->irq_urb->dev = mdc800->dev;
        retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
        if (retval) {
index 0dd2b032c90b9bc6196ab7a3752e327c18a61fb0..c6101ed2d9d49a3d556b0175ed72cdb1a9cf9193 100644 (file)
@@ -260,7 +260,7 @@ static int onboard_hub_probe(struct platform_device *pdev)
        if (!hub)
                return -ENOMEM;
 
-       hub->pdata = device_get_match_data(&pdev->dev);
+       hub->pdata = device_get_match_data(dev);
        if (!hub->pdata)
                return -EINVAL;
 
@@ -454,6 +454,8 @@ static const struct usb_device_id onboard_hub_id_table[] = {
        { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */
        { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */
        { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */
+       { USB_DEVICE(VENDOR_ID_TI, 0x8025) }, /* TI USB8020B 3.0 */
+       { USB_DEVICE(VENDOR_ID_TI, 0x8027) }, /* TI USB8020B 2.0 */
        { USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 */
        { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 */
        { USB_DEVICE(VENDOR_ID_VIA, 0x0817) }, /* VIA VL817 3.1 */
index f360d5cf8d8a047bf8464bec36fa5fc3ab9e2dd9..b4b15d45f84d67d07c1167e852b9e5f1dd2da962 100644 (file)
@@ -26,6 +26,11 @@ static const struct onboard_hub_pdata realtek_rts5411_data = {
        .num_supplies = 1,
 };
 
+static const struct onboard_hub_pdata ti_tusb8020b_data = {
+       .reset_us = 3000,
+       .num_supplies = 1,
+};
+
 static const struct onboard_hub_pdata ti_tusb8041_data = {
        .reset_us = 3000,
        .num_supplies = 1,
@@ -62,6 +67,8 @@ static const struct of_device_id onboard_hub_match[] = {
        { .compatible = "usb424,2517", .data = &microchip_usb424_data, },
        { .compatible = "usb424,2744", .data = &microchip_usb5744_data, },
        { .compatible = "usb424,5744", .data = &microchip_usb5744_data, },
+       { .compatible = "usb451,8025", .data = &ti_tusb8020b_data, },
+       { .compatible = "usb451,8027", .data = &ti_tusb8020b_data, },
        { .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
        { .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
        { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, },
index 9f2be22af8440557e6b056b8e1664ad3d807b511..7c657ea2dabd13a4ad3668f87df11317f720359b 100644 (file)
 #define WC0_SSUSB0_CDEN                BIT(6)
 #define WC0_IS_SPM_EN          BIT(1)
 
+/* mt8195 */
+#define PERI_WK_CTRL0_8195     0x04
+#define WC0_IS_P_95            BIT(30) /* polarity */
+#define WC0_IS_C_95(x)         ((u32)(((x) & 0x7) << 27))
+#define WC0_IS_EN_P3_95                BIT(26)
+#define WC0_IS_EN_P2_95                BIT(25)
+
+#define PERI_WK_CTRL1_8195     0x20
+#define WC1_IS_C_95(x)         ((u32)(((x) & 0xf) << 28))
+#define WC1_IS_P_95            BIT(12)
+#define WC1_IS_EN_P0_95                BIT(6)
+
 /* mt2712 etc */
 #define PERI_SSUSB_SPM_CTRL    0x0
 #define SSC_IP_SLEEP_EN        BIT(4)
@@ -44,6 +56,9 @@ enum ssusb_uwk_vers {
        SSUSB_UWK_V2,
        SSUSB_UWK_V1_1 = 101,   /* specific revision 1.01 */
        SSUSB_UWK_V1_2,         /* specific revision 1.02 */
+       SSUSB_UWK_V1_3,         /* mt8195 IP0 */
+       SSUSB_UWK_V1_5 = 105,   /* mt8195 IP2 */
+       SSUSB_UWK_V1_6,         /* mt8195 IP3 */
 };
 
 /*
@@ -70,6 +85,21 @@ static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable)
                msk = WC0_SSUSB0_CDEN | WC0_IS_SPM_EN;
                val = enable ? msk : 0;
                break;
+       case SSUSB_UWK_V1_3:
+               reg = ssusb->uwk_reg_base + PERI_WK_CTRL1_8195;
+               msk = WC1_IS_EN_P0_95 | WC1_IS_C_95(0xf) | WC1_IS_P_95;
+               val = enable ? (WC1_IS_EN_P0_95 | WC1_IS_C_95(0x1)) : 0;
+               break;
+       case SSUSB_UWK_V1_5:
+               reg = ssusb->uwk_reg_base + PERI_WK_CTRL0_8195;
+               msk = WC0_IS_EN_P2_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+               val = enable ? (WC0_IS_EN_P2_95 | WC0_IS_C_95(0x1)) : 0;
+               break;
+       case SSUSB_UWK_V1_6:
+               reg = ssusb->uwk_reg_base + PERI_WK_CTRL0_8195;
+               msk = WC0_IS_EN_P3_95 | WC0_IS_C_95(0x7) | WC0_IS_P_95;
+               val = enable ? (WC0_IS_EN_P3_95 | WC0_IS_C_95(0x1)) : 0;
+               break;
        case SSUSB_UWK_V2:
                reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
                msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
index 051c6da7cf6d74de81ca35ed186963c2f6c9b01e..55df0ee413d8e21d2d8be634591c2c85aff008fb 100644 (file)
@@ -1744,7 +1744,6 @@ static inline void musb_g_init_endpoints(struct musb *musb)
 {
        u8                      epnum;
        struct musb_hw_ep       *hw_ep;
-       unsigned                count = 0;
 
        /* initialize endpoint list just once */
        INIT_LIST_HEAD(&(musb->g.ep_list));
@@ -1754,17 +1753,14 @@ static inline void musb_g_init_endpoints(struct musb *musb)
                        epnum++, hw_ep++) {
                if (hw_ep->is_shared_fifo /* || !epnum */) {
                        init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 0);
-                       count++;
                } else {
                        if (hw_ep->max_packet_sz_tx) {
                                init_peripheral_ep(musb, &hw_ep->ep_in,
                                                        epnum, 1);
-                               count++;
                        }
                        if (hw_ep->max_packet_sz_rx) {
                                init_peripheral_ep(musb, &hw_ep->ep_out,
                                                        epnum, 0);
-                               count++;
                        }
                }
        }
index 9ab50f26db607180ab687e28e860dd38318d5386..8f735a86cd197275480ef69145ef0dee9f739a27 100644 (file)
@@ -74,33 +74,26 @@ static void nop_reset(struct usb_phy_generic *nop)
 }
 
 /* interface to regulator framework */
-static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
+static int nop_set_vbus(struct usb_otg *otg, bool enable)
 {
-       struct regulator *vbus_draw = nop->vbus_draw;
-       int enabled;
-       int ret;
+       int ret = 0;
+       struct usb_phy_generic *nop = dev_get_drvdata(otg->usb_phy->dev);
 
-       if (!vbus_draw)
-               return;
+       if (!nop->vbus_draw)
+               return 0;
 
-       enabled = nop->vbus_draw_enabled;
-       if (mA) {
-               regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
-               if (!enabled) {
-                       ret = regulator_enable(vbus_draw);
-                       if (ret < 0)
-                               return;
-                       nop->vbus_draw_enabled = 1;
-               }
-       } else {
-               if (enabled) {
-                       ret = regulator_disable(vbus_draw);
-                       if (ret < 0)
-                               return;
-                       nop->vbus_draw_enabled = 0;
-               }
+       if (enable && !nop->vbus_draw_enabled) {
+               ret = regulator_enable(nop->vbus_draw);
+               if (ret)
+                       nop->vbus_draw_enabled = false;
+               else
+                       nop->vbus_draw_enabled = true;
+
+       } else if (!enable && nop->vbus_draw_enabled) {
+               ret = regulator_disable(nop->vbus_draw);
+               nop->vbus_draw_enabled = false;
        }
-       nop->mA = mA;
+       return ret;
 }
 
 
@@ -120,14 +113,9 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
                otg->state = OTG_STATE_B_PERIPHERAL;
                nop->phy.last_event = status;
 
-               /* drawing a "unit load" is *always* OK, except for OTG */
-               nop_set_vbus_draw(nop, 100);
-
                atomic_notifier_call_chain(&nop->phy.notifier, status,
                                           otg->gadget);
        } else {
-               nop_set_vbus_draw(nop, 0);
-
                status = USB_EVENT_NONE;
                otg->state = OTG_STATE_B_IDLE;
                nop->phy.last_event = status;
@@ -274,6 +262,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
                return dev_err_probe(dev, PTR_ERR(nop->vbus_draw),
                                     "could not get vbus regulator\n");
 
+       nop->vbus_draw = devm_regulator_get_exclusive(dev, "vbus");
+       if (PTR_ERR(nop->vbus_draw) == -ENODEV)
+               nop->vbus_draw = NULL;
+       if (IS_ERR(nop->vbus_draw))
+               return dev_err_probe(dev, PTR_ERR(nop->vbus_draw),
+                                    "could not get vbus regulator\n");
+
        nop->dev                = dev;
        nop->phy.dev            = nop->dev;
        nop->phy.label          = "nop-xceiv";
@@ -284,6 +279,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
        nop->phy.otg->usb_phy           = &nop->phy;
        nop->phy.otg->set_host          = nop_set_host;
        nop->phy.otg->set_peripheral    = nop_set_peripheral;
+       nop->phy.otg->set_vbus          = nop_set_vbus;
 
        return 0;
 }
@@ -341,6 +337,9 @@ static void usb_phy_generic_remove(struct platform_device *pdev)
        struct usb_phy_generic *nop = platform_get_drvdata(pdev);
 
        usb_remove_phy(&nop->phy);
+
+       if (nop->vbus_draw && nop->vbus_draw_enabled)
+               regulator_disable(nop->vbus_draw);
 }
 
 static const struct of_device_id nop_xceiv_dt_ids[] = {
index 4b468bde19cfb4f0a3725b8713850b622a5196ae..06e0fb23566cefdc0d25c4b234e7e0a89b7e0783 100644 (file)
@@ -699,7 +699,7 @@ out:
 }
 EXPORT_SYMBOL_GPL(usb_add_phy);
 
-static struct device_type usb_phy_dev_type = {
+static const struct device_type usb_phy_dev_type = {
        .name = "usb_phy",
        .uevent = usb_phy_uevent,
 };
index 70165dd86b5de958ab4f5fe0d1573988977be425..d7aa913ceb8a0bf8531f27ea474c8cd86a505781 100644 (file)
@@ -7,6 +7,7 @@
  *         Hans de Goede <hdegoede@redhat.com>
  */
 
+#include <linux/component.h>
 #include <linux/usb/role.h>
 #include <linux/property.h>
 #include <linux/device.h>
@@ -36,6 +37,32 @@ struct usb_role_switch {
 
 #define to_role_switch(d)      container_of(d, struct usb_role_switch, dev)
 
+static int connector_bind(struct device *dev, struct device *connector, void *data)
+{
+       int ret;
+
+       ret = sysfs_create_link(&dev->kobj, &connector->kobj, "connector");
+       if (ret)
+               return ret;
+
+       ret = sysfs_create_link(&connector->kobj, &dev->kobj, "usb-role-switch");
+       if (ret)
+               sysfs_remove_link(&dev->kobj, "connector");
+
+       return ret;
+}
+
+static void connector_unbind(struct device *dev, struct device *connector, void *data)
+{
+       sysfs_remove_link(&connector->kobj, "usb-role-switch");
+       sysfs_remove_link(&dev->kobj, "connector");
+}
+
+static const struct component_ops connector_ops = {
+       .bind = connector_bind,
+       .unbind = connector_unbind,
+};
+
 /**
  * usb_role_switch_set_role - Set USB role for a switch
  * @sw: USB role switch
@@ -361,6 +388,12 @@ usb_role_switch_register(struct device *parent,
                return ERR_PTR(ret);
        }
 
+       if (dev_fwnode(&sw->dev)) {
+               ret = component_add(&sw->dev, &connector_ops);
+               if (ret)
+                       dev_warn(&sw->dev, "failed to add component\n");
+       }
+
        sw->registered = true;
 
        /* TODO: Symlinks for the host port and the device controller. */
@@ -377,10 +410,12 @@ EXPORT_SYMBOL_GPL(usb_role_switch_register);
  */
 void usb_role_switch_unregister(struct usb_role_switch *sw)
 {
-       if (!IS_ERR_OR_NULL(sw)) {
-               sw->registered = false;
-               device_unregister(&sw->dev);
-       }
+       if (IS_ERR_OR_NULL(sw))
+               return;
+       sw->registered = false;
+       if (dev_fwnode(&sw->dev))
+               component_del(&sw->dev, &connector_ops);
+       device_unregister(&sw->dev);
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
 
index 923e0ed85444be9fde31e0b0d965813fc99c5acf..21fd26609252bea34ec95983daf5a3073d8827d2 100644 (file)
@@ -56,6 +56,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
        { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
        { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
+       { USB_DEVICE(0x04BF, 0x1301) }, /* TDK Corporation NC0110013M - Network Controller */
+       { USB_DEVICE(0x04BF, 0x1303) }, /* TDK Corporation MM0110113M - i3 Micro Module */
        { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
        { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
        { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
@@ -144,6 +146,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
        { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
        { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
+       { USB_DEVICE(0x10C4, 0x863C) }, /* MGP Instruments PDS100 */
        { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
        { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
        { USB_DEVICE(0x10C4, 0x87ED) }, /* IMST USB-Stick for Smart Meter */
@@ -177,6 +180,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
        { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
        { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
+       { USB_DEVICE(0x11CA, 0x0212) }, /* Verifone USB to Printer (UART, CP2102) */
        { USB_DEVICE(0x12B8, 0xEC60) }, /* Link G4 ECU */
        { USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */
        { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
index 13a56783830df2503edf24eba00436b9a03c4bcf..76a04ab411006d9b1f10562b23c90c0431301bfe 100644 (file)
@@ -1077,6 +1077,8 @@ static const struct usb_device_id id_table_combined[] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       /* GMC devices */
+       { USB_DEVICE(GMC_VID, GMC_Z216C_PID) },
        { }                                     /* Terminating entry */
 };
 
@@ -2610,7 +2612,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
        struct device *ddev = &port->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct ktermios *termios = &tty->termios;
-       unsigned int cflag = termios->c_cflag;
+       unsigned int cflag;
        u16 value, index;
        int ret;
 
index 21a2b5a25fc09732800830401546626d91074ffa..5ee60ba2a73cdbeaa117a2f81ad46c20c837d8c7 100644 (file)
 #define UBLOX_VID                      0x1546
 #define UBLOX_C099F9P_ZED_PID          0x0502
 #define UBLOX_C099F9P_ODIN_PID         0x0503
+
+/*
+ * GMC devices
+ */
+#define GMC_VID                                0x1cd7
+#define GMC_Z216C_PID                  0x0217 /* GMC Z216C Adapter IR-USB */
index 93b17e0e05a33ec18863343bbacd0285cde89ae0..0a783985197c3da110205cfe3b36900ddccf46f0 100644 (file)
@@ -921,7 +921,6 @@ static void usa28_indat_callback(struct urb *urb)
 
        port =  urb->context;
        p_priv = usb_get_serial_port_data(port);
-       data = urb->transfer_buffer;
 
        if (urb != p_priv->in_urbs[p_priv->in_flip])
                return;
index 2ae124c49d448f63b6d6a3078ad08fffee3ad2d0..55a65d941ccbfb1161d363ac72881ce0f490a8df 100644 (file)
@@ -613,6 +613,11 @@ static void option_instat_callback(struct urb *urb);
 /* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */
 #define LUAT_PRODUCT_AIR720U                   0x4e00
 
+/* MeiG Smart Technology products */
+#define MEIGSMART_VENDOR_ID                    0x2dee
+/* MeiG Smart SLM320 based on UNISOC UIS8910 */
+#define MEIGSMART_PRODUCT_SLM320               0x4d41
+
 /* Device flags */
 
 /* Highest interface number which can be used with NCTRL() and RSVD() */
@@ -2282,6 +2287,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 6365cfe5402cb52aa6a177195a5c0c0ff8a52451..fa07f6ff9ecc84486828cfe27d286e8594cd56ca 100644 (file)
@@ -409,7 +409,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
        cflag = tty->termios.c_cflag;
 
        spin_lock_irqsave(&priv->lock, flags);
-       divisor = priv->pending_setup.divisor;
        frame_fmt = priv->pending_setup.frame_fmt;
        control = priv->pending_setup.control;
        spin_unlock_irqrestore(&priv->lock, flags);
index 2b098b55c4cbb702639545b8365026b41015e3dd..c3ce51c2dabde38104121dda91cd44cf7ab5d8e9 100644 (file)
@@ -534,7 +534,6 @@ static void pdump(struct us_data *us, void *ibuffer, int length)
        }
        line[offset] = 0;
        usb_stor_dbg(us, "%s\n", line);
-       offset = 0;
 }
 #endif
 
index 15dc25801cdcc52f292313db6d0f5e9e81329d14..0aa079405d23c277f694050899f8c66ac928cb16 100644 (file)
@@ -196,7 +196,7 @@ static int sddr55_read_data(struct us_data *us,
        unsigned char *buffer;
 
        unsigned int pba;
-       unsigned long address;
+       unsigned int address;
 
        unsigned short pages;
        unsigned int len, offset;
@@ -316,7 +316,7 @@ static int sddr55_write_data(struct us_data *us,
 
        unsigned int pba;
        unsigned int new_pba;
-       unsigned long address;
+       unsigned int address;
 
        unsigned short pages;
        int i;
index f8ea3054be54245c4233b48facaabe91f52868ed..038dc51f429dda5146cb0d92d8146880c39d2b61 100644 (file)
@@ -50,13 +50,17 @@ enum {
 enum dp_state {
        DP_STATE_IDLE,
        DP_STATE_ENTER,
+       DP_STATE_ENTER_PRIME,
        DP_STATE_UPDATE,
        DP_STATE_CONFIGURE,
+       DP_STATE_CONFIGURE_PRIME,
        DP_STATE_EXIT,
+       DP_STATE_EXIT_PRIME,
 };
 
 struct dp_altmode {
        struct typec_displayport_data data;
+       struct typec_displayport_data data_prime;
 
        enum dp_state state;
        bool hpd;
@@ -67,6 +71,7 @@ struct dp_altmode {
        struct typec_altmode *alt;
        const struct typec_altmode *port;
        struct fwnode_handle *connector_fwnode;
+       struct typec_altmode *plug_prime;
 };
 
 static int dp_altmode_notify(struct dp_altmode *dp)
@@ -99,12 +104,18 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
                conf |= DP_CONF_UFP_U_AS_DFP_D;
                pin_assign = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) &
                             DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo);
+               /* Account for active cable capabilities */
+               if (dp->plug_prime)
+                       pin_assign &= DP_CAP_DFP_D_PIN_ASSIGN(dp->plug_prime->vdo);
                break;
        case DP_STATUS_CON_UFP_D:
        case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */
                conf |= DP_CONF_UFP_U_AS_UFP_D;
                pin_assign = DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo) &
                                 DP_CAP_PIN_ASSIGN_DFP_D(dp->port->vdo);
+               /* Account for active cable capabilities */
+               if (dp->plug_prime)
+                       pin_assign &= DP_CAP_UFP_D_PIN_ASSIGN(dp->plug_prime->vdo);
                break;
        default:
                break;
@@ -130,6 +141,8 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
        }
 
        dp->data.conf = conf;
+       if (dp->plug_prime)
+               dp->data_prime.conf = conf;
 
        return 0;
 }
@@ -143,13 +156,16 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
 
        if (configured && (dp->data.status & DP_STATUS_SWITCH_TO_USB)) {
                dp->data.conf = 0;
-               dp->state = DP_STATE_CONFIGURE;
+               dp->data_prime.conf = 0;
+               dp->state = dp->plug_prime ? DP_STATE_CONFIGURE_PRIME :
+                                            DP_STATE_CONFIGURE;
        } else if (dp->data.status & DP_STATUS_EXIT_DP_MODE) {
                dp->state = DP_STATE_EXIT;
        } else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) {
                ret = dp_altmode_configure(dp, con);
                if (!ret) {
-                       dp->state = DP_STATE_CONFIGURE;
+                       dp->state = dp->plug_prime ? DP_STATE_CONFIGURE_PRIME :
+                                                    DP_STATE_CONFIGURE;
                        if (dp->hpd != hpd) {
                                dp->hpd = hpd;
                                dp->pending_hpd = true;
@@ -209,6 +225,19 @@ static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
        return ret;
 }
 
+static int dp_altmode_configure_vdm_cable(struct dp_altmode *dp, u32 conf)
+{
+       int svdm_version = typec_altmode_get_cable_svdm_version(dp->plug_prime);
+       u32 header;
+
+       if (svdm_version < 0)
+               return svdm_version;
+
+       header = DP_HEADER(dp, svdm_version, DP_CMD_CONFIGURE);
+
+       return typec_cable_altmode_vdm(dp->plug_prime, TYPEC_PLUG_SOP_P, header, &conf, 2);
+}
+
 static void dp_altmode_work(struct work_struct *work)
 {
        struct dp_altmode *dp = container_of(work, struct dp_altmode, work);
@@ -225,6 +254,19 @@ static void dp_altmode_work(struct work_struct *work)
                if (ret && ret != -EBUSY)
                        dev_err(&dp->alt->dev, "failed to enter mode\n");
                break;
+       case DP_STATE_ENTER_PRIME:
+               ret = typec_cable_altmode_enter(dp->alt, TYPEC_PLUG_SOP_P, NULL);
+               /*
+                * If we fail to enter Alt Mode on SOP', then we should drop the
+                * plug from the driver and attempt to run the driver without
+                * it.
+                */
+               if (ret && ret != -EBUSY) {
+                       dev_err(&dp->alt->dev, "plug failed to enter mode\n");
+                       dp->state = DP_STATE_ENTER;
+                       goto disable_prime;
+               }
+               break;
        case DP_STATE_UPDATE:
                svdm_version = typec_altmode_get_svdm_version(dp->alt);
                if (svdm_version < 0)
@@ -243,10 +285,24 @@ static void dp_altmode_work(struct work_struct *work)
                        dev_err(&dp->alt->dev,
                                "unable to send Configure command (%d)\n", ret);
                break;
+       case DP_STATE_CONFIGURE_PRIME:
+               ret = dp_altmode_configure_vdm_cable(dp, dp->data_prime.conf);
+               if (ret) {
+                       dev_err(&dp->plug_prime->dev,
+                               "unable to send Configure command (%d)\n",
+                               ret);
+                       dp->state = DP_STATE_CONFIGURE;
+                       goto disable_prime;
+               }
+               break;
        case DP_STATE_EXIT:
                if (typec_altmode_exit(dp->alt))
                        dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
                break;
+       case DP_STATE_EXIT_PRIME:
+               if (typec_cable_altmode_exit(dp->plug_prime, TYPEC_PLUG_SOP_P))
+                       dev_err(&dp->plug_prime->dev, "Exit Mode Failed!\n");
+               break;
        default:
                break;
        }
@@ -254,6 +310,13 @@ static void dp_altmode_work(struct work_struct *work)
        dp->state = DP_STATE_IDLE;
 
        mutex_unlock(&dp->lock);
+       return;
+
+disable_prime:
+       typec_altmode_put_plug(dp->plug_prime);
+       dp->plug_prime = NULL;
+       schedule_work(&dp->work);
+       mutex_unlock(&dp->lock);
 }
 
 static void dp_altmode_attention(struct typec_altmode *alt, const u32 vdo)
@@ -314,6 +377,8 @@ static int dp_altmode_vdm(struct typec_altmode *alt,
                                dp->hpd = false;
                                sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
                        }
+                       if (dp->plug_prime)
+                               dp->state = DP_STATE_EXIT_PRIME;
                        break;
                case DP_CMD_STATUS_UPDATE:
                        dp->data.status = *vdo;
@@ -348,10 +413,84 @@ err_unlock:
        return ret;
 }
 
+static int dp_cable_altmode_vdm(struct typec_altmode *alt, enum typec_plug_index sop,
+                               const u32 hdr, const u32 *vdo, int count)
+{
+       struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
+       int cmd_type = PD_VDO_CMDT(hdr);
+       int cmd = PD_VDO_CMD(hdr);
+       int ret = 0;
+
+       mutex_lock(&dp->lock);
+
+       if (dp->state != DP_STATE_IDLE) {
+               ret = -EBUSY;
+               goto err_unlock;
+       }
+
+       switch (cmd_type) {
+       case CMDT_RSP_ACK:
+               switch (cmd) {
+               case CMD_ENTER_MODE:
+                       typec_altmode_update_active(dp->plug_prime, true);
+                       dp->state = DP_STATE_ENTER;
+                       break;
+               case CMD_EXIT_MODE:
+                       dp->data_prime.status = 0;
+                       dp->data_prime.conf = 0;
+                       typec_altmode_update_active(dp->plug_prime, false);
+                       break;
+               case DP_CMD_CONFIGURE:
+                       dp->state = DP_STATE_CONFIGURE;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case CMDT_RSP_NAK:
+               switch (cmd) {
+               case DP_CMD_CONFIGURE:
+                       dp->data_prime.conf = 0;
+                       /* Attempt to configure on SOP, drop plug */
+                       typec_altmode_put_plug(dp->plug_prime);
+                       dp->plug_prime = NULL;
+                       dp->state = DP_STATE_CONFIGURE;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (dp->state != DP_STATE_IDLE)
+               schedule_work(&dp->work);
+
+err_unlock:
+       mutex_unlock(&dp->lock);
+       return ret;
+}
+
 static int dp_altmode_activate(struct typec_altmode *alt, int activate)
 {
-       return activate ? typec_altmode_enter(alt, NULL) :
-                         typec_altmode_exit(alt);
+       struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
+       int ret;
+
+       if (activate) {
+               if (dp->plug_prime) {
+                       ret = typec_cable_altmode_enter(alt, TYPEC_PLUG_SOP_P, NULL);
+                       if (ret < 0) {
+                               typec_altmode_put_plug(dp->plug_prime);
+                               dp->plug_prime = NULL;
+                       } else {
+                               return ret;
+                       }
+               }
+               return typec_altmode_enter(alt, NULL);
+       } else {
+               return typec_altmode_exit(alt);
+       }
 }
 
 static const struct typec_altmode_ops dp_altmode_ops = {
@@ -360,6 +499,10 @@ static const struct typec_altmode_ops dp_altmode_ops = {
        .activate = dp_altmode_activate,
 };
 
+static const struct typec_cable_ops dp_cable_ops = {
+       .vdm = dp_cable_altmode_vdm,
+};
+
 static const char * const configurations[] = {
        [DP_CONF_USB]   = "USB",
        [DP_CONF_DFP_D] = "source",
@@ -501,6 +644,7 @@ pin_assignment_store(struct device *dev, struct device_attribute *attr,
 
        /* Only send Configure command if a configuration has been set */
        if (dp->alt->active && DP_CONF_CURRENTLY(dp->data.conf)) {
+               /* todo: send manual configure over SOP'*/
                ret = dp_altmode_configure_vdm(dp, conf);
                if (ret)
                        goto out_unlock;
@@ -579,6 +723,7 @@ static const struct attribute_group *displayport_groups[] = {
 int dp_altmode_probe(struct typec_altmode *alt)
 {
        const struct typec_altmode *port = typec_altmode_get_partner(alt);
+       struct typec_altmode *plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P);
        struct fwnode_handle *fwnode;
        struct dp_altmode *dp;
 
@@ -603,6 +748,13 @@ int dp_altmode_probe(struct typec_altmode *alt)
        alt->desc = "DisplayPort";
        alt->ops = &dp_altmode_ops;
 
+       if (plug) {
+               plug->desc = "Displayport";
+               plug->cable_ops = &dp_cable_ops;
+       }
+
+       dp->plug_prime = plug;
+
        fwnode = dev_fwnode(alt->dev.parent->parent); /* typec_port fwnode */
        if (fwnode_property_present(fwnode, "displayport"))
                dp->connector_fwnode = fwnode_find_reference(fwnode, "displayport", 0);
@@ -612,8 +764,10 @@ int dp_altmode_probe(struct typec_altmode *alt)
                dp->connector_fwnode = NULL;
 
        typec_altmode_set_drvdata(alt, dp);
+       if (plug)
+               typec_altmode_set_drvdata(plug, dp);
 
-       dp->state = DP_STATE_ENTER;
+       dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
        schedule_work(&dp->work);
 
        return 0;
@@ -625,6 +779,7 @@ void dp_altmode_remove(struct typec_altmode *alt)
        struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
 
        cancel_work_sync(&dp->work);
+       typec_altmode_put_plug(dp->plug_prime);
 
        if (dp->connector_fwnode) {
                drm_connector_oob_hotplug_event(dp->connector_fwnode,
index e95ec7e382bb79031b276105b2a94f0509f9c33b..6ea103e1abae909614bff350f8d11cff82bf4945 100644 (file)
@@ -244,6 +244,108 @@ typec_altmode_get_partner(struct typec_altmode *adev)
 }
 EXPORT_SYMBOL_GPL(typec_altmode_get_partner);
 
+/* -------------------------------------------------------------------------- */
+/* API for cable alternate modes */
+
+/**
+ * typec_cable_altmode_enter - Enter Mode
+ * @adev: The alternate mode
+ * @sop: Cable plug target for Enter Mode command
+ * @vdo: VDO for the Enter Mode command
+ *
+ * Alternate mode drivers use this function to enter mode on the cable plug.
+ * If the alternate mode does not require VDO, @vdo must be NULL.
+ */
+int typec_cable_altmode_enter(struct typec_altmode *adev, enum typec_plug_index sop, u32 *vdo)
+{
+       struct altmode *partner = to_altmode(adev)->partner;
+       struct typec_altmode *pdev;
+
+       if (!adev || adev->active)
+               return 0;
+
+       if (!partner)
+               return -ENODEV;
+
+       pdev = &partner->adev;
+
+       if (!pdev->active)
+               return -EPERM;
+
+       if (!pdev->cable_ops || !pdev->cable_ops->enter)
+               return -EOPNOTSUPP;
+
+       return pdev->cable_ops->enter(pdev, sop, vdo);
+}
+EXPORT_SYMBOL_GPL(typec_cable_altmode_enter);
+
+/**
+ * typec_cable_altmode_exit - Exit Mode
+ * @adev: The alternate mode
+ * @sop: Cable plug target for Exit Mode command
+ *
+ * The alternate mode drivers use this function to exit mode on the cable plug.
+ */
+int typec_cable_altmode_exit(struct typec_altmode *adev, enum typec_plug_index sop)
+{
+       struct altmode *partner = to_altmode(adev)->partner;
+       struct typec_altmode *pdev;
+
+       if (!adev || !adev->active)
+               return 0;
+
+       if (!partner)
+               return -ENODEV;
+
+       pdev = &partner->adev;
+
+       if (!pdev->cable_ops || !pdev->cable_ops->exit)
+               return -EOPNOTSUPP;
+
+       return pdev->cable_ops->exit(pdev, sop);
+}
+EXPORT_SYMBOL_GPL(typec_cable_altmode_exit);
+
+/**
+ * typec_cable_altmode_vdm - Send Vendor Defined Messages (VDM) between the cable plug and port.
+ * @adev: Alternate mode handle
+ * @sop: Cable plug target for VDM
+ * @header: VDM Header
+ * @vdo: Array of Vendor Defined Data Objects
+ * @count: Number of Data Objects
+ *
+ * The alternate mode drivers use this function for SVID specific communication
+ * with the cable plugs. The port drivers use it to deliver the Structured VDMs
+ * received from the cable plugs to the alternate mode drivers.
+ */
+int typec_cable_altmode_vdm(struct typec_altmode *adev, enum typec_plug_index sop,
+                           const u32 header, const u32 *vdo, int count)
+{
+       struct altmode *altmode;
+       struct typec_altmode *pdev;
+
+       if (!adev)
+               return 0;
+
+       altmode = to_altmode(adev);
+
+       if (is_typec_plug(adev->dev.parent)) {
+               if (!altmode->partner)
+                       return -ENODEV;
+               pdev = &altmode->partner->adev;
+       } else {
+               if (!altmode->plug[sop])
+                       return -ENODEV;
+               pdev = &altmode->plug[sop]->adev;
+       }
+
+       if (!pdev->cable_ops || !pdev->cable_ops->vdm)
+               return -EOPNOTSUPP;
+
+       return pdev->cable_ops->vdm(pdev, sop, header, vdo, count);
+}
+EXPORT_SYMBOL_GPL(typec_cable_altmode_vdm);
+
 /* -------------------------------------------------------------------------- */
 /* API for the alternate mode drivers */
 
index 015aa925335360709fa54498a05eb9db72b1c64a..389c7f0b8d9358431890bc843e8007b6e92e9d97 100644 (file)
@@ -21,7 +21,7 @@
 
 static DEFINE_IDA(typec_index_ida);
 
-struct class typec_class = {
+const struct class typec_class = {
        .name = "typec",
 };
 
@@ -2131,6 +2131,46 @@ int typec_get_negotiated_svdm_version(struct typec_port *port)
 }
 EXPORT_SYMBOL_GPL(typec_get_negotiated_svdm_version);
 
+/**
+ * typec_get_cable_svdm_version - Get cable negotiated SVDM Version
+ * @port: USB Type-C Port.
+ *
+ * Get the negotiated SVDM Version for the cable. The Version is set to the port
+ * default value based on the PD Revision during cable registration, and updated
+ * after a successful Discover Identity if the negotiated value is less than the
+ * default.
+ *
+ * Returns usb_pd_svdm_ver if the cable has been registered otherwise -ENODEV.
+ */
+int typec_get_cable_svdm_version(struct typec_port *port)
+{
+       enum usb_pd_svdm_ver svdm_version;
+       struct device *cable_dev;
+
+       cable_dev = device_find_child(&port->dev, NULL, cable_match);
+       if (!cable_dev)
+               return -ENODEV;
+
+       svdm_version = to_typec_cable(cable_dev)->svdm_version;
+       put_device(cable_dev);
+
+       return svdm_version;
+}
+EXPORT_SYMBOL_GPL(typec_get_cable_svdm_version);
+
+/**
+ * typec_cable_set_svdm_version - Set negotiated Structured VDM (SVDM) Version
+ * @cable: USB Type-C Active Cable that supports SVDM
+ * @svdm_version: Negotiated SVDM Version
+ *
+ * This routine is used to save the negotiated SVDM Version.
+ */
+void typec_cable_set_svdm_version(struct typec_cable *cable, enum usb_pd_svdm_ver svdm_version)
+{
+       cable->svdm_version = svdm_version;
+}
+EXPORT_SYMBOL_GPL(typec_cable_set_svdm_version);
+
 /**
  * typec_get_drvdata - Return private driver data pointer
  * @port: USB Type-C port
@@ -2280,6 +2320,25 @@ void typec_port_register_altmodes(struct typec_port *port,
 }
 EXPORT_SYMBOL_GPL(typec_port_register_altmodes);
 
+/**
+ * typec_port_register_cable_ops - Register typec_cable_ops to port altmodes
+ * @altmodes: USB Type-C Port's altmode vector
+ * @max_altmodes: The maximum number of alt modes supported by the port
+ * @ops: Cable alternate mode vector
+ */
+void typec_port_register_cable_ops(struct typec_altmode **altmodes, int max_altmodes,
+                                  const struct typec_cable_ops *ops)
+{
+       int i;
+
+       for (i = 0; i < max_altmodes; i++) {
+               if (!altmodes[i])
+                       return;
+               altmodes[i]->cable_ops = ops;
+       }
+}
+EXPORT_SYMBOL_GPL(typec_port_register_cable_ops);
+
 /**
  * typec_register_port - Register a USB Type-C Port
  * @parent: Parent device
index c36761ba3f5998e367c420700c60a21aeed43688..7485cdb9dd2017ce1d55987de2ca6a3f63fe38ae 100644 (file)
@@ -23,6 +23,7 @@ struct typec_cable {
        struct usb_pd_identity          *identity;
        unsigned int                    active:1;
        u16                             pd_revision; /* 0300H = "3.0" */
+       enum usb_pd_svdm_ver            svdm_version;
 };
 
 struct typec_partner {
@@ -92,9 +93,9 @@ extern const struct device_type typec_port_dev_type;
 #define is_typec_plug(dev) ((dev)->type == &typec_plug_dev_type)
 #define is_typec_port(dev) ((dev)->type == &typec_port_dev_type)
 
-extern struct class typec_mux_class;
-extern struct class retimer_class;
-extern struct class typec_class;
+extern const struct class typec_mux_class;
+extern const struct class retimer_class;
+extern const struct class typec_class;
 
 #if defined(CONFIG_ACPI)
 int typec_link_ports(struct typec_port *connector);
index 80dd91938d96066d5286d8096cefb47c4b355c7c..49926d6e72c71b895072ec252e5e1200085f4d4e 100644 (file)
@@ -469,6 +469,6 @@ void *typec_mux_get_drvdata(struct typec_mux_dev *mux_dev)
 }
 EXPORT_SYMBOL_GPL(typec_mux_get_drvdata);
 
-struct class typec_mux_class = {
+const struct class typec_mux_class = {
        .name = "typec_mux",
 };
index d2cb5e733e57359d16d90418a4dc66c4d60bc449..399c7b0983df321e5bfe283738d2e698c9052f20 100644 (file)
@@ -36,6 +36,16 @@ config TYPEC_MUX_INTEL_PMC
          control the USB role switch and also the multiplexer/demultiplexer
          switches used with USB Type-C Alternate Modes.
 
+config TYPEC_MUX_IT5205
+       tristate "ITE IT5205 Type-C USB Alt Mode Passive MUX driver"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Driver for the ITE IT5205 Type-C USB Alternate Mode Passive MUX
+         which provides support for muxing DisplayPort and sideband signals
+         on a common USB Type-C connector.
+         If compiled as a module, the module will be named it5205.
+
 config TYPEC_MUX_NB7VPQ904M
        tristate "On Semiconductor NB7VPQ904M Type-C redriver driver"
        depends on I2C
index 57dc9ac6f8dcfc24d632e02d43266314c6f90364..bb96f30267af05b33b9277dcf1cc0e1527d2dcdd 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_TYPEC_MUX_FSA4480)         += fsa4480.o
 obj-$(CONFIG_TYPEC_MUX_GPIO_SBU)       += gpio-sbu-mux.o
 obj-$(CONFIG_TYPEC_MUX_PI3USB30532)    += pi3usb30532.o
 obj-$(CONFIG_TYPEC_MUX_INTEL_PMC)      += intel_pmc_mux.o
+obj-$(CONFIG_TYPEC_MUX_IT5205)         += it5205.o
 obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M)     += nb7vpq904m.o
 obj-$(CONFIG_TYPEC_MUX_PTN36502)       += ptn36502.o
 obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS)  += wcd939x-usbss.o
diff --git a/drivers/usb/typec/mux/it5205.c b/drivers/usb/typec/mux/it5205.c
new file mode 100644 (file)
index 0000000..5535932
--- /dev/null
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ITE IT5205 Type-C USB alternate mode passive mux
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2024 Collabora Ltd.
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/tcpm.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+
+#define IT5205_REG_CHIP_ID(x)  (0x4 + (x))
+#define IT5205FN_CHIP_ID       0x35323035 /* "5205" */
+
+/* MUX power down register */
+#define IT5205_REG_MUXPDR        0x10
+#define IT5205_MUX_POWER_DOWN    BIT(0)
+
+/* MUX control register */
+#define IT5205_REG_MUXCR         0x11
+#define IT5205_POLARITY_INVERTED BIT(4)
+#define IT5205_DP_USB_CTRL_MASK  GENMASK(3, 0)
+#define IT5205_DP                0x0f
+#define IT5205_DP_USB            0x03
+#define IT5205_USB               0x07
+
+/* Vref Select Register */
+#define IT5205_REG_VSR            0x10
+#define IT5205_VREF_SELECT_MASK   GENMASK(5, 4)
+#define IT5205_VREF_SELECT_3_3V   0x00
+#define IT5205_VREF_SELECT_OFF    0x20
+
+/* CSBU Over Voltage Protection Register */
+#define IT5205_REG_CSBUOVPSR      0x1e
+#define IT5205_OVP_SELECT_MASK    GENMASK(5, 4)
+#define IT5205_OVP_3_90V          0x00
+#define IT5205_OVP_3_68V          0x10
+#define IT5205_OVP_3_62V          0x20
+#define IT5205_OVP_3_57V          0x30
+
+/* CSBU Switch Register */
+#define IT5205_REG_CSBUSR         0x22
+#define IT5205_CSBUSR_SWITCH      BIT(0)
+
+/* Interrupt Switch Register */
+#define IT5205_REG_ISR            0x25
+#define IT5205_ISR_CSBU_MASK      BIT(4)
+#define IT5205_ISR_CSBU_OVP       BIT(0)
+
+struct it5205 {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct typec_switch_dev *sw;
+       struct typec_mux_dev *mux;
+};
+
+static int it5205_switch_set(struct typec_switch_dev *sw, enum typec_orientation orientation)
+{
+       struct it5205 *it = typec_switch_get_drvdata(sw);
+
+       switch (orientation) {
+       case TYPEC_ORIENTATION_NORMAL:
+               regmap_update_bits(it->regmap, IT5205_REG_MUXCR,
+                                  IT5205_POLARITY_INVERTED, 0);
+               break;
+       case TYPEC_ORIENTATION_REVERSE:
+               regmap_update_bits(it->regmap, IT5205_REG_MUXCR,
+                                  IT5205_POLARITY_INVERTED, IT5205_POLARITY_INVERTED);
+               break;
+       case TYPEC_ORIENTATION_NONE:
+               fallthrough;
+       default:
+               regmap_write(it->regmap, IT5205_REG_MUXCR, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static int it5205_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
+{
+       struct it5205 *it = typec_mux_get_drvdata(mux);
+       u8 val;
+
+       if (state->mode >= TYPEC_STATE_MODAL &&
+           state->alt->svid != USB_TYPEC_DP_SID)
+               return -EINVAL;
+
+       switch (state->mode) {
+       case TYPEC_STATE_USB:
+               val = IT5205_USB;
+               break;
+       case TYPEC_DP_STATE_C:
+               fallthrough;
+       case TYPEC_DP_STATE_E:
+               val = IT5205_DP;
+               break;
+       case TYPEC_DP_STATE_D:
+               val = IT5205_DP_USB;
+               break;
+       case TYPEC_STATE_SAFE:
+               fallthrough;
+       default:
+               val = 0;
+               break;
+       }
+
+       return regmap_update_bits(it->regmap, IT5205_REG_MUXCR,
+                                 IT5205_DP_USB_CTRL_MASK, val);
+}
+
+static irqreturn_t it5205_irq_handler(int irq, void *data)
+{
+       struct it5205 *it = data;
+       int ret;
+       u32 val;
+
+       ret = regmap_read(it->regmap, IT5205_REG_ISR, &val);
+       if (ret)
+               return IRQ_NONE;
+
+       if (val & IT5205_ISR_CSBU_OVP) {
+               dev_warn(&it->client->dev, "Overvoltage detected!\n");
+
+               /* Reset CSBU */
+               regmap_update_bits(it->regmap, IT5205_REG_CSBUSR,
+                                  IT5205_CSBUSR_SWITCH, 0);
+               regmap_update_bits(it->regmap, IT5205_REG_CSBUSR,
+                                  IT5205_CSBUSR_SWITCH, IT5205_CSBUSR_SWITCH);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void it5205_enable_ovp(struct it5205 *it)
+{
+       /* Select Vref 3.3v */
+       regmap_update_bits(it->regmap, IT5205_REG_VSR,
+                          IT5205_VREF_SELECT_MASK, IT5205_VREF_SELECT_3_3V);
+
+       /* Trigger OVP at 3.68V */
+       regmap_update_bits(it->regmap, IT5205_REG_CSBUOVPSR,
+                          IT5205_OVP_SELECT_MASK, IT5205_OVP_3_68V);
+
+       /* Unmask OVP interrupt */
+       regmap_update_bits(it->regmap, IT5205_REG_ISR,
+                          IT5205_ISR_CSBU_MASK, 0);
+
+       /* Enable CSBU Interrupt */
+       regmap_update_bits(it->regmap, IT5205_REG_CSBUSR,
+                          IT5205_CSBUSR_SWITCH, IT5205_CSBUSR_SWITCH);
+}
+
+static const struct regmap_config it5205_regmap = {
+       .max_register = 0x2f,
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int it5205_probe(struct i2c_client *client)
+{
+       struct typec_switch_desc sw_desc = { };
+       struct typec_mux_desc mux_desc = { };
+       struct device *dev = &client->dev;
+       struct it5205 *it;
+       u32 val, chipid = 0;
+       int i, ret;
+
+       it = devm_kzalloc(dev, sizeof(*it), GFP_KERNEL);
+       if (!it)
+               return -ENOMEM;
+
+       ret = devm_regulator_get_enable(dev, "vcc");
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to get regulator\n");
+
+       it->client = client;
+
+       it->regmap = devm_regmap_init_i2c(client, &it5205_regmap);
+       if (IS_ERR(it->regmap))
+               return dev_err_probe(dev, PTR_ERR(it->regmap),
+                                    "Failed to init regmap\n");
+
+       /* IT5205 needs a long time to power up after enabling regulator */
+       msleep(50);
+
+       /* Unset poweroff bit */
+       ret = regmap_write(it->regmap, IT5205_REG_MUXPDR, 0);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to set power on\n");
+
+       /* Read the 32 bits ChipID */
+       for (i = 3; i >= 0; i--) {
+               ret = regmap_read(it->regmap, IT5205_REG_CHIP_ID(i), &val);
+               if (ret)
+                       return ret;
+
+               chipid |= val << (i * 8);
+       }
+
+       if (chipid != IT5205FN_CHIP_ID)
+               return dev_err_probe(dev, -EINVAL,
+                                    "Unknown ChipID 0x%x\n", chipid);
+
+       /* Initialize as USB mode with default (non-inverted) polarity */
+       ret = regmap_write(it->regmap, IT5205_REG_MUXCR, IT5205_USB);
+       if (ret)
+               return dev_err_probe(dev, ret, "Cannot set mode to USB\n");
+
+       sw_desc.drvdata = it;
+       sw_desc.fwnode = dev_fwnode(dev);
+       sw_desc.set = it5205_switch_set;
+
+       it->sw = typec_switch_register(dev, &sw_desc);
+       if (IS_ERR(it->sw))
+               return dev_err_probe(dev, PTR_ERR(it->sw),
+                                    "failed to register typec switch\n");
+
+       mux_desc.drvdata = it;
+       mux_desc.fwnode = dev_fwnode(dev);
+       mux_desc.set = it5205_mux_set;
+
+       it->mux = typec_mux_register(dev, &mux_desc);
+       if (IS_ERR(it->mux)) {
+               typec_switch_unregister(it->sw);
+               return dev_err_probe(dev, PTR_ERR(it->mux),
+                                    "failed to register typec mux\n");
+       }
+
+       i2c_set_clientdata(client, it);
+
+       if (of_property_read_bool(dev->of_node, "ite,ovp-enable") && client->irq) {
+               it5205_enable_ovp(it);
+
+               ret = devm_request_threaded_irq(dev, client->irq, NULL,
+                                               it5205_irq_handler,
+                                               IRQF_ONESHOT, dev_name(dev), it);
+               if (ret) {
+                       typec_mux_unregister(it->mux);
+                       typec_switch_unregister(it->sw);
+                       return dev_err_probe(dev, ret, "Failed to request irq\n");
+               }
+       }
+
+       return 0;
+}
+
+static void it5205_remove(struct i2c_client *client)
+{
+       struct it5205 *it = i2c_get_clientdata(client);
+
+       typec_mux_unregister(it->mux);
+       typec_switch_unregister(it->sw);
+}
+
+static const struct i2c_device_id it5205_table[] = {
+       { "it5205" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, it5205_table);
+
+static const struct of_device_id it5205_of_table[] = {
+       { .compatible = "ite,it5205" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, it5205_of_table);
+
+static struct i2c_driver it5205_driver = {
+       .driver = {
+               .name = "it5205",
+               .of_match_table = it5205_of_table,
+       },
+       .probe = it5205_probe,
+       .remove = it5205_remove,
+       .id_table = it5205_table,
+};
+module_i2c_driver(it5205_driver);
+
+MODULE_AUTHOR("Tianping Fang <tianping.fang@mediatek.com>");
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("ITE IT5205 alternate mode passive MUX driver");
+MODULE_LICENSE("GPL");
index b9cca2be76fce447970ba08beb6419262bf95a14..d78c04a421bc2e7a52cdfe659245887bbae870ae 100644 (file)
@@ -157,7 +157,7 @@ static const struct attribute_group source_fixed_supply_group = {
 };
 __ATTRIBUTE_GROUPS(source_fixed_supply);
 
-static struct device_type source_fixed_supply_type = {
+static const struct device_type source_fixed_supply_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = source_fixed_supply_groups,
@@ -182,7 +182,7 @@ static const struct attribute_group sink_fixed_supply_group = {
 };
 __ATTRIBUTE_GROUPS(sink_fixed_supply);
 
-static struct device_type sink_fixed_supply_type = {
+static const struct device_type sink_fixed_supply_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = sink_fixed_supply_groups,
@@ -213,7 +213,7 @@ static struct attribute *source_variable_supply_attrs[] = {
 };
 ATTRIBUTE_GROUPS(source_variable_supply);
 
-static struct device_type source_variable_supply_type = {
+static const struct device_type source_variable_supply_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = source_variable_supply_groups,
@@ -227,7 +227,7 @@ static struct attribute *sink_variable_supply_attrs[] = {
 };
 ATTRIBUTE_GROUPS(sink_variable_supply);
 
-static struct device_type sink_variable_supply_type = {
+static const struct device_type sink_variable_supply_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = sink_variable_supply_groups,
@@ -258,7 +258,7 @@ static struct attribute *source_battery_attrs[] = {
 };
 ATTRIBUTE_GROUPS(source_battery);
 
-static struct device_type source_battery_type = {
+static const struct device_type source_battery_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = source_battery_groups,
@@ -272,7 +272,7 @@ static struct attribute *sink_battery_attrs[] = {
 };
 ATTRIBUTE_GROUPS(sink_battery);
 
-static struct device_type sink_battery_type = {
+static const struct device_type sink_battery_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = sink_battery_groups,
@@ -339,7 +339,7 @@ static struct attribute *source_pps_attrs[] = {
 };
 ATTRIBUTE_GROUPS(source_pps);
 
-static struct device_type source_pps_type = {
+static const struct device_type source_pps_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = source_pps_groups,
@@ -353,7 +353,7 @@ static struct attribute *sink_pps_attrs[] = {
 };
 ATTRIBUTE_GROUPS(sink_pps);
 
-static struct device_type sink_pps_type = {
+static const struct device_type sink_pps_type = {
        .name = "pdo",
        .release = pdo_release,
        .groups = sink_pps_groups,
@@ -371,30 +371,30 @@ static const char * const apdo_supply_name[] = {
        [APDO_TYPE_PPS]  = "programmable_supply",
 };
 
-static struct device_type *source_type[] = {
+static const struct device_type *source_type[] = {
        [PDO_TYPE_FIXED] = &source_fixed_supply_type,
        [PDO_TYPE_BATT]  = &source_battery_type,
        [PDO_TYPE_VAR]   = &source_variable_supply_type,
 };
 
-static struct device_type *source_apdo_type[] = {
+static const struct device_type *source_apdo_type[] = {
        [APDO_TYPE_PPS]  = &source_pps_type,
 };
 
-static struct device_type *sink_type[] = {
+static const struct device_type *sink_type[] = {
        [PDO_TYPE_FIXED] = &sink_fixed_supply_type,
        [PDO_TYPE_BATT]  = &sink_battery_type,
        [PDO_TYPE_VAR]   = &sink_variable_supply_type,
 };
 
-static struct device_type *sink_apdo_type[] = {
+static const struct device_type *sink_apdo_type[] = {
        [APDO_TYPE_PPS]  = &sink_pps_type,
 };
 
 /* REVISIT: Export when EPR_*_Capabilities need to be supported. */
 static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position)
 {
-       struct device_type *type;
+       const struct device_type *type;
        const char *name;
        struct pdo *p;
        int ret;
@@ -460,7 +460,7 @@ static void pd_capabilities_release(struct device *dev)
        kfree(to_usb_power_delivery_capabilities(dev));
 }
 
-static struct device_type pd_capabilities_type = {
+static const struct device_type pd_capabilities_type = {
        .name = "capabilities",
        .release = pd_capabilities_release,
 };
@@ -575,7 +575,7 @@ static void pd_release(struct device *dev)
        kfree(pd);
 }
 
-static struct device_type pd_type = {
+static const struct device_type pd_type = {
        .name = "usb_power_delivery",
        .release = pd_release,
        .groups = pd_groups,
index 4a7d1b5c4d866b13ffcc97a0cd4b2eb63207d0c2..b519fcf358caf6cb63a7ba1212ca9c7aab93a97b 100644 (file)
@@ -155,6 +155,6 @@ void *typec_retimer_get_drvdata(struct typec_retimer *retimer)
 }
 EXPORT_SYMBOL_GPL(typec_retimer_get_drvdata);
 
-struct class retimer_class = {
+const struct class retimer_class = {
        .name = "retimer",
 };
index bc21006e979c66d16303868c928787b817eda681..ef18a448b7406bbc4443e39cf75597454640f43b 100644 (file)
@@ -1467,7 +1467,7 @@ static int fusb302_pd_read_message(struct fusb302_chip *chip,
        if ((!len) && (pd_header_type_le(msg->header) == PD_CTRL_GOOD_CRC))
                tcpm_pd_transmit_complete(chip->tcpm_port, TCPC_TX_SUCCESS);
        else
-               tcpm_pd_receive(chip->tcpm_port, msg);
+               tcpm_pd_receive(chip->tcpm_port, msg, TCPC_TX_SOP);
 
        return ret;
 }
index dc1e8832e197a68b4592163ecd4cc1877bb43d1c..cc23042b9487850ea39c88151a1f36898a8e9c3c 100644 (file)
@@ -3,4 +3,5 @@
 obj-$(CONFIG_TYPEC_QCOM_PMIC)          += qcom_pmic_tcpm.o
 qcom_pmic_tcpm-y                       += qcom_pmic_typec.o \
                                           qcom_pmic_typec_port.o \
-                                          qcom_pmic_typec_pdphy.o
+                                          qcom_pmic_typec_pdphy.o \
+                                          qcom_pmic_typec_pdphy_stub.o \
index 1a2b4bddaa97e86da87b18ae5174413e3238af6a..e48412cdcb0fb5b5562afb2ce65af38a1d31840c 100644 (file)
 
 #include <drm/bridge/aux-bridge.h>
 
+#include "qcom_pmic_typec.h"
 #include "qcom_pmic_typec_pdphy.h"
 #include "qcom_pmic_typec_port.h"
 
 struct pmic_typec_resources {
-       struct pmic_typec_pdphy_resources       *pdphy_res;
-       struct pmic_typec_port_resources        *port_res;
+       const struct pmic_typec_pdphy_resources *pdphy_res;
+       const struct pmic_typec_port_resources  *port_res;
 };
 
-struct pmic_typec {
-       struct device           *dev;
-       struct tcpm_port        *tcpm_port;
-       struct tcpc_dev         tcpc;
-       struct pmic_typec_pdphy *pmic_typec_pdphy;
-       struct pmic_typec_port  *pmic_typec_port;
-       bool                    vbus_enabled;
-       struct mutex            lock;           /* VBUS state serialization */
-};
-
-#define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc)
-
-static int qcom_pmic_typec_get_vbus(struct tcpc_dev *tcpc)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-       int ret;
-
-       mutex_lock(&tcpm->lock);
-       ret = tcpm->vbus_enabled || qcom_pmic_typec_port_get_vbus(tcpm->pmic_typec_port);
-       mutex_unlock(&tcpm->lock);
-
-       return ret;
-}
-
-static int qcom_pmic_typec_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-       int ret = 0;
-
-       mutex_lock(&tcpm->lock);
-       if (tcpm->vbus_enabled == on)
-               goto done;
-
-       ret = qcom_pmic_typec_port_set_vbus(tcpm->pmic_typec_port, on);
-       if (ret)
-               goto done;
-
-       tcpm->vbus_enabled = on;
-       tcpm_vbus_change(tcpm->tcpm_port);
-
-done:
-       dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret);
-       mutex_unlock(&tcpm->lock);
-
-       return ret;
-}
-
-static int qcom_pmic_typec_set_vconn(struct tcpc_dev *tcpc, bool on)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_port_set_vconn(tcpm->pmic_typec_port, on);
-}
-
-static int qcom_pmic_typec_get_cc(struct tcpc_dev *tcpc,
-                                 enum typec_cc_status *cc1,
-                                 enum typec_cc_status *cc2)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_port_get_cc(tcpm->pmic_typec_port, cc1, cc2);
-}
-
-static int qcom_pmic_typec_set_cc(struct tcpc_dev *tcpc,
-                                 enum typec_cc_status cc)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_port_set_cc(tcpm->pmic_typec_port, cc);
-}
-
-static int qcom_pmic_typec_set_polarity(struct tcpc_dev *tcpc,
-                                       enum typec_cc_polarity pol)
-{
-       /* Polarity is set separately by phy-qcom-qmp.c */
-       return 0;
-}
-
-static int qcom_pmic_typec_start_toggling(struct tcpc_dev *tcpc,
-                                         enum typec_port_type port_type,
-                                         enum typec_cc_status cc)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_port_start_toggling(tcpm->pmic_typec_port,
-                                                  port_type, cc);
-}
-
-static int qcom_pmic_typec_set_roles(struct tcpc_dev *tcpc, bool attached,
-                                    enum typec_role power_role,
-                                    enum typec_data_role data_role)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_pdphy_set_roles(tcpm->pmic_typec_pdphy,
-                                              data_role, power_role);
-}
-
-static int qcom_pmic_typec_set_pd_rx(struct tcpc_dev *tcpc, bool on)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_pdphy_set_pd_rx(tcpm->pmic_typec_pdphy, on);
-}
-
-static int qcom_pmic_typec_pd_transmit(struct tcpc_dev *tcpc,
-                                      enum tcpm_transmit_type type,
-                                      const struct pd_message *msg,
-                                      unsigned int negotiated_rev)
-{
-       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
-
-       return qcom_pmic_typec_pdphy_pd_transmit(tcpm->pmic_typec_pdphy, type,
-                                                msg, negotiated_rev);
-}
-
 static int qcom_pmic_typec_init(struct tcpc_dev *tcpc)
 {
        return 0;
@@ -157,7 +42,7 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
        const struct pmic_typec_resources *res;
        struct regmap *regmap;
        struct device *bridge_dev;
-       u32 base[2];
+       u32 base;
        int ret;
 
        res = of_device_get_match_data(dev);
@@ -170,16 +55,6 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
 
        tcpm->dev = dev;
        tcpm->tcpc.init = qcom_pmic_typec_init;
-       tcpm->tcpc.get_vbus = qcom_pmic_typec_get_vbus;
-       tcpm->tcpc.set_vbus = qcom_pmic_typec_set_vbus;
-       tcpm->tcpc.set_cc = qcom_pmic_typec_set_cc;
-       tcpm->tcpc.get_cc = qcom_pmic_typec_get_cc;
-       tcpm->tcpc.set_polarity = qcom_pmic_typec_set_polarity;
-       tcpm->tcpc.set_vconn = qcom_pmic_typec_set_vconn;
-       tcpm->tcpc.start_toggling = qcom_pmic_typec_start_toggling;
-       tcpm->tcpc.set_pd_rx = qcom_pmic_typec_set_pd_rx;
-       tcpm->tcpc.set_roles = qcom_pmic_typec_set_roles;
-       tcpm->tcpc.pd_transmit = qcom_pmic_typec_pd_transmit;
 
        regmap = dev_get_regmap(dev->parent, NULL);
        if (!regmap) {
@@ -187,29 +62,30 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ret = of_property_read_u32_array(np, "reg", base, 2);
+       ret = of_property_read_u32_index(np, "reg", 0, &base);
        if (ret)
                return ret;
 
-       tcpm->pmic_typec_port = qcom_pmic_typec_port_alloc(dev);
-       if (IS_ERR(tcpm->pmic_typec_port))
-               return PTR_ERR(tcpm->pmic_typec_port);
-
-       tcpm->pmic_typec_pdphy = qcom_pmic_typec_pdphy_alloc(dev);
-       if (IS_ERR(tcpm->pmic_typec_pdphy))
-               return PTR_ERR(tcpm->pmic_typec_pdphy);
-
-       ret = qcom_pmic_typec_port_probe(pdev, tcpm->pmic_typec_port,
-                                        res->port_res, regmap, base[0]);
+       ret = qcom_pmic_typec_port_probe(pdev, tcpm,
+                                        res->port_res, regmap, base);
        if (ret)
                return ret;
 
-       ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm->pmic_typec_pdphy,
-                                         res->pdphy_res, regmap, base[1]);
-       if (ret)
-               return ret;
+       if (res->pdphy_res) {
+               ret = of_property_read_u32_index(np, "reg", 1, &base);
+               if (ret)
+                       return ret;
+
+               ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm,
+                                                 res->pdphy_res, regmap, base);
+               if (ret)
+                       return ret;
+       } else {
+               ret = qcom_pmic_typec_pdphy_stub_probe(pdev, tcpm);
+               if (ret)
+                       return ret;
+       }
 
-       mutex_init(&tcpm->lock);
        platform_set_drvdata(pdev, tcpm);
 
        tcpm->tcpc.fwnode = device_get_named_child_node(tcpm->dev, "connector");
@@ -226,13 +102,11 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
                goto fwnode_remove;
        }
 
-       ret = qcom_pmic_typec_port_start(tcpm->pmic_typec_port,
-                                        tcpm->tcpm_port);
+       ret = tcpm->port_start(tcpm, tcpm->tcpm_port);
        if (ret)
                goto fwnode_remove;
 
-       ret = qcom_pmic_typec_pdphy_start(tcpm->pmic_typec_pdphy,
-                                         tcpm->tcpm_port);
+       ret = tcpm->pdphy_start(tcpm, tcpm->tcpm_port);
        if (ret)
                goto fwnode_remove;
 
@@ -248,91 +122,25 @@ static void qcom_pmic_typec_remove(struct platform_device *pdev)
 {
        struct pmic_typec *tcpm = platform_get_drvdata(pdev);
 
-       qcom_pmic_typec_pdphy_stop(tcpm->pmic_typec_pdphy);
-       qcom_pmic_typec_port_stop(tcpm->pmic_typec_port);
+       tcpm->pdphy_stop(tcpm);
+       tcpm->port_stop(tcpm);
        tcpm_unregister_port(tcpm->tcpm_port);
        fwnode_remove_software_node(tcpm->tcpc.fwnode);
 }
 
-static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = {
-       .irq_params = {
-               {
-                       .virq = PMIC_PDPHY_SIG_TX_IRQ,
-                       .irq_name = "sig-tx",
-               },
-               {
-                       .virq = PMIC_PDPHY_SIG_RX_IRQ,
-                       .irq_name = "sig-rx",
-               },
-               {
-                       .virq = PMIC_PDPHY_MSG_TX_IRQ,
-                       .irq_name = "msg-tx",
-               },
-               {
-                       .virq = PMIC_PDPHY_MSG_RX_IRQ,
-                       .irq_name = "msg-rx",
-               },
-               {
-                       .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ,
-                       .irq_name = "msg-tx-failed",
-               },
-               {
-                       .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ,
-                       .irq_name = "msg-tx-discarded",
-               },
-               {
-                       .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ,
-                       .irq_name = "msg-rx-discarded",
-               },
-       },
-       .nr_irqs = 7,
-};
-
-static struct pmic_typec_port_resources pm8150b_port_res = {
-       .irq_params = {
-               {
-                       .irq_name = "vpd-detect",
-                       .virq = PMIC_TYPEC_VPD_IRQ,
-               },
-
-               {
-                       .irq_name = "cc-state-change",
-                       .virq = PMIC_TYPEC_CC_STATE_IRQ,
-               },
-               {
-                       .irq_name = "vconn-oc",
-                       .virq = PMIC_TYPEC_VCONN_OC_IRQ,
-               },
-
-               {
-                       .irq_name = "vbus-change",
-                       .virq = PMIC_TYPEC_VBUS_IRQ,
-               },
-
-               {
-                       .irq_name = "attach-detach",
-                       .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ,
-               },
-               {
-                       .irq_name = "legacy-cable-detect",
-                       .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ,
-               },
-
-               {
-                       .irq_name = "try-snk-src-detect",
-                       .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ,
-               },
-       },
-       .nr_irqs = 7,
+static const struct pmic_typec_resources pm8150b_typec_res = {
+       .pdphy_res = &pm8150b_pdphy_res,
+       .port_res = &pm8150b_port_res,
 };
 
-static struct pmic_typec_resources pm8150b_typec_res = {
-       .pdphy_res = &pm8150b_pdphy_res,
+static const struct pmic_typec_resources pmi632_typec_res = {
+       /* PD PHY not present */
        .port_res = &pm8150b_port_res,
 };
 
 static const struct of_device_id qcom_pmic_typec_table[] = {
        { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res },
+       { .compatible = "qcom,pmi632-typec", .data = &pmi632_typec_res },
        { }
 };
 MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table);
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h
new file mode 100644 (file)
index 0000000..3c75820
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Linaro Ltd. All rights reserved.
+ */
+
+#ifndef __QCOM_PMIC_TYPEC_H__
+#define __QCOM_PMIC_TYPEC_H__
+
+struct pmic_typec {
+       struct device           *dev;
+       struct tcpm_port        *tcpm_port;
+       struct tcpc_dev         tcpc;
+       struct pmic_typec_pdphy *pmic_typec_pdphy;
+       struct pmic_typec_port  *pmic_typec_port;
+
+       int (*pdphy_start)(struct pmic_typec *tcpm,
+                          struct tcpm_port *tcpm_port);
+       void (*pdphy_stop)(struct pmic_typec *tcpm);
+
+       int (*port_start)(struct pmic_typec *tcpm,
+                         struct tcpm_port *tcpm_port);
+       void (*port_stop)(struct pmic_typec *tcpm);
+};
+
+#define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc)
+
+#endif
index 52c81378e36ef4e0b58c8af5097cef7220ccc499..6560f4fc98d5a3444ab33cc2ab29cd83890ac06b 100644 (file)
 #include <linux/slab.h>
 #include <linux/usb/pd.h>
 #include <linux/usb/tcpm.h>
+#include "qcom_pmic_typec.h"
 #include "qcom_pmic_typec_pdphy.h"
 
+/* PD PHY register offsets and bit fields */
+#define USB_PDPHY_MSG_CONFIG_REG       0x40
+#define MSG_CONFIG_PORT_DATA_ROLE      BIT(3)
+#define MSG_CONFIG_PORT_POWER_ROLE     BIT(2)
+#define MSG_CONFIG_SPEC_REV_MASK       (BIT(1) | BIT(0))
+
+#define USB_PDPHY_EN_CONTROL_REG       0x46
+#define CONTROL_ENABLE                 BIT(0)
+
+#define USB_PDPHY_RX_STATUS_REG                0x4A
+#define RX_FRAME_TYPE                  (BIT(0) | BIT(1) | BIT(2))
+
+#define USB_PDPHY_FRAME_FILTER_REG     0x4C
+#define FRAME_FILTER_EN_HARD_RESET     BIT(5)
+#define FRAME_FILTER_EN_SOP            BIT(0)
+
+#define USB_PDPHY_TX_SIZE_REG          0x42
+#define TX_SIZE_MASK                   0xF
+
+#define USB_PDPHY_TX_CONTROL_REG       0x44
+#define TX_CONTROL_RETRY_COUNT(n)      (((n) & 0x3) << 5)
+#define TX_CONTROL_FRAME_TYPE(n)        (((n) & 0x7) << 2)
+#define TX_CONTROL_FRAME_TYPE_CABLE_RESET      (0x1 << 2)
+#define TX_CONTROL_SEND_SIGNAL         BIT(1)
+#define TX_CONTROL_SEND_MSG            BIT(0)
+
+#define USB_PDPHY_RX_SIZE_REG          0x48
+
+#define USB_PDPHY_RX_ACKNOWLEDGE_REG   0x4B
+#define RX_BUFFER_TOKEN                        BIT(0)
+
+#define USB_PDPHY_BIST_MODE_REG                0x4E
+#define BIST_MODE_MASK                 0xF
+#define BIST_ENABLE                    BIT(7)
+#define PD_MSG_BIST                    0x3
+#define PD_BIST_TEST_DATA_MODE         0x8
+
+#define USB_PDPHY_TX_BUFFER_HDR_REG    0x60
+#define USB_PDPHY_TX_BUFFER_DATA_REG   0x62
+
+#define USB_PDPHY_RX_BUFFER_REG                0x80
+
+/* VDD regulator */
+#define VDD_PDPHY_VOL_MIN              2800000 /* uV */
+#define VDD_PDPHY_VOL_MAX              3300000 /* uV */
+#define VDD_PDPHY_HPM_LOAD             3000    /* uA */
+
+/* Message Spec Rev field */
+#define PD_MSG_HDR_REV(hdr)            (((hdr) >> 6) & 3)
+
+/* timers */
+#define RECEIVER_RESPONSE_TIME         15      /* tReceiverResponse */
+#define HARD_RESET_COMPLETE_TIME       5       /* tHardResetComplete */
+
+/* Interrupt numbers */
+#define PMIC_PDPHY_SIG_TX_IRQ          0x0
+#define PMIC_PDPHY_SIG_RX_IRQ          0x1
+#define PMIC_PDPHY_MSG_TX_IRQ          0x2
+#define PMIC_PDPHY_MSG_RX_IRQ          0x3
+#define PMIC_PDPHY_MSG_TX_FAIL_IRQ     0x4
+#define PMIC_PDPHY_MSG_TX_DISCARD_IRQ  0x5
+#define PMIC_PDPHY_MSG_RX_DISCARD_IRQ  0x6
+#define PMIC_PDPHY_FR_SWAP_IRQ         0x7
+
+
 struct pmic_typec_pdphy_irq_data {
        int                             virq;
        int                             irq;
@@ -231,11 +297,13 @@ done:
        return ret;
 }
 
-int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy,
-                                     enum tcpm_transmit_type type,
-                                     const struct pd_message *msg,
-                                     unsigned int negotiated_rev)
+static int qcom_pmic_typec_pdphy_pd_transmit(struct tcpc_dev *tcpc,
+                                            enum tcpm_transmit_type type,
+                                            const struct pd_message *msg,
+                                            unsigned int negotiated_rev)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        struct device *dev = pmic_typec_pdphy->dev;
        int ret;
 
@@ -299,7 +367,7 @@ done:
 
        if (!ret) {
                dev_vdbg(dev, "pd_receive: handing %d bytes to tcpm\n", size);
-               tcpm_pd_receive(pmic_typec_pdphy->tcpm_port, &msg);
+               tcpm_pd_receive(pmic_typec_pdphy->tcpm_port, &msg, TCPC_TX_SOP);
        }
 }
 
@@ -336,8 +404,10 @@ static irqreturn_t qcom_pmic_typec_pdphy_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on)
+static int qcom_pmic_typec_pdphy_set_pd_rx(struct tcpc_dev *tcpc, bool on)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        unsigned long flags;
        int ret;
 
@@ -353,9 +423,12 @@ int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, b
        return ret;
 }
 
-int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy,
-                                   bool data_role_host, bool power_role_src)
+static int qcom_pmic_typec_pdphy_set_roles(struct tcpc_dev *tcpc, bool attached,
+                                          enum typec_role power_role,
+                                          enum typec_data_role data_role)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        struct device *dev = pmic_typec_pdphy->dev;
        unsigned long flags;
        int ret;
@@ -366,12 +439,13 @@ int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy,
                                 pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG,
                                 MSG_CONFIG_PORT_DATA_ROLE |
                                 MSG_CONFIG_PORT_POWER_ROLE,
-                                data_role_host << 3 | power_role_src << 2);
+                                (data_role == TYPEC_HOST ? MSG_CONFIG_PORT_DATA_ROLE : 0) |
+                                (power_role == TYPEC_SOURCE ? MSG_CONFIG_PORT_POWER_ROLE : 0));
 
        spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags);
 
        dev_dbg(dev, "pdphy_set_roles: data_role_host=%d power_role_src=%d\n",
-               data_role_host, power_role_src);
+               data_role, power_role);
 
        return ret;
 }
@@ -435,9 +509,10 @@ done:
        return ret;
 }
 
-int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
-                               struct tcpm_port *tcpm_port)
+static int qcom_pmic_typec_pdphy_start(struct pmic_typec *tcpm,
+                                      struct tcpm_port *tcpm_port)
 {
+       struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        int i;
        int ret;
 
@@ -457,8 +532,9 @@ int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
        return 0;
 }
 
-void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy)
+static void qcom_pmic_typec_pdphy_stop(struct pmic_typec *tcpm)
 {
+       struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
        int i;
 
        for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++)
@@ -469,21 +545,21 @@ void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy)
        regulator_disable(pmic_typec_pdphy->vdd_pdphy);
 }
 
-struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev)
-{
-       return devm_kzalloc(dev, sizeof(struct pmic_typec_pdphy), GFP_KERNEL);
-}
-
 int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev,
-                               struct pmic_typec_pdphy *pmic_typec_pdphy,
-                               struct pmic_typec_pdphy_resources *res,
+                               struct pmic_typec *tcpm,
+                               const struct pmic_typec_pdphy_resources *res,
                                struct regmap *regmap,
                                u32 base)
 {
+       struct pmic_typec_pdphy *pmic_typec_pdphy;
        struct device *dev = &pdev->dev;
        struct pmic_typec_pdphy_irq_data *irq_data;
        int i, ret, irq;
 
+       pmic_typec_pdphy = devm_kzalloc(dev, sizeof(*pmic_typec_pdphy), GFP_KERNEL);
+       if (!pmic_typec_pdphy)
+               return -ENOMEM;
+
        if (!res->nr_irqs || res->nr_irqs > PMIC_PDPHY_MAX_IRQS)
                return -EINVAL;
 
@@ -522,5 +598,48 @@ int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev,
                        return ret;
        }
 
+       tcpm->pmic_typec_pdphy = pmic_typec_pdphy;
+
+       tcpm->tcpc.set_pd_rx = qcom_pmic_typec_pdphy_set_pd_rx;
+       tcpm->tcpc.set_roles = qcom_pmic_typec_pdphy_set_roles;
+       tcpm->tcpc.pd_transmit = qcom_pmic_typec_pdphy_pd_transmit;
+
+       tcpm->pdphy_start = qcom_pmic_typec_pdphy_start;
+       tcpm->pdphy_stop = qcom_pmic_typec_pdphy_stop;
+
        return 0;
 }
+
+const struct pmic_typec_pdphy_resources pm8150b_pdphy_res = {
+       .irq_params = {
+               {
+                       .virq = PMIC_PDPHY_SIG_TX_IRQ,
+                       .irq_name = "sig-tx",
+               },
+               {
+                       .virq = PMIC_PDPHY_SIG_RX_IRQ,
+                       .irq_name = "sig-rx",
+               },
+               {
+                       .virq = PMIC_PDPHY_MSG_TX_IRQ,
+                       .irq_name = "msg-tx",
+               },
+               {
+                       .virq = PMIC_PDPHY_MSG_RX_IRQ,
+                       .irq_name = "msg-rx",
+               },
+               {
+                       .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ,
+                       .irq_name = "msg-tx-failed",
+               },
+               {
+                       .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ,
+                       .irq_name = "msg-tx-discarded",
+               },
+               {
+                       .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ,
+                       .irq_name = "msg-rx-discarded",
+               },
+       },
+       .nr_irqs = 7,
+};
index e67954e31b149cd086c40cc44ca34ea51613bcc3..04dee20293cfad55d92cb2cefc3bfbef589ea308 100644 (file)
@@ -8,74 +8,6 @@
 
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
-#include <linux/usb/tcpm.h>
-
-#define USB_PDPHY_MAX_DATA_OBJ_LEN     28
-#define USB_PDPHY_MSG_HDR_LEN          2
-
-/* PD PHY register offsets and bit fields */
-#define USB_PDPHY_MSG_CONFIG_REG       0x40
-#define MSG_CONFIG_PORT_DATA_ROLE      BIT(3)
-#define MSG_CONFIG_PORT_POWER_ROLE     BIT(2)
-#define MSG_CONFIG_SPEC_REV_MASK       (BIT(1) | BIT(0))
-
-#define USB_PDPHY_EN_CONTROL_REG       0x46
-#define CONTROL_ENABLE                 BIT(0)
-
-#define USB_PDPHY_RX_STATUS_REG                0x4A
-#define RX_FRAME_TYPE                  (BIT(0) | BIT(1) | BIT(2))
-
-#define USB_PDPHY_FRAME_FILTER_REG     0x4C
-#define FRAME_FILTER_EN_HARD_RESET     BIT(5)
-#define FRAME_FILTER_EN_SOP            BIT(0)
-
-#define USB_PDPHY_TX_SIZE_REG          0x42
-#define TX_SIZE_MASK                   0xF
-
-#define USB_PDPHY_TX_CONTROL_REG       0x44
-#define TX_CONTROL_RETRY_COUNT(n)      (((n) & 0x3) << 5)
-#define TX_CONTROL_FRAME_TYPE(n)        (((n) & 0x7) << 2)
-#define TX_CONTROL_FRAME_TYPE_CABLE_RESET      (0x1 << 2)
-#define TX_CONTROL_SEND_SIGNAL         BIT(1)
-#define TX_CONTROL_SEND_MSG            BIT(0)
-
-#define USB_PDPHY_RX_SIZE_REG          0x48
-
-#define USB_PDPHY_RX_ACKNOWLEDGE_REG   0x4B
-#define RX_BUFFER_TOKEN                        BIT(0)
-
-#define USB_PDPHY_BIST_MODE_REG                0x4E
-#define BIST_MODE_MASK                 0xF
-#define BIST_ENABLE                    BIT(7)
-#define PD_MSG_BIST                    0x3
-#define PD_BIST_TEST_DATA_MODE         0x8
-
-#define USB_PDPHY_TX_BUFFER_HDR_REG    0x60
-#define USB_PDPHY_TX_BUFFER_DATA_REG   0x62
-
-#define USB_PDPHY_RX_BUFFER_REG                0x80
-
-/* VDD regulator */
-#define VDD_PDPHY_VOL_MIN              2800000 /* uV */
-#define VDD_PDPHY_VOL_MAX              3300000 /* uV */
-#define VDD_PDPHY_HPM_LOAD             3000    /* uA */
-
-/* Message Spec Rev field */
-#define PD_MSG_HDR_REV(hdr)            (((hdr) >> 6) & 3)
-
-/* timers */
-#define RECEIVER_RESPONSE_TIME         15      /* tReceiverResponse */
-#define HARD_RESET_COMPLETE_TIME       5       /* tHardResetComplete */
-
-/* Interrupt numbers */
-#define PMIC_PDPHY_SIG_TX_IRQ          0x0
-#define PMIC_PDPHY_SIG_RX_IRQ          0x1
-#define PMIC_PDPHY_MSG_TX_IRQ          0x2
-#define PMIC_PDPHY_MSG_RX_IRQ          0x3
-#define PMIC_PDPHY_MSG_TX_FAIL_IRQ     0x4
-#define PMIC_PDPHY_MSG_TX_DISCARD_IRQ  0x5
-#define PMIC_PDPHY_MSG_RX_DISCARD_IRQ  0x6
-#define PMIC_PDPHY_FR_SWAP_IRQ         0x7
 
 /* Resources */
 #define PMIC_PDPHY_MAX_IRQS            0x08
@@ -87,33 +19,19 @@ struct pmic_typec_pdphy_irq_params {
 
 struct pmic_typec_pdphy_resources {
        unsigned int                            nr_irqs;
-       struct pmic_typec_pdphy_irq_params      irq_params[PMIC_PDPHY_MAX_IRQS];
+       const struct pmic_typec_pdphy_irq_params        irq_params[PMIC_PDPHY_MAX_IRQS];
 };
 
 /* API */
 struct pmic_typec_pdphy;
 
-struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev);
-
+extern const struct pmic_typec_pdphy_resources pm8150b_pdphy_res;
 int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev,
-                               struct pmic_typec_pdphy *pmic_typec_pdphy,
-                               struct pmic_typec_pdphy_resources *res,
+                               struct pmic_typec *tcpm,
+                               const struct pmic_typec_pdphy_resources *res,
                                struct regmap *regmap,
                                u32 base);
-
-int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
-                               struct tcpm_port *tcpm_port);
-
-void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy);
-
-int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy,
-                                   bool power_role_src, bool data_role_host);
-
-int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on);
-
-int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy,
-                                     enum tcpm_transmit_type type,
-                                     const struct pd_message *msg,
-                                     unsigned int negotiated_rev);
+int qcom_pmic_typec_pdphy_stub_probe(struct platform_device *pdev,
+                                    struct pmic_typec *tcpm);
 
 #endif /* __QCOM_PMIC_TYPEC_PDPHY_H__ */
diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c
new file mode 100644 (file)
index 0000000..df79059
--- /dev/null
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024, Linaro Ltd. All rights reserved.
+ */
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/tcpm.h>
+#include "qcom_pmic_typec.h"
+#include "qcom_pmic_typec_pdphy.h"
+
+static int qcom_pmic_typec_pdphy_stub_pd_transmit(struct tcpc_dev *tcpc,
+                                                 enum tcpm_transmit_type type,
+                                                 const struct pd_message *msg,
+                                                 unsigned int negotiated_rev)
+{
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct device *dev = tcpm->dev;
+
+       dev_dbg(dev, "pdphy_transmit: type=%d\n", type);
+
+       tcpm_pd_transmit_complete(tcpm->tcpm_port,
+                                 TCPC_TX_SUCCESS);
+
+       return 0;
+}
+
+static int qcom_pmic_typec_pdphy_stub_set_pd_rx(struct tcpc_dev *tcpc, bool on)
+{
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct device *dev = tcpm->dev;
+
+       dev_dbg(dev, "set_pd_rx: %s\n", on ? "on" : "off");
+
+       return 0;
+}
+
+static int qcom_pmic_typec_pdphy_stub_set_roles(struct tcpc_dev *tcpc, bool attached,
+                                               enum typec_role power_role,
+                                               enum typec_data_role data_role)
+{
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct device *dev = tcpm->dev;
+
+       dev_dbg(dev, "pdphy_set_roles: data_role_host=%d power_role_src=%d\n",
+               data_role, power_role);
+
+       return 0;
+}
+
+static int qcom_pmic_typec_pdphy_stub_start(struct pmic_typec *tcpm,
+                                           struct tcpm_port *tcpm_port)
+{
+       return 0;
+}
+
+static void qcom_pmic_typec_pdphy_stub_stop(struct pmic_typec *tcpm)
+{
+}
+
+int qcom_pmic_typec_pdphy_stub_probe(struct platform_device *pdev,
+                                    struct pmic_typec *tcpm)
+{
+       tcpm->tcpc.set_pd_rx = qcom_pmic_typec_pdphy_stub_set_pd_rx;
+       tcpm->tcpc.set_roles = qcom_pmic_typec_pdphy_stub_set_roles;
+       tcpm->tcpc.pd_transmit = qcom_pmic_typec_pdphy_stub_pd_transmit;
+
+       tcpm->pdphy_start = qcom_pmic_typec_pdphy_stub_start;
+       tcpm->pdphy_stop = qcom_pmic_typec_pdphy_stub_stop;
+
+       return 0;
+}
index a8f3f4d3a4509d3f3f7332a02e50da8d2a7c2dab..a747baa2978498cc13d8660ee9da10880dbda416 100644 (file)
 #include <linux/usb/tcpm.h>
 #include <linux/usb/typec_mux.h>
 #include <linux/workqueue.h>
+
+#include "qcom_pmic_typec.h"
 #include "qcom_pmic_typec_port.h"
 
+#define TYPEC_SNK_STATUS_REG                           0x06
+#define DETECTED_SNK_TYPE_MASK                         GENMASK(6, 0)
+#define SNK_DAM_MASK                                   GENMASK(6, 4)
+#define SNK_DAM_500MA                                  BIT(6)
+#define SNK_DAM_1500MA                                 BIT(5)
+#define SNK_DAM_3000MA                                 BIT(4)
+#define SNK_RP_STD                                     BIT(3)
+#define SNK_RP_1P5                                     BIT(2)
+#define SNK_RP_3P0                                     BIT(1)
+#define SNK_RP_SHORT                                   BIT(0)
+
+#define TYPEC_SRC_STATUS_REG                           0x08
+#define DETECTED_SRC_TYPE_MASK                         GENMASK(4, 0)
+#define SRC_HIGH_BATT                                  BIT(5)
+#define SRC_DEBUG_ACCESS                               BIT(4)
+#define SRC_RD_OPEN                                    BIT(3)
+#define SRC_RD_RA_VCONN                                        BIT(2)
+#define SRC_RA_OPEN                                    BIT(1)
+#define AUDIO_ACCESS_RA_RA                             BIT(0)
+
+#define TYPEC_STATE_MACHINE_STATUS_REG                 0x09
+#define TYPEC_ATTACH_DETACH_STATE                      BIT(5)
+
+#define TYPEC_SM_STATUS_REG                            0x0A
+#define TYPEC_SM_VBUS_VSAFE5V                          BIT(5)
+#define TYPEC_SM_VBUS_VSAFE0V                          BIT(6)
+#define TYPEC_SM_USBIN_LT_LV                           BIT(7)
+
+#define TYPEC_MISC_STATUS_REG                          0x0B
+#define TYPEC_WATER_DETECTION_STATUS                   BIT(7)
+#define SNK_SRC_MODE                                   BIT(6)
+#define TYPEC_VBUS_DETECT                              BIT(5)
+#define TYPEC_VBUS_ERROR_STATUS                                BIT(4)
+#define TYPEC_DEBOUNCE_DONE                            BIT(3)
+#define CC_ORIENTATION                                 BIT(1)
+#define CC_ATTACHED                                    BIT(0)
+
+#define LEGACY_CABLE_STATUS_REG                                0x0D
+#define TYPEC_LEGACY_CABLE_STATUS                      BIT(1)
+#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS              BIT(0)
+
+#define TYPEC_U_USB_STATUS_REG                         0x0F
+#define U_USB_GROUND_NOVBUS                            BIT(6)
+#define U_USB_GROUND                                   BIT(4)
+#define U_USB_FMB1                                     BIT(3)
+#define U_USB_FLOAT1                                   BIT(2)
+#define U_USB_FMB2                                     BIT(1)
+#define U_USB_FLOAT2                                   BIT(0)
+
+#define TYPEC_MODE_CFG_REG                             0x44
+#define TYPEC_TRY_MODE_MASK                            GENMASK(4, 3)
+#define EN_TRY_SNK                                     BIT(4)
+#define EN_TRY_SRC                                     BIT(3)
+#define TYPEC_POWER_ROLE_CMD_MASK                      GENMASK(2, 0)
+#define EN_SRC_ONLY                                    BIT(2)
+#define EN_SNK_ONLY                                    BIT(1)
+#define TYPEC_DISABLE_CMD                              BIT(0)
+
+#define TYPEC_VCONN_CONTROL_REG                                0x46
+#define VCONN_EN_ORIENTATION                           BIT(2)
+#define VCONN_EN_VALUE                                 BIT(1)
+#define VCONN_EN_SRC                                   BIT(0)
+
+#define TYPEC_CCOUT_CONTROL_REG                                0x48
+#define TYPEC_CCOUT_BUFFER_EN                          BIT(2)
+#define TYPEC_CCOUT_VALUE                              BIT(1)
+#define TYPEC_CCOUT_SRC                                        BIT(0)
+
+#define DEBUG_ACCESS_SRC_CFG_REG                       0x4C
+#define EN_UNORIENTED_DEBUG_ACCESS_SRC                 BIT(0)
+
+#define TYPE_C_CRUDE_SENSOR_CFG_REG                    0x4e
+#define EN_SRC_CRUDE_SENSOR                            BIT(1)
+#define EN_SNK_CRUDE_SENSOR                            BIT(0)
+
+#define TYPEC_EXIT_STATE_CFG_REG                       0x50
+#define BYPASS_VSAFE0V_DURING_ROLE_SWAP                        BIT(3)
+#define SEL_SRC_UPPER_REF                              BIT(2)
+#define USE_TPD_FOR_EXITING_ATTACHSRC                  BIT(1)
+#define EXIT_SNK_BASED_ON_CC                           BIT(0)
+
+#define TYPEC_CURRSRC_CFG_REG                          0x52
+#define TYPEC_SRC_RP_SEL_330UA                         BIT(1)
+#define TYPEC_SRC_RP_SEL_180UA                         BIT(0)
+#define TYPEC_SRC_RP_SEL_80UA                          0
+#define TYPEC_SRC_RP_SEL_MASK                          GENMASK(1, 0)
+
+#define TYPEC_INTERRUPT_EN_CFG_1_REG                   0x5E
+#define TYPEC_LEGACY_CABLE_INT_EN                      BIT(7)
+#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN         BIT(6)
+#define TYPEC_TRYSOURCE_DETECT_INT_EN                  BIT(5)
+#define TYPEC_TRYSINK_DETECT_INT_EN                    BIT(4)
+#define TYPEC_CCOUT_DETACH_INT_EN                      BIT(3)
+#define TYPEC_CCOUT_ATTACH_INT_EN                      BIT(2)
+#define TYPEC_VBUS_DEASSERT_INT_EN                     BIT(1)
+#define TYPEC_VBUS_ASSERT_INT_EN                       BIT(0)
+
+#define TYPEC_INTERRUPT_EN_CFG_2_REG                   0x60
+#define TYPEC_SRC_BATT_HPWR_INT_EN                     BIT(6)
+#define MICRO_USB_STATE_CHANGE_INT_EN                  BIT(5)
+#define TYPEC_STATE_MACHINE_CHANGE_INT_EN              BIT(4)
+#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN               BIT(3)
+#define TYPEC_WATER_DETECTION_INT_EN                   BIT(2)
+#define TYPEC_VBUS_ERROR_INT_EN                                BIT(1)
+#define TYPEC_DEBOUNCE_DONE_INT_EN                     BIT(0)
+
+#define TYPEC_DEBOUNCE_OPTION_REG                      0x62
+#define REDUCE_TCCDEBOUNCE_TO_2MS                      BIT(2)
+
+#define TYPE_C_SBU_CFG_REG                             0x6A
+#define SEL_SBU1_ISRC_VAL                              0x04
+#define SEL_SBU2_ISRC_VAL                              0x01
+
+#define TYPEC_U_USB_CFG_REG                            0x70
+#define EN_MICRO_USB_FACTORY_MODE                      BIT(1)
+#define EN_MICRO_USB_MODE                              BIT(0)
+
+#define TYPEC_PMI632_U_USB_WATER_PROTECTION_CFG_REG    0x72
+
+#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG           0x73
+#define EN_MICRO_USB_WATER_PROTECTION                  BIT(4)
+#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK           GENMASK(3, 2)
+#define MICRO_USB_DETECTION_PERIOD_CFG_MASK            GENMASK(1, 0)
+
+#define TYPEC_PMI632_MICRO_USB_MODE_REG                        0x73
+#define MICRO_USB_MODE_ONLY                            BIT(0)
+
+/* Interrupt numbers */
+#define PMIC_TYPEC_OR_RID_IRQ                          0x0
+#define PMIC_TYPEC_VPD_IRQ                             0x1
+#define PMIC_TYPEC_CC_STATE_IRQ                                0x2
+#define PMIC_TYPEC_VCONN_OC_IRQ                                0x3
+#define PMIC_TYPEC_VBUS_IRQ                            0x4
+#define PMIC_TYPEC_ATTACH_DETACH_IRQ                   0x5
+#define PMIC_TYPEC_LEGACY_CABLE_IRQ                    0x6
+#define PMIC_TYPEC_TRY_SNK_SRC_IRQ                     0x7
+
 struct pmic_typec_port_irq_data {
        int                             virq;
        int                             irq;
@@ -33,6 +172,8 @@ struct pmic_typec_port {
        struct pmic_typec_port_irq_data *irq_data;
 
        struct regulator                *vdd_vbus;
+       bool                            vbus_enabled;
+       struct mutex                    vbus_lock;              /* VBUS state serialization */
 
        int                             cc;
        bool                            debouncing_cc;
@@ -131,7 +272,7 @@ done:
        return IRQ_HANDLED;
 }
 
-int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port)
+static int qcom_pmic_typec_port_vbus_detect(struct pmic_typec_port *pmic_typec_port)
 {
        struct device *dev = pmic_typec_port->dev;
        unsigned int misc;
@@ -148,7 +289,7 @@ int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port)
        return !!(misc & TYPEC_VBUS_DETECT);
 }
 
-int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool on)
+static int qcom_pmic_typec_port_vbus_toggle(struct pmic_typec_port *pmic_typec_port, bool on)
 {
        u32 sm_stat;
        u32 val;
@@ -179,10 +320,49 @@ int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool
        return 0;
 }
 
-int qcom_pmic_typec_port_get_cc(struct pmic_typec_port *pmic_typec_port,
-                               enum typec_cc_status *cc1,
-                               enum typec_cc_status *cc2)
+static int qcom_pmic_typec_port_get_vbus(struct tcpc_dev *tcpc)
+{
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
+       int ret;
+
+       mutex_lock(&pmic_typec_port->vbus_lock);
+       ret = pmic_typec_port->vbus_enabled || qcom_pmic_typec_port_vbus_detect(pmic_typec_port);
+       mutex_unlock(&pmic_typec_port->vbus_lock);
+
+       return ret;
+}
+
+static int qcom_pmic_typec_port_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink)
+{
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
+       int ret = 0;
+
+       mutex_lock(&pmic_typec_port->vbus_lock);
+       if (pmic_typec_port->vbus_enabled == on)
+               goto done;
+
+       ret = qcom_pmic_typec_port_vbus_toggle(pmic_typec_port, on);
+       if (ret)
+               goto done;
+
+       pmic_typec_port->vbus_enabled = on;
+       tcpm_vbus_change(tcpm->tcpm_port);
+
+done:
+       dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret);
+       mutex_unlock(&pmic_typec_port->vbus_lock);
+
+       return ret;
+}
+
+static int qcom_pmic_typec_port_get_cc(struct tcpc_dev *tcpc,
+                                      enum typec_cc_status *cc1,
+                                      enum typec_cc_status *cc2)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
        struct device *dev = pmic_typec_port->dev;
        unsigned int misc, val;
        bool attached;
@@ -275,9 +455,11 @@ static void qcom_pmic_set_cc_debounce(struct pmic_typec_port *pmic_typec_port)
                              msecs_to_jiffies(2));
 }
 
-int qcom_pmic_typec_port_set_cc(struct pmic_typec_port *pmic_typec_port,
-                               enum typec_cc_status cc)
+static int qcom_pmic_typec_port_set_cc(struct tcpc_dev *tcpc,
+                                      enum typec_cc_status cc)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
        struct device *dev = pmic_typec_port->dev;
        unsigned int mode, currsrc;
        unsigned int misc;
@@ -341,8 +523,17 @@ done:
        return ret;
 }
 
-int qcom_pmic_typec_port_set_vconn(struct pmic_typec_port *pmic_typec_port, bool on)
+static int qcom_pmic_typec_port_set_polarity(struct tcpc_dev *tcpc,
+                                            enum typec_cc_polarity pol)
+{
+       /* Polarity is set separately by phy-qcom-qmp.c */
+       return 0;
+}
+
+static int qcom_pmic_typec_port_set_vconn(struct tcpc_dev *tcpc, bool on)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
        struct device *dev = pmic_typec_port->dev;
        unsigned int orientation, misc, mask, value;
        unsigned long flags;
@@ -377,10 +568,12 @@ done:
        return ret;
 }
 
-int qcom_pmic_typec_port_start_toggling(struct pmic_typec_port *pmic_typec_port,
-                                       enum typec_port_type port_type,
-                                       enum typec_cc_status cc)
+static int qcom_pmic_typec_port_start_toggling(struct tcpc_dev *tcpc,
+                                              enum typec_port_type port_type,
+                                              enum typec_cc_status cc)
 {
+       struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
        struct device *dev = pmic_typec_port->dev;
        unsigned int misc;
        u8 mode = 0;
@@ -441,9 +634,10 @@ done:
        (TYPEC_STATE_MACHINE_CHANGE_INT_EN | TYPEC_VBUS_ERROR_INT_EN | \
         TYPEC_DEBOUNCE_DONE_INT_EN)
 
-int qcom_pmic_typec_port_start(struct pmic_typec_port *pmic_typec_port,
-                              struct tcpm_port *tcpm_port)
+static int qcom_pmic_typec_port_start(struct pmic_typec *tcpm,
+                                     struct tcpm_port *tcpm_port)
 {
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
        int i;
        int mask;
        int ret;
@@ -491,29 +685,30 @@ done:
        return ret;
 }
 
-void qcom_pmic_typec_port_stop(struct pmic_typec_port *pmic_typec_port)
+static void qcom_pmic_typec_port_stop(struct pmic_typec *tcpm)
 {
+       struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port;
        int i;
 
        for (i = 0; i < pmic_typec_port->nr_irqs; i++)
                disable_irq(pmic_typec_port->irq_data[i].irq);
 }
 
-struct pmic_typec_port *qcom_pmic_typec_port_alloc(struct device *dev)
-{
-       return devm_kzalloc(dev, sizeof(struct pmic_typec_port), GFP_KERNEL);
-}
-
 int qcom_pmic_typec_port_probe(struct platform_device *pdev,
-                              struct pmic_typec_port *pmic_typec_port,
-                              struct pmic_typec_port_resources *res,
+                              struct pmic_typec *tcpm,
+                              const struct pmic_typec_port_resources *res,
                               struct regmap *regmap,
                               u32 base)
 {
        struct device *dev = &pdev->dev;
        struct pmic_typec_port_irq_data *irq_data;
+       struct pmic_typec_port *pmic_typec_port;
        int i, ret, irq;
 
+       pmic_typec_port = devm_kzalloc(dev, sizeof(*pmic_typec_port), GFP_KERNEL);
+       if (!pmic_typec_port)
+               return -ENOMEM;
+
        if (!res->nr_irqs || res->nr_irqs > PMIC_TYPEC_MAX_IRQS)
                return -EINVAL;
 
@@ -522,6 +717,8 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev,
        if (!irq_data)
                return -ENOMEM;
 
+       mutex_init(&pmic_typec_port->vbus_lock);
+
        pmic_typec_port->vdd_vbus = devm_regulator_get(dev, "vdd-vbus");
        if (IS_ERR(pmic_typec_port->vdd_vbus))
                return PTR_ERR(pmic_typec_port->vdd_vbus);
@@ -556,5 +753,56 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev,
                        return ret;
        }
 
+       tcpm->pmic_typec_port = pmic_typec_port;
+
+       tcpm->tcpc.get_vbus = qcom_pmic_typec_port_get_vbus;
+       tcpm->tcpc.set_vbus = qcom_pmic_typec_port_set_vbus;
+       tcpm->tcpc.set_cc = qcom_pmic_typec_port_set_cc;
+       tcpm->tcpc.get_cc = qcom_pmic_typec_port_get_cc;
+       tcpm->tcpc.set_polarity = qcom_pmic_typec_port_set_polarity;
+       tcpm->tcpc.set_vconn = qcom_pmic_typec_port_set_vconn;
+       tcpm->tcpc.start_toggling = qcom_pmic_typec_port_start_toggling;
+
+       tcpm->port_start = qcom_pmic_typec_port_start;
+       tcpm->port_stop = qcom_pmic_typec_port_stop;
+
        return 0;
 }
+
+const struct pmic_typec_port_resources pm8150b_port_res = {
+       .irq_params = {
+               {
+                       .irq_name = "vpd-detect",
+                       .virq = PMIC_TYPEC_VPD_IRQ,
+               },
+
+               {
+                       .irq_name = "cc-state-change",
+                       .virq = PMIC_TYPEC_CC_STATE_IRQ,
+               },
+               {
+                       .irq_name = "vconn-oc",
+                       .virq = PMIC_TYPEC_VCONN_OC_IRQ,
+               },
+
+               {
+                       .irq_name = "vbus-change",
+                       .virq = PMIC_TYPEC_VBUS_IRQ,
+               },
+
+               {
+                       .irq_name = "attach-detach",
+                       .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ,
+               },
+               {
+                       .irq_name = "legacy-cable-detect",
+                       .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ,
+               },
+
+               {
+                       .irq_name = "try-snk-src-detect",
+                       .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ,
+               },
+       },
+       .nr_irqs = 7,
+};
index d4d358c680b6bf0de590b99077f37bbb31a500d5..2ca83a46cf3b5d69805f7a9490cbd220dfe71055 100644 (file)
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
  * Copyright (c) 2023, Linaro Ltd. All rights reserved.
  */
-#ifndef __QCOM_PMIC_TYPEC_H__
-#define __QCOM_PMIC_TYPEC_H__
+#ifndef __QCOM_PMIC_TYPEC_PORT_H__
+#define __QCOM_PMIC_TYPEC_PORT_H__
 
 #include <linux/platform_device.h>
 #include <linux/usb/tcpm.h>
 
-#define TYPEC_SNK_STATUS_REG                           0x06
-#define DETECTED_SNK_TYPE_MASK                         GENMASK(6, 0)
-#define SNK_DAM_MASK                                   GENMASK(6, 4)
-#define SNK_DAM_500MA                                  BIT(6)
-#define SNK_DAM_1500MA                                 BIT(5)
-#define SNK_DAM_3000MA                                 BIT(4)
-#define SNK_RP_STD                                     BIT(3)
-#define SNK_RP_1P5                                     BIT(2)
-#define SNK_RP_3P0                                     BIT(1)
-#define SNK_RP_SHORT                                   BIT(0)
-
-#define TYPEC_SRC_STATUS_REG                           0x08
-#define DETECTED_SRC_TYPE_MASK                         GENMASK(4, 0)
-#define SRC_HIGH_BATT                                  BIT(5)
-#define SRC_DEBUG_ACCESS                               BIT(4)
-#define SRC_RD_OPEN                                    BIT(3)
-#define SRC_RD_RA_VCONN                                        BIT(2)
-#define SRC_RA_OPEN                                    BIT(1)
-#define AUDIO_ACCESS_RA_RA                             BIT(0)
-
-#define TYPEC_STATE_MACHINE_STATUS_REG                 0x09
-#define TYPEC_ATTACH_DETACH_STATE                      BIT(5)
-
-#define TYPEC_SM_STATUS_REG                            0x0A
-#define TYPEC_SM_VBUS_VSAFE5V                          BIT(5)
-#define TYPEC_SM_VBUS_VSAFE0V                          BIT(6)
-#define TYPEC_SM_USBIN_LT_LV                           BIT(7)
-
-#define TYPEC_MISC_STATUS_REG                          0x0B
-#define TYPEC_WATER_DETECTION_STATUS                   BIT(7)
-#define SNK_SRC_MODE                                   BIT(6)
-#define TYPEC_VBUS_DETECT                              BIT(5)
-#define TYPEC_VBUS_ERROR_STATUS                                BIT(4)
-#define TYPEC_DEBOUNCE_DONE                            BIT(3)
-#define CC_ORIENTATION                                 BIT(1)
-#define CC_ATTACHED                                    BIT(0)
-
-#define LEGACY_CABLE_STATUS_REG                                0x0D
-#define TYPEC_LEGACY_CABLE_STATUS                      BIT(1)
-#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS              BIT(0)
-
-#define TYPEC_U_USB_STATUS_REG                         0x0F
-#define U_USB_GROUND_NOVBUS                            BIT(6)
-#define U_USB_GROUND                                   BIT(4)
-#define U_USB_FMB1                                     BIT(3)
-#define U_USB_FLOAT1                                   BIT(2)
-#define U_USB_FMB2                                     BIT(1)
-#define U_USB_FLOAT2                                   BIT(0)
-
-#define TYPEC_MODE_CFG_REG                             0x44
-#define TYPEC_TRY_MODE_MASK                            GENMASK(4, 3)
-#define EN_TRY_SNK                                     BIT(4)
-#define EN_TRY_SRC                                     BIT(3)
-#define TYPEC_POWER_ROLE_CMD_MASK                      GENMASK(2, 0)
-#define EN_SRC_ONLY                                    BIT(2)
-#define EN_SNK_ONLY                                    BIT(1)
-#define TYPEC_DISABLE_CMD                              BIT(0)
-
-#define TYPEC_VCONN_CONTROL_REG                                0x46
-#define VCONN_EN_ORIENTATION                           BIT(2)
-#define VCONN_EN_VALUE                                 BIT(1)
-#define VCONN_EN_SRC                                   BIT(0)
-
-#define TYPEC_CCOUT_CONTROL_REG                                0x48
-#define TYPEC_CCOUT_BUFFER_EN                          BIT(2)
-#define TYPEC_CCOUT_VALUE                              BIT(1)
-#define TYPEC_CCOUT_SRC                                        BIT(0)
-
-#define DEBUG_ACCESS_SRC_CFG_REG                       0x4C
-#define EN_UNORIENTED_DEBUG_ACCESS_SRC                 BIT(0)
-
-#define TYPE_C_CRUDE_SENSOR_CFG_REG                    0x4e
-#define EN_SRC_CRUDE_SENSOR                            BIT(1)
-#define EN_SNK_CRUDE_SENSOR                            BIT(0)
-
-#define TYPEC_EXIT_STATE_CFG_REG                       0x50
-#define BYPASS_VSAFE0V_DURING_ROLE_SWAP                        BIT(3)
-#define SEL_SRC_UPPER_REF                              BIT(2)
-#define USE_TPD_FOR_EXITING_ATTACHSRC                  BIT(1)
-#define EXIT_SNK_BASED_ON_CC                           BIT(0)
-
-#define TYPEC_CURRSRC_CFG_REG                          0x52
-#define TYPEC_SRC_RP_SEL_330UA                         BIT(1)
-#define TYPEC_SRC_RP_SEL_180UA                         BIT(0)
-#define TYPEC_SRC_RP_SEL_80UA                          0
-#define TYPEC_SRC_RP_SEL_MASK                          GENMASK(1, 0)
-
-#define TYPEC_INTERRUPT_EN_CFG_1_REG                   0x5E
-#define TYPEC_LEGACY_CABLE_INT_EN                      BIT(7)
-#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN         BIT(6)
-#define TYPEC_TRYSOURCE_DETECT_INT_EN                  BIT(5)
-#define TYPEC_TRYSINK_DETECT_INT_EN                    BIT(4)
-#define TYPEC_CCOUT_DETACH_INT_EN                      BIT(3)
-#define TYPEC_CCOUT_ATTACH_INT_EN                      BIT(2)
-#define TYPEC_VBUS_DEASSERT_INT_EN                     BIT(1)
-#define TYPEC_VBUS_ASSERT_INT_EN                       BIT(0)
-
-#define TYPEC_INTERRUPT_EN_CFG_2_REG                   0x60
-#define TYPEC_SRC_BATT_HPWR_INT_EN                     BIT(6)
-#define MICRO_USB_STATE_CHANGE_INT_EN                  BIT(5)
-#define TYPEC_STATE_MACHINE_CHANGE_INT_EN              BIT(4)
-#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN               BIT(3)
-#define TYPEC_WATER_DETECTION_INT_EN                   BIT(2)
-#define TYPEC_VBUS_ERROR_INT_EN                                BIT(1)
-#define TYPEC_DEBOUNCE_DONE_INT_EN                     BIT(0)
-
-#define TYPEC_DEBOUNCE_OPTION_REG                      0x62
-#define REDUCE_TCCDEBOUNCE_TO_2MS                      BIT(2)
-
-#define TYPE_C_SBU_CFG_REG                             0x6A
-#define SEL_SBU1_ISRC_VAL                              0x04
-#define SEL_SBU2_ISRC_VAL                              0x01
-
-#define TYPEC_U_USB_CFG_REG                            0x70
-#define EN_MICRO_USB_FACTORY_MODE                      BIT(1)
-#define EN_MICRO_USB_MODE                              BIT(0)
-
-#define TYPEC_PMI632_U_USB_WATER_PROTECTION_CFG_REG    0x72
-
-#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG           0x73
-#define EN_MICRO_USB_WATER_PROTECTION                  BIT(4)
-#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK           GENMASK(3, 2)
-#define MICRO_USB_DETECTION_PERIOD_CFG_MASK            GENMASK(1, 0)
-
-#define TYPEC_PMI632_MICRO_USB_MODE_REG                        0x73
-#define MICRO_USB_MODE_ONLY                            BIT(0)
-
-/* Interrupt numbers */
-#define PMIC_TYPEC_OR_RID_IRQ                          0x0
-#define PMIC_TYPEC_VPD_IRQ                             0x1
-#define PMIC_TYPEC_CC_STATE_IRQ                                0x2
-#define PMIC_TYPEC_VCONN_OC_IRQ                                0x3
-#define PMIC_TYPEC_VBUS_IRQ                            0x4
-#define PMIC_TYPEC_ATTACH_DETACH_IRQ                   0x5
-#define PMIC_TYPEC_LEGACY_CABLE_IRQ                    0x6
-#define PMIC_TYPEC_TRY_SNK_SRC_IRQ                     0x7
-
 /* Resources */
 #define PMIC_TYPEC_MAX_IRQS                            0x08
 
@@ -156,40 +19,17 @@ struct pmic_typec_port_irq_params {
 
 struct pmic_typec_port_resources {
        unsigned int                            nr_irqs;
-       struct pmic_typec_port_irq_params       irq_params[PMIC_TYPEC_MAX_IRQS];
+       const struct pmic_typec_port_irq_params irq_params[PMIC_TYPEC_MAX_IRQS];
 };
 
 /* API */
-struct pmic_typec;
 
-struct pmic_typec_port *qcom_pmic_typec_port_alloc(struct device *dev);
+extern const struct pmic_typec_port_resources pm8150b_port_res;
 
 int qcom_pmic_typec_port_probe(struct platform_device *pdev,
-                              struct pmic_typec_port *pmic_typec_port,
-                              struct pmic_typec_port_resources *res,
+                              struct pmic_typec *tcpm,
+                              const struct pmic_typec_port_resources *res,
                               struct regmap *regmap,
                               u32 base);
 
-int qcom_pmic_typec_port_start(struct pmic_typec_port *pmic_typec_port,
-                              struct tcpm_port *tcpm_port);
-
-void qcom_pmic_typec_port_stop(struct pmic_typec_port *pmic_typec_port);
-
-int qcom_pmic_typec_port_get_cc(struct pmic_typec_port *pmic_typec_port,
-                               enum typec_cc_status *cc1,
-                               enum typec_cc_status *cc2);
-
-int qcom_pmic_typec_port_set_cc(struct pmic_typec_port *pmic_typec_port,
-                               enum typec_cc_status cc);
-
-int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port);
-
-int qcom_pmic_typec_port_set_vconn(struct pmic_typec_port *pmic_typec_port, bool on);
-
-int qcom_pmic_typec_port_start_toggling(struct pmic_typec_port *pmic_typec_port,
-                                       enum typec_port_type port_type,
-                                       enum typec_cc_status cc);
-
-int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool on);
-
 #endif /* __QCOM_PMIC_TYPE_C_PORT_H__ */
index 0ee3e6e29bb178418dbcfb60c3d5eaeb542245da..c962014bba4e85e8585f2e2ab6677ef8b4d9b34f 100644 (file)
@@ -445,8 +445,11 @@ static int tcpci_set_pd_rx(struct tcpc_dev *tcpc, bool enable)
        unsigned int reg = 0;
        int ret;
 
-       if (enable)
+       if (enable) {
                reg = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET;
+               if (tcpci->data->cable_comm_capable)
+                       reg |= TCPC_RX_DETECT_SOP1;
+       }
        ret = regmap_write(tcpci->regmap, TCPC_RX_DETECT, reg);
        if (ret < 0)
                return ret;
@@ -584,6 +587,23 @@ static int tcpci_pd_transmit(struct tcpc_dev *tcpc, enum tcpm_transmit_type type
        return 0;
 }
 
+static bool tcpci_cable_comm_capable(struct tcpc_dev *tcpc)
+{
+       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+
+       return tcpci->data->cable_comm_capable;
+}
+
+static bool tcpci_attempt_vconn_swap_discovery(struct tcpc_dev *tcpc)
+{
+       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+
+       if (tcpci->data->attempt_vconn_swap_discovery)
+               return tcpci->data->attempt_vconn_swap_discovery(tcpci, tcpci->data);
+
+       return false;
+}
+
 static int tcpci_init(struct tcpc_dev *tcpc)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -712,7 +732,7 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
                /* Read complete, clear RX status alert bit */
                tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
 
-               tcpm_pd_receive(tcpci->port, &msg);
+               tcpm_pd_receive(tcpci->port, &msg, TCPC_TX_SOP);
        }
 
        if (tcpci->data->vbus_vsafe0v && (status & TCPC_ALERT_EXTENDED_STATUS)) {
@@ -793,6 +813,8 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
        tcpci->tcpc.enable_frs = tcpci_enable_frs;
        tcpci->tcpc.frs_sourcing_vbus = tcpci_frs_sourcing_vbus;
        tcpci->tcpc.set_partner_usb_comm_capable = tcpci_set_partner_usb_comm_capable;
+       tcpci->tcpc.cable_comm_capable = tcpci_cable_comm_capable;
+       tcpci->tcpc.attempt_vconn_swap_discovery = tcpci_attempt_vconn_swap_discovery;
 
        if (tcpci->data->check_contaminant)
                tcpci->tcpc.check_contaminant = tcpci_check_contaminant;
@@ -889,6 +911,7 @@ MODULE_DEVICE_TABLE(i2c, tcpci_id);
 #ifdef CONFIG_OF
 static const struct of_device_id tcpci_of_match[] = {
        { .compatible = "nxp,ptn5110", },
+       { .compatible = "tcpci", },
        {},
 };
 MODULE_DEVICE_TABLE(of, tcpci_of_match);
index 2c1c4d161b0dcbcdaadb7616b59ef94e281b6ecf..78ff3b73ee7e3c623386ecd35264454ab857c15a 100644 (file)
@@ -62,6 +62,7 @@ struct max_tcpci_chip {
        struct i2c_client *client;
        struct tcpm_port *port;
        enum contamiant_state contaminant_state;
+       bool veto_vconn_swap;
 };
 
 static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
index 7fb966fd639b32296f443a8701e4968c5084bad5..eec3bcec119c1a8c207f0e0b5d9d128625758d70 100644 (file)
@@ -128,6 +128,7 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
        u8 count, frame_type, rx_buf[TCPC_RECEIVE_BUFFER_LEN];
        int ret, payload_index;
        u8 *rx_buf_ptr;
+       enum tcpm_transmit_type rx_type;
 
        /*
         * READABLE_BYTE_COUNT: Indicates the number of bytes in the RX_BUF_BYTE_x registers
@@ -143,10 +144,23 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
        count = rx_buf[TCPC_RECEIVE_BUFFER_COUNT_OFFSET];
        frame_type = rx_buf[TCPC_RECEIVE_BUFFER_FRAME_TYPE_OFFSET];
 
-       if (count == 0 || frame_type != TCPC_RX_BUF_FRAME_TYPE_SOP) {
+       switch (frame_type) {
+       case TCPC_RX_BUF_FRAME_TYPE_SOP1:
+               rx_type = TCPC_TX_SOP_PRIME;
+               break;
+       case TCPC_RX_BUF_FRAME_TYPE_SOP:
+               rx_type = TCPC_TX_SOP;
+               break;
+       default:
+               rx_type = TCPC_TX_SOP;
+               break;
+       }
+
+       if (count == 0 || (frame_type != TCPC_RX_BUF_FRAME_TYPE_SOP &&
+           frame_type != TCPC_RX_BUF_FRAME_TYPE_SOP1)) {
                max_tcpci_write16(chip, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
                dev_err(chip->dev, "%s\n", count ==  0 ? "error: count is 0" :
-                       "error frame_type is not SOP");
+                       "error frame_type is not SOP/SOP'");
                return;
        }
 
@@ -183,7 +197,7 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
        if (ret < 0)
                return;
 
-       tcpm_pd_receive(chip->port, &msg);
+       tcpm_pd_receive(chip->port, &msg, rx_type);
 }
 
 static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink)
@@ -309,8 +323,10 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
                if (ret < 0)
                        return ret;
 
-               if (reg_status & TCPC_FAULT_STATUS_VCONN_OC)
+               if (reg_status & TCPC_FAULT_STATUS_VCONN_OC) {
+                       chip->veto_vconn_swap = true;
                        tcpm_port_error_recovery(chip->port);
+               }
        }
 
        if (status & TCPC_ALERT_EXTND) {
@@ -444,6 +460,18 @@ static void max_tcpci_check_contaminant(struct tcpci *tcpci, struct tcpci_data *
                tcpm_port_clean(chip->port);
 }
 
+static bool max_tcpci_attempt_vconn_swap_discovery(struct tcpci *tcpci, struct tcpci_data *tdata)
+{
+       struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
+
+       if (chip->veto_vconn_swap) {
+               chip->veto_vconn_swap = false;
+               return false;
+       }
+
+       return true;
+}
+
 static int max_tcpci_probe(struct i2c_client *client)
 {
        int ret;
@@ -478,6 +506,8 @@ static int max_tcpci_probe(struct i2c_client *client)
        chip->data.vbus_vsafe0v = true;
        chip->data.set_partner_usb_comm_capable = max_tcpci_set_partner_usb_comm_capable;
        chip->data.check_contaminant = max_tcpci_check_contaminant;
+       chip->data.cable_comm_capable = true;
+       chip->data.attempt_vconn_swap_discovery = max_tcpci_attempt_vconn_swap_discovery;
 
        max_tcpci_init_regs(chip);
        chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
index 0965972310275e1c4d82be94051573648175a4fe..ae2b6c94482d5fab23f26be2b12491a52b15419d 100644 (file)
        S(VCONN_SWAP_WAIT_FOR_VCONN),           \
        S(VCONN_SWAP_TURN_ON_VCONN),            \
        S(VCONN_SWAP_TURN_OFF_VCONN),           \
+       S(VCONN_SWAP_SEND_SOFT_RESET),          \
                                                \
        S(FR_SWAP_SEND),                        \
        S(FR_SWAP_SEND_TIMEOUT),                \
        S(PORT_RESET_WAIT_OFF),                 \
                                                \
        S(AMS_START),                           \
-       S(CHUNK_NOT_SUPP)
+       S(CHUNK_NOT_SUPP),                      \
+                                               \
+       S(SRC_VDM_IDENTITY_REQUEST)
 
 #define FOREACH_AMS(S)                         \
        S(NONE_AMS),                            \
@@ -327,6 +330,12 @@ struct tcpm_port {
        struct typec_partner_desc partner_desc;
        struct typec_partner *partner;
 
+       struct usb_pd_identity cable_ident;
+       struct typec_cable_desc cable_desc;
+       struct typec_cable *cable;
+       struct typec_plug_desc plug_prime_desc;
+       struct typec_plug *plug_prime;
+
        enum typec_cc_status cc_req;
        enum typec_cc_status src_rp;    /* work only if pd_supported == false */
 
@@ -468,7 +477,9 @@ struct tcpm_port {
 
        /* Alternate mode data */
        struct pd_mode_data mode_data;
+       struct pd_mode_data mode_data_prime;
        struct typec_altmode *partner_altmode[ALTMODE_DISCOVERY_MAX];
+       struct typec_altmode *plug_prime_altmode[ALTMODE_DISCOVERY_MAX];
        struct typec_altmode *port_altmode[ALTMODE_DISCOVERY_MAX];
 
        /* Deadline in jiffies to exit src_try_wait state */
@@ -505,6 +516,41 @@ struct tcpm_port {
         * transitions.
         */
        bool potential_contaminant;
+
+       /* SOP* Related Fields */
+       /*
+        * Flag to determine if SOP' Discover Identity is available. The flag
+        * is set if Discover Identity on SOP' does not immediately follow
+        * Discover Identity on SOP.
+        */
+       bool send_discover_prime;
+       /*
+        * tx_sop_type determines which SOP* a message is being sent on.
+        * For messages that are queued and not sent immediately such as in
+        * tcpm_queue_message or messages that send after state changes,
+        * the tx_sop_type is set accordingly.
+        */
+       enum tcpm_transmit_type tx_sop_type;
+       /*
+        * Prior to discovering the port partner's Specification Revision, the
+        * Vconn source and cable plug will use the lower of their two revisions.
+        *
+        * When the port partner's Specification Revision is discovered, the following
+        * rules are put in place.
+        *      1. If the cable revision (1) is lower than the revision negotiated
+        * between the port and partner (2), the port and partner will communicate
+        * on revision (2), but the port and cable will communicate on revision (1).
+        *      2. If the cable revision (1) is higher than the revision negotiated
+        * between the port and partner (2), the port and partner will communicate
+        * on revision (2), and the port and cable will communicate on revision (2)
+        * as well.
+        */
+       unsigned int negotiated_rev_prime;
+       /*
+        * Each SOP* type must maintain their own tx and rx message IDs
+        */
+       unsigned int message_id_prime;
+       unsigned int rx_msgid_prime;
 #ifdef CONFIG_DEBUG_FS
        struct dentry *dentry;
        struct mutex logbuffer_lock;    /* log buffer access lock */
@@ -518,6 +564,7 @@ struct pd_rx_event {
        struct kthread_work work;
        struct tcpm_port *port;
        struct pd_message msg;
+       enum tcpm_transmit_type rx_sop_type;
 };
 
 static const char * const pd_rev[] = {
@@ -893,19 +940,30 @@ static void tcpm_ams_finish(struct tcpm_port *port)
 }
 
 static int tcpm_pd_transmit(struct tcpm_port *port,
-                           enum tcpm_transmit_type type,
+                           enum tcpm_transmit_type tx_sop_type,
                            const struct pd_message *msg)
 {
        unsigned long timeout;
        int ret;
+       unsigned int negotiated_rev;
+
+       switch (tx_sop_type) {
+       case TCPC_TX_SOP_PRIME:
+               negotiated_rev = port->negotiated_rev_prime;
+               break;
+       case TCPC_TX_SOP:
+       default:
+               negotiated_rev = port->negotiated_rev;
+               break;
+       }
 
        if (msg)
                tcpm_log(port, "PD TX, header: %#x", le16_to_cpu(msg->header));
        else
-               tcpm_log(port, "PD TX, type: %#x", type);
+               tcpm_log(port, "PD TX, type: %#x", tx_sop_type);
 
        reinit_completion(&port->tx_complete);
-       ret = port->tcpc->pd_transmit(port->tcpc, type, msg, port->negotiated_rev);
+       ret = port->tcpc->pd_transmit(port->tcpc, tx_sop_type, msg, negotiated_rev);
        if (ret < 0)
                return ret;
 
@@ -918,7 +976,17 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
 
        switch (port->tx_status) {
        case TCPC_TX_SUCCESS:
-               port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK;
+               switch (tx_sop_type) {
+               case TCPC_TX_SOP_PRIME:
+                       port->message_id_prime = (port->message_id_prime + 1) &
+                                                PD_HEADER_ID_MASK;
+                       break;
+               case TCPC_TX_SOP:
+               default:
+                       port->message_id = (port->message_id + 1) &
+                                          PD_HEADER_ID_MASK;
+                       break;
+               }
                /*
                 * USB PD rev 2.0, 8.3.2.2.1:
                 * USB PD rev 3.0, 8.3.2.1.3:
@@ -1099,6 +1167,12 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
        if (ret < 0)
                return ret;
 
+       if (port->tcpc->set_orientation) {
+               ret = port->tcpc->set_orientation(port->tcpc, orientation);
+               if (ret < 0)
+                       return ret;
+       }
+
        port->pwr_role = role;
        port->data_role = data;
        typec_set_data_role(port->typec_port, data);
@@ -1456,7 +1530,7 @@ static int tcpm_ams_start(struct tcpm_port *port, enum tcpm_ams ams)
  * VDM/VDO handling functions
  */
 static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
-                          const u32 *data, int cnt)
+                          const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
 {
        u32 vdo_hdr = port->vdo_data[0];
 
@@ -1464,7 +1538,10 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
 
        /* If is sending discover_identity, handle received message first */
        if (PD_VDO_SVDM(vdo_hdr) && PD_VDO_CMD(vdo_hdr) == CMD_DISCOVER_IDENT) {
-               port->send_discover = true;
+               if (tx_sop_type == TCPC_TX_SOP_PRIME)
+                       port->send_discover_prime = true;
+               else
+                       port->send_discover = true;
                mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS);
        } else {
                /* Make sure we are not still processing a previous VDM packet */
@@ -1479,14 +1556,16 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
        port->vdm_state = VDM_STATE_READY;
        port->vdm_sm_running = true;
 
+       port->tx_sop_type = tx_sop_type;
+
        mod_vdm_delayed_work(port, 0);
 }
 
 static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header,
-                                   const u32 *data, int cnt)
+                                   const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type)
 {
        mutex_lock(&port->lock);
-       tcpm_queue_vdm(port, header, data, cnt);
+       tcpm_queue_vdm(port, header, data, cnt, TCPC_TX_SOP);
        mutex_unlock(&port->lock);
 }
 
@@ -1508,9 +1587,68 @@ static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt)
                 PD_PRODUCT_PID(product), product & 0xffff);
 }
 
-static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt)
+static void svdm_consume_identity_sop_prime(struct tcpm_port *port, const u32 *p, int cnt)
 {
-       struct pd_mode_data *pmdata = &port->mode_data;
+       u32 idh = p[VDO_INDEX_IDH];
+       u32 product = p[VDO_INDEX_PRODUCT];
+       int svdm_version;
+
+       /*
+        * Attempt to consume identity only if cable currently is not set
+        */
+       if (!IS_ERR_OR_NULL(port->cable))
+               goto register_plug;
+
+       /* Reset cable identity */
+       memset(&port->cable_ident, 0, sizeof(port->cable_ident));
+
+       /* Fill out id header, cert, product, cable VDO 1 */
+       port->cable_ident.id_header = idh;
+       port->cable_ident.cert_stat = p[VDO_INDEX_CSTAT];
+       port->cable_ident.product = product;
+       port->cable_ident.vdo[0] = p[VDO_INDEX_CABLE_1];
+
+       /* Fill out cable desc, infer svdm_version from pd revision */
+       port->cable_desc.type = (enum typec_plug_type) (VDO_TYPEC_CABLE_TYPE(p[VDO_INDEX_CABLE_1]) +
+                                                       USB_PLUG_TYPE_A);
+       port->cable_desc.active = PD_IDH_PTYPE(idh) == IDH_PTYPE_ACABLE ? 1 : 0;
+       /* Log PD Revision and additional cable VDO from negotiated revision */
+       switch (port->negotiated_rev_prime) {
+       case PD_REV30:
+               port->cable_desc.pd_revision = 0x0300;
+               if (port->cable_desc.active)
+                       port->cable_ident.vdo[1] = p[VDO_INDEX_CABLE_2];
+               break;
+       case PD_REV20:
+               port->cable_desc.pd_revision = 0x0200;
+               break;
+       default:
+               port->cable_desc.pd_revision = 0x0200;
+               break;
+       }
+       port->cable_desc.identity = &port->cable_ident;
+       /* Register Cable, set identity and svdm_version */
+       port->cable = typec_register_cable(port->typec_port, &port->cable_desc);
+       if (IS_ERR_OR_NULL(port->cable))
+               return;
+       typec_cable_set_identity(port->cable);
+       /* Get SVDM version */
+       svdm_version = PD_VDO_SVDM_VER(p[VDO_INDEX_HDR]);
+       typec_cable_set_svdm_version(port->cable, svdm_version);
+
+register_plug:
+       if (IS_ERR_OR_NULL(port->plug_prime)) {
+               port->plug_prime_desc.index = TYPEC_PLUG_SOP_P;
+               port->plug_prime = typec_register_plug(port->cable,
+                                                      &port->plug_prime_desc);
+       }
+}
+
+static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt,
+                              enum tcpm_transmit_type rx_sop_type)
+{
+       struct pd_mode_data *pmdata = rx_sop_type == TCPC_TX_SOP_PRIME ?
+                                     &port->mode_data_prime : &port->mode_data;
        int i;
 
        for (i = 1; i < cnt; i++) {
@@ -1556,14 +1694,29 @@ abort:
        return false;
 }
 
-static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt)
+static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt,
+                              enum tcpm_transmit_type rx_sop_type)
 {
        struct pd_mode_data *pmdata = &port->mode_data;
        struct typec_altmode_desc *paltmode;
        int i;
 
-       if (pmdata->altmodes >= ARRAY_SIZE(port->partner_altmode)) {
-               /* Already logged in svdm_consume_svids() */
+       switch (rx_sop_type) {
+       case TCPC_TX_SOP_PRIME:
+               pmdata = &port->mode_data_prime;
+               if (pmdata->altmodes >= ARRAY_SIZE(port->plug_prime_altmode)) {
+                       /* Already logged in svdm_consume_svids() */
+                       return;
+               }
+               break;
+       case TCPC_TX_SOP:
+               pmdata = &port->mode_data;
+               if (pmdata->altmodes >= ARRAY_SIZE(port->partner_altmode)) {
+                       /* Already logged in svdm_consume_svids() */
+                       return;
+               }
+               break;
+       default:
                return;
        }
 
@@ -1601,20 +1754,129 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
        }
 }
 
+static void tcpm_register_plug_altmodes(struct tcpm_port *port)
+{
+       struct pd_mode_data *modep = &port->mode_data_prime;
+       struct typec_altmode *altmode;
+       int i;
+
+       typec_plug_set_num_altmodes(port->plug_prime, modep->altmodes);
+
+       for (i = 0; i < modep->altmodes; i++) {
+               altmode = typec_plug_register_altmode(port->plug_prime,
+                                               &modep->altmode_desc[i]);
+               if (IS_ERR(altmode)) {
+                       tcpm_log(port, "Failed to register plug SVID 0x%04x",
+                                modep->altmode_desc[i].svid);
+                       altmode = NULL;
+               }
+               port->plug_prime_altmode[i] = altmode;
+       }
+}
+
 #define supports_modal(port)   PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
+#define supports_modal_cable(port)     PD_IDH_MODAL_SUPP((port)->cable_ident.id_header)
+#define supports_host(port)    PD_IDH_HOST_SUPP((port->partner_ident.id_header))
+
+/*
+ * Helper to determine whether the port is capable of SOP' communication at the
+ * current point in time.
+ */
+static bool tcpm_can_communicate_sop_prime(struct tcpm_port *port)
+{
+       /* Check to see if tcpc supports SOP' communication */
+       if (!port->tcpc->cable_comm_capable || !port->tcpc->cable_comm_capable(port->tcpc))
+               return false;
+       /*
+        * Power Delivery 2.0 Section 6.3.11
+        * Before communicating with a Cable Plug a Port Should ensure that it
+        * is the Vconn Source and that the Cable Plugs are powered by
+        * performing a Vconn swap if necessary. Since it cannot be guaranteed
+        * that the present Vconn Source is supplying Vconn, the only means to
+        * ensure that the Cable Plugs are powered is for a Port wishing to
+        * communicate with a Cable Plug is to become the Vconn Source.
+        *
+        * Power Delivery 3.0 Section 6.3.11
+        * Before communicating with a Cable Plug a Port Shall ensure that it
+        * is the Vconn source.
+        */
+       if (port->vconn_role != TYPEC_SOURCE)
+               return false;
+       /*
+        * Power Delivery 2.0 Section 2.4.4
+        * When no Contract or an Implicit Contract is in place the Source can
+        * communicate with a Cable Plug using SOP' packets in order to discover
+        * its characteristics.
+        *
+        * Power Delivery 3.0 Section 2.4.4
+        * When no Contract or an Implicit Contract is in place only the Source
+        * port that is supplying Vconn is allowed to send packets to a Cable
+        * Plug and is allowed to respond to packets from the Cable Plug.
+        */
+       if (!port->explicit_contract)
+               return port->pwr_role == TYPEC_SOURCE;
+       if (port->negotiated_rev == PD_REV30)
+               return true;
+       /*
+        * Power Delivery 2.0 Section 2.4.4
+        *
+        * When an Explicit Contract is in place the DFP (either the Source or
+        * the Sink) can communicate with the Cable Plug(s) using SOP’/SOP”
+        * Packets (see Figure 2-3).
+        */
+       if (port->negotiated_rev == PD_REV20)
+               return port->data_role == TYPEC_HOST;
+       return false;
+}
+
+static bool tcpm_attempt_vconn_swap_discovery(struct tcpm_port *port)
+{
+       if (!port->tcpc->attempt_vconn_swap_discovery)
+               return false;
+
+       /* Port is already source, no need to perform swap */
+       if (port->vconn_role == TYPEC_SOURCE)
+               return false;
+
+       /*
+        * Partner needs to support Alternate Modes with modal support. If
+        * partner is also capable of being a USB Host, it could be a device
+        * that supports Alternate Modes as the DFP.
+        */
+       if (!supports_modal(port) || supports_host(port))
+               return false;
+
+       if ((port->negotiated_rev == PD_REV20 && port->data_role == TYPEC_HOST) ||
+           port->negotiated_rev == PD_REV30)
+               return port->tcpc->attempt_vconn_swap_discovery(port->tcpc);
+
+       return false;
+}
+
+
+static bool tcpm_cable_vdm_supported(struct tcpm_port *port)
+{
+       return !IS_ERR_OR_NULL(port->cable) &&
+              typec_cable_is_active(port->cable) &&
+              supports_modal_cable(port) &&
+              tcpm_can_communicate_sop_prime(port);
+}
 
 static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
                        const u32 *p, int cnt, u32 *response,
-                       enum adev_actions *adev_action)
+                       enum adev_actions *adev_action,
+                       enum tcpm_transmit_type rx_sop_type,
+                       enum tcpm_transmit_type *response_tx_sop_type)
 {
        struct typec_port *typec = port->typec_port;
-       struct typec_altmode *pdev;
-       struct pd_mode_data *modep;
+       struct typec_altmode *pdev, *pdev_prime;
+       struct pd_mode_data *modep, *modep_prime;
        int svdm_version;
        int rlen = 0;
        int cmd_type;
        int cmd;
        int i;
+       int ret;
 
        cmd_type = PD_VDO_CMDT(p[0]);
        cmd = PD_VDO_CMD(p[0]);
@@ -1622,17 +1884,54 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
        tcpm_log(port, "Rx VDM cmd 0x%x type %d cmd %d len %d",
                 p[0], cmd_type, cmd, cnt);
 
-       modep = &port->mode_data;
-
-       pdev = typec_match_altmode(port->partner_altmode, ALTMODE_DISCOVERY_MAX,
-                                  PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0]));
-
-       svdm_version = typec_get_negotiated_svdm_version(typec);
-       if (svdm_version < 0)
-               return 0;
+       switch (rx_sop_type) {
+       case TCPC_TX_SOP_PRIME:
+               modep_prime = &port->mode_data_prime;
+               pdev_prime = typec_match_altmode(port->plug_prime_altmode,
+                                                ALTMODE_DISCOVERY_MAX,
+                                                PD_VDO_VID(p[0]),
+                                                PD_VDO_OPOS(p[0]));
+               svdm_version = typec_get_cable_svdm_version(typec);
+               /*
+                * Update SVDM version if cable was discovered before port partner.
+                */
+               if (!IS_ERR_OR_NULL(port->cable) &&
+                   PD_VDO_SVDM_VER(p[0]) < svdm_version)
+                       typec_cable_set_svdm_version(port->cable, svdm_version);
+               break;
+       case TCPC_TX_SOP:
+               modep = &port->mode_data;
+               pdev = typec_match_altmode(port->partner_altmode,
+                                          ALTMODE_DISCOVERY_MAX,
+                                          PD_VDO_VID(p[0]),
+                                          PD_VDO_OPOS(p[0]));
+               svdm_version = typec_get_negotiated_svdm_version(typec);
+               if (svdm_version < 0)
+                       return 0;
+               break;
+       default:
+               modep = &port->mode_data;
+               pdev = typec_match_altmode(port->partner_altmode,
+                                          ALTMODE_DISCOVERY_MAX,
+                                          PD_VDO_VID(p[0]),
+                                          PD_VDO_OPOS(p[0]));
+               svdm_version = typec_get_negotiated_svdm_version(typec);
+               if (svdm_version < 0)
+                       return 0;
+               break;
+       }
 
        switch (cmd_type) {
        case CMDT_INIT:
+               /*
+                * Only the port or port partner is allowed to initialize SVDM
+                * commands over SOP'. In case the port partner initializes a
+                * sequence when it is not allowed to send SOP' messages, drop
+                * the message should the TCPM port try to process it.
+                */
+               if (rx_sop_type == TCPC_TX_SOP_PRIME)
+                       return 0;
+
                switch (cmd) {
                case CMD_DISCOVER_IDENT:
                        if (PD_VDO_VID(p[0]) != USB_SID_PD)
@@ -1699,55 +1998,186 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
                              (VDO_SVDM_VERS(typec_get_negotiated_svdm_version(typec)));
                break;
        case CMDT_RSP_ACK:
-               /* silently drop message if we are not connected */
-               if (IS_ERR_OR_NULL(port->partner))
+               /*
+                * Silently drop message if we are not connected, but can process
+                * if SOP' Discover Identity prior to explicit contract.
+                */
+               if (IS_ERR_OR_NULL(port->partner) &&
+                   !(rx_sop_type == TCPC_TX_SOP_PRIME && cmd == CMD_DISCOVER_IDENT))
                        break;
 
                tcpm_ams_finish(port);
 
                switch (cmd) {
+               /*
+                * SVDM Command Flow for SOP and SOP':
+                * SOP          Discover Identity
+                * SOP'         Discover Identity
+                * SOP          Discover SVIDs
+                *              Discover Modes
+                * (Active Cables)
+                * SOP'         Discover SVIDs
+                *              Discover Modes
+                *
+                * Perform Discover SOP' if the port can communicate with cable
+                * plug.
+                */
                case CMD_DISCOVER_IDENT:
-                       if (PD_VDO_SVDM_VER(p[0]) < svdm_version)
-                               typec_partner_set_svdm_version(port->partner,
-                                                              PD_VDO_SVDM_VER(p[0]));
-                       /* 6.4.4.3.1 */
-                       svdm_consume_identity(port, p, cnt);
-                       response[0] = VDO(USB_SID_PD, 1, typec_get_negotiated_svdm_version(typec),
-                                         CMD_DISCOVER_SVID);
-                       rlen = 1;
+                       switch (rx_sop_type) {
+                       case TCPC_TX_SOP:
+                               if (PD_VDO_SVDM_VER(p[0]) < svdm_version) {
+                                       typec_partner_set_svdm_version(port->partner,
+                                                                      PD_VDO_SVDM_VER(p[0]));
+                                       /* If cable is discovered before partner, downgrade svdm */
+                                       if (!IS_ERR_OR_NULL(port->cable) &&
+                                           (typec_get_cable_svdm_version(port->typec_port) >
+                                           svdm_version))
+                                               typec_cable_set_svdm_version(port->cable,
+                                                                            svdm_version);
+                               }
+                               /* 6.4.4.3.1 */
+                               svdm_consume_identity(port, p, cnt);
+                               /* Attempt Vconn swap, delay SOP' discovery if necessary */
+                               if (tcpm_attempt_vconn_swap_discovery(port)) {
+                                       port->send_discover_prime = true;
+                                       port->upcoming_state = VCONN_SWAP_SEND;
+                                       ret = tcpm_ams_start(port, VCONN_SWAP);
+                                       if (!ret)
+                                               return 0;
+                                       /* Cannot perform Vconn swap */
+                                       port->upcoming_state = INVALID_STATE;
+                                       port->send_discover_prime = false;
+                               }
+
+                               /*
+                                * Attempt Discover Identity on SOP' if the
+                                * cable was not discovered previously, and use
+                                * the SVDM version of the partner to probe.
+                                */
+                               if (IS_ERR_OR_NULL(port->cable) &&
+                                   tcpm_can_communicate_sop_prime(port)) {
+                                       *response_tx_sop_type = TCPC_TX_SOP_PRIME;
+                                       port->send_discover_prime = true;
+                                       response[0] = VDO(USB_SID_PD, 1,
+                                                         typec_get_negotiated_svdm_version(typec),
+                                                         CMD_DISCOVER_IDENT);
+                                       rlen = 1;
+                               } else {
+                                       *response_tx_sop_type = TCPC_TX_SOP;
+                                       response[0] = VDO(USB_SID_PD, 1,
+                                                         typec_get_negotiated_svdm_version(typec),
+                                                         CMD_DISCOVER_SVID);
+                                       rlen = 1;
+                               }
+                               break;
+                       case TCPC_TX_SOP_PRIME:
+                               /*
+                                * svdm_consume_identity_sop_prime will determine
+                                * the svdm_version for the cable moving forward.
+                                */
+                               svdm_consume_identity_sop_prime(port, p, cnt);
+
+                               /*
+                                * If received in SRC_VDM_IDENTITY_REQUEST, continue
+                                * to SRC_SEND_CAPABILITIES
+                                */
+                               if (port->state == SRC_VDM_IDENTITY_REQUEST) {
+                                       tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+                                       return 0;
+                               }
+
+                               *response_tx_sop_type = TCPC_TX_SOP;
+                               response[0] = VDO(USB_SID_PD, 1,
+                                                 typec_get_negotiated_svdm_version(typec),
+                                                 CMD_DISCOVER_SVID);
+                               rlen = 1;
+                               break;
+                       default:
+                               return 0;
+                       }
                        break;
                case CMD_DISCOVER_SVID:
+                       *response_tx_sop_type = rx_sop_type;
                        /* 6.4.4.3.2 */
-                       if (svdm_consume_svids(port, p, cnt)) {
+                       if (svdm_consume_svids(port, p, cnt, rx_sop_type)) {
                                response[0] = VDO(USB_SID_PD, 1, svdm_version, CMD_DISCOVER_SVID);
                                rlen = 1;
-                       } else if (modep->nsvids && supports_modal(port)) {
-                               response[0] = VDO(modep->svids[0], 1, svdm_version,
-                                                 CMD_DISCOVER_MODES);
-                               rlen = 1;
+                       } else {
+                               if (rx_sop_type == TCPC_TX_SOP) {
+                                       if (modep->nsvids && supports_modal(port)) {
+                                               response[0] = VDO(modep->svids[0], 1, svdm_version,
+                                                               CMD_DISCOVER_MODES);
+                                               rlen = 1;
+                                       }
+                               } else if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+                                       if (modep_prime->nsvids) {
+                                               response[0] = VDO(modep_prime->svids[0], 1,
+                                                                 svdm_version, CMD_DISCOVER_MODES);
+                                               rlen = 1;
+                                       }
+                               }
                        }
                        break;
                case CMD_DISCOVER_MODES:
-                       /* 6.4.4.3.3 */
-                       svdm_consume_modes(port, p, cnt);
-                       modep->svid_index++;
-                       if (modep->svid_index < modep->nsvids) {
-                               u16 svid = modep->svids[modep->svid_index];
-                               response[0] = VDO(svid, 1, svdm_version, CMD_DISCOVER_MODES);
-                               rlen = 1;
-                       } else {
-                               tcpm_register_partner_altmodes(port);
+                       if (rx_sop_type == TCPC_TX_SOP) {
+                               /* 6.4.4.3.3 */
+                               svdm_consume_modes(port, p, cnt, rx_sop_type);
+                               modep->svid_index++;
+                               if (modep->svid_index < modep->nsvids) {
+                                       u16 svid = modep->svids[modep->svid_index];
+                                       *response_tx_sop_type = TCPC_TX_SOP;
+                                       response[0] = VDO(svid, 1, svdm_version,
+                                                         CMD_DISCOVER_MODES);
+                                       rlen = 1;
+                               } else if (tcpm_cable_vdm_supported(port)) {
+                                       *response_tx_sop_type = TCPC_TX_SOP_PRIME;
+                                       response[0] = VDO(USB_SID_PD, 1,
+                                                         typec_get_cable_svdm_version(typec),
+                                                         CMD_DISCOVER_SVID);
+                                       rlen = 1;
+                               } else {
+                                       tcpm_register_partner_altmodes(port);
+                               }
+                       } else if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+                               /* 6.4.4.3.3 */
+                               svdm_consume_modes(port, p, cnt, rx_sop_type);
+                               modep_prime->svid_index++;
+                               if (modep_prime->svid_index < modep_prime->nsvids) {
+                                       u16 svid = modep_prime->svids[modep_prime->svid_index];
+                                       *response_tx_sop_type = TCPC_TX_SOP_PRIME;
+                                       response[0] = VDO(svid, 1,
+                                                         typec_get_cable_svdm_version(typec),
+                                                         CMD_DISCOVER_MODES);
+                                       rlen = 1;
+                               } else {
+                                       tcpm_register_plug_altmodes(port);
+                                       tcpm_register_partner_altmodes(port);
+                               }
                        }
                        break;
                case CMD_ENTER_MODE:
-                       if (adev && pdev)
-                               *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
+                       *response_tx_sop_type = rx_sop_type;
+                       if (rx_sop_type == TCPC_TX_SOP) {
+                               if (adev && pdev) {
+                                       typec_altmode_update_active(pdev, true);
+                                       *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
+                               }
+                       } else if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+                               if (adev && pdev_prime) {
+                                       typec_altmode_update_active(pdev_prime, true);
+                                       *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL;
+                               }
+                       }
                        return 0;
                case CMD_EXIT_MODE:
-                       if (adev && pdev) {
-                               /* Back to USB Operation */
-                               *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
-                               return 0;
+                       *response_tx_sop_type = rx_sop_type;
+                       if (rx_sop_type == TCPC_TX_SOP) {
+                               if (adev && pdev) {
+                                       typec_altmode_update_active(pdev, false);
+                                       /* Back to USB Operation */
+                                       *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM;
+                                       return 0;
+                               }
                        }
                        break;
                case VDO_CMD_VENDOR(0) ... VDO_CMD_VENDOR(15):
@@ -1800,13 +2230,15 @@ static void tcpm_pd_handle_msg(struct tcpm_port *port,
                               enum tcpm_ams ams);
 
 static void tcpm_handle_vdm_request(struct tcpm_port *port,
-                                   const __le32 *payload, int cnt)
+                                   const __le32 *payload, int cnt,
+                                   enum tcpm_transmit_type rx_sop_type)
 {
        enum adev_actions adev_action = ADEV_NONE;
        struct typec_altmode *adev;
        u32 p[PD_MAX_PAYLOAD];
        u32 response[8] = { };
        int i, rlen = 0;
+       enum tcpm_transmit_type response_tx_sop_type = TCPC_TX_SOP;
 
        for (i = 0; i < cnt; i++)
                p[i] = le32_to_cpu(payload[i]);
@@ -1841,7 +2273,8 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
                 *  - We will send NAK and the flag will be cleared in the state machine.
                 */
                port->vdm_sm_running = true;
-               rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action);
+               rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action,
+                                   rx_sop_type, &response_tx_sop_type);
        } else {
                if (port->negotiated_rev >= PD_REV30)
                        tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS);
@@ -1877,19 +2310,37 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
                        typec_altmode_vdm(adev, p[0], &p[1], cnt);
                        break;
                case ADEV_QUEUE_VDM:
-                       typec_altmode_vdm(adev, p[0], &p[1], cnt);
+                       if (response_tx_sop_type == TCPC_TX_SOP_PRIME)
+                               typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt);
+                       else
+                               typec_altmode_vdm(adev, p[0], &p[1], cnt);
                        break;
                case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL:
-                       if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
-                               int svdm_version = typec_get_negotiated_svdm_version(
-                                                                       port->typec_port);
-                               if (svdm_version < 0)
-                                       break;
-
-                               response[0] = VDO(adev->svid, 1, svdm_version,
-                                                 CMD_EXIT_MODE);
-                               response[0] |= VDO_OPOS(adev->mode);
-                               rlen = 1;
+                       if (response_tx_sop_type == TCPC_TX_SOP_PRIME) {
+                               if (typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P,
+                                                           p[0], &p[1], cnt)) {
+                                       int svdm_version = typec_get_cable_svdm_version(
+                                                                               port->typec_port);
+                                       if (svdm_version < 0)
+                                               break;
+
+                                       response[0] = VDO(adev->svid, 1, svdm_version,
+                                                       CMD_EXIT_MODE);
+                                       response[0] |= VDO_OPOS(adev->mode);
+                                       rlen = 1;
+                               }
+                       } else {
+                               if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
+                                       int svdm_version = typec_get_negotiated_svdm_version(
+                                                                               port->typec_port);
+                                       if (svdm_version < 0)
+                                               break;
+
+                                       response[0] = VDO(adev->svid, 1, svdm_version,
+                                                       CMD_EXIT_MODE);
+                                       response[0] |= VDO_OPOS(adev->mode);
+                                       rlen = 1;
+                               }
                        }
                        break;
                case ADEV_ATTENTION:
@@ -1909,19 +2360,38 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
        mutex_lock(&port->lock);
 
        if (rlen > 0)
-               tcpm_queue_vdm(port, response[0], &response[1], rlen - 1);
+               tcpm_queue_vdm(port, response[0], &response[1], rlen - 1, response_tx_sop_type);
        else
                port->vdm_sm_running = false;
 }
 
 static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd,
-                         const u32 *data, int count)
+                         const u32 *data, int count, enum tcpm_transmit_type tx_sop_type)
 {
-       int svdm_version = typec_get_negotiated_svdm_version(port->typec_port);
+       int svdm_version;
        u32 header;
 
-       if (svdm_version < 0)
-               return;
+       switch (tx_sop_type) {
+       case TCPC_TX_SOP_PRIME:
+               /*
+                * If the port partner is discovered, then the port partner's
+                * SVDM Version will be returned
+                */
+               svdm_version = typec_get_cable_svdm_version(port->typec_port);
+               if (svdm_version < 0)
+                       svdm_version = SVDM_VER_MAX;
+               break;
+       case TCPC_TX_SOP:
+               svdm_version = typec_get_negotiated_svdm_version(port->typec_port);
+               if (svdm_version < 0)
+                       return;
+               break;
+       default:
+               svdm_version = typec_get_negotiated_svdm_version(port->typec_port);
+               if (svdm_version < 0)
+                       return;
+               break;
+       }
 
        if (WARN_ON(count > VDO_MAX_SIZE - 1))
                count = VDO_MAX_SIZE - 1;
@@ -1930,7 +2400,7 @@ static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd,
        header = VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ?
                        1 : (PD_VDO_CMD(cmd) <= CMD_ATTENTION),
                        svdm_version, cmd);
-       tcpm_queue_vdm(port, header, data, count);
+       tcpm_queue_vdm(port, header, data, count, tx_sop_type);
 }
 
 static unsigned int vdm_ready_timeout(u32 vdm_hdr)
@@ -1964,6 +2434,7 @@ static void vdm_run_state_machine(struct tcpm_port *port)
        struct pd_message msg;
        int i, res = 0;
        u32 vdo_hdr = port->vdo_data[0];
+       u32 response[8] = { };
 
        switch (port->vdm_state) {
        case VDM_STATE_READY:
@@ -1977,7 +2448,8 @@ static void vdm_run_state_machine(struct tcpm_port *port)
                 * if there's traffic or we're not in PDO ready state don't send
                 * a VDM.
                 */
-               if (port->state != SRC_READY && port->state != SNK_READY) {
+               if (port->state != SRC_READY && port->state != SNK_READY &&
+                   port->state != SRC_VDM_IDENTITY_REQUEST) {
                        port->vdm_sm_running = false;
                        break;
                }
@@ -1988,7 +2460,17 @@ static void vdm_run_state_machine(struct tcpm_port *port)
                        case CMD_DISCOVER_IDENT:
                                res = tcpm_ams_start(port, DISCOVER_IDENTITY);
                                if (res == 0) {
-                                       port->send_discover = false;
+                                       switch (port->tx_sop_type) {
+                                       case TCPC_TX_SOP_PRIME:
+                                               port->send_discover_prime = false;
+                                               break;
+                                       case TCPC_TX_SOP:
+                                               port->send_discover = false;
+                                               break;
+                                       default:
+                                               port->send_discover = false;
+                                               break;
+                                       }
                                } else if (res == -EAGAIN) {
                                        port->vdo_data[0] = 0;
                                        mod_send_discover_delayed_work(port,
@@ -2043,13 +2525,22 @@ static void vdm_run_state_machine(struct tcpm_port *port)
                        tcpm_ams_finish(port);
                break;
        case VDM_STATE_ERR_SEND:
+               /*
+                * When sending Discover Identity to SOP' before establishing an
+                * explicit contract, do not retry. Instead, weave sending
+                * Source_Capabilities over SOP and Discover Identity over SOP'.
+                */
+               if (port->state == SRC_VDM_IDENTITY_REQUEST) {
+                       tcpm_ams_finish(port);
+                       port->vdm_state = VDM_STATE_DONE;
+                       tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
                /*
                 * A partner which does not support USB PD will not reply,
                 * so this is not a fatal error. At the same time, some
                 * devices may not return GoodCRC under some circumstances,
                 * so we need to retry.
                 */
-               if (port->vdm_retries < 3) {
+               } else if (port->vdm_retries < 3) {
                        tcpm_log(port, "VDM Tx error, retry");
                        port->vdm_retries++;
                        port->vdm_state = VDM_STATE_READY;
@@ -2057,19 +2548,59 @@ static void vdm_run_state_machine(struct tcpm_port *port)
                                tcpm_ams_finish(port);
                } else {
                        tcpm_ams_finish(port);
+                       if (port->tx_sop_type == TCPC_TX_SOP)
+                               break;
+                       /* Handle SOP' Transmission Errors */
+                       switch (PD_VDO_CMD(vdo_hdr)) {
+                       /*
+                        * If Discover Identity fails on SOP', then resume
+                        * discovery process on SOP only.
+                        */
+                       case CMD_DISCOVER_IDENT:
+                               port->vdo_data[0] = 0;
+                               response[0] = VDO(USB_SID_PD, 1,
+                                                 typec_get_negotiated_svdm_version(
+                                                                       port->typec_port),
+                                                 CMD_DISCOVER_SVID);
+                               tcpm_queue_vdm(port, response[0], &response[1],
+                                              0, TCPC_TX_SOP);
+                               break;
+                       /*
+                        * If Discover SVIDs or Discover Modes fail, then
+                        * proceed with Alt Mode discovery process on SOP.
+                        */
+                       case CMD_DISCOVER_SVID:
+                               tcpm_register_partner_altmodes(port);
+                               break;
+                       case CMD_DISCOVER_MODES:
+                               tcpm_register_partner_altmodes(port);
+                               break;
+                       default:
+                               break;
+                       }
                }
                break;
        case VDM_STATE_SEND_MESSAGE:
                /* Prepare and send VDM */
                memset(&msg, 0, sizeof(msg));
-               msg.header = PD_HEADER_LE(PD_DATA_VENDOR_DEF,
-                                         port->pwr_role,
-                                         port->data_role,
-                                         port->negotiated_rev,
-                                         port->message_id, port->vdo_count);
+               if (port->tx_sop_type == TCPC_TX_SOP_PRIME) {
+                       msg.header = PD_HEADER_LE(PD_DATA_VENDOR_DEF,
+                                                 0,    /* Cable Plug Indicator for DFP/UFP */
+                                                 0,    /* Reserved */
+                                                 port->negotiated_rev_prime,
+                                                 port->message_id_prime,
+                                                 port->vdo_count);
+               } else {
+                       msg.header = PD_HEADER_LE(PD_DATA_VENDOR_DEF,
+                                                 port->pwr_role,
+                                                 port->data_role,
+                                                 port->negotiated_rev,
+                                                 port->message_id,
+                                                 port->vdo_count);
+               }
                for (i = 0; i < port->vdo_count; i++)
                        msg.payload[i] = cpu_to_le32(port->vdo_data[i]);
-               res = tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+               res = tcpm_pd_transmit(port, port->tx_sop_type, &msg);
                if (res < 0) {
                        port->vdm_state = VDM_STATE_ERR_SEND;
                } else {
@@ -2244,7 +2775,7 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo)
        header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
        header |= VDO_OPOS(altmode->mode);
 
-       tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0);
+       tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP);
        return 0;
 }
 
@@ -2261,7 +2792,7 @@ static int tcpm_altmode_exit(struct typec_altmode *altmode)
        header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE);
        header |= VDO_OPOS(altmode->mode);
 
-       tcpm_queue_vdm_unlocked(port, header, NULL, 0);
+       tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP);
        return 0;
 }
 
@@ -2270,7 +2801,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode,
 {
        struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
 
-       tcpm_queue_vdm_unlocked(port, header, data, count - 1);
+       tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP);
 
        return 0;
 }
@@ -2281,6 +2812,58 @@ static const struct typec_altmode_ops tcpm_altmode_ops = {
        .vdm = tcpm_altmode_vdm,
 };
 
+
+static int tcpm_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop,
+                                   u32 *vdo)
+{
+       struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
+       int svdm_version;
+       u32 header;
+
+       svdm_version = typec_get_cable_svdm_version(port->typec_port);
+       if (svdm_version < 0)
+               return svdm_version;
+
+       header = VDO(altmode->svid, vdo ? 2 : 1, svdm_version, CMD_ENTER_MODE);
+       header |= VDO_OPOS(altmode->mode);
+
+       tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0, TCPC_TX_SOP_PRIME);
+       return 0;
+}
+
+static int tcpm_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop)
+{
+       struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
+       int svdm_version;
+       u32 header;
+
+       svdm_version = typec_get_cable_svdm_version(port->typec_port);
+       if (svdm_version < 0)
+               return svdm_version;
+
+       header = VDO(altmode->svid, 1, svdm_version, CMD_EXIT_MODE);
+       header |= VDO_OPOS(altmode->mode);
+
+       tcpm_queue_vdm_unlocked(port, header, NULL, 0, TCPC_TX_SOP_PRIME);
+       return 0;
+}
+
+static int tcpm_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop,
+                                 u32 header, const u32 *data, int count)
+{
+       struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
+
+       tcpm_queue_vdm_unlocked(port, header, data, count - 1, TCPC_TX_SOP_PRIME);
+
+       return 0;
+}
+
+static const struct typec_cable_ops tcpm_cable_ops = {
+       .enter = tcpm_cable_altmode_enter,
+       .exit = tcpm_cable_altmode_exit,
+       .vdm = tcpm_cable_altmode_vdm,
+};
+
 /*
  * PD (data, control) command handling functions
  */
@@ -2293,7 +2876,8 @@ static inline enum tcpm_state ready_state(struct tcpm_port *port)
 }
 
 static int tcpm_pd_send_control(struct tcpm_port *port,
-                               enum pd_ctrl_msg_type type);
+                               enum pd_ctrl_msg_type type,
+                               enum tcpm_transmit_type tx_sop_type);
 
 static void tcpm_handle_alert(struct tcpm_port *port, const __le32 *payload,
                              int cnt)
@@ -2455,7 +3039,8 @@ static int tcpm_register_sink_caps(struct tcpm_port *port)
 }
 
 static void tcpm_pd_data_request(struct tcpm_port *port,
-                                const struct pd_message *msg)
+                                const struct pd_message *msg,
+                                enum tcpm_transmit_type rx_sop_type)
 {
        enum pd_data_msg_type type = pd_header_type_le(msg->header);
        unsigned int cnt = pd_header_cnt_le(msg->header);
@@ -2496,8 +3081,11 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
                        break;
                }
 
-               if (rev < PD_MAX_REV)
+               if (rev < PD_MAX_REV) {
                        port->negotiated_rev = rev;
+                       if (port->negotiated_rev_prime > port->negotiated_rev)
+                               port->negotiated_rev_prime = port->negotiated_rev;
+               }
 
                if (port->pwr_role == TYPEC_SOURCE) {
                        if (port->ams == GET_SOURCE_CAPABILITIES)
@@ -2548,8 +3136,11 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
                        break;
                }
 
-               if (rev < PD_MAX_REV)
+               if (rev < PD_MAX_REV) {
                        port->negotiated_rev = rev;
+                       if (port->negotiated_rev_prime > port->negotiated_rev)
+                               port->negotiated_rev_prime = port->negotiated_rev;
+               }
 
                if (port->pwr_role != TYPEC_SOURCE || cnt != 1) {
                        tcpm_pd_handle_msg(port,
@@ -2605,7 +3196,7 @@ static void tcpm_pd_data_request(struct tcpm_port *port,
                                           NONE_AMS);
                break;
        case PD_DATA_VENDOR_DEF:
-               tcpm_handle_vdm_request(port, msg->payload, cnt);
+               tcpm_handle_vdm_request(port, msg->payload, cnt, rx_sop_type);
                break;
        case PD_DATA_BIST:
                port->bist_request = le32_to_cpu(msg->payload[0]);
@@ -2647,10 +3238,12 @@ static void tcpm_pps_complete(struct tcpm_port *port, int result)
 }
 
 static void tcpm_pd_ctrl_request(struct tcpm_port *port,
-                                const struct pd_message *msg)
+                                const struct pd_message *msg,
+                                enum tcpm_transmit_type rx_sop_type)
 {
        enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
        enum tcpm_state next_state;
+       unsigned int rev = pd_header_rev_le(msg->header);
 
        /*
         * Stop VDM state machine if interrupted by other Messages while NOT_SUPP is allowed in
@@ -2815,6 +3408,16 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
                case SOFT_RESET_SEND:
                        if (port->ams == SOFT_RESET_AMS)
                                tcpm_ams_finish(port);
+                       /*
+                        * SOP' Soft Reset is done after Vconn Swap,
+                        * which returns to ready state
+                        */
+                       if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+                               if (rev < port->negotiated_rev_prime)
+                                       port->negotiated_rev_prime = rev;
+                               tcpm_set_state(port, ready_state(port), 0);
+                               break;
+                       }
                        if (port->pwr_role == TYPEC_SOURCE) {
                                port->upcoming_state = SRC_SEND_CAPABILITIES;
                                tcpm_ams_start(port, POWER_NEGOTIATION);
@@ -2981,6 +3584,7 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
        const struct pd_message *msg = &event->msg;
        unsigned int cnt = pd_header_cnt_le(msg->header);
        struct tcpm_port *port = event->port;
+       enum tcpm_transmit_type rx_sop_type = event->rx_sop_type;
 
        mutex_lock(&port->lock);
 
@@ -2991,6 +3595,14 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
                enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
                unsigned int msgid = pd_header_msgid_le(msg->header);
 
+               /*
+                * Drop SOP' messages if cannot receive via
+                * tcpm_can_communicate_sop_prime
+                */
+               if (rx_sop_type == TCPC_TX_SOP_PRIME &&
+                   !tcpm_can_communicate_sop_prime(port))
+                       goto done;
+
                /*
                 * USB PD standard, 6.6.1.2:
                 * "... if MessageID value in a received Message is the
@@ -3000,16 +3612,26 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
                 * Message). Note: this shall not apply to the Soft_Reset
                 * Message which always has a MessageID value of zero."
                 */
-               if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET)
-                       goto done;
-               port->rx_msgid = msgid;
+               switch (rx_sop_type) {
+               case TCPC_TX_SOP_PRIME:
+                       if (msgid == port->rx_msgid_prime)
+                               goto done;
+                       port->rx_msgid_prime = msgid;
+                       break;
+               case TCPC_TX_SOP:
+               default:
+                       if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET)
+                               goto done;
+                       port->rx_msgid = msgid;
+                       break;
+               }
 
                /*
                 * If both ends believe to be DFP/host, we have a data role
                 * mismatch.
                 */
                if (!!(le16_to_cpu(msg->header) & PD_HEADER_DATA_ROLE) ==
-                   (port->data_role == TYPEC_HOST)) {
+                   (port->data_role == TYPEC_HOST) && rx_sop_type == TCPC_TX_SOP) {
                        tcpm_log(port,
                                 "Data role mismatch, initiating error recovery");
                        tcpm_set_state(port, ERROR_RECOVERY, 0);
@@ -3017,9 +3639,9 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
                        if (le16_to_cpu(msg->header) & PD_HEADER_EXT_HDR)
                                tcpm_pd_ext_msg_request(port, msg);
                        else if (cnt)
-                               tcpm_pd_data_request(port, msg);
+                               tcpm_pd_data_request(port, msg, rx_sop_type);
                        else
-                               tcpm_pd_ctrl_request(port, msg);
+                               tcpm_pd_ctrl_request(port, msg, rx_sop_type);
                }
        }
 
@@ -3028,7 +3650,8 @@ done:
        kfree(event);
 }
 
-void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg)
+void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg,
+                    enum tcpm_transmit_type rx_sop_type)
 {
        struct pd_rx_event *event;
 
@@ -3038,23 +3661,47 @@ void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg)
 
        kthread_init_work(&event->work, tcpm_pd_rx_handler);
        event->port = port;
+       event->rx_sop_type = rx_sop_type;
        memcpy(&event->msg, msg, sizeof(*msg));
        kthread_queue_work(port->wq, &event->work);
 }
 EXPORT_SYMBOL_GPL(tcpm_pd_receive);
 
 static int tcpm_pd_send_control(struct tcpm_port *port,
-                               enum pd_ctrl_msg_type type)
+                               enum pd_ctrl_msg_type type,
+                               enum tcpm_transmit_type tx_sop_type)
 {
        struct pd_message msg;
 
        memset(&msg, 0, sizeof(msg));
-       msg.header = PD_HEADER_LE(type, port->pwr_role,
-                                 port->data_role,
-                                 port->negotiated_rev,
-                                 port->message_id, 0);
+       switch (tx_sop_type) {
+       case TCPC_TX_SOP_PRIME:
+               msg.header = PD_HEADER_LE(type,
+                                         0,    /* Cable Plug Indicator for DFP/UFP */
+                                         0,    /* Reserved */
+                                         port->negotiated_rev,
+                                         port->message_id_prime,
+                                         0);
+               break;
+       case TCPC_TX_SOP:
+               msg.header = PD_HEADER_LE(type,
+                                         port->pwr_role,
+                                         port->data_role,
+                                         port->negotiated_rev,
+                                         port->message_id,
+                                         0);
+               break;
+       default:
+               msg.header = PD_HEADER_LE(type,
+                                         port->pwr_role,
+                                         port->data_role,
+                                         port->negotiated_rev,
+                                         port->message_id,
+                                         0);
+               break;
+       }
 
-       return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+       return tcpm_pd_transmit(port, tx_sop_type, &msg);
 }
 
 /*
@@ -3073,13 +3720,13 @@ static bool tcpm_send_queued_message(struct tcpm_port *port)
 
                switch (queued_message) {
                case PD_MSG_CTRL_WAIT:
-                       tcpm_pd_send_control(port, PD_CTRL_WAIT);
+                       tcpm_pd_send_control(port, PD_CTRL_WAIT, TCPC_TX_SOP);
                        break;
                case PD_MSG_CTRL_REJECT:
-                       tcpm_pd_send_control(port, PD_CTRL_REJECT);
+                       tcpm_pd_send_control(port, PD_CTRL_REJECT, TCPC_TX_SOP);
                        break;
                case PD_MSG_CTRL_NOT_SUPP:
-                       tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP);
+                       tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP);
                        break;
                case PD_MSG_DATA_SINK_CAP:
                        ret = tcpm_pd_send_sink_caps(port);
@@ -3649,6 +4296,7 @@ static int tcpm_src_attach(struct tcpm_port *port)
 
        port->attached = true;
        port->send_discover = true;
+       port->send_discover_prime = false;
 
        return 0;
 
@@ -3665,6 +4313,15 @@ out_disable_mux:
 
 static void tcpm_typec_disconnect(struct tcpm_port *port)
 {
+       /*
+        * Unregister plug/cable outside of port->connected because cable can
+        * be discovered before SRC_READY/SNK_READY states where port->connected
+        * is set.
+        */
+       typec_unregister_plug(port->plug_prime);
+       typec_unregister_cable(port->cable);
+       port->plug_prime = NULL;
+       port->cable = NULL;
        if (port->connected) {
                typec_partner_set_usb_power_delivery(port->partner, NULL);
                typec_unregister_partner(port->partner);
@@ -3676,14 +4333,20 @@ static void tcpm_typec_disconnect(struct tcpm_port *port)
 static void tcpm_unregister_altmodes(struct tcpm_port *port)
 {
        struct pd_mode_data *modep = &port->mode_data;
+       struct pd_mode_data *modep_prime = &port->mode_data_prime;
        int i;
 
        for (i = 0; i < modep->altmodes; i++) {
                typec_unregister_altmode(port->partner_altmode[i]);
                port->partner_altmode[i] = NULL;
        }
+       for (i = 0; i < modep_prime->altmodes; i++) {
+               typec_unregister_altmode(port->plug_prime_altmode[i]);
+               port->plug_prime_altmode[i] = NULL;
+       }
 
        memset(modep, 0, sizeof(*modep));
+       memset(modep_prime, 0, sizeof(*modep_prime));
 }
 
 static void tcpm_set_partner_usb_comm_capable(struct tcpm_port *port, bool capable)
@@ -3712,6 +4375,7 @@ static void tcpm_reset_port(struct tcpm_port *port)
         * we can check tcpm_pd_rx_handler() if we had seen it before.
         */
        port->rx_msgid = -1;
+       port->rx_msgid_prime = -1;
 
        port->tcpc->set_pd_rx(port->tcpc, false);
        tcpm_init_vbus(port);   /* also disables charging */
@@ -3783,6 +4447,7 @@ static int tcpm_snk_attach(struct tcpm_port *port)
 
        port->attached = true;
        port->send_discover = true;
+       port->send_discover_prime = false;
 
        return 0;
 }
@@ -4023,8 +4688,11 @@ static void run_state_machine(struct tcpm_port *port)
                port->pwr_opmode = TYPEC_PWR_MODE_USB;
                port->caps_count = 0;
                port->negotiated_rev = PD_MAX_REV;
+               port->negotiated_rev_prime = PD_MAX_REV;
                port->message_id = 0;
+               port->message_id_prime = 0;
                port->rx_msgid = -1;
+               port->rx_msgid_prime = -1;
                port->explicit_contract = false;
                /* SNK -> SRC POWER/FAST_ROLE_SWAP finished */
                if (port->ams == POWER_ROLE_SWAP ||
@@ -4045,8 +4713,12 @@ static void run_state_machine(struct tcpm_port *port)
                }
                ret = tcpm_pd_send_source_caps(port);
                if (ret < 0) {
-                       tcpm_set_state(port, SRC_SEND_CAPABILITIES,
-                                      PD_T_SEND_SOURCE_CAP);
+                       if (tcpm_can_communicate_sop_prime(port) &&
+                           IS_ERR_OR_NULL(port->cable))
+                               tcpm_set_state(port, SRC_VDM_IDENTITY_REQUEST, 0);
+                       else
+                               tcpm_set_state(port, SRC_SEND_CAPABILITIES,
+                                              PD_T_SEND_SOURCE_CAP);
                } else {
                        /*
                         * Per standard, we should clear the reset counter here.
@@ -4087,7 +4759,7 @@ static void run_state_machine(struct tcpm_port *port)
        case SRC_NEGOTIATE_CAPABILITIES:
                ret = tcpm_pd_check_request(port);
                if (ret < 0) {
-                       tcpm_pd_send_control(port, PD_CTRL_REJECT);
+                       tcpm_pd_send_control(port, PD_CTRL_REJECT, TCPC_TX_SOP);
                        if (!port->explicit_contract) {
                                tcpm_set_state(port,
                                               SRC_WAIT_NEW_CAPABILITIES, 0);
@@ -4095,7 +4767,7 @@ static void run_state_machine(struct tcpm_port *port)
                                tcpm_set_state(port, SRC_READY, 0);
                        }
                } else {
-                       tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+                       tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP);
                        tcpm_set_partner_usb_comm_capable(port,
                                                          !!(port->sink_request & RDO_USB_COMM));
                        tcpm_set_state(port, SRC_TRANSITION_SUPPLY,
@@ -4104,7 +4776,7 @@ static void run_state_machine(struct tcpm_port *port)
                break;
        case SRC_TRANSITION_SUPPLY:
                /* XXX: regulator_set_voltage(vbus, ...) */
-               tcpm_pd_send_control(port, PD_CTRL_PS_RDY);
+               tcpm_pd_send_control(port, PD_CTRL_PS_RDY, TCPC_TX_SOP);
                port->explicit_contract = true;
                typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_PD);
                port->pwr_opmode = TYPEC_PWR_MODE_PD;
@@ -4141,14 +4813,23 @@ static void run_state_machine(struct tcpm_port *port)
                 * 6.4.4.3.1 Discover Identity
                 * "The Discover Identity Command Shall only be sent to SOP when there is an
                 * Explicit Contract."
-                * For now, this driver only supports SOP for DISCOVER_IDENTITY, thus using
-                * port->explicit_contract to decide whether to send the command.
+                *
+                * Discover Identity on SOP' should be discovered prior to the
+                * ready state, but if done after a Vconn Swap following Discover
+                * Identity on SOP then the discovery process can be run here
+                * as well.
                 */
                if (port->explicit_contract) {
-                       tcpm_set_initial_svdm_version(port);
+                       if (port->send_discover_prime) {
+                               port->tx_sop_type = TCPC_TX_SOP_PRIME;
+                       } else {
+                               port->tx_sop_type = TCPC_TX_SOP;
+                               tcpm_set_initial_svdm_version(port);
+                       }
                        mod_send_discover_delayed_work(port, 0);
                } else {
                        port->send_discover = false;
+                       port->send_discover_prime = false;
                }
 
                /*
@@ -4264,8 +4945,11 @@ static void run_state_machine(struct tcpm_port *port)
                typec_set_pwr_opmode(port->typec_port, opmode);
                port->pwr_opmode = TYPEC_PWR_MODE_USB;
                port->negotiated_rev = PD_MAX_REV;
+               port->negotiated_rev_prime = PD_MAX_REV;
                port->message_id = 0;
+               port->message_id_prime = 0;
                port->rx_msgid = -1;
+               port->rx_msgid_prime = -1;
                port->explicit_contract = false;
 
                if (port->ams == POWER_ROLE_SWAP ||
@@ -4437,14 +5121,23 @@ static void run_state_machine(struct tcpm_port *port)
                 * 6.4.4.3.1 Discover Identity
                 * "The Discover Identity Command Shall only be sent to SOP when there is an
                 * Explicit Contract."
-                * For now, this driver only supports SOP for DISCOVER_IDENTITY, thus using
-                * port->explicit_contract.
+                *
+                * Discover Identity on SOP' should be discovered prior to the
+                * ready state, but if done after a Vconn Swap following Discover
+                * Identity on SOP then the discovery process can be run here
+                * as well.
                 */
                if (port->explicit_contract) {
-                       tcpm_set_initial_svdm_version(port);
+                       if (port->send_discover_prime) {
+                               port->tx_sop_type = TCPC_TX_SOP_PRIME;
+                       } else {
+                               port->tx_sop_type = TCPC_TX_SOP;
+                               tcpm_set_initial_svdm_version(port);
+                       }
                        mod_send_discover_delayed_work(port, 0);
                } else {
                        port->send_discover = false;
+                       port->send_discover_prime = false;
                }
 
                power_supply_changed(port->psy);
@@ -4485,6 +5178,7 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_unregister_altmodes(port);
                port->nr_sink_caps = 0;
                port->send_discover = true;
+               port->send_discover_prime = false;
                if (port->pwr_role == TYPEC_SOURCE)
                        tcpm_set_state(port, SRC_HARD_RESET_VBUS_OFF,
                                       PD_T_PS_HARD_RESET);
@@ -4586,7 +5280,7 @@ static void run_state_machine(struct tcpm_port *port)
                /* remove existing capabilities */
                usb_power_delivery_unregister_capabilities(port->partner_source_caps);
                port->partner_source_caps = NULL;
-               tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+               tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP);
                tcpm_ams_finish(port);
                if (port->pwr_role == TYPEC_SOURCE) {
                        port->upcoming_state = SRC_SEND_CAPABILITIES;
@@ -4603,35 +5297,53 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_ams_start(port, SOFT_RESET_AMS);
                break;
        case SOFT_RESET_SEND:
-               port->message_id = 0;
-               port->rx_msgid = -1;
-               /* remove existing capabilities */
-               usb_power_delivery_unregister_capabilities(port->partner_source_caps);
-               port->partner_source_caps = NULL;
-               if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET))
-                       tcpm_set_state_cond(port, hard_reset_state(port), 0);
-               else
-                       tcpm_set_state_cond(port, hard_reset_state(port),
-                                           PD_T_SENDER_RESPONSE);
+               /*
+                * Power Delivery 3.0 Section 6.3.13
+                *
+                * A Soft_Reset Message Shall be targeted at a specific entity
+                * depending on the type of SOP* packet used.
+                */
+               if (port->tx_sop_type == TCPC_TX_SOP_PRIME) {
+                       port->message_id_prime = 0;
+                       port->rx_msgid_prime = -1;
+                       tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET, TCPC_TX_SOP_PRIME);
+                       tcpm_set_state_cond(port, ready_state(port), PD_T_SENDER_RESPONSE);
+               } else {
+                       port->message_id = 0;
+                       port->rx_msgid = -1;
+                       /* remove existing capabilities */
+                       usb_power_delivery_unregister_capabilities(port->partner_source_caps);
+                       port->partner_source_caps = NULL;
+                       if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET, TCPC_TX_SOP))
+                               tcpm_set_state_cond(port, hard_reset_state(port), 0);
+                       else
+                               tcpm_set_state_cond(port, hard_reset_state(port),
+                                                   PD_T_SENDER_RESPONSE);
+               }
                break;
 
        /* DR_Swap states */
        case DR_SWAP_SEND:
-               tcpm_pd_send_control(port, PD_CTRL_DR_SWAP);
-               if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20)
+               tcpm_pd_send_control(port, PD_CTRL_DR_SWAP, TCPC_TX_SOP);
+               if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20) {
                        port->send_discover = true;
+                       port->send_discover_prime = false;
+               }
                tcpm_set_state_cond(port, DR_SWAP_SEND_TIMEOUT,
                                    PD_T_SENDER_RESPONSE);
                break;
        case DR_SWAP_ACCEPT:
-               tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
-               if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20)
+               tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP);
+               if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20) {
                        port->send_discover = true;
+                       port->send_discover_prime = false;
+               }
                tcpm_set_state_cond(port, DR_SWAP_CHANGE_DR, 0);
                break;
        case DR_SWAP_SEND_TIMEOUT:
                tcpm_swap_complete(port, -ETIMEDOUT);
                port->send_discover = false;
+               port->send_discover_prime = false;
                tcpm_ams_finish(port);
                tcpm_set_state(port, ready_state(port), 0);
                break;
@@ -4648,7 +5360,7 @@ static void run_state_machine(struct tcpm_port *port)
                break;
 
        case FR_SWAP_SEND:
-               if (tcpm_pd_send_control(port, PD_CTRL_FR_SWAP)) {
+               if (tcpm_pd_send_control(port, PD_CTRL_FR_SWAP, TCPC_TX_SOP)) {
                        tcpm_set_state(port, ERROR_RECOVERY, 0);
                        break;
                }
@@ -4668,7 +5380,7 @@ static void run_state_machine(struct tcpm_port *port)
                break;
        case FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED:
                tcpm_set_pwr_role(port, TYPEC_SOURCE);
-               if (tcpm_pd_send_control(port, PD_CTRL_PS_RDY)) {
+               if (tcpm_pd_send_control(port, PD_CTRL_PS_RDY, TCPC_TX_SOP)) {
                        tcpm_set_state(port, ERROR_RECOVERY, 0);
                        break;
                }
@@ -4678,11 +5390,11 @@ static void run_state_machine(struct tcpm_port *port)
 
        /* PR_Swap states */
        case PR_SWAP_ACCEPT:
-               tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+               tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP);
                tcpm_set_state(port, PR_SWAP_START, 0);
                break;
        case PR_SWAP_SEND:
-               tcpm_pd_send_control(port, PD_CTRL_PR_SWAP);
+               tcpm_pd_send_control(port, PD_CTRL_PR_SWAP, TCPC_TX_SOP);
                tcpm_set_state_cond(port, PR_SWAP_SEND_TIMEOUT,
                                    PD_T_SENDER_RESPONSE);
                break;
@@ -4724,7 +5436,7 @@ static void run_state_machine(struct tcpm_port *port)
                 * supply is turned off"
                 */
                tcpm_set_pwr_role(port, TYPEC_SINK);
-               if (tcpm_pd_send_control(port, PD_CTRL_PS_RDY)) {
+               if (tcpm_pd_send_control(port, PD_CTRL_PS_RDY, TCPC_TX_SOP)) {
                        tcpm_set_state(port, ERROR_RECOVERY, 0);
                        break;
                }
@@ -4771,17 +5483,17 @@ static void run_state_machine(struct tcpm_port *port)
                 * Source."
                 */
                tcpm_set_pwr_role(port, TYPEC_SOURCE);
-               tcpm_pd_send_control(port, PD_CTRL_PS_RDY);
+               tcpm_pd_send_control(port, PD_CTRL_PS_RDY, TCPC_TX_SOP);
                tcpm_set_state(port, SRC_STARTUP, PD_T_SWAP_SRC_START);
                break;
 
        case VCONN_SWAP_ACCEPT:
-               tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+               tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP);
                tcpm_ams_finish(port);
                tcpm_set_state(port, VCONN_SWAP_START, 0);
                break;
        case VCONN_SWAP_SEND:
-               tcpm_pd_send_control(port, PD_CTRL_VCONN_SWAP);
+               tcpm_pd_send_control(port, PD_CTRL_VCONN_SWAP, TCPC_TX_SOP);
                tcpm_set_state(port, VCONN_SWAP_SEND_TIMEOUT,
                               PD_T_SENDER_RESPONSE);
                break;
@@ -4800,14 +5512,34 @@ static void run_state_machine(struct tcpm_port *port)
                               PD_T_VCONN_SOURCE_ON);
                break;
        case VCONN_SWAP_TURN_ON_VCONN:
-               tcpm_set_vconn(port, true);
-               tcpm_pd_send_control(port, PD_CTRL_PS_RDY);
-               tcpm_set_state(port, ready_state(port), 0);
+               ret = tcpm_set_vconn(port, true);
+               tcpm_pd_send_control(port, PD_CTRL_PS_RDY, TCPC_TX_SOP);
+               /*
+                * USB PD 3.0 Section 6.4.4.3.1
+                *
+                * Note that a Cable Plug or VPD will not be ready for PD
+                * Communication until tVCONNStable after VCONN has been applied
+                */
+               if (!ret)
+                       tcpm_set_state(port, VCONN_SWAP_SEND_SOFT_RESET,
+                                      PD_T_VCONN_STABLE);
+               else
+                       tcpm_set_state(port, ready_state(port), 0);
                break;
        case VCONN_SWAP_TURN_OFF_VCONN:
                tcpm_set_vconn(port, false);
                tcpm_set_state(port, ready_state(port), 0);
                break;
+       case VCONN_SWAP_SEND_SOFT_RESET:
+               tcpm_swap_complete(port, port->swap_status);
+               if (tcpm_can_communicate_sop_prime(port)) {
+                       port->tx_sop_type = TCPC_TX_SOP_PRIME;
+                       port->upcoming_state = SOFT_RESET_SEND;
+                       tcpm_ams_start(port, SOFT_RESET_AMS);
+               } else {
+                       tcpm_set_state(port, ready_state(port), 0);
+               }
+               break;
 
        case DR_SWAP_CANCEL:
        case PR_SWAP_CANCEL:
@@ -4843,7 +5575,7 @@ static void run_state_machine(struct tcpm_port *port)
                }
                break;
        case GET_STATUS_SEND:
-               tcpm_pd_send_control(port, PD_CTRL_GET_STATUS);
+               tcpm_pd_send_control(port, PD_CTRL_GET_STATUS, TCPC_TX_SOP);
                tcpm_set_state(port, GET_STATUS_SEND_TIMEOUT,
                               PD_T_SENDER_RESPONSE);
                break;
@@ -4851,7 +5583,7 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_set_state(port, ready_state(port), 0);
                break;
        case GET_PPS_STATUS_SEND:
-               tcpm_pd_send_control(port, PD_CTRL_GET_PPS_STATUS);
+               tcpm_pd_send_control(port, PD_CTRL_GET_PPS_STATUS, TCPC_TX_SOP);
                tcpm_set_state(port, GET_PPS_STATUS_SEND_TIMEOUT,
                               PD_T_SENDER_RESPONSE);
                break;
@@ -4859,7 +5591,7 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_set_state(port, ready_state(port), 0);
                break;
        case GET_SINK_CAP:
-               tcpm_pd_send_control(port, PD_CTRL_GET_SINK_CAP);
+               tcpm_pd_send_control(port, PD_CTRL_GET_SINK_CAP, TCPC_TX_SOP);
                tcpm_set_state(port, GET_SINK_CAP_TIMEOUT, PD_T_SENDER_RESPONSE);
                break;
        case GET_SINK_CAP_TIMEOUT:
@@ -4902,9 +5634,18 @@ static void run_state_machine(struct tcpm_port *port)
 
        /* Chunk state */
        case CHUNK_NOT_SUPP:
-               tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP);
+               tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP);
                tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0);
                break;
+
+       /* Cable states */
+       case SRC_VDM_IDENTITY_REQUEST:
+               port->send_discover_prime = true;
+               port->tx_sop_type = TCPC_TX_SOP_PRIME;
+               mod_send_discover_delayed_work(port, 0);
+               port->upcoming_state = SRC_SEND_CAPABILITIES;
+               break;
+
        default:
                WARN(1, "Unexpected port state %d\n", port->state);
                break;
@@ -5596,7 +6337,8 @@ static void tcpm_enable_frs_work(struct kthread_work *work)
                goto unlock;
 
        /* Send when the state machine is idle */
-       if (port->state != SNK_READY || port->vdm_sm_running || port->send_discover)
+       if (port->state != SNK_READY || port->vdm_sm_running || port->send_discover ||
+           port->send_discover_prime)
                goto resched;
 
        port->upcoming_state = GET_SINK_CAP;
@@ -5619,21 +6361,23 @@ static void tcpm_send_discover_work(struct kthread_work *work)
 
        mutex_lock(&port->lock);
        /* No need to send DISCOVER_IDENTITY anymore */
-       if (!port->send_discover)
+       if (!port->send_discover && !port->send_discover_prime)
                goto unlock;
 
        if (port->data_role == TYPEC_DEVICE && port->negotiated_rev < PD_REV30) {
                port->send_discover = false;
+               port->send_discover_prime = false;
                goto unlock;
        }
 
        /* Retry if the port is not idle */
-       if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) {
+       if ((port->state != SRC_READY && port->state != SNK_READY &&
+            port->state != SRC_VDM_IDENTITY_REQUEST) || port->vdm_sm_running) {
                mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS);
                goto unlock;
        }
 
-       tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0);
+       tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0, port->tx_sop_type);
 
 unlock:
        mutex_unlock(&port->lock);
@@ -6860,6 +7604,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
        typec_port_register_altmodes(port->typec_port,
                                     &tcpm_altmode_ops, port,
                                     port->port_altmode, ALTMODE_DISCOVERY_MAX);
+       typec_port_register_cable_ops(port->port_altmode, ARRAY_SIZE(port->port_altmode),
+                                     &tcpm_cable_ops);
        port->registered = true;
 
        mutex_lock(&port->lock);
index 87d4abde0ea279f53a35da67051114228c27fe7f..cf719307b3f6b9e3af41870fd76604b113166ba8 100644 (file)
@@ -535,7 +535,7 @@ static irqreturn_t wcove_typec_irq(int irq, void *data)
                                goto err;
                        }
 
-                       tcpm_pd_receive(wcove->tcpm, &msg);
+                       tcpm_pd_receive(wcove->tcpm, &msg, TCPC_TX_SOP);
 
                        ret = regmap_read(wcove->regmap, USBC_RXSTATUS,
                                          &status);
index 14f5a7bfae2e92873e405b369ca8ce5620d856c0..cf52cb34d28592ccc76044a18a2cecc7f6280fda 100644 (file)
  */
 #define UCSI_SWAP_TIMEOUT_MS   5000
 
+static int ucsi_read_message_in(struct ucsi *ucsi, void *buf,
+                                         size_t buf_size)
+{
+       /*
+        * Below UCSI 2.0, MESSAGE_IN was limited to 16 bytes. Truncate the
+        * reads here.
+        */
+       if (ucsi->version <= UCSI_VERSION_1_2)
+               buf_size = clamp(buf_size, 0, 16);
+
+       return ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, buf, buf_size);
+}
+
 static int ucsi_acknowledge_command(struct ucsi *ucsi)
 {
        u64 ctrl;
@@ -72,7 +85,7 @@ static int ucsi_read_error(struct ucsi *ucsi)
        if (ret < 0)
                return ret;
 
-       ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, &error, sizeof(error));
+       ret = ucsi_read_message_in(ucsi, &error, sizeof(error));
        if (ret)
                return ret;
 
@@ -170,7 +183,7 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command,
        length = ret;
 
        if (data) {
-               ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size);
+               ret = ucsi_read_message_in(ucsi, data, size);
                if (ret)
                        goto out;
        }
@@ -386,6 +399,27 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
 
                con->partner_altmode[i] = alt;
                break;
+       case UCSI_RECIPIENT_SOP_P:
+               i = ucsi_next_altmode(con->plug_altmode);
+               if (i < 0) {
+                       ret = i;
+                       goto err;
+               }
+
+               ret = ucsi_altmode_next_mode(con->plug_altmode, desc->svid);
+               if (ret < 0)
+                       return ret;
+
+               desc->mode = ret;
+
+               alt = typec_plug_register_altmode(con->plug, desc);
+               if (IS_ERR(alt)) {
+                       ret = PTR_ERR(alt);
+                       goto err;
+               }
+
+               con->plug_altmode[i] = alt;
+               break;
        default:
                return -EINVAL;
        }
@@ -553,6 +587,9 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
        case UCSI_RECIPIENT_SOP:
                adev = con->partner_altmode;
                break;
+       case UCSI_RECIPIENT_SOP_P:
+               adev = con->plug_altmode;
+               break;
        default:
                return;
        }
@@ -633,6 +670,108 @@ static int ucsi_get_src_pdos(struct ucsi_connector *con)
        return ret;
 }
 
+static int ucsi_read_identity(struct ucsi_connector *con, u8 recipient,
+                             u8 offset, u8 bytes, void *resp)
+{
+       struct ucsi *ucsi = con->ucsi;
+       u64 command;
+       int ret;
+
+       command = UCSI_COMMAND(UCSI_GET_PD_MESSAGE) |
+           UCSI_CONNECTOR_NUMBER(con->num);
+       command |= UCSI_GET_PD_MESSAGE_RECIPIENT(recipient);
+       command |= UCSI_GET_PD_MESSAGE_OFFSET(offset);
+       command |= UCSI_GET_PD_MESSAGE_BYTES(bytes);
+       command |= UCSI_GET_PD_MESSAGE_TYPE(UCSI_GET_PD_MESSAGE_TYPE_IDENTITY);
+
+       ret = ucsi_send_command(ucsi, command, resp, bytes);
+       if (ret < 0)
+               dev_err(ucsi->dev, "UCSI_GET_PD_MESSAGE failed (%d)\n", ret);
+
+       return ret;
+}
+
+static int ucsi_get_identity(struct ucsi_connector *con, u8 recipient,
+                             struct usb_pd_identity *id)
+{
+       struct ucsi *ucsi = con->ucsi;
+       struct ucsi_pd_message_disc_id resp = {};
+       int ret;
+
+       if (ucsi->version < UCSI_VERSION_2_0) {
+               /*
+                * Before UCSI v2.0, MESSAGE_IN is 16 bytes which cannot fit
+                * the 28 byte identity response including the VDM header.
+                * First request the VDM header, ID Header VDO, Cert Stat VDO
+                * and Product VDO.
+                */
+               ret = ucsi_read_identity(con, recipient, 0, 0x10, &resp);
+               if (ret < 0)
+                       return ret;
+
+
+               /* Then request Product Type VDO1 through Product Type VDO3. */
+               ret = ucsi_read_identity(con, recipient, 0x10, 0xc,
+                                        &resp.vdo[0]);
+               if (ret < 0)
+                       return ret;
+
+       } else {
+               /*
+                * In UCSI v2.0 and after, MESSAGE_IN is large enough to request
+                * the large enough to request the full Discover Identity
+                * response at once.
+                */
+               ret = ucsi_read_identity(con, recipient, 0x0, 0x1c, &resp);
+               if (ret < 0)
+                       return ret;
+       }
+
+       id->id_header = resp.id_header;
+       id->cert_stat = resp.cert_stat;
+       id->product = resp.product;
+       id->vdo[0] = resp.vdo[0];
+       id->vdo[1] = resp.vdo[1];
+       id->vdo[2] = resp.vdo[2];
+       return 0;
+}
+
+static int ucsi_get_partner_identity(struct ucsi_connector *con)
+{
+       int ret;
+
+       ret = ucsi_get_identity(con, UCSI_RECIPIENT_SOP,
+                                &con->partner_identity);
+       if (ret < 0)
+               return ret;
+
+       ret = typec_partner_set_identity(con->partner);
+       if (ret < 0) {
+               dev_err(con->ucsi->dev, "Failed to set partner identity (%d)\n",
+                       ret);
+       }
+
+       return ret;
+}
+
+static int ucsi_get_cable_identity(struct ucsi_connector *con)
+{
+       int ret;
+
+       ret = ucsi_get_identity(con, UCSI_RECIPIENT_SOP_P,
+                                &con->cable_identity);
+       if (ret < 0)
+               return ret;
+
+       ret = typec_cable_set_identity(con->cable);
+       if (ret < 0) {
+               dev_err(con->ucsi->dev, "Failed to set cable identity (%d)\n",
+                       ret);
+       }
+
+       return ret;
+}
+
 static int ucsi_check_altmodes(struct ucsi_connector *con)
 {
        int ret, num_partner_am;
@@ -721,6 +860,82 @@ static void ucsi_unregister_partner_pdos(struct ucsi_connector *con)
        con->partner_pd = NULL;
 }
 
+static int ucsi_register_plug(struct ucsi_connector *con)
+{
+       struct typec_plug *plug;
+       struct typec_plug_desc desc = {.index = TYPEC_PLUG_SOP_P};
+
+       plug = typec_register_plug(con->cable, &desc);
+       if (IS_ERR(plug)) {
+               dev_err(con->ucsi->dev,
+                       "con%d: failed to register plug (%ld)\n", con->num,
+                       PTR_ERR(plug));
+               return PTR_ERR(plug);
+       }
+
+       con->plug = plug;
+       return 0;
+}
+
+static void ucsi_unregister_plug(struct ucsi_connector *con)
+{
+       if (!con->plug)
+               return;
+
+       ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP_P);
+       typec_unregister_plug(con->plug);
+       con->plug = NULL;
+}
+
+static int ucsi_register_cable(struct ucsi_connector *con)
+{
+       struct typec_cable *cable;
+       struct typec_cable_desc desc = {};
+
+       switch (UCSI_CABLE_PROP_FLAG_PLUG_TYPE(con->cable_prop.flags)) {
+       case UCSI_CABLE_PROPERTY_PLUG_TYPE_A:
+               desc.type = USB_PLUG_TYPE_A;
+               break;
+       case UCSI_CABLE_PROPERTY_PLUG_TYPE_B:
+               desc.type = USB_PLUG_TYPE_B;
+               break;
+       case UCSI_CABLE_PROPERTY_PLUG_TYPE_C:
+               desc.type = USB_PLUG_TYPE_C;
+               break;
+       default:
+               desc.type = USB_PLUG_NONE;
+               break;
+       }
+
+       desc.identity = &con->cable_identity;
+       desc.active = !!(UCSI_CABLE_PROP_FLAG_ACTIVE_CABLE &
+                        con->cable_prop.flags);
+       desc.pd_revision = UCSI_CABLE_PROP_FLAG_PD_MAJOR_REV_AS_BCD(
+           con->cable_prop.flags);
+
+       cable = typec_register_cable(con->port, &desc);
+       if (IS_ERR(cable)) {
+               dev_err(con->ucsi->dev,
+                       "con%d: failed to register cable (%ld)\n", con->num,
+                       PTR_ERR(cable));
+               return PTR_ERR(cable);
+       }
+
+       con->cable = cable;
+       return 0;
+}
+
+static void ucsi_unregister_cable(struct ucsi_connector *con)
+{
+       if (!con->cable)
+               return;
+
+       ucsi_unregister_plug(con);
+       typec_unregister_cable(con->cable);
+       memset(&con->cable_identity, 0, sizeof(con->cable_identity));
+       con->cable = NULL;
+}
+
 static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
 {
        switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
@@ -768,7 +983,9 @@ static int ucsi_register_partner(struct ucsi_connector *con)
                break;
        }
 
+       desc.identity = &con->partner_identity;
        desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD;
+       desc.pd_revision = UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags);
 
        partner = typec_register_partner(con->port, &desc);
        if (IS_ERR(partner)) {
@@ -793,7 +1010,9 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
        typec_partner_set_usb_power_delivery(con->partner, NULL);
        ucsi_unregister_partner_pdos(con);
        ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP);
+       ucsi_unregister_cable(con);
        typec_unregister_partner(con->partner);
+       memset(&con->partner_identity, 0, sizeof(con->partner_identity));
        con->partner = NULL;
 }
 
@@ -843,6 +1062,27 @@ static void ucsi_partner_change(struct ucsi_connector *con)
                        con->num, u_role);
 }
 
+static int ucsi_check_connector_capability(struct ucsi_connector *con)
+{
+       u64 command;
+       int ret;
+
+       if (!con->partner || con->ucsi->version < UCSI_VERSION_2_0)
+               return 0;
+
+       command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num);
+       ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap));
+       if (ret < 0) {
+               dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret);
+               return ret;
+       }
+
+       typec_partner_set_pd_revision(con->partner,
+               UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags));
+
+       return ret;
+}
+
 static int ucsi_check_connection(struct ucsi_connector *con)
 {
        u8 prev_flags = con->status.flags;
@@ -872,6 +1112,42 @@ static int ucsi_check_connection(struct ucsi_connector *con)
        return 0;
 }
 
+static int ucsi_check_cable(struct ucsi_connector *con)
+{
+       u64 command;
+       int ret;
+
+       if (con->cable)
+               return 0;
+
+       command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num);
+       ret = ucsi_send_command(con->ucsi, command, &con->cable_prop,
+                               sizeof(con->cable_prop));
+       if (ret < 0) {
+               dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n",
+                       ret);
+               return ret;
+       }
+
+       ret = ucsi_register_cable(con);
+       if (ret < 0)
+               return ret;
+
+       ret = ucsi_get_cable_identity(con);
+       if (ret < 0)
+               return ret;
+
+       ret = ucsi_register_plug(con);
+       if (ret < 0)
+               return ret;
+
+       ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP_P);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static void ucsi_handle_connector_change(struct work_struct *work)
 {
        struct ucsi_connector *con = container_of(work, struct ucsi_connector,
@@ -912,6 +1188,9 @@ static void ucsi_handle_connector_change(struct work_struct *work)
                if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
                        ucsi_register_partner(con);
                        ucsi_partner_task(con, ucsi_check_connection, 1, HZ);
+                       ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ);
+                       ucsi_partner_task(con, ucsi_get_partner_identity, 1, HZ);
+                       ucsi_partner_task(con, ucsi_check_cable, 1, HZ);
 
                        if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) ==
                            UCSI_CONSTAT_PWR_OPMODE_PD)
@@ -1310,6 +1589,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
                ucsi_register_partner(con);
                ucsi_pwr_opmode_change(con);
                ucsi_port_psy_changed(con);
+               ucsi_get_partner_identity(con);
+               ucsi_check_cable(con);
        }
 
        /* Only notify USB controller if partner supports USB data */
@@ -1558,6 +1839,15 @@ int ucsi_register(struct ucsi *ucsi)
        if (!ucsi->version)
                return -ENODEV;
 
+       /*
+        * Version format is JJ.M.N (JJ = Major version, M = Minor version,
+        * N = sub-minor version).
+        */
+       dev_dbg(ucsi->dev, "Registered UCSI interface with version %x.%x.%x",
+               UCSI_BCD_GET_MAJOR(ucsi->version),
+               UCSI_BCD_GET_MINOR(ucsi->version),
+               UCSI_BCD_GET_SUBMINOR(ucsi->version));
+
        queue_delayed_work(system_long_wq, &ucsi->work, 0);
 
        ucsi_debugfs_register(ucsi);
index 6478016d5cb8bf405f8590b8d475a8933504cad3..32daf5f5865053d8a239d6be911644ce481d9e69 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/usb/typec.h>
 #include <linux/usb/pd.h>
 #include <linux/usb/role.h>
+#include <asm/unaligned.h>
 
 /* -------------------------------------------------------------------------- */
 
@@ -23,6 +24,23 @@ struct dentry;
 #define UCSI_CONTROL                   8
 #define UCSI_MESSAGE_IN                        16
 #define UCSI_MESSAGE_OUT               32
+#define UCSIv2_MESSAGE_OUT             272
+
+/* UCSI versions */
+#define UCSI_VERSION_1_2       0x0120
+#define UCSI_VERSION_2_0       0x0200
+#define UCSI_VERSION_2_1       0x0210
+#define UCSI_VERSION_3_0       0x0300
+
+#define UCSI_BCD_GET_MAJOR(_v_)                (((_v_) >> 8) & 0xFF)
+#define UCSI_BCD_GET_MINOR(_v_)                (((_v_) >> 4) & 0x0F)
+#define UCSI_BCD_GET_SUBMINOR(_v_)     ((_v_) & 0x0F)
+
+/*
+ * Per USB PD 3.2, Section 6.2.1.1.5, the spec revision is represented by 2 bits
+ * 0b00 = 1.0, 0b01 = 2.0, 0b10 = 3.0, 0b11 = Reserved, Shall NOT be used.
+ */
+#define UCSI_SPEC_REVISION_TO_BCD(_v_)  (((_v_) + 1) << 8)
 
 /* Command Status and Connector Change Indication (CCI) bits */
 #define UCSI_CCI_CONNECTOR(_c_)                (((_c_) & GENMASK(7, 1)) >> 1)
@@ -88,6 +106,7 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
 #define UCSI_GET_CABLE_PROPERTY                0x11
 #define UCSI_GET_CONNECTOR_STATUS      0x12
 #define UCSI_GET_ERROR_STATUS          0x13
+#define UCSI_GET_PD_MESSAGE            0x15
 
 #define UCSI_CONNECTOR_NUMBER(_num_)           ((u64)(_num_) << 16)
 #define UCSI_COMMAND(_cmd_)                    ((_cmd_) & 0xff)
@@ -141,6 +160,18 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
 #define UCSI_MAX_PDOS                          (4)
 #define UCSI_GET_PDOS_SRC_PDOS                 ((u64)1 << 34)
 
+/* GET_PD_MESSAGE command bits */
+#define UCSI_GET_PD_MESSAGE_RECIPIENT(_r_)     ((u64)(_r_) << 23)
+#define UCSI_GET_PD_MESSAGE_OFFSET(_r_)                ((u64)(_r_) << 26)
+#define UCSI_GET_PD_MESSAGE_BYTES(_r_)         ((u64)(_r_) << 34)
+#define UCSI_GET_PD_MESSAGE_TYPE(_r_)          ((u64)(_r_) << 42)
+#define   UCSI_GET_PD_MESSAGE_TYPE_SNK_CAP_EXT 0
+#define   UCSI_GET_PD_MESSAGE_TYPE_SRC_CAP_EXT 1
+#define   UCSI_GET_PD_MESSAGE_TYPE_BAT_CAP     2
+#define   UCSI_GET_PD_MESSAGE_TYPE_BAT_STAT    3
+#define   UCSI_GET_PD_MESSAGE_TYPE_IDENTITY    4
+#define   UCSI_GET_PD_MESSAGE_TYPE_REVISION    5
+
 /* -------------------------------------------------------------------------- */
 
 /* Error information returned by PPM in response to GET_ERROR_STATUS command. */
@@ -203,9 +234,29 @@ struct ucsi_connector_capability {
 #define UCSI_CONCAP_OPMODE_USB2                        BIT(5)
 #define UCSI_CONCAP_OPMODE_USB3                        BIT(6)
 #define UCSI_CONCAP_OPMODE_ALT_MODE            BIT(7)
-       u8 flags;
+       u32 flags;
 #define UCSI_CONCAP_FLAG_PROVIDER              BIT(0)
 #define UCSI_CONCAP_FLAG_CONSUMER              BIT(1)
+#define UCSI_CONCAP_FLAG_SWAP_TO_DFP           BIT(2)
+#define UCSI_CONCAP_FLAG_SWAP_TO_UFP           BIT(3)
+#define UCSI_CONCAP_FLAG_SWAP_TO_SRC           BIT(4)
+#define UCSI_CONCAP_FLAG_SWAP_TO_SINK          BIT(5)
+#define UCSI_CONCAP_FLAG_EX_OP_MODE(_f_) \
+       (((_f_) & GENMASK(13, 6)) >> 6)
+#define   UCSI_CONCAP_EX_OP_MODE_USB4_GEN2     BIT(0)
+#define   UCSI_CONCAP_EX_OP_MODE_EPR_SRC       BIT(1)
+#define   UCSI_CONCAP_EX_OP_MODE_EPR_SINK      BIT(2)
+#define   UCSI_CONCAP_EX_OP_MODE_USB4_GEN3     BIT(3)
+#define   UCSI_CONCAP_EX_OP_MODE_USB4_GEN4     BIT(4)
+#define UCSI_CONCAP_FLAG_MISC_CAPS(_f_) \
+       (((_f_) & GENMASK(17, 14)) >> 14)
+#define   UCSI_CONCAP_MISC_CAP_FW_UPDATE       BIT(0)
+#define   UCSI_CONCAP_MISC_CAP_SECURITY                BIT(1)
+#define UCSI_CONCAP_FLAG_REV_CURR_PROT_SUPPORT BIT(18)
+#define UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV(_f_) \
+       (((_f_) & GENMASK(20, 19)) >> 19)
+#define UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(_f_) \
+       UCSI_SPEC_REVISION_TO_BCD(UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV(_f_))
 } __packed;
 
 struct ucsi_altmode {
@@ -221,12 +272,15 @@ struct ucsi_cable_property {
 #define UCSI_CABLE_PROP_FLAG_VBUS_IN_CABLE     BIT(0)
 #define UCSI_CABLE_PROP_FLAG_ACTIVE_CABLE      BIT(1)
 #define UCSI_CABLE_PROP_FLAG_DIRECTIONALITY    BIT(2)
-#define UCSI_CABLE_PROP_FLAG_PLUG_TYPE(_f_)    ((_f_) & GENMASK(3, 0))
+#define UCSI_CABLE_PROP_FLAG_PLUG_TYPE(_f_)    (((_f_) & GENMASK(4, 3)) >> 3)
 #define   UCSI_CABLE_PROPERTY_PLUG_TYPE_A      0
 #define   UCSI_CABLE_PROPERTY_PLUG_TYPE_B      1
 #define   UCSI_CABLE_PROPERTY_PLUG_TYPE_C      2
 #define   UCSI_CABLE_PROPERTY_PLUG_OTHER       3
-#define UCSI_CABLE_PROP_MODE_SUPPORT           BIT(5)
+#define UCSI_CABLE_PROP_FLAG_MODE_SUPPORT      BIT(5)
+#define UCSI_CABLE_PROP_FLAG_PD_MAJOR_REV(_f_) (((_f_) & GENMASK(7, 6)) >> 6)
+#define UCSI_CABLE_PROP_FLAG_PD_MAJOR_REV_AS_BCD(_f_) \
+       UCSI_SPEC_REVISION_TO_BCD(UCSI_CABLE_PROP_FLAG_PD_MAJOR_REV(_f_))
        u8 latency;
 } __packed;
 
@@ -265,15 +319,48 @@ struct ucsi_connector_status {
 #define   UCSI_CONSTAT_PARTNER_TYPE_DEBUG      5
 #define   UCSI_CONSTAT_PARTNER_TYPE_AUDIO      6
        u32 request_data_obj;
-       u8 pwr_status;
-#define UCSI_CONSTAT_BC_STATUS(_p_)            ((_p_) & GENMASK(2, 0))
+
+       u8 pwr_status[3];
+#define UCSI_CONSTAT_BC_STATUS(_p_)            ((_p_[0]) & GENMASK(1, 0))
 #define   UCSI_CONSTAT_BC_NOT_CHARGING         0
 #define   UCSI_CONSTAT_BC_NOMINAL_CHARGING     1
 #define   UCSI_CONSTAT_BC_SLOW_CHARGING                2
 #define   UCSI_CONSTAT_BC_TRICKLE_CHARGING     3
-#define UCSI_CONSTAT_PROVIDER_CAP_LIMIT(_p_)   (((_p_) & GENMASK(6, 3)) >> 3)
+#define UCSI_CONSTAT_PROVIDER_CAP_LIMIT(_p_)   (((_p_[0]) & GENMASK(5, 2)) >> 2)
 #define   UCSI_CONSTAT_CAP_PWR_LOWERED         0
 #define   UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT    1
+#define UCSI_CONSTAT_PROVIDER_PD_VERSION_OPER_MODE(_p_)        \
+       ((get_unaligned_le32(_p_) & GENMASK(21, 6)) >> 6)
+#define UCSI_CONSTAT_ORIENTATION(_p_)          (((_p_[2]) & GENMASK(6, 6)) >> 6)
+#define   UCSI_CONSTAT_ORIENTATION_DIRECT      0
+#define   UCSI_CONSTAT_ORIENTATION_FLIPPED     1
+#define UCSI_CONSTAT_SINK_PATH_STATUS(_p_)     (((_p_[2]) & GENMASK(7, 7)) >> 7)
+#define   UCSI_CONSTAT_SINK_PATH_DISABLED      0
+#define   UCSI_CONSTAT_SINK_PATH_ENABLED       1
+       u8 pwr_readings[9];
+#define UCSI_CONSTAT_REV_CURR_PROT_STATUS(_p_) ((_p_[0]) & 0x1)
+#define UCSI_CONSTAT_PWR_READING_VALID(_p_)    (((_p_[0]) & GENMASK(1, 1)) >> 1)
+#define UCSI_CONSTAT_CURRENT_SCALE(_p_)                (((_p_[0]) & GENMASK(4, 2)) >> 2)
+#define UCSI_CONSTAT_PEAK_CURRENT(_p_) \
+       ((get_unaligned_le32(_p_) & GENMASK(20, 5)) >> 5)
+#define UCSI_CONSTAT_AVG_CURRENT(_p_) \
+       ((get_unaligned_le32(&(_p_)[2]) & GENMASK(20, 5)) >> 5)
+#define UCSI_CONSTAT_VOLTAGE_SCALE(_p_) \
+       ((get_unaligned_le16(&(_p_)[4]) & GENMASK(8, 5)) >> 5)
+#define UCSI_CONSTAT_VOLTAGE_READING(_p_) \
+       ((get_unaligned_le32(&(_p_)[5]) & GENMASK(16, 1)) >> 1)
+} __packed;
+
+/*
+ * Data structure filled by PPM in response to GET_PD_MESSAGE command with the
+ * Response Message Type set to Discover Identity Response.
+ */
+struct ucsi_pd_message_disc_id {
+       u32 vdm_header;
+       u32 id_header;
+       u32 cert_stat;
+       u32 product;
+       u32 vdo[3];
 } __packed;
 
 /* -------------------------------------------------------------------------- */
@@ -341,14 +428,18 @@ struct ucsi_connector {
 
        struct typec_port *port;
        struct typec_partner *partner;
+       struct typec_cable *cable;
+       struct typec_plug *plug;
 
        struct typec_altmode *port_altmode[UCSI_MAX_ALTMODES];
        struct typec_altmode *partner_altmode[UCSI_MAX_ALTMODES];
+       struct typec_altmode *plug_altmode[UCSI_MAX_ALTMODES];
 
        struct typec_capability typec_cap;
 
        struct ucsi_connector_status status;
        struct ucsi_connector_capability cap;
+       struct ucsi_cable_property cable_prop;
        struct power_supply *psy;
        struct power_supply_desc psy_desc;
        u32 rdo;
@@ -364,6 +455,10 @@ struct ucsi_connector {
        struct usb_power_delivery_capabilities *partner_sink_caps;
 
        struct usb_role_switch *usb_role_sw;
+
+       /* USB PD identity */
+       struct usb_pd_identity partner_identity;
+       struct usb_pd_identity cable_identity;
 };
 
 int ucsi_send_command(struct ucsi *ucsi, u64 command,
index 449c125f6f87008ec636c95491180aef1e81cfcf..dda7c7c94e08a95a37059574206448bb77820d90 100644 (file)
@@ -192,6 +192,12 @@ struct ucsi_ccg_altmode {
        bool checked;
 } __packed;
 
+#define CCGX_MESSAGE_IN_MAX 4
+struct op_region {
+       __le32 cci;
+       __le32 message_in[CCGX_MESSAGE_IN_MAX];
+};
+
 struct ucsi_ccg {
        struct device *dev;
        struct ucsi *ucsi;
@@ -222,6 +228,13 @@ struct ucsi_ccg {
        bool has_multiple_dp;
        struct ucsi_ccg_altmode orig[UCSI_MAX_ALTMODES];
        struct ucsi_ccg_altmode updated[UCSI_MAX_ALTMODES];
+
+       /*
+        * This spinlock protects op_data which includes CCI and MESSAGE_IN that
+        * will be updated in ISR
+        */
+       spinlock_t op_lock;
+       struct op_region op_data;
 };
 
 static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -305,12 +318,42 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, const u8 *data, u32 len)
        return 0;
 }
 
+static int ccg_op_region_update(struct ucsi_ccg *uc, u32 cci)
+{
+       u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_MESSAGE_IN);
+       struct op_region *data = &uc->op_data;
+       unsigned char *buf;
+       size_t size = sizeof(data->message_in);
+
+       buf = kzalloc(size, GFP_ATOMIC);
+       if (!buf)
+               return -ENOMEM;
+       if (UCSI_CCI_LENGTH(cci)) {
+               int ret = ccg_read(uc, reg, (void *)buf, size);
+
+               if (ret) {
+                       kfree(buf);
+                       return ret;
+               }
+       }
+
+       spin_lock(&uc->op_lock);
+       data->cci = cpu_to_le32(cci);
+       if (UCSI_CCI_LENGTH(cci))
+               memcpy(&data->message_in, buf, size);
+       spin_unlock(&uc->op_lock);
+       kfree(buf);
+       return 0;
+}
+
 static int ucsi_ccg_init(struct ucsi_ccg *uc)
 {
        unsigned int count = 10;
        u8 data;
        int status;
 
+       spin_lock_init(&uc->op_lock);
+
        data = CCGX_RAB_UCSI_CONTROL_STOP;
        status = ccg_write(uc, CCGX_RAB_UCSI_CONTROL, &data, sizeof(data));
        if (status < 0)
@@ -520,9 +563,20 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset,
        u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset);
        struct ucsi_capability *cap;
        struct ucsi_altmode *alt;
-       int ret;
+       int ret = 0;
+
+       if (offset == UCSI_CCI) {
+               spin_lock(&uc->op_lock);
+               memcpy(val, &(uc->op_data).cci, val_len);
+               spin_unlock(&uc->op_lock);
+       } else if (offset == UCSI_MESSAGE_IN) {
+               spin_lock(&uc->op_lock);
+               memcpy(val, &(uc->op_data).message_in, val_len);
+               spin_unlock(&uc->op_lock);
+       } else {
+               ret = ccg_read(uc, reg, val, val_len);
+       }
 
-       ret = ccg_read(uc, reg, val, val_len);
        if (ret)
                return ret;
 
@@ -559,9 +613,18 @@ static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset,
 static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset,
                                const void *val, size_t val_len)
 {
+       struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi);
        u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset);
 
-       return ccg_write(ucsi_get_drvdata(ucsi), reg, val, val_len);
+       /*
+        * UCSI may read CCI instantly after async_write,
+        * clear CCI to avoid caller getting wrong data before we get CCI from ISR
+        */
+       spin_lock(&uc->op_lock);
+       uc->op_data.cci = 0;
+       spin_unlock(&uc->op_lock);
+
+       return ccg_write(uc, reg, val, val_len);
 }
 
 static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset,
@@ -615,13 +678,18 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
        u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_CCI);
        struct ucsi_ccg *uc = data;
        u8 intr_reg;
-       u32 cci;
-       int ret;
+       u32 cci = 0;
+       int ret = 0;
 
        ret = ccg_read(uc, CCGX_RAB_INTR_REG, &intr_reg, sizeof(intr_reg));
        if (ret)
                return ret;
 
+       if (!intr_reg)
+               return IRQ_HANDLED;
+       else if (!(intr_reg & UCSI_READ_INT))
+               goto err_clear_irq;
+
        ret = ccg_read(uc, reg, (void *)&cci, sizeof(cci));
        if (ret)
                goto err_clear_irq;
@@ -629,13 +697,21 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
        if (UCSI_CCI_CONNECTOR(cci))
                ucsi_connector_change(uc->ucsi, UCSI_CCI_CONNECTOR(cci));
 
-       if (test_bit(DEV_CMD_PENDING, &uc->flags) &&
-           cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
-               complete(&uc->complete);
+       /*
+        * As per CCGx UCSI interface guide, copy CCI and MESSAGE_IN
+        * to the OpRegion before clear the UCSI interrupt
+        */
+       ret = ccg_op_region_update(uc, cci);
+       if (ret)
+               goto err_clear_irq;
 
 err_clear_irq:
        ccg_write(uc, CCGX_RAB_INTR_REG, &intr_reg, sizeof(intr_reg));
 
+       if (!ret && test_bit(DEV_CMD_PENDING, &uc->flags) &&
+           cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
+               complete(&uc->complete);
+
        return IRQ_HANDLED;
 }
 
index faccc942b381be43700f0de95401bef80af500ec..932e7bf694473586b06d311311c2720ff9143a85 100644 (file)
@@ -298,6 +298,7 @@ static void pmic_glink_ucsi_destroy(void *data)
 }
 
 static const struct of_device_id pmic_glink_ucsi_of_quirks[] = {
+       { .compatible = "qcom,qcm6490-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
        { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
        { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
        { .compatible = "qcom,sm8350-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, },
index cce3d1837104c34f0bf331db33d5a81f64c0a6e7..ad7f3447fe90ccfc6720b2a2e79abbf3986b3391 100644 (file)
@@ -254,6 +254,13 @@ static u16 eni_vdpa_get_vq_num_min(struct vdpa_device *vdpa)
        return vp_legacy_get_queue_size(ldev, 0);
 }
 
+static u16 eni_vdpa_get_vq_size(struct vdpa_device *vdpa, u16 qid)
+{
+       struct virtio_pci_legacy_device *ldev = vdpa_to_ldev(vdpa);
+
+       return vp_legacy_get_queue_size(ldev, qid);
+}
+
 static int eni_vdpa_get_vq_state(struct vdpa_device *vdpa, u16 qid,
                                struct vdpa_vq_state *state)
 {
@@ -416,6 +423,7 @@ static const struct vdpa_config_ops eni_vdpa_ops = {
        .reset          = eni_vdpa_reset,
        .get_vq_num_max = eni_vdpa_get_vq_num_max,
        .get_vq_num_min = eni_vdpa_get_vq_num_min,
+       .get_vq_size    = eni_vdpa_get_vq_size,
        .get_vq_state   = eni_vdpa_get_vq_state,
        .set_vq_state   = eni_vdpa_set_vq_state,
        .set_vq_cb      = eni_vdpa_set_vq_cb,
index 060f837a4f9f762018fd29d52bcb10c91a9436aa..472daa588a9d214aa1518530255afdc9a1919e1f 100644 (file)
@@ -69,20 +69,19 @@ static int ifcvf_read_config_range(struct pci_dev *dev,
        return 0;
 }
 
-static u16 ifcvf_get_vq_size(struct ifcvf_hw *hw, u16 qid)
+u16 ifcvf_get_vq_size(struct ifcvf_hw *hw, u16 qid)
 {
        u16 queue_size;
 
+       if (qid >= hw->nr_vring)
+               return 0;
+
        vp_iowrite16(qid, &hw->common_cfg->queue_select);
        queue_size = vp_ioread16(&hw->common_cfg->queue_size);
 
        return queue_size;
 }
 
-/* This function returns the max allowed safe size for
- * all virtqueues. It is the minimal size that can be
- * suppprted by all virtqueues.
- */
 u16 ifcvf_get_max_vq_size(struct ifcvf_hw *hw)
 {
        u16 queue_size, max_size, qid;
@@ -94,7 +93,7 @@ u16 ifcvf_get_max_vq_size(struct ifcvf_hw *hw)
                if (!queue_size)
                        continue;
 
-               max_size = min(queue_size, max_size);
+               max_size = max(queue_size, max_size);
        }
 
        return max_size;
index b57849c643f611fc271d894eb24075f99a0c6fed..0f347717021a2eb2d827e11b59e11f9cafb43f5e 100644 (file)
@@ -28,6 +28,7 @@
 #define IFCVF_PCI_MAX_RESOURCE 6
 
 #define IFCVF_LM_BAR                   4
+#define IFCVF_MIN_VQ_SIZE              64
 
 #define IFCVF_ERR(pdev, fmt, ...)      dev_err(&pdev->dev, fmt, ##__VA_ARGS__)
 #define IFCVF_DBG(pdev, fmt, ...)      dev_dbg(&pdev->dev, fmt, ##__VA_ARGS__)
@@ -131,4 +132,5 @@ void ifcvf_set_vq_ready(struct ifcvf_hw *hw, u16 qid, bool ready);
 void ifcvf_set_driver_features(struct ifcvf_hw *hw, u64 features);
 u64 ifcvf_get_driver_features(struct ifcvf_hw *hw);
 u16 ifcvf_get_max_vq_size(struct ifcvf_hw *hw);
+u16 ifcvf_get_vq_size(struct ifcvf_hw *hw, u16 qid);
 #endif /* _IFCVF_H_ */
index e98fa8100f3cc796f2f3b543cadd7f9a694313c7..80d0a046088589a989072d0f2dbe92339a7e9674 100644 (file)
@@ -456,6 +456,11 @@ static u16 ifcvf_vdpa_get_vq_num_max(struct vdpa_device *vdpa_dev)
        return ifcvf_get_max_vq_size(vf);
 }
 
+static u16 ifcvf_vdpa_get_vq_num_min(struct vdpa_device *vdpa_dev)
+{
+       return IFCVF_MIN_VQ_SIZE;
+}
+
 static int ifcvf_vdpa_get_vq_state(struct vdpa_device *vdpa_dev, u16 qid,
                                   struct vdpa_vq_state *state)
 {
@@ -597,6 +602,14 @@ static int ifcvf_vdpa_get_vq_irq(struct vdpa_device *vdpa_dev,
                return -EINVAL;
 }
 
+static u16 ifcvf_vdpa_get_vq_size(struct vdpa_device *vdpa_dev,
+                            u16 qid)
+{
+       struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
+
+       return ifcvf_get_vq_size(vf, qid);
+}
+
 static struct vdpa_notification_area ifcvf_get_vq_notification(struct vdpa_device *vdpa_dev,
                                                               u16 idx)
 {
@@ -624,6 +637,7 @@ static const struct vdpa_config_ops ifc_vdpa_ops = {
        .set_status     = ifcvf_vdpa_set_status,
        .reset          = ifcvf_vdpa_reset,
        .get_vq_num_max = ifcvf_vdpa_get_vq_num_max,
+       .get_vq_num_min = ifcvf_vdpa_get_vq_num_min,
        .get_vq_state   = ifcvf_vdpa_get_vq_state,
        .set_vq_state   = ifcvf_vdpa_set_vq_state,
        .set_vq_cb      = ifcvf_vdpa_set_vq_cb,
@@ -632,6 +646,7 @@ static const struct vdpa_config_ops ifc_vdpa_ops = {
        .set_vq_num     = ifcvf_vdpa_set_vq_num,
        .set_vq_address = ifcvf_vdpa_set_vq_address,
        .get_vq_irq     = ifcvf_vdpa_get_vq_irq,
+       .get_vq_size    = ifcvf_vdpa_get_vq_size,
        .kick_vq        = ifcvf_vdpa_kick_vq,
        .get_generation = ifcvf_vdpa_get_generation,
        .get_device_id  = ifcvf_vdpa_get_device_id,
index 778821bab7d93e3393440656306e60cfae52d096..ecfc16151d61913408b1ce838b6774bdb1bfe1da 100644 (file)
@@ -151,8 +151,6 @@ static void teardown_driver(struct mlx5_vdpa_net *ndev);
 
 static bool mlx5_vdpa_debug;
 
-#define MLX5_CVQ_MAX_ENT 16
-
 #define MLX5_LOG_VIO_FLAG(_feature)                                                                \
        do {                                                                                       \
                if (features & BIT_ULL(_feature))                                                  \
@@ -2276,9 +2274,16 @@ static void mlx5_vdpa_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num)
        struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
        struct mlx5_vdpa_virtqueue *mvq;
 
-       if (!is_index_valid(mvdev, idx) || is_ctrl_vq_idx(mvdev, idx))
+       if (!is_index_valid(mvdev, idx))
                return;
 
+        if (is_ctrl_vq_idx(mvdev, idx)) {
+                struct mlx5_control_vq *cvq = &mvdev->cvq;
+
+                cvq->vring.vring.num = num;
+                return;
+        }
+
        mvq = &ndev->vqs[idx];
        mvq->num_ent = num;
 }
@@ -2963,7 +2968,7 @@ static int setup_cvq_vring(struct mlx5_vdpa_dev *mvdev)
                u16 idx = cvq->vring.last_avail_idx;
 
                err = vringh_init_iotlb(&cvq->vring, mvdev->actual_features,
-                                       MLX5_CVQ_MAX_ENT, false,
+                                       cvq->vring.vring.num, false,
                                        (struct vring_desc *)(uintptr_t)cvq->desc_addr,
                                        (struct vring_avail *)(uintptr_t)cvq->driver_addr,
                                        (struct vring_used *)(uintptr_t)cvq->device_addr);
index 186e9ee22eb1126127a829f221d67dd76e8b3252..f57330cf90246dd30b9ec9b6fac91a613fee6c0f 100644 (file)
@@ -93,8 +93,8 @@ static void pds_vdpa_remove(struct auxiliary_device *aux_dev)
        struct device *dev = &aux_dev->dev;
 
        vdpa_mgmtdev_unregister(&vdpa_aux->vdpa_mdev);
+       pds_vdpa_release_irqs(vdpa_aux->pdsv);
        vp_modern_remove(&vdpa_aux->vd_mdev);
-       pci_free_irq_vectors(vdpa_aux->padev->vf_pdev);
 
        pds_vdpa_debugfs_del_vdpadev(vdpa_aux);
        kfree(vdpa_aux);
index 25c0fe5ec3d5dfacdb53fa31a709851adb118942..301d95e085960d6d132f7bab59f930e38fbc8f88 100644 (file)
@@ -426,12 +426,18 @@ err_release:
        return err;
 }
 
-static void pds_vdpa_release_irqs(struct pds_vdpa_device *pdsv)
+void pds_vdpa_release_irqs(struct pds_vdpa_device *pdsv)
 {
-       struct pci_dev *pdev = pdsv->vdpa_aux->padev->vf_pdev;
-       struct pds_vdpa_aux *vdpa_aux = pdsv->vdpa_aux;
+       struct pds_vdpa_aux *vdpa_aux;
+       struct pci_dev *pdev;
        int qid;
 
+       if (!pdsv)
+               return;
+
+       pdev = pdsv->vdpa_aux->padev->vf_pdev;
+       vdpa_aux = pdsv->vdpa_aux;
+
        if (!vdpa_aux->nintrs)
                return;
 
@@ -612,6 +618,7 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
        struct device *dma_dev;
        struct pci_dev *pdev;
        struct device *dev;
+       u8 status;
        int err;
        int i;
 
@@ -638,6 +645,13 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
        dma_dev = &pdev->dev;
        pdsv->vdpa_dev.dma_dev = dma_dev;
 
+       status = pds_vdpa_get_status(&pdsv->vdpa_dev);
+       if (status == 0xff) {
+               dev_err(dev, "Broken PCI - status %#x\n", status);
+               err = -ENXIO;
+               goto err_unmap;
+       }
+
        pdsv->supported_features = mgmt->supported_features;
 
        if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
index d984ba24a7dae13d928e4402139d9c906845e90a..84bdb45871ff07db13a56affc213d72511fd440d 100644 (file)
@@ -46,5 +46,6 @@ struct pds_vdpa_device {
 
 #define PDS_VDPA_PACKED_INVERT_IDX     0x8000
 
+void pds_vdpa_release_irqs(struct pds_vdpa_device *pdsv);
 int pds_vdpa_get_mgmt_info(struct pds_vdpa_aux *vdpa_aux);
 #endif /* _VDPA_DEV_H_ */
index d0695680b282ec7812983a7bd37cd9729dfa0126..b246067e074bc0718ad49ad582b3ad9e382c9af0 100644 (file)
@@ -115,7 +115,7 @@ static const struct attribute_group vdpa_dev_group = {
 };
 __ATTRIBUTE_GROUPS(vdpa_dev);
 
-static struct bus_type vdpa_bus = {
+static const struct bus_type vdpa_bus = {
        .name  = "vdpa",
        .dev_groups = vdpa_dev_groups,
        .match = vdpa_dev_match,
@@ -944,6 +944,215 @@ static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *ms
        return vdpa_dev_net_mq_config_fill(msg, features_device, &config);
 }
 
+static int
+vdpa_dev_blk_capacity_config_fill(struct sk_buff *msg,
+                                 const struct virtio_blk_config *config)
+{
+       u64 val_u64;
+
+       val_u64 = __virtio64_to_cpu(true, config->capacity);
+
+       return nla_put_u64_64bit(msg, VDPA_ATTR_DEV_BLK_CFG_CAPACITY,
+                                val_u64, VDPA_ATTR_PAD);
+}
+
+static int
+vdpa_dev_blk_seg_size_config_fill(struct sk_buff *msg, u64 features,
+                                 const struct virtio_blk_config *config)
+{
+       u32 val_u32;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_SIZE_MAX)) == 0)
+               return 0;
+
+       val_u32 = __virtio32_to_cpu(true, config->size_max);
+
+       return nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_SEG_SIZE, val_u32);
+}
+
+/* fill the block size*/
+static int
+vdpa_dev_blk_block_size_config_fill(struct sk_buff *msg, u64 features,
+                                   const struct virtio_blk_config *config)
+{
+       u32 val_u32;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_BLK_SIZE)) == 0)
+               return 0;
+
+       val_u32 = __virtio32_to_cpu(true, config->blk_size);
+
+       return nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_BLK_SIZE, val_u32);
+}
+
+static int
+vdpa_dev_blk_seg_max_config_fill(struct sk_buff *msg, u64 features,
+                                const struct virtio_blk_config *config)
+{
+       u32 val_u32;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_SEG_MAX)) == 0)
+               return 0;
+
+       val_u32 = __virtio32_to_cpu(true, config->seg_max);
+
+       return nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_SEG_MAX, val_u32);
+}
+
+static int vdpa_dev_blk_mq_config_fill(struct sk_buff *msg, u64 features,
+                                      const struct virtio_blk_config *config)
+{
+       u16 val_u16;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_MQ)) == 0)
+               return 0;
+
+       val_u16 = __virtio16_to_cpu(true, config->num_queues);
+
+       return nla_put_u16(msg, VDPA_ATTR_DEV_BLK_CFG_NUM_QUEUES, val_u16);
+}
+
+static int vdpa_dev_blk_topology_config_fill(struct sk_buff *msg, u64 features,
+                                      const struct virtio_blk_config *config)
+{
+       u16 min_io_size;
+       u32 opt_io_size;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_TOPOLOGY)) == 0)
+               return 0;
+
+       min_io_size = __virtio16_to_cpu(true, config->min_io_size);
+       opt_io_size = __virtio32_to_cpu(true, config->opt_io_size);
+
+       if (nla_put_u8(msg, VDPA_ATTR_DEV_BLK_CFG_PHY_BLK_EXP,
+           config->physical_block_exp))
+               return -EMSGSIZE;
+
+       if (nla_put_u8(msg, VDPA_ATTR_DEV_BLK_CFG_ALIGN_OFFSET,
+           config->alignment_offset))
+               return -EMSGSIZE;
+
+       if (nla_put_u16(msg, VDPA_ATTR_DEV_BLK_CFG_MIN_IO_SIZE, min_io_size))
+               return -EMSGSIZE;
+
+       if (nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_OPT_IO_SIZE, opt_io_size))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int vdpa_dev_blk_discard_config_fill(struct sk_buff *msg, u64 features,
+                                      const struct virtio_blk_config *config)
+{
+       u32 val_u32;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_DISCARD)) == 0)
+               return 0;
+
+       val_u32 = __virtio32_to_cpu(true, config->max_discard_sectors);
+       if (nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_MAX_DISCARD_SEC, val_u32))
+               return -EMSGSIZE;
+
+       val_u32 = __virtio32_to_cpu(true, config->max_discard_seg);
+       if (nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_MAX_DISCARD_SEG, val_u32))
+               return -EMSGSIZE;
+
+       val_u32 = __virtio32_to_cpu(true, config->discard_sector_alignment);
+       if (nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_DISCARD_SEC_ALIGN, val_u32))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+vdpa_dev_blk_write_zeroes_config_fill(struct sk_buff *msg, u64 features,
+                                    const struct virtio_blk_config *config)
+{
+       u32 val_u32;
+
+       if ((features & BIT_ULL(VIRTIO_BLK_F_WRITE_ZEROES)) == 0)
+               return 0;
+
+       val_u32 = __virtio32_to_cpu(true, config->max_write_zeroes_sectors);
+       if (nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_MAX_WRITE_ZEROES_SEC, val_u32))
+               return -EMSGSIZE;
+
+       val_u32 = __virtio32_to_cpu(true, config->max_write_zeroes_seg);
+       if (nla_put_u32(msg, VDPA_ATTR_DEV_BLK_CFG_MAX_WRITE_ZEROES_SEG, val_u32))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int vdpa_dev_blk_ro_config_fill(struct sk_buff *msg, u64 features)
+{
+       u8 ro;
+
+       ro = ((features & BIT_ULL(VIRTIO_BLK_F_RO)) == 0) ? 0 : 1;
+       if (nla_put_u8(msg, VDPA_ATTR_DEV_BLK_CFG_READ_ONLY, ro))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int vdpa_dev_blk_flush_config_fill(struct sk_buff *msg, u64 features)
+{
+       u8 flush;
+
+       flush = ((features & BIT_ULL(VIRTIO_BLK_F_FLUSH)) == 0) ? 0 : 1;
+       if (nla_put_u8(msg, VDPA_ATTR_DEV_BLK_CFG_FLUSH, flush))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int vdpa_dev_blk_config_fill(struct vdpa_device *vdev,
+                                   struct sk_buff *msg)
+{
+       struct virtio_blk_config config = {};
+       u64 features_device;
+
+       vdev->config->get_config(vdev, 0, &config, sizeof(config));
+
+       features_device = vdev->config->get_device_features(vdev);
+
+       if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_FEATURES, features_device,
+                             VDPA_ATTR_PAD))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_capacity_config_fill(msg, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_seg_size_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_block_size_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_seg_max_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_mq_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_topology_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_discard_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_write_zeroes_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_ro_config_fill(msg, features_device))
+               return -EMSGSIZE;
+
+       if (vdpa_dev_blk_flush_config_fill(msg, features_device))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
 static int
 vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, u32 seq,
                     int flags, struct netlink_ext_ack *extack)
@@ -988,6 +1197,9 @@ vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid,
        case VIRTIO_ID_NET:
                err = vdpa_dev_net_config_fill(vdev, msg);
                break;
+       case VIRTIO_ID_BLOCK:
+               err = vdpa_dev_blk_config_fill(vdev, msg);
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
index be2925d0d28368e8959a9696f2d1c92ba4eb7fd8..8ffea8430f95fec128759fbcca2698dbdabf4179 100644 (file)
@@ -160,7 +160,7 @@ static void vdpasim_do_reset(struct vdpasim *vdpasim, u32 flags)
                }
        }
 
-       vdpasim->running = true;
+       vdpasim->running = false;
        spin_unlock(&vdpasim->iommu_lock);
 
        vdpasim->features = 0;
@@ -311,6 +311,17 @@ static void vdpasim_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num)
        vq->num = num;
 }
 
+static u16 vdpasim_get_vq_size(struct vdpa_device *vdpa, u16 idx)
+{
+       struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
+       struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx];
+
+       if (vdpasim->status & VIRTIO_CONFIG_S_DRIVER_OK)
+               return vq->num;
+       else
+               return VDPASIM_QUEUE_MAX;
+}
+
 static void vdpasim_kick_vq(struct vdpa_device *vdpa, u16 idx)
 {
        struct vdpasim *vdpasim = vdpa_to_sim(vdpa);
@@ -483,6 +494,7 @@ static void vdpasim_set_status(struct vdpa_device *vdpa, u8 status)
 
        mutex_lock(&vdpasim->mutex);
        vdpasim->status = status;
+       vdpasim->running = (status & VIRTIO_CONFIG_S_DRIVER_OK) != 0;
        mutex_unlock(&vdpasim->mutex);
 }
 
@@ -774,6 +786,7 @@ static const struct vdpa_config_ops vdpasim_config_ops = {
        .get_driver_features    = vdpasim_get_driver_features,
        .set_config_cb          = vdpasim_set_config_cb,
        .get_vq_num_max         = vdpasim_get_vq_num_max,
+       .get_vq_size            = vdpasim_get_vq_size,
        .get_device_id          = vdpasim_get_device_id,
        .get_vendor_id          = vdpasim_get_vendor_id,
        .get_status             = vdpasim_get_status,
index 5e4a77b9bae6bea6402626b3ad00134d67aa31d2..791d38d6284c562b21f1eec662a95bdf2b4c2d12 100644 (file)
@@ -373,6 +373,26 @@ static void vduse_domain_free_iova(struct iova_domain *iovad,
        free_iova_fast(iovad, iova >> shift, iova_len);
 }
 
+void vduse_domain_sync_single_for_device(struct vduse_iova_domain *domain,
+                                     dma_addr_t dma_addr, size_t size,
+                                     enum dma_data_direction dir)
+{
+       read_lock(&domain->bounce_lock);
+       if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
+               vduse_domain_bounce(domain, dma_addr, size, DMA_TO_DEVICE);
+       read_unlock(&domain->bounce_lock);
+}
+
+void vduse_domain_sync_single_for_cpu(struct vduse_iova_domain *domain,
+                                     dma_addr_t dma_addr, size_t size,
+                                     enum dma_data_direction dir)
+{
+       read_lock(&domain->bounce_lock);
+       if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+               vduse_domain_bounce(domain, dma_addr, size, DMA_FROM_DEVICE);
+       read_unlock(&domain->bounce_lock);
+}
+
 dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
                                 struct page *page, unsigned long offset,
                                 size_t size, enum dma_data_direction dir,
@@ -393,7 +413,8 @@ dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
        if (vduse_domain_map_bounce_page(domain, (u64)iova, (u64)size, pa))
                goto err_unlock;
 
-       if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
+       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+           (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
                vduse_domain_bounce(domain, iova, size, DMA_TO_DEVICE);
 
        read_unlock(&domain->bounce_lock);
@@ -411,9 +432,9 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
                             enum dma_data_direction dir, unsigned long attrs)
 {
        struct iova_domain *iovad = &domain->stream_iovad;
-
        read_lock(&domain->bounce_lock);
-       if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
+           (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
                vduse_domain_bounce(domain, dma_addr, size, DMA_FROM_DEVICE);
 
        vduse_domain_unmap_bounce_page(domain, (u64)dma_addr, (u64)size);
index 173e979b84a937c6d67254430ddb392843f3f6cb..f92f22a7267d70f46d008723ecb40f36c841c1f2 100644 (file)
@@ -44,6 +44,14 @@ int vduse_domain_set_map(struct vduse_iova_domain *domain,
 void vduse_domain_clear_map(struct vduse_iova_domain *domain,
                            struct vhost_iotlb *iotlb);
 
+void vduse_domain_sync_single_for_device(struct vduse_iova_domain *domain,
+                                     dma_addr_t dma_addr, size_t size,
+                                     enum dma_data_direction dir);
+
+void vduse_domain_sync_single_for_cpu(struct vduse_iova_domain *domain,
+                                     dma_addr_t dma_addr, size_t size,
+                                     enum dma_data_direction dir);
+
 dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
                                 struct page *page, unsigned long offset,
                                 size_t size, enum dma_data_direction dir,
index 1d24da79c39956ae59400ac6ec4406494ba8c655..73c89701fc9d403183387e69b3b62e1e8e90db05 100644 (file)
@@ -541,6 +541,17 @@ static void vduse_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 idx, u32 num)
        vq->num = num;
 }
 
+static u16 vduse_vdpa_get_vq_size(struct vdpa_device *vdpa, u16 idx)
+{
+       struct vduse_dev *dev = vdpa_to_vduse(vdpa);
+       struct vduse_virtqueue *vq = dev->vqs[idx];
+
+       if (vq->num)
+               return vq->num;
+       else
+               return vq->num_max;
+}
+
 static void vduse_vdpa_set_vq_ready(struct vdpa_device *vdpa,
                                        u16 idx, bool ready)
 {
@@ -773,6 +784,7 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
        .kick_vq                = vduse_vdpa_kick_vq,
        .set_vq_cb              = vduse_vdpa_set_vq_cb,
        .set_vq_num             = vduse_vdpa_set_vq_num,
+       .get_vq_size            = vduse_vdpa_get_vq_size,
        .set_vq_ready           = vduse_vdpa_set_vq_ready,
        .get_vq_ready           = vduse_vdpa_get_vq_ready,
        .set_vq_state           = vduse_vdpa_set_vq_state,
@@ -798,6 +810,26 @@ static const struct vdpa_config_ops vduse_vdpa_config_ops = {
        .free                   = vduse_vdpa_free,
 };
 
+static void vduse_dev_sync_single_for_device(struct device *dev,
+                                            dma_addr_t dma_addr, size_t size,
+                                            enum dma_data_direction dir)
+{
+       struct vduse_dev *vdev = dev_to_vduse(dev);
+       struct vduse_iova_domain *domain = vdev->domain;
+
+       vduse_domain_sync_single_for_device(domain, dma_addr, size, dir);
+}
+
+static void vduse_dev_sync_single_for_cpu(struct device *dev,
+                                            dma_addr_t dma_addr, size_t size,
+                                            enum dma_data_direction dir)
+{
+       struct vduse_dev *vdev = dev_to_vduse(dev);
+       struct vduse_iova_domain *domain = vdev->domain;
+
+       vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir);
+}
+
 static dma_addr_t vduse_dev_map_page(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size,
                                     enum dma_data_direction dir,
@@ -858,6 +890,8 @@ static size_t vduse_dev_max_mapping_size(struct device *dev)
 }
 
 static const struct dma_map_ops vduse_dev_dma_ops = {
+       .sync_single_for_device = vduse_dev_sync_single_for_device,
+       .sync_single_for_cpu = vduse_dev_sync_single_for_cpu,
        .map_page = vduse_dev_map_page,
        .unmap_page = vduse_dev_unmap_page,
        .alloc = vduse_dev_alloc_coherent,
index 281287fae89f137e18e09d5c259115f3af1fcb4f..df5f4a3bccb57ab63ae14be32c3a30692eeb8ac0 100644 (file)
@@ -328,6 +328,13 @@ static void vp_vdpa_set_vq_num(struct vdpa_device *vdpa, u16 qid,
        vp_modern_set_queue_size(mdev, qid, num);
 }
 
+static u16 vp_vdpa_get_vq_size(struct vdpa_device *vdpa, u16 qid)
+{
+       struct virtio_pci_modern_device *mdev = vdpa_to_mdev(vdpa);
+
+       return vp_modern_get_queue_size(mdev, qid);
+}
+
 static int vp_vdpa_set_vq_address(struct vdpa_device *vdpa, u16 qid,
                                  u64 desc_area, u64 driver_area,
                                  u64 device_area)
@@ -449,6 +456,7 @@ static const struct vdpa_config_ops vp_vdpa_ops = {
        .set_vq_ready   = vp_vdpa_set_vq_ready,
        .get_vq_ready   = vp_vdpa_get_vq_ready,
        .set_vq_num     = vp_vdpa_set_vq_num,
+       .get_vq_size    = vp_vdpa_get_vq_size,
        .set_vq_address = vp_vdpa_set_vq_address,
        .kick_vq        = vp_vdpa_kick_vq,
        .get_generation = vp_vdpa_get_generation,
index 4b2fcb228a0a7930e19390cc21149b3f9a696e7e..c64ded183f8dd8eb13442185f5780de737b0edda 100644 (file)
@@ -697,6 +697,9 @@ static int vhost_net_build_xdp(struct vhost_net_virtqueue *nvq,
        hdr = buf;
        gso = &hdr->gso;
 
+       if (!sock_hlen)
+               memset(buf, 0, pad);
+
        if ((gso->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
            vhost16_to_cpu(vq, gso->csum_start) +
            vhost16_to_cpu(vq, gso->csum_offset) + 2 >
index bc4a51e4638b46c79345f2be89dc7639b81ee28a..ba52d128aeb76bc1d52b375707f12875915bc7e6 100644 (file)
@@ -595,6 +595,9 @@ static long vhost_vdpa_suspend(struct vhost_vdpa *v)
        const struct vdpa_config_ops *ops = vdpa->config;
        int ret;
 
+       if (!(ops->get_status(vdpa) & VIRTIO_CONFIG_S_DRIVER_OK))
+               return 0;
+
        if (!ops->suspend)
                return -EOPNOTSUPP;
 
@@ -615,6 +618,9 @@ static long vhost_vdpa_resume(struct vhost_vdpa *v)
        const struct vdpa_config_ops *ops = vdpa->config;
        int ret;
 
+       if (!(ops->get_status(vdpa) & VIRTIO_CONFIG_S_DRIVER_OK))
+               return 0;
+
        if (!ops->resume)
                return -EOPNOTSUPP;
 
@@ -681,6 +687,14 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
                if (!ops->set_group_asid)
                        return -EOPNOTSUPP;
                return ops->set_group_asid(vdpa, idx, s.num);
+       case VHOST_VDPA_GET_VRING_SIZE:
+               if (!ops->get_vq_size)
+                       return -EOPNOTSUPP;
+               s.index = idx;
+               s.num = ops->get_vq_size(vdpa, idx);
+               if (copy_to_user(argp, &s, sizeof(s)))
+                       return -EFAULT;
+               return 0;
        case VHOST_GET_VRING_BASE:
                r = ops->get_vq_state(v->vdpa, idx, &vq_state);
                if (r)
index 14af5d9e13b00efd153c03f4f4553f52a6a01080..139049368fdcf86f8174208d950448d340dfee25 100644 (file)
@@ -50,7 +50,8 @@ void dummycon_unregister_output_notifier(struct notifier_block *nb)
        raw_notifier_chain_unregister(&dummycon_output_nh, nb);
 }
 
-static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
+static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y,
+                          unsigned int x)
 {
        WARN_CONSOLE_UNLOCKED();
 
@@ -58,10 +59,10 @@ static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
        raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
 }
 
-static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
-                          int count, int ypos, int xpos)
+static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
+                          unsigned int ypos, unsigned int xpos)
 {
-       int i;
+       unsigned int i;
 
        if (!dummycon_putc_called) {
                /* Ignore erases */
@@ -78,18 +79,21 @@ static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
        raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
 }
 
-static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
+static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
+                          bool mode_switch)
 {
        /* Redraw, so that we get putc(s) for output done while blanked */
-       return 1;
+       return true;
 }
 #else
-static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
-static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
-                          int count, int ypos, int xpos) { }
-static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
+static void dummycon_putc(struct vc_data *vc, u16 c, unsigned int y,
+                         unsigned int x) { }
+static void dummycon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
+                          unsigned int ypos, unsigned int xpos) { }
+static bool dummycon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
+                          bool mode_switch)
 {
-       return 0;
+       return false;
 }
 #endif
 
@@ -98,7 +102,7 @@ static const char *dummycon_startup(void)
     return "dummy device";
 }
 
-static void dummycon_init(struct vc_data *vc, int init)
+static void dummycon_init(struct vc_data *vc, bool init)
 {
     vc->vc_can_do_color = 1;
     if (init) {
@@ -109,9 +113,9 @@ static void dummycon_init(struct vc_data *vc, int init)
 }
 
 static void dummycon_deinit(struct vc_data *vc) { }
-static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height,
-                          int width) { }
-static void dummycon_cursor(struct vc_data *vc, int mode) { }
+static void dummycon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                          unsigned int width) { }
+static void dummycon_cursor(struct vc_data *vc, bool enable) { }
 
 static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
                            unsigned int bottom, enum con_scroll dir,
@@ -120,9 +124,9 @@ static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
        return false;
 }
 
-static int dummycon_switch(struct vc_data *vc)
+static bool dummycon_switch(struct vc_data *vc)
 {
-       return 0;
+       return false;
 }
 
 /*
index ef29b321967f07353f92714f78a58522e907ddf5..c0e1f4554a44b08e927e932d7e3ba2005f60ad84 100644 (file)
@@ -352,7 +352,7 @@ static const char *mdacon_startup(void)
        return "MDA-2";
 }
 
-static void mdacon_init(struct vc_data *c, int init)
+static void mdacon_init(struct vc_data *c, bool init)
 {
        c->vc_complement_mask = 0x0800;  /* reverse video */
        c->vc_display_fg = &mda_display_fg;
@@ -427,13 +427,8 @@ static inline u16 *mda_addr(unsigned int x, unsigned int y)
        return mda_vram_base + y * mda_num_columns + x;
 }
 
-static void mdacon_putc(struct vc_data *c, int ch, int y, int x)
-{
-       scr_writew(mda_convert_attr(ch), mda_addr(x, y));
-}
-
-static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
-                        int count, int y, int x)
+static void mdacon_putcs(struct vc_data *c, const u16 *s, unsigned int count,
+                        unsigned int y, unsigned int x)
 {
        u16 *dest = mda_addr(x, y);
 
@@ -442,29 +437,22 @@ static void mdacon_putcs(struct vc_data *c, const unsigned short *s,
        }
 }
 
-static void mdacon_clear(struct vc_data *c, int y, int x, 
-                         int height, int width)
+static void mdacon_clear(struct vc_data *c, unsigned int y, unsigned int x,
+                        unsigned int width)
 {
        u16 *dest = mda_addr(x, y);
        u16 eattr = mda_convert_attr(c->vc_video_erase_char);
 
-       if (width <= 0 || height <= 0)
-               return;
-
-       if (x==0 && width==mda_num_columns) {
-               scr_memsetw(dest, eattr, height*width*2);
-       } else {
-               for (; height > 0; height--, dest+=mda_num_columns)
-                       scr_memsetw(dest, eattr, width*2);
-       }
+       scr_memsetw(dest, eattr, width * 2);
 }
-                        
-static int mdacon_switch(struct vc_data *c)
+
+static bool mdacon_switch(struct vc_data *c)
 {
-       return 1;       /* redrawing needed */
+       return true;    /* redrawing needed */
 }
 
-static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
+static bool mdacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
+                        bool mode_switch)
 {
        if (mda_type == TYPE_MDA) {
                if (blank) 
@@ -472,20 +460,20 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
                                mda_convert_attr(c->vc_video_erase_char),
                                c->vc_screenbuf_size);
                /* Tell console.c that it has to restore the screen itself */
-               return 1;
+               return true;
        } else {
                if (blank)
                        outb_p(0x00, mda_mode_port);    /* disable video */
                else
                        outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, 
                                mda_mode_port);
-               return 0;
+               return false;
        }
 }
 
-static void mdacon_cursor(struct vc_data *c, int mode)
+static void mdacon_cursor(struct vc_data *c, bool enable)
 {
-       if (mode == CM_ERASE) {
+       if (!enable) {
                mda_set_cursor(mda_vram_len - 1);
                return;
        }
@@ -544,7 +532,6 @@ static const struct consw mda_con = {
        .con_init =             mdacon_init,
        .con_deinit =           mdacon_deinit,
        .con_clear =            mdacon_clear,
-       .con_putc =             mdacon_putc,
        .con_putcs =            mdacon_putcs,
        .con_cursor =           mdacon_cursor,
        .con_scroll =           mdacon_scroll,
index e8e4f82cd4a1b845c83f36d126745fffbf176b46..a51cfc1d560e7af172b30da70b1f06668b5e48b1 100644 (file)
@@ -324,7 +324,7 @@ out_unmap:
        return NULL;
 }
 
-static void newport_init(struct vc_data *vc, int init)
+static void newport_init(struct vc_data *vc, bool init)
 {
        int cols, rows;
 
@@ -346,12 +346,12 @@ static void newport_deinit(struct vc_data *c)
        }
 }
 
-static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
-                         int width)
+static void newport_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                         unsigned int width)
 {
        int xend = ((sx + width) << 3) - 1;
        int ystart = ((sy << 4) + topscan) & 0x3ff;
-       int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
+       int yend = (((sy + 1) << 4) + topscan - 1) & 0x3ff;
 
        if (logo_active)
                return;
@@ -367,8 +367,8 @@ static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
        }
 }
 
-static void newport_putc(struct vc_data *vc, int charattr, int ypos,
-                        int xpos)
+static void newport_putc(struct vc_data *vc, u16 charattr, unsigned int ypos,
+                        unsigned int xpos)
 {
        unsigned char *p;
 
@@ -396,12 +396,13 @@ static void newport_putc(struct vc_data *vc, int charattr, int ypos,
        RENDER(npregs, p);
 }
 
-static void newport_putcs(struct vc_data *vc, const unsigned short *s,
-                         int count, int ypos, int xpos)
+static void newport_putcs(struct vc_data *vc, const u16 *s,
+                         unsigned int count, unsigned int ypos,
+                         unsigned int xpos)
 {
-       int i;
-       int charattr;
        unsigned char *p;
+       unsigned int i;
+       u16 charattr;
 
        charattr = (scr_readw(s) >> 8) & 0xff;
 
@@ -437,32 +438,28 @@ static void newport_putcs(struct vc_data *vc, const unsigned short *s,
        }
 }
 
-static void newport_cursor(struct vc_data *vc, int mode)
+static void newport_cursor(struct vc_data *vc, bool enable)
 {
        unsigned short treg;
        int xcurs, ycurs;
 
-       switch (mode) {
-       case CM_ERASE:
-               treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-               newport_vc2_set(npregs, VC2_IREG_CONTROL,
-                               (treg & ~(VC2_CTRL_ECDISP)));
-               break;
+       treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
 
-       case CM_MOVE:
-       case CM_DRAW:
-               treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+       if (!enable) {
                newport_vc2_set(npregs, VC2_IREG_CONTROL,
-                               (treg | VC2_CTRL_ECDISP));
-               xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
-               ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
-               xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
-               newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
-               newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
+                               (treg & ~(VC2_CTRL_ECDISP)));
+               return;
        }
+
+       newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
+       xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
+       ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
+       xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
+       newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
+       newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
 }
 
-static int newport_switch(struct vc_data *vc)
+static bool newport_switch(struct vc_data *vc)
 {
        static int logo_drawn = 0;
 
@@ -476,14 +473,15 @@ static int newport_switch(struct vc_data *vc)
                }
        }
 
-       return 1;
+       return true;
 }
 
-static int newport_blank(struct vc_data *c, int blank, int mode_switch)
+static bool newport_blank(struct vc_data *c, enum vesa_blank_mode blank,
+                         bool mode_switch)
 {
        unsigned short treg;
 
-       if (blank == 0) {
+       if (blank == VESA_NO_BLANKING) {
                /* unblank console */
                treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
                newport_vc2_set(npregs, VC2_IREG_CONTROL,
@@ -494,10 +492,12 @@ static int newport_blank(struct vc_data *c, int blank, int mode_switch)
                newport_vc2_set(npregs, VC2_IREG_CONTROL,
                                (treg & ~(VC2_CTRL_EDISP)));
        }
-       return 1;
+
+       return true;
 }
 
-static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch)
+static int newport_set_font(int unit, const struct console_font *op,
+                           unsigned int vpitch)
 {
        int w = op->width;
        int h = op->height;
@@ -564,12 +564,13 @@ static int newport_set_def_font(int unit, struct console_font *op)
        return 0;
 }
 
-static int newport_font_default(struct vc_data *vc, struct console_font *op, char *name)
+static int newport_font_default(struct vc_data *vc, struct console_font *op,
+                               const char *name)
 {
        return newport_set_def_font(vc->vc_num, op);
 }
 
-static int newport_font_set(struct vc_data *vc, struct console_font *font,
+static int newport_font_set(struct vc_data *vc, const struct console_font *font,
                            unsigned int vpitch, unsigned int flags)
 {
        return newport_set_font(vc->vc_num, font, vpitch);
index 992a4fa431aaa90cbf8f47f9d86a51169b3dda38..4c7b4959a1aab7cb46ebca80c1bba3e0d7b8d911 100644 (file)
@@ -71,19 +71,8 @@ static const char *sticon_startup(void)
     return "STI console";
 }
 
-static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
-{
-    if (vga_is_gfx || console_blanked)
-           return;
-
-    if (conp->vc_mode != KD_TEXT)
-           return;
-
-    sti_putc(sticon_sti, c, ypos, xpos, font_data[conp->vc_num]);
-}
-
-static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
-                        int count, int ypos, int xpos)
+static void sticon_putcs(struct vc_data *conp, const u16 *s, unsigned int count,
+                        unsigned int ypos, unsigned int xpos)
 {
     if (vga_is_gfx || console_blanked)
            return;
@@ -97,7 +86,7 @@ static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
     }
 }
 
-static void sticon_cursor(struct vc_data *conp, int mode)
+static void sticon_cursor(struct vc_data *conp, bool enable)
 {
     unsigned short car1;
 
@@ -106,23 +95,20 @@ static void sticon_cursor(struct vc_data *conp, int mode)
        return;
 
     car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];
-    switch (mode) {
-    case CM_ERASE:
+    if (!enable) {
        sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,
                 font_data[conp->vc_num]);
-       break;
-    case CM_MOVE:
-    case CM_DRAW:
-       switch (CUR_SIZE(conp->vc_cursor_type)) {
-       case CUR_UNDERLINE:
-       case CUR_LOWER_THIRD:
-       case CUR_LOWER_HALF:
-       case CUR_TWO_THIRDS:
-       case CUR_BLOCK:
-           sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
-                    conp->state.y, conp->state.x, font_data[conp->vc_num]);
-           break;
-       }
+       return;
+    }
+
+    switch (CUR_SIZE(conp->vc_cursor_type)) {
+    case CUR_UNDERLINE:
+    case CUR_LOWER_THIRD:
+    case CUR_LOWER_HALF:
+    case CUR_TWO_THIRDS:
+    case CUR_BLOCK:
+       sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
+                conp->state.y, conp->state.x, font_data[conp->vc_num]);
        break;
     }
 }
@@ -135,7 +121,7 @@ static bool sticon_scroll(struct vc_data *conp, unsigned int t,
     if (vga_is_gfx)
         return false;
 
-    sticon_cursor(conp, CM_ERASE);
+    sticon_cursor(conp, false);
 
     switch (dir) {
     case SM_UP:
@@ -167,7 +153,7 @@ static void sticon_set_def_font(int unit)
        }
 }
 
-static int sticon_set_font(struct vc_data *vc, struct console_font *op,
+static int sticon_set_font(struct vc_data *vc, const struct console_font *op,
                           unsigned int vpitch)
 {
        struct sti_struct *sti = sticon_sti;
@@ -260,20 +246,21 @@ static int sticon_set_font(struct vc_data *vc, struct console_font *op,
        return 0;
 }
 
-static int sticon_font_default(struct vc_data *vc, struct console_font *op, char *name)
+static int sticon_font_default(struct vc_data *vc, struct console_font *op,
+                              const char *name)
 {
        sticon_set_def_font(vc->vc_num);
 
        return 0;
 }
 
-static int sticon_font_set(struct vc_data *vc, struct console_font *font,
+static int sticon_font_set(struct vc_data *vc, const struct console_font *font,
                           unsigned int vpitch, unsigned int flags)
 {
        return sticon_set_font(vc, font, vpitch);
 }
 
-static void sticon_init(struct vc_data *c, int init)
+static void sticon_init(struct vc_data *c, bool init)
 {
     struct sti_struct *sti = sticon_sti;
     int vc_cols, vc_rows;
@@ -300,33 +287,32 @@ static void sticon_deinit(struct vc_data *c)
        sticon_set_def_font(i);
 }
 
-static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
-                        int width)
+static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx,
+                        unsigned int width)
 {
-    if (!height || !width)
-       return;
-
-    sti_clear(sticon_sti, sy, sx, height, width,
+    sti_clear(sticon_sti, sy, sx, 1, width,
              conp->vc_video_erase_char, font_data[conp->vc_num]);
 }
 
-static int sticon_switch(struct vc_data *conp)
+static bool sticon_switch(struct vc_data *conp)
 {
-    return 1;  /* needs refreshing */
+    return true;       /* needs refreshing */
 }
 
-static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
+static bool sticon_blank(struct vc_data *c, enum vesa_blank_mode blank,
+                        bool mode_switch)
 {
-    if (blank == 0) {
+    if (blank == VESA_NO_BLANKING) {
        if (mode_switch)
            vga_is_gfx = 0;
-       return 1;
+       return true;
     }
     sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK,
              font_data[c->vc_num]);
     if (mode_switch)
        vga_is_gfx = 1;
-    return 1;
+
+    return true;
 }
 
 static u8 sticon_build_attr(struct vc_data *conp, u8 color,
@@ -365,7 +351,6 @@ static const struct consw sti_con = {
        .con_init               = sticon_init,
        .con_deinit             = sticon_deinit,
        .con_clear              = sticon_clear,
-       .con_putc               = sticon_putc,
        .con_putcs              = sticon_putcs,
        .con_cursor             = sticon_cursor,
        .con_scroll             = sticon_scroll,
index 8ef1579fa57fdda1b079a17247286d0c809018d9..7597f04b0dc77e7e67516cb69be98a399da8e7c5 100644 (file)
@@ -65,7 +65,7 @@ static struct vgastate vgastate;
  *  Interface used by the world
  */
 
-static int vgacon_set_origin(struct vc_data *c);
+static bool vgacon_set_origin(struct vc_data *c);
 
 static struct uni_pagedict *vgacon_uni_pagedir;
 static int vgacon_refcount;
@@ -81,7 +81,7 @@ static unsigned int   vga_video_num_lines;                    /* Number of text lines */
 static bool            vga_can_do_color;                       /* Do we support colors? */
 static unsigned int    vga_default_font_height __read_mostly;  /* Height of default screen font */
 static unsigned char   vga_video_type          __read_mostly;  /* Card type */
-static int             vga_vesa_blanked;
+static enum vesa_blank_mode vga_vesa_blanked;
 static bool            vga_palette_blanked;
 static bool            vga_is_gfx;
 static bool            vga_512_chars;
@@ -138,8 +138,40 @@ static inline void vga_set_mem_top(struct vc_data *c)
 
 static void vgacon_scrolldelta(struct vc_data *c, int lines)
 {
-       vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
-                       vga_vram_size);
+       unsigned long scr_end = c->vc_scr_end - vga_vram_base;
+       unsigned long vorigin = c->vc_visible_origin - vga_vram_base;
+       unsigned long origin = c->vc_origin - vga_vram_base;
+       int margin = c->vc_size_row * 4;
+       int from, wrap, from_off, avail;
+
+       /* Turn scrollback off */
+       if (!lines) {
+               c->vc_visible_origin = c->vc_origin;
+               return;
+       }
+
+       /* Do we have already enough to allow jumping from 0 to the end? */
+       if (vga_rolled_over > scr_end + margin) {
+               from = scr_end;
+               wrap = vga_rolled_over + c->vc_size_row;
+       } else {
+               from = 0;
+               wrap = vga_vram_size;
+       }
+
+       from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
+       avail = (origin - from + wrap) % wrap;
+
+       /* Only a little piece would be left? Show all incl. the piece! */
+       if (avail < 2 * margin)
+               margin = 0;
+       if (from_off < margin)
+               from_off = 0;
+       if (from_off > avail - margin)
+               from_off = avail;
+
+       c->vc_visible_origin = vga_vram_base + (from + from_off) % wrap;
+
        vga_set_mem_top(c);
 }
 
@@ -335,7 +367,7 @@ static const char *vgacon_startup(void)
        return display_desc;
 }
 
-static void vgacon_init(struct vc_data *c, int init)
+static void vgacon_init(struct vc_data *c, bool init)
 {
        struct uni_pagedict *p;
 
@@ -352,7 +384,7 @@ static void vgacon_init(struct vc_data *c, int init)
        c->vc_scan_lines = vga_scan_lines;
        c->vc_font.height = c->vc_cell_height = vga_video_font_height;
 
-       /* set dimensions manually if init != 0 since vc_resize() will fail */
+       /* set dimensions manually if init is true since vc_resize() will fail */
        if (init) {
                c->vc_cols = vga_video_num_columns;
                c->vc_rows = vga_video_num_lines;
@@ -471,7 +503,7 @@ static void vgacon_set_cursor_size(int from, int to)
        raw_spin_unlock_irqrestore(&vga_lock, flags);
 }
 
-static void vgacon_cursor(struct vc_data *c, int mode)
+static void vgacon_cursor(struct vc_data *c, bool enable)
 {
        unsigned int c_height;
 
@@ -482,47 +514,41 @@ static void vgacon_cursor(struct vc_data *c, int mode)
 
        c_height = c->vc_cell_height;
 
-       switch (mode) {
-       case CM_ERASE:
-               write_vga(14, (c->vc_pos - vga_vram_base) / 2);
+       write_vga(14, (c->vc_pos - vga_vram_base) / 2);
+
+       if (!enable) {
                if (vga_video_type >= VIDEO_TYPE_VGAC)
                        vgacon_set_cursor_size(31, 30);
                else
                        vgacon_set_cursor_size(31, 31);
-               break;
+               return;
+       }
 
-       case CM_MOVE:
-       case CM_DRAW:
-               write_vga(14, (c->vc_pos - vga_vram_base) / 2);
-               switch (CUR_SIZE(c->vc_cursor_type)) {
-               case CUR_UNDERLINE:
-                       vgacon_set_cursor_size(c_height -
-                                              (c_height < 10 ? 2 : 3),
-                                              c_height -
-                                              (c_height < 10 ? 1 : 2));
-                       break;
-               case CUR_TWO_THIRDS:
-                       vgacon_set_cursor_size(c_height / 3, c_height -
-                                              (c_height < 10 ? 1 : 2));
-                       break;
-               case CUR_LOWER_THIRD:
-                       vgacon_set_cursor_size(c_height * 2 / 3, c_height -
-                                              (c_height < 10 ? 1 : 2));
-                       break;
-               case CUR_LOWER_HALF:
-                       vgacon_set_cursor_size(c_height / 2, c_height -
-                                              (c_height < 10 ? 1 : 2));
-                       break;
-               case CUR_NONE:
-                       if (vga_video_type >= VIDEO_TYPE_VGAC)
-                               vgacon_set_cursor_size(31, 30);
-                       else
-                               vgacon_set_cursor_size(31, 31);
-                       break;
-               default:
-                       vgacon_set_cursor_size(1, c_height);
-                       break;
-               }
+       switch (CUR_SIZE(c->vc_cursor_type)) {
+       case CUR_UNDERLINE:
+               vgacon_set_cursor_size(c_height - (c_height < 10 ? 2 : 3),
+                                      c_height - (c_height < 10 ? 1 : 2));
+               break;
+       case CUR_TWO_THIRDS:
+               vgacon_set_cursor_size(c_height / 3,
+                                      c_height - (c_height < 10 ? 1 : 2));
+               break;
+       case CUR_LOWER_THIRD:
+               vgacon_set_cursor_size(c_height * 2 / 3,
+                                      c_height - (c_height < 10 ? 1 : 2));
+               break;
+       case CUR_LOWER_HALF:
+               vgacon_set_cursor_size(c_height / 2,
+                                      c_height - (c_height < 10 ? 1 : 2));
+               break;
+       case CUR_NONE:
+               if (vga_video_type >= VIDEO_TYPE_VGAC)
+                       vgacon_set_cursor_size(31, 30);
+               else
+                       vgacon_set_cursor_size(31, 31);
+               break;
+       default:
+               vgacon_set_cursor_size(1, c_height);
                break;
        }
 }
@@ -588,7 +614,7 @@ static void vgacon_doresize(struct vc_data *c,
        raw_spin_unlock_irqrestore(&vga_lock, flags);
 }
 
-static int vgacon_switch(struct vc_data *c)
+static bool vgacon_switch(struct vc_data *c)
 {
        int x = c->vc_cols * VGA_FONTWIDTH;
        int y = c->vc_rows * c->vc_cell_height;
@@ -617,7 +643,7 @@ static int vgacon_switch(struct vc_data *c)
                        vgacon_doresize(c, c->vc_cols, c->vc_rows);
        }
 
-       return 0;               /* Redrawing not needed */
+       return false;           /* Redrawing not needed */
 }
 
 static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
@@ -657,7 +683,7 @@ static struct {
        unsigned char ClockingMode;     /* Seq-Controller:01h */
 } vga_state;
 
-static void vga_vesa_blank(struct vgastate *state, int mode)
+static void vga_vesa_blank(struct vgastate *state, enum vesa_blank_mode mode)
 {
        /* save original values of VGA controller registers */
        if (!vga_vesa_blanked) {
@@ -771,13 +797,14 @@ static void vga_pal_blank(struct vgastate *state)
        }
 }
 
-static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
+static bool vgacon_blank(struct vc_data *c, enum vesa_blank_mode blank,
+                        bool mode_switch)
 {
        switch (blank) {
-       case 0:         /* Unblank */
+       case VESA_NO_BLANKING:          /* Unblank */
                if (vga_vesa_blanked) {
                        vga_vesa_unblank(&vgastate);
-                       vga_vesa_blanked = 0;
+                       vga_vesa_blanked = VESA_NO_BLANKING;
                }
                if (vga_palette_blanked) {
                        vga_set_palette(c, color_table);
@@ -787,8 +814,7 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
                vga_is_gfx = false;
                /* Tell console.c that it has to restore the screen itself */
                return 1;
-       case 1:         /* Normal blanking */
-       case -1:        /* Obsolete */
+       case VESA_VSYNC_SUSPEND:        /* Normal blanking */
                if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
                        vga_pal_blank(&vgastate);
                        vga_palette_blanked = true;
@@ -1004,7 +1030,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
                                /* void size to cause regs to be rewritten */
                                cursor_size_lastfrom = 0;
                                cursor_size_lastto = 0;
-                               c->vc_sw->con_cursor(c, CM_DRAW);
+                               c->vc_sw->con_cursor(c, true);
                        }
                        c->vc_font.height = c->vc_cell_height = fontheight;
                        vc_resize(c, 0, rows);  /* Adjust console size */
@@ -1013,7 +1039,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
        return 0;
 }
 
-static int vgacon_font_set(struct vc_data *c, struct console_font *font,
+static int vgacon_font_set(struct vc_data *c, const struct console_font *font,
                           unsigned int vpitch, unsigned int flags)
 {
        unsigned charcount = font->charcount;
@@ -1049,12 +1075,12 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigne
 }
 
 static int vgacon_resize(struct vc_data *c, unsigned int width,
-                        unsigned int height, unsigned int user)
+                        unsigned int height, bool from_user)
 {
        if ((width << 1) * height > vga_vram_size)
                return -EINVAL;
 
-       if (user) {
+       if (from_user) {
                /*
                 * Ho ho!  Someone (svgatextmode, eh?) may have reprogrammed
                 * the video mode!  Set the new defaults then and go away.
@@ -1074,15 +1100,15 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
        return 0;
 }
 
-static int vgacon_set_origin(struct vc_data *c)
+static bool vgacon_set_origin(struct vc_data *c)
 {
        if (vga_is_gfx ||       /* We don't play origin tricks in graphic modes */
            (console_blanked && !vga_palette_blanked))  /* Nor we write to blanked screens */
-               return 0;
+               return false;
        c->vc_origin = c->vc_visible_origin = vga_vram_base;
        vga_set_mem_top(c);
        vga_rolled_over = 0;
-       return 1;
+       return true;
 }
 
 static void vgacon_save_screen(struct vc_data *c)
@@ -1159,11 +1185,10 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
  *  The console `switch' structure for the VGA based console
  */
 
-static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
-                        int width) { }
-static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
-static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
-                        int count, int ypos, int xpos) { }
+static void vgacon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                        unsigned int width) { }
+static void vgacon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
+                        unsigned int ypos, unsigned int xpos) { }
 
 const struct consw vga_con = {
        .owner = THIS_MODULE,
@@ -1171,7 +1196,6 @@ const struct consw vga_con = {
        .con_init = vgacon_init,
        .con_deinit = vgacon_deinit,
        .con_clear = vgacon_clear,
-       .con_putc = vgacon_putc,
        .con_putcs = vgacon_putcs,
        .con_cursor = vgacon_cursor,
        .con_scroll = vgacon_scroll,
index a61b8260b8f36c4f311490813ac6c22c584a20e9..e3179e987cdb32b16b317b199238057ed187f125 100644 (file)
@@ -1523,7 +1523,7 @@ config FB_FSL_DIU
 config FB_SH_MOBILE_LCDC
        tristate "SuperH Mobile LCDC framebuffer support"
        depends on FB && HAVE_CLK && HAS_IOMEM
-       depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
+       depends on SUPERH || COMPILE_TEST
        depends on FB_DEVICE
        select FB_BACKLIGHT
        select FB_DEFERRED_IO
index dca9c0325b3f0a703a597c4e6226a7185f982f6b..082501feceb96a118df3b0f9e25f04d3708ebc7a 100644 (file)
@@ -622,8 +622,13 @@ static int arkfb_set_par(struct fb_info *info)
                info->tileops = NULL;
 
                /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
-               info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
-               info->pixmap.blit_y = ~(u32)0;
+               if (bpp == 4) {
+                       bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+                       set_bit(8 - 1, info->pixmap.blit_x);
+               } else {
+                       bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+               }
+               bitmap_fill(info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
 
                offset_value = (info->var.xres_virtual * bpp) / 64;
                screen_size = info->var.yres_virtual * info->fix.line_length;
@@ -635,8 +640,10 @@ static int arkfb_set_par(struct fb_info *info)
                info->tileops = &arkfb_tile_ops;
 
                /* supports 8x16 tiles only */
-               info->pixmap.blit_x = 1 << (8 - 1);
-               info->pixmap.blit_y = 1 << (16 - 1);
+               bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+               set_bit(8 - 1, info->pixmap.blit_x);
+               bitmap_zero(info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
+               set_bit(16 - 1, info->pixmap.blit_y);
 
                offset_value = info->var.xres_virtual / 16;
                screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
index 8587c9da067003f74f50d3234a759bf3f218bf12..3ff1b2a8659e87c746c39a9fd47815eb82ffdb41 100644 (file)
@@ -233,7 +233,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info,
        }
 }
 
-static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+static void bit_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
                       int fg, int bg)
 {
        struct fb_cursor cursor;
@@ -348,16 +348,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
                        mask[i++] = msk;
        }
 
-       switch (mode) {
-       case CM_ERASE:
-               ops->cursor_state.enable = 0;
-               break;
-       case CM_DRAW:
-       case CM_MOVE:
-       default:
-               ops->cursor_state.enable = (use_sw) ? 0 : 1;
-               break;
-       }
+       ops->cursor_state.enable = enable && !use_sw;
 
        cursor.image.data = src;
        cursor.image.fg_color = ops->cursor_state.image.fg_color;
index 46823c2e2ba1207e327607fa0ca0c757bc0968aa..fcabc668e9fbe794c5f94b10db26f93387ec4ebd 100644 (file)
@@ -351,7 +351,7 @@ static void fb_flashcursor(struct work_struct *work)
        struct fb_info *info;
        struct vc_data *vc = NULL;
        int c;
-       int mode;
+       bool enable;
        int ret;
 
        /* FIXME: we should sort out the unbind locking instead */
@@ -375,9 +375,8 @@ static void fb_flashcursor(struct work_struct *work)
        }
 
        c = scr_readw((u16 *) vc->vc_pos);
-       mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
-               CM_ERASE : CM_DRAW;
-       ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
+       enable = ops->cursor_flash && !ops->cursor_state.enable;
+       ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
        console_unlock();
 
@@ -920,7 +919,7 @@ static void display_to_var(struct fb_var_screeninfo *var,
 
 static const char *fbcon_startup(void)
 {
-       const char *display_desc = "frame buffer device";
+       static const char display_desc[] = "frame buffer device";
        struct fbcon_display *p = &fb_display[fg_console];
        struct vc_data *vc = vc_cons[fg_console].d;
        const struct font_desc *font = NULL;
@@ -987,7 +986,7 @@ static const char *fbcon_startup(void)
        return display_desc;
 }
 
-static void fbcon_init(struct vc_data *vc, int init)
+static void fbcon_init(struct vc_data *vc, bool init)
 {
        struct fb_info *info;
        struct fbcon_ops *ops;
@@ -1234,8 +1233,8 @@ finished:
  *  restriction is simplicity & efficiency at the moment.
  */
 
-static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
-                       int width)
+static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                         unsigned int height, unsigned int width)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
@@ -1272,8 +1271,14 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
                ops->clear(vc, info, real_y(p, sy), sx, height, width);
 }
 
-static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
-                       int count, int ypos, int xpos)
+static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+                       unsigned int width)
+{
+       __fbcon_clear(vc, sy, sx, 1, width);
+}
+
+static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
+                       unsigned int ypos, unsigned int xpos)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_display *p = &fb_display[vc->vc_num];
@@ -1285,14 +1290,6 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
                           get_color(vc, info, scr_readw(s), 0));
 }
 
-static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
-{
-       unsigned short chr;
-
-       scr_writew(c, &chr);
-       fbcon_putcs(vc, &chr, 1, ypos, xpos);
-}
-
 static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
@@ -1302,7 +1299,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
                ops->clear_margins(vc, info, margin_color, bottom_only);
 }
 
-static void fbcon_cursor(struct vc_data *vc, int mode)
+static void fbcon_cursor(struct vc_data *vc, bool enable)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
@@ -1318,12 +1315,12 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
        else
                fbcon_add_cursor_work(info);
 
-       ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
+       ops->cursor_flash = enable;
 
        if (!ops->cursor)
                return;
 
-       ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
+       ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
 }
 
@@ -1743,7 +1740,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
        if (fbcon_is_inactive(vc, info))
                return true;
 
-       fbcon_cursor(vc, CM_ERASE);
+       fbcon_cursor(vc, false);
 
        /*
         * ++Geert: Only use ywrap/ypan if the console is in text mode
@@ -1759,7 +1756,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                case SCROLL_MOVE:
                        fbcon_redraw_blit(vc, info, p, t, b - t - count,
                                     count);
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        (b - count)),
@@ -1782,7 +1779,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_up;
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        break;
 
                case SCROLL_PAN_REDRAW:
@@ -1800,7 +1797,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                                                          vc->vc_rows - b, b);
                        } else
                                fbcon_redraw_move(vc, p, t + count, b - t - count, t);
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        break;
 
                case SCROLL_PAN_MOVE:
@@ -1823,14 +1820,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_up;
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        break;
 
                case SCROLL_REDRAW:
                      redraw_up:
                        fbcon_redraw(vc, t, b - t - count,
                                     count * vc->vc_cols);
-                       fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        (b - count)),
@@ -1847,7 +1844,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                case SCROLL_MOVE:
                        fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
                                     -count);
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        t),
@@ -1870,7 +1867,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_down;
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        break;
 
                case SCROLL_PAN_MOVE:
@@ -1892,7 +1889,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                                            b - t - count, vc->vc_cols);
                        else
                                goto redraw_down;
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        break;
 
                case SCROLL_PAN_REDRAW:
@@ -1909,14 +1906,14 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
                                        fbcon_redraw_move(vc, p, count, t, 0);
                        } else
                                fbcon_redraw_move(vc, p, t, b - t - count, t + count);
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        break;
 
                case SCROLL_REDRAW:
                      redraw_down:
                        fbcon_redraw(vc, b - 1, b - t - count,
                                     -count * vc->vc_cols);
-                       fbcon_clear(vc, t, 0, count, vc->vc_cols);
+                       __fbcon_clear(vc, t, 0, count, vc->vc_cols);
                        scr_memsetw((unsigned short *) (vc->vc_origin +
                                                        vc->vc_size_row *
                                                        t),
@@ -1995,7 +1992,7 @@ static void updatescrollmode(struct fbcon_display *p,
 #define CALC_FONTSZ(h, p, c) ((h) * (p) * (c)) /* size = height * pitch * charcount */
 
 static int fbcon_resize(struct vc_data *vc, unsigned int width,
-                       unsigned int height, unsigned int user)
+                       unsigned int height, bool from_user)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
@@ -2058,7 +2055,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
        return 0;
 }
 
-static int fbcon_switch(struct vc_data *vc)
+static bool fbcon_switch(struct vc_data *vc)
 {
        struct fb_info *info, *old_info = NULL;
        struct fbcon_ops *ops;
@@ -2180,9 +2177,9 @@ static int fbcon_switch(struct vc_data *vc)
                              vc->vc_origin + vc->vc_size_row * vc->vc_top,
                              vc->vc_size_row * (vc->vc_bottom -
                                                 vc->vc_top) / 2);
-               return 0;
+               return false;
        }
-       return 1;
+       return true;
 }
 
 static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
@@ -2195,12 +2192,13 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
 
                oldc = vc->vc_video_erase_char;
                vc->vc_video_erase_char &= charmask;
-               fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
+               __fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
                vc->vc_video_erase_char = oldc;
        }
 }
 
-static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
+                       bool mode_switch)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
@@ -2222,7 +2220,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
        if (!fbcon_is_inactive(vc, info)) {
                if (ops->blank_state != blank) {
                        ops->blank_state = blank;
-                       fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
+                       fbcon_cursor(vc, !blank);
                        ops->cursor_flash = (!blank);
 
                        if (fb_blank(info, blank))
@@ -2239,10 +2237,10 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
        else
                fbcon_add_cursor_work(info);
 
-       return 0;
+       return false;
 }
 
-static int fbcon_debug_enter(struct vc_data *vc)
+static void fbcon_debug_enter(struct vc_data *vc)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
@@ -2252,10 +2250,9 @@ static int fbcon_debug_enter(struct vc_data *vc)
        if (info->fbops->fb_debug_enter)
                info->fbops->fb_debug_enter(info);
        fbcon_set_palette(vc, color_table);
-       return 0;
 }
 
-static int fbcon_debug_leave(struct vc_data *vc)
+static void fbcon_debug_leave(struct vc_data *vc)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        struct fbcon_ops *ops = info->fbcon_par;
@@ -2263,7 +2260,6 @@ static int fbcon_debug_leave(struct vc_data *vc)
        ops->graphics = ops->save_graphics;
        if (info->fbops->fb_debug_leave)
                info->fbops->fb_debug_leave(info);
-       return 0;
 }
 
 static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
@@ -2461,7 +2457,7 @@ err_out:
  *  but lets not assume that, since charcount of 512 is small for unicode support.
  */
 
-static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
+static int fbcon_set_font(struct vc_data *vc, const struct console_font *font,
                          unsigned int vpitch, unsigned int flags)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
@@ -2483,12 +2479,12 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
            h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
                return -EINVAL;
 
-       if (font->width > 32 || font->height > 32)
+       if (font->width > FB_MAX_BLIT_WIDTH || font->height > FB_MAX_BLIT_HEIGHT)
                return -EINVAL;
 
        /* Make sure drawing engine can handle the font */
-       if (!(info->pixmap.blit_x & BIT(font->width - 1)) ||
-           !(info->pixmap.blit_y & BIT(font->height - 1)))
+       if (!test_bit(font->width - 1, info->pixmap.blit_x) ||
+           !test_bit(font->height - 1, info->pixmap.blit_y))
                return -EINVAL;
 
        /* Make sure driver can handle the font length */
@@ -2534,7 +2530,8 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
        return fbcon_do_set_font(vc, font->width, font->height, charcount, new_data, 1);
 }
 
-static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
+static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font,
+                             const char *name)
 {
        struct fb_info *info = fbcon_info_from_console(vc->vc_num);
        const struct font_desc *f;
@@ -2593,35 +2590,6 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
        fb_set_cmap(&palette_cmap, info);
 }
 
-static u16 *fbcon_screen_pos(const struct vc_data *vc, int offset)
-{
-       return (u16 *) (vc->vc_origin + offset);
-}
-
-static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
-                                int *px, int *py)
-{
-       unsigned long ret;
-       int x, y;
-
-       if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
-               unsigned long offset = (pos - vc->vc_origin) / 2;
-
-               x = offset % vc->vc_cols;
-               y = offset / vc->vc_cols;
-               ret = pos + (vc->vc_cols - x) * 2;
-       } else {
-               /* Should not happen */
-               x = y = 0;
-               ret = vc->vc_origin;
-       }
-       if (px)
-               *px = x;
-       if (py)
-               *py = y;
-       return ret;
-}
-
 /* As we might be inside of softback, we may work with non-contiguous buffer,
    that's why we have to use a separate routine. */
 static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
@@ -2650,7 +2618,7 @@ void fbcon_suspended(struct fb_info *info)
        vc = vc_cons[ops->currcon].d;
 
        /* Clear cursor, restore saved data */
-       fbcon_cursor(vc, CM_ERASE);
+       fbcon_cursor(vc, false);
 }
 
 void fbcon_resumed(struct fb_info *info)
@@ -3082,8 +3050,8 @@ void fbcon_get_requirement(struct fb_info *info,
                        vc = vc_cons[i].d;
                        if (vc && vc->vc_mode == KD_TEXT &&
                            info->node == con2fb_map[i]) {
-                               caps->x |= 1 << (vc->vc_font.width - 1);
-                               caps->y |= 1 << (vc->vc_font.height - 1);
+                               set_bit(vc->vc_font.width - 1, caps->x);
+                               set_bit(vc->vc_font.height - 1, caps->y);
                                charcnt = vc->vc_font.charcount;
                                if (caps->len < charcnt)
                                        caps->len = charcnt;
@@ -3094,8 +3062,10 @@ void fbcon_get_requirement(struct fb_info *info,
 
                if (vc && vc->vc_mode == KD_TEXT &&
                    info->node == con2fb_map[fg_console]) {
-                       caps->x = 1 << (vc->vc_font.width - 1);
-                       caps->y = 1 << (vc->vc_font.height - 1);
+                       bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
+                       set_bit(vc->vc_font.width - 1, caps->x);
+                       bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT);
+                       set_bit(vc->vc_font.height - 1, caps->y);
                        caps->len = vc->vc_font.charcount;
                }
        }
@@ -3152,7 +3122,6 @@ static const struct consw fb_con = {
        .con_init               = fbcon_init,
        .con_deinit             = fbcon_deinit,
        .con_clear              = fbcon_clear,
-       .con_putc               = fbcon_putc,
        .con_putcs              = fbcon_putcs,
        .con_cursor             = fbcon_cursor,
        .con_scroll             = fbcon_scroll,
@@ -3163,8 +3132,6 @@ static const struct consw fb_con = {
        .con_font_default       = fbcon_set_def_font,
        .con_set_palette        = fbcon_set_palette,
        .con_invert_region      = fbcon_invert_region,
-       .con_screen_pos         = fbcon_screen_pos,
-       .con_getxy              = fbcon_getxy,
        .con_resize             = fbcon_resize,
        .con_debug_enter        = fbcon_debug_enter,
        .con_debug_leave        = fbcon_debug_leave,
index 0eaf54a211516786ca2863c865654fb248a045e5..df70ea5ec5b379a95105fc35a067181531cfc217 100644 (file)
@@ -61,8 +61,8 @@ struct fbcon_ops {
                      int fg, int bg);
        void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
                              int color, int bottom_only);
-       void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
-                      int fg, int bg);
+       void (*cursor)(struct vc_data *vc, struct fb_info *info,
+                      bool enable, int fg, int bg);
        int  (*update_start)(struct fb_info *info);
        int  (*rotate_font)(struct fb_info *info, struct vc_data *vc);
        struct fb_var_screeninfo var;  /* copy of the current fb_var_screeninfo */
index 2789ace7963427fe80b82c19eb706daa21e316d9..f9b794ff7d396854ccc2dadbb0f41f1b2606dd23 100644 (file)
@@ -218,7 +218,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
        }
 }
 
-static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+static void ccw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
                       int fg, int bg)
 {
        struct fb_cursor cursor;
@@ -349,16 +349,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
                kfree(tmp);
        }
 
-       switch (mode) {
-       case CM_ERASE:
-               ops->cursor_state.enable = 0;
-               break;
-       case CM_DRAW:
-       case CM_MOVE:
-       default:
-               ops->cursor_state.enable = (use_sw) ? 0 : 1;
-               break;
-       }
+       ops->cursor_state.enable = enable && !use_sw;
 
        cursor.image.data = src;
        cursor.image.fg_color = ops->cursor_state.image.fg_color;
index 86a254c1b2b7b6bd039fde6cbc588f009b7ed338..903f6fc174e14623eacc2ef2a23bb54d072e2f8e 100644 (file)
@@ -201,7 +201,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
        }
 }
 
-static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+static void cw_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
                      int fg, int bg)
 {
        struct fb_cursor cursor;
@@ -332,16 +332,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
                kfree(tmp);
        }
 
-       switch (mode) {
-       case CM_ERASE:
-               ops->cursor_state.enable = 0;
-               break;
-       case CM_DRAW:
-       case CM_MOVE:
-       default:
-               ops->cursor_state.enable = (use_sw) ? 0 : 1;
-               break;
-       }
+       ops->cursor_state.enable = enable && !use_sw;
 
        cursor.image.data = src;
        cursor.image.fg_color = ops->cursor_state.image.fg_color;
index 23bc045769d088e8f9690c03dc8228d71635daa0..594331936fd3cffbd3e75c4ff93dbab8be68cae8 100644 (file)
@@ -248,7 +248,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
        }
 }
 
-static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+static void ud_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
                      int fg, int bg)
 {
        struct fb_cursor cursor;
@@ -372,16 +372,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
                        mask[i++] = ~msk;
        }
 
-       switch (mode) {
-       case CM_ERASE:
-               ops->cursor_state.enable = 0;
-               break;
-       case CM_DRAW:
-       case CM_MOVE:
-       default:
-               ops->cursor_state.enable = (use_sw) ? 0 : 1;
-               break;
-       }
+       ops->cursor_state.enable = enable && !use_sw;
 
        cursor.image.data = src;
        cursor.image.fg_color = ops->cursor_state.image.fg_color;
index 48287366e0d4a1925211ec9c29a3a1c425640308..4c4ad0a86a5044dea7b6c89aad242ecc5477a9b9 100644 (file)
@@ -212,8 +212,8 @@ static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
        fbcon_get_requirement(info, &caps);
        info->fbops->fb_get_caps(info, &fbcaps, var);
 
-       if (((fbcaps.x ^ caps.x) & caps.x) ||
-           ((fbcaps.y ^ caps.y) & caps.y) ||
+       if (!bitmap_subset(caps.x, fbcaps.x, FB_MAX_BLIT_WIDTH) ||
+           !bitmap_subset(caps.y, fbcaps.y, FB_MAX_BLIT_HEIGHT) ||
            (fbcaps.len < caps.len))
                err = -EINVAL;
 
@@ -420,11 +420,11 @@ static int do_register_framebuffer(struct fb_info *fb_info)
        }
        fb_info->pixmap.offset = 0;
 
-       if (!fb_info->pixmap.blit_x)
-               fb_info->pixmap.blit_x = ~(u32)0;
+       if (bitmap_empty(fb_info->pixmap.blit_x, FB_MAX_BLIT_WIDTH))
+               bitmap_fill(fb_info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
 
-       if (!fb_info->pixmap.blit_y)
-               fb_info->pixmap.blit_y = ~(u32)0;
+       if (bitmap_empty(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT))
+               bitmap_fill(fb_info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
 
        if (!fb_info->modelist.prev || !fb_info->modelist.next)
                INIT_LIST_HEAD(&fb_info->modelist);
index 79e5bfbdd34c26af7345d433e1c551321031aa6e..0a26399dbc899d6a658d2403d5de891d72f3bcec 100644 (file)
@@ -1311,7 +1311,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
 int fb_videomode_from_videomode(const struct videomode *vm,
                                struct fb_videomode *fbmode)
 {
-       unsigned int htotal, vtotal;
+       unsigned int htotal, vtotal, total;
 
        fbmode->xres = vm->hactive;
        fbmode->left_margin = vm->hback_porch;
@@ -1344,8 +1344,9 @@ int fb_videomode_from_videomode(const struct videomode *vm,
        vtotal = vm->vactive + vm->vfront_porch + vm->vback_porch +
                 vm->vsync_len;
        /* prevent division by zero */
-       if (htotal && vtotal) {
-               fbmode->refresh = vm->pixelclock / (htotal * vtotal);
+       total = htotal * vtotal;
+       if (total) {
+               fbmode->refresh = vm->pixelclock / total;
        /* a mode must have htotal and vtotal != 0 or it is invalid */
        } else {
                fbmode->refresh = 0;
index 2cba158888ea4e9fda92b267c98e07c4e8c7f093..821b89a0a6453bc16724802d85b1957fd89b4c75 100644 (file)
@@ -354,12 +354,19 @@ void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
 {
        if (var->bits_per_pixel == 0) {
                /* can only support 256 8x16 bitmap */
-               caps->x = 1 << (8 - 1);
-               caps->y = 1 << (16 - 1);
+               bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
+               set_bit(8 - 1, caps->x);
+               bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT);
+               set_bit(16 - 1, caps->y);
                caps->len = 256;
        } else {
-               caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
-               caps->y = ~(u32)0;
+               if (var->bits_per_pixel == 4) {
+                       bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
+                       set_bit(8 - 1, caps->x);
+               } else {
+                       bitmap_fill(caps->x, FB_MAX_BLIT_WIDTH);
+               }
+               bitmap_fill(caps->y, FB_MAX_BLIT_HEIGHT);
                caps->len = ~(u32)0;
        }
 }
index 2768eff247ba4623dd0beaa8e2d96926c472f519..eff7ec4da1671f0a13c919ec9aad225c071ae0ff 100644 (file)
@@ -79,7 +79,7 @@ static void tile_clear_margins(struct vc_data *vc, struct fb_info *info,
        return;
 }
 
-static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+static void tile_cursor(struct vc_data *vc, struct fb_info *info, bool enable,
                        int fg, int bg)
 {
        struct fb_tilecursor cursor;
@@ -87,7 +87,7 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 
        cursor.sx = vc->state.x;
        cursor.sy = vc->state.y;
-       cursor.mode = (mode == CM_ERASE || use_sw) ? 0 : 1;
+       cursor.mode = enable && !use_sw;
        cursor.fg = fg;
        cursor.bg = bg;
 
index 7c402e9fd7a98d9e3e1c1c90f41066418937df7b..baec312d7b33bc9f03a7aa8c5155358e3a791331 100644 (file)
 #define CARMINE_MEM_SIZE       0x8000000
 #define DRV_NAME               "mb862xxfb"
 
-#if defined(CONFIG_SOCRATES)
-static struct mb862xx_gc_mode socrates_gc_mode = {
-       /* Mode for Prime View PM070WL4 TFT LCD Panel */
-       { "800x480", 45, 800, 480, 40000, 86, 42, 33, 10, 128, 2, 0, 0, 0 },
-       /* 16 bits/pixel, 16MB, 133MHz, SDRAM memory mode value */
-       16, 0x1000000, GC_CCF_COT_133, 0x4157ba63
-};
-#endif
-
 /* Helpers */
 static inline int h_total(struct fb_var_screeninfo *var)
 {
@@ -666,6 +657,15 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par)
        return 0;
 }
 
+#if defined(CONFIG_SOCRATES)
+static struct mb862xx_gc_mode socrates_gc_mode = {
+       /* Mode for Prime View PM070WL4 TFT LCD Panel */
+       { "800x480", 45, 800, 480, 40000, 86, 42, 33, 10, 128, 2, 0, 0, 0 },
+       /* 16 bits/pixel, 16MB, 133MHz, SDRAM memory mode value */
+       16, 0x1000000, GC_CCF_COT_133, 0x4157ba63
+};
+#endif
+
 static int of_platform_mb862xx_probe(struct platform_device *ofdev)
 {
        struct device_node *np = ofdev->dev.of_node;
index 477789cff8e08d5e620a0754feb1f1dba6008370..d487941853e64704ccc68a632bb2df19998c7461 100644 (file)
@@ -225,17 +225,12 @@ static ssize_t tpo_td043_gamma_show(struct device *dev,
 {
        struct panel_drv_data *ddata = dev_get_drvdata(dev);
        ssize_t len = 0;
-       int ret;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++) {
-               ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
-                               ddata->gamma[i]);
-               if (ret < 0)
-                       return ret;
-               len += ret;
-       }
-       buf[len - 1] = '\n';
+       for (i = 0; i < ARRAY_SIZE(ddata->gamma); i++)
+               len += sysfs_emit_at(buf, len, "%u ", ddata->gamma[i]);
+       if (len)
+               buf[len - 1] = '\n';
 
        return len;
 }
index 07722a5ea8eff8a63e5827e4a79349f00689ee46..ff84106ecf1c11d726afec9e0e888bf158eb31b1 100644 (file)
@@ -617,8 +617,13 @@ static int s3fb_set_par(struct fb_info *info)
                info->tileops = NULL;
 
                /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
-               info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
-               info->pixmap.blit_y = ~(u32)0;
+               if (bpp == 4) {
+                       bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+                       set_bit(8 - 1, info->pixmap.blit_x);
+               } else {
+                       bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+               }
+               bitmap_fill(info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
 
                offset_value = (info->var.xres_virtual * bpp) / 64;
                screen_size = info->var.yres_virtual * info->fix.line_length;
@@ -630,8 +635,10 @@ static int s3fb_set_par(struct fb_info *info)
                info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops;
 
                /* supports 8x16 tiles only */
-               info->pixmap.blit_x = 1 << (8 - 1);
-               info->pixmap.blit_y = 1 << (16 - 1);
+               bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+               set_bit(8 - 1, info->pixmap.blit_x);
+               bitmap_zero(info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
+               set_bit(16 - 1, info->pixmap.blit_y);
 
                offset_value = info->var.xres_virtual / 16;
                screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
index ca43774f3156e3d901ca6a8c4d7223581a1e91c3..dccfc38cfbd5232109ab55b2efa9c337f3d250b8 100644 (file)
@@ -380,7 +380,7 @@ tgafb_set_par(struct fb_info *info)
                BT463_LOAD_ADDR(par, 0x0000);
                TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
 
-#ifdef CONFIG_HW_CONSOLE
+#ifdef CONFIG_VT
                for (i = 0; i < 16; i++) {
                        int j = color_table[i];
 
index e1f421e91b4fb0f297e57cbc3f2bf9571d44a867..73f00c079a9499b51a35dc52d7bb52213849c331 100644 (file)
@@ -1546,7 +1546,7 @@ static ssize_t uvesafb_show_vbe_ver(struct device *dev,
        struct fb_info *info = dev_get_drvdata(dev);
        struct uvesafb_par *par = info->par;
 
-       return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version);
+       return sysfs_emit(buf, "%.4x\n", par->vbe_ib.vbe_version);
 }
 
 static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL);
index b485e919820134cd334f76689cfaa99c9756289d..a87bafbb119cc1dc6b60732d14ef6260fe8ca7c5 100644 (file)
@@ -1353,7 +1353,11 @@ static int vga16fb_probe(struct platform_device *dev)
        info->var = vga16fb_defined;
        info->fix = vga16fb_fix;
        /* supports rectangles with widths of multiples of 8 */
-       info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
+       bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+       set_bit(8 - 1, info->pixmap.blit_x);
+       set_bit(16 - 1, info->pixmap.blit_x);
+       set_bit(24 - 1, info->pixmap.blit_x);
+       set_bit(32 - 1, info->pixmap.blit_x);
        info->flags = FBINFO_HWACCEL_YPAN;
 
        i = (info->var.bits_per_pixel == 8) ? 256 : 16;
index 0a1bc7a4d7853cebb85b46a90a11a4c25257717c..1e04026f0809185a91486043abca094d19d43c45 100644 (file)
@@ -115,7 +115,7 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
 
        if (op != VIA_BITBLT_FILL) {
                tmp = src_mem ? 0 : src_addr;
-               if (dst_addr & 0xE0000007) {
+               if (tmp & 0xE0000007) {
                        printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
                                "address %X\n", tmp);
                        return -EINVAL;
@@ -260,7 +260,7 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
                writel(tmp, engine + 0x18);
 
                tmp = src_mem ? 0 : src_addr;
-               if (dst_addr & 0xE0000007) {
+               if (tmp & 0xE0000007) {
                        printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
                                "address %X\n", tmp);
                        return -EINVAL;
index f8d022cb61e8d10ec091a3ec1776a7be49b97178..df984f3a7ff64165178e6f528d8bacdee5f3bf23 100644 (file)
@@ -390,8 +390,13 @@ static int vt8623fb_set_par(struct fb_info *info)
                info->tileops = NULL;
 
                /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
-               info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
-               info->pixmap.blit_y = ~(u32)0;
+               if (bpp == 4) {
+                       bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+                       set_bit(8 - 1, info->pixmap.blit_x);
+               } else {
+                       bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+               }
+               bitmap_fill(info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
 
                offset_value = (info->var.xres_virtual * bpp) / 64;
                fetch_value  = ((info->var.xres * bpp) / 128) + 4;
@@ -408,8 +413,10 @@ static int vt8623fb_set_par(struct fb_info *info)
                info->tileops = &vt8623fb_tile_ops;
 
                /* supports 8x16 tiles only */
-               info->pixmap.blit_x = 1 << (8 - 1);
-               info->pixmap.blit_y = 1 << (16 - 1);
+               bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
+               set_bit(8 - 1, info->pixmap.blit_x);
+               bitmap_zero(info->pixmap.blit_y, FB_MAX_BLIT_HEIGHT);
+               set_bit(16 - 1, info->pixmap.blit_y);
 
                offset_value = info->var.xres_virtual / 16;
                fetch_value  = (info->var.xres / 8) + 8;
index 7115b325817f621d54e7ead9432cbbd7674aca39..88a1758616e021e7e3e691e715d47b854ac37a70 100644 (file)
@@ -529,7 +529,7 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
        if (fbfont_name && strlen(fbfont_name))
                fbfont = find_font(fbfont_name);
        if (!fbfont)
-               fbfont = get_default_font(1024,768, ~(u32)0, ~(u32)0);
+               fbfont = get_default_font(1024, 768, NULL, NULL);
        if (!fbfont)
                return NULL;
 
index f4080692b3513bd67a6d946c355c2cfbd7496ecd..f173587893cb34cadbfb4c6e548c158522c7749d 100644 (file)
@@ -353,7 +353,7 @@ static void virtio_dev_remove(struct device *_d)
        of_node_put(dev->dev.of_node);
 }
 
-static struct bus_type virtio_bus = {
+static const struct bus_type virtio_bus = {
        .name  = "virtio",
        .match = virtio_dev_match,
        .dev_groups = virtio_dev_groups,
@@ -510,8 +510,10 @@ int virtio_device_freeze(struct virtio_device *dev)
 
        if (drv && drv->freeze) {
                ret = drv->freeze(dev);
-               if (ret)
+               if (ret) {
+                       virtio_config_enable(dev);
                        return ret;
+               }
        }
 
        if (dev->config->destroy_avq)
index 49299b1f9ec746bcfae28186c7644092c4849fd8..6f7e5010a6735daf093952bad0025f0acd356253 100644 (file)
@@ -1340,7 +1340,7 @@ static int virtqueue_add_indirect_packed(struct vring_virtqueue *vq,
                                sizeof(struct vring_packed_desc));
        vq->packed.vring.desc[head].id = cpu_to_le16(id);
 
-       if (vq->do_unmap) {
+       if (vq->use_dma_api) {
                vq->packed.desc_extra[id].addr = addr;
                vq->packed.desc_extra[id].len = total_sg *
                                sizeof(struct vring_packed_desc);
@@ -1481,7 +1481,7 @@ static inline int virtqueue_add_packed(struct virtqueue *_vq,
                        desc[i].len = cpu_to_le32(sg->length);
                        desc[i].id = cpu_to_le16(id);
 
-                       if (unlikely(vq->do_unmap)) {
+                       if (unlikely(vq->use_dma_api)) {
                                vq->packed.desc_extra[curr].addr = addr;
                                vq->packed.desc_extra[curr].len = sg->length;
                                vq->packed.desc_extra[curr].flags =
@@ -1615,7 +1615,7 @@ static void detach_buf_packed(struct vring_virtqueue *vq,
        vq->free_head = id;
        vq->vq.num_free += state->num;
 
-       if (unlikely(vq->do_unmap)) {
+       if (unlikely(vq->use_dma_api)) {
                curr = id;
                for (i = 0; i < state->num; i++) {
                        vring_unmap_extra_packed(vq,
index 8d63e5923d245b2eef2c7a51e9456b96b9636ca4..e803db0da307a8fe1b75c8f7f5ad9c8c99393d4b 100644 (file)
@@ -183,8 +183,11 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index,
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return ERR_PTR(-ENOMEM);
+       if (ops->get_vq_size)
+               max_num = ops->get_vq_size(vdpa, index);
+       else
+               max_num = ops->get_vq_num_max(vdpa);
 
-       max_num = ops->get_vq_num_max(vdpa);
        if (max_num == 0) {
                err = -ENOENT;
                goto error_new_virtqueue;
index 513c0b114337c43a1e7b55c2038679b9fb91a387..e6049a75b35b8f099b779104ed9302147e001df8 100644 (file)
@@ -78,5 +78,15 @@ config W1_MASTER_SGI
          This support is also available as a module.  If so, the module
          will be called sgi_w1.
 
+config W1_MASTER_UART
+       tristate "UART 1-wire driver"
+       depends on SERIAL_DEV_BUS
+       help
+         Say Y here if you want to communicate with your 1-wire devices using
+         UART interface.
+
+         This support is also available as a module.  If so, the module
+         will be called w1-uart.
+
 endmenu
 
index 6c5a21f9b88ce211cf80ecad925e9cb8a7e0fa04..227f80987e6986056f47bb7ec096ed17445171ae 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_W1_MASTER_MXC)           += mxc_w1.o
 obj-$(CONFIG_W1_MASTER_GPIO)           += w1-gpio.o
 obj-$(CONFIG_HDQ_MASTER_OMAP)          += omap_hdq.o
 obj-$(CONFIG_W1_MASTER_SGI)            += sgi_w1.o
+obj-$(CONFIG_W1_MASTER_UART)           += w1-uart.o
index 090cbbf9e1e2259fc74c020bd2a220f4f3988277..ba1d0866d1c40c99205aae5a15539954e64806fb 100644 (file)
@@ -151,15 +151,13 @@ out_disable_clk:
 /*
  * disassociate the w1 device from the driver
  */
-static int mxc_w1_remove(struct platform_device *pdev)
+static void mxc_w1_remove(struct platform_device *pdev)
 {
        struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
 
        w1_remove_master_device(&mdev->bus_master);
 
        clk_disable_unprepare(mdev->clk);
-
-       return 0;
 }
 
 static const struct of_device_id mxc_w1_dt_ids[] = {
@@ -174,7 +172,7 @@ static struct platform_driver mxc_w1_driver = {
                .of_match_table = mxc_w1_dt_ids,
        },
        .probe = mxc_w1_probe,
-       .remove = mxc_w1_remove,
+       .remove_new = mxc_w1_remove,
 };
 module_platform_driver(mxc_w1_driver);
 
index 6a39b71eb7184e2a7f148cbe077904279273ba30..d1cb5190445a9035799c3879037ee0252bcfcd95 100644 (file)
@@ -647,7 +647,7 @@ err_w1:
        return ret;
 }
 
-static int omap_hdq_remove(struct platform_device *pdev)
+static void omap_hdq_remove(struct platform_device *pdev)
 {
        int active;
 
@@ -661,8 +661,6 @@ static int omap_hdq_remove(struct platform_device *pdev)
        if (active >= 0)
                pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-
-       return 0;
 }
 
 static const struct of_device_id omap_hdq_dt_ids[] = {
@@ -674,7 +672,7 @@ MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids);
 
 static struct platform_driver omap_hdq_driver = {
        .probe = omap_hdq_probe,
-       .remove = omap_hdq_remove,
+       .remove_new = omap_hdq_remove,
        .driver = {
                .name = "omap_hdq",
                .of_match_table = omap_hdq_dt_ids,
index d7fbc3c146e1c2b98aa3146942416222b19355b3..7bb7876aa70e6f561e16d7f0f198a25f8eee5401 100644 (file)
@@ -105,13 +105,11 @@ static int sgi_w1_probe(struct platform_device *pdev)
 /*
  * disassociate the w1 device from the driver
  */
-static int sgi_w1_remove(struct platform_device *pdev)
+static void sgi_w1_remove(struct platform_device *pdev)
 {
        struct sgi_w1_device *sdev = platform_get_drvdata(pdev);
 
        w1_remove_master_device(&sdev->bus_master);
-
-       return 0;
 }
 
 static struct platform_driver sgi_w1_driver = {
@@ -119,7 +117,7 @@ static struct platform_driver sgi_w1_driver = {
                .name = "sgi_w1",
        },
        .probe = sgi_w1_probe,
-       .remove = sgi_w1_remove,
+       .remove_new = sgi_w1_remove,
 };
 module_platform_driver(sgi_w1_driver);
 
index 05c67038ed20c35e99ff9bbb6de4a771fdf0c74d..34128e6bbbfaf607726be95d4f5a442fdc7117a7 100644 (file)
@@ -141,7 +141,7 @@ static int w1_gpio_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int w1_gpio_remove(struct platform_device *pdev)
+static void w1_gpio_remove(struct platform_device *pdev)
 {
        struct w1_bus_master *master = platform_get_drvdata(pdev);
        struct w1_gpio_ddata *ddata = master->data;
@@ -150,8 +150,6 @@ static int w1_gpio_remove(struct platform_device *pdev)
                gpiod_set_value(ddata->pullup_gpiod, 0);
 
        w1_remove_master_device(master);
-
-       return 0;
 }
 
 static struct platform_driver w1_gpio_driver = {
@@ -160,7 +158,7 @@ static struct platform_driver w1_gpio_driver = {
                .of_match_table = of_match_ptr(w1_gpio_dt_ids),
        },
        .probe = w1_gpio_probe,
-       .remove = w1_gpio_remove,
+       .remove_new = w1_gpio_remove,
 };
 
 module_platform_driver(w1_gpio_driver);
diff --git a/drivers/w1/masters/w1-uart.c b/drivers/w1/masters/w1-uart.c
new file mode 100644 (file)
index 0000000..a31782e
--- /dev/null
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * w1-uart - UART 1-Wire bus driver
+ *
+ * Uses the UART interface (via Serial Device Bus) to create the 1-Wire
+ * timing patterns. Implements the following 1-Wire master interface:
+ *
+ * - reset_bus: requests baud-rate 9600
+ *
+ * - touch_bit: requests baud-rate 115200
+ *
+ * Author: Christoph Winklhofer <cj.winklhofer@gmail.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
+#include <linux/w1.h>
+
+/* UART packet contains start and stop bit */
+#define W1_UART_BITS_PER_PACKET (BITS_PER_BYTE + 2)
+
+/* Timeout to wait for completion of serdev-receive */
+#define W1_UART_TIMEOUT msecs_to_jiffies(500)
+
+/**
+ * struct w1_uart_config - configuration for 1-Wire operation
+ * @baudrate: baud-rate returned from serdev
+ * @delay_us: delay to complete a 1-Wire cycle (in us)
+ * @tx_byte: byte to generate 1-Wire timing pattern
+ */
+struct w1_uart_config {
+       unsigned int baudrate;
+       unsigned int delay_us;
+       u8 tx_byte;
+};
+
+/**
+ * struct w1_uart_device - 1-Wire UART device structure
+ * @serdev: serial device
+ * @bus: w1-bus master
+ * @cfg_reset: config for 1-Wire reset
+ * @cfg_touch_0: config for 1-Wire write-0 cycle
+ * @cfg_touch_1: config for 1-Wire write-1 and read cycle
+ * @rx_byte_received: completion for serdev receive
+ * @rx_mutex: mutex to protect rx_err and rx_byte
+ * @rx_err: indicates an error in serdev-receive
+ * @rx_byte: result byte from serdev-receive
+ */
+struct w1_uart_device {
+       struct serdev_device *serdev;
+       struct w1_bus_master bus;
+
+       struct w1_uart_config cfg_reset;
+       struct w1_uart_config cfg_touch_0;
+       struct w1_uart_config cfg_touch_1;
+
+       struct completion rx_byte_received;
+       /*
+        * protect rx_err and rx_byte from concurrent access in
+        * w1-callbacks and serdev-receive.
+        */
+       struct mutex rx_mutex;
+       int rx_err;
+       u8 rx_byte;
+};
+
+/**
+ * struct w1_uart_limits - limits for 1-Wire operations
+ * @baudrate: Requested baud-rate to create 1-Wire timing pattern
+ * @bit_min_us: minimum time for a bit (in us)
+ * @bit_max_us: maximum time for a bit (in us)
+ * @sample_us: timespan to sample 1-Wire response
+ * @cycle_us: duration of the 1-Wire cycle
+ */
+struct w1_uart_limits {
+       unsigned int baudrate;
+       unsigned int bit_min_us;
+       unsigned int bit_max_us;
+       unsigned int sample_us;
+       unsigned int cycle_us;
+};
+
+static inline unsigned int baud_to_bit_ns(unsigned int baud)
+{
+       return NSEC_PER_SEC / baud;
+}
+
+static inline unsigned int to_ns(unsigned int us)
+{
+       return us * NSEC_PER_USEC;
+}
+
+/*
+ * Set baud-rate, delay and tx-byte to create a 1-Wire pulse and adapt
+ * the tx-byte according to the actual baud-rate.
+ *
+ * Reject when:
+ * - time for a bit outside min/max range
+ * - a 1-Wire response is not detectable for sent byte
+ */
+static int w1_uart_set_config(struct serdev_device *serdev,
+                             const struct w1_uart_limits *limits,
+                             struct w1_uart_config *w1cfg)
+{
+       unsigned int packet_ns;
+       unsigned int bits_low;
+       unsigned int bit_ns;
+       unsigned int low_ns;
+
+       w1cfg->baudrate = serdev_device_set_baudrate(serdev, limits->baudrate);
+       if (w1cfg->baudrate == 0)
+               return -EINVAL;
+
+       /* Compute in nanoseconds for accuracy */
+       bit_ns = baud_to_bit_ns(w1cfg->baudrate);
+       bits_low = to_ns(limits->bit_min_us) / bit_ns;
+       /* start bit is always low */
+       low_ns = bit_ns * (bits_low + 1);
+
+       if (low_ns < to_ns(limits->bit_min_us))
+               return -EINVAL;
+
+       if (low_ns > to_ns(limits->bit_max_us))
+               return -EINVAL;
+
+       /* 1-Wire response detectable for sent byte */
+       if (limits->sample_us > 0 &&
+           bit_ns * BITS_PER_BYTE < low_ns + to_ns(limits->sample_us))
+               return -EINVAL;
+
+       /* delay: 1-Wire cycle takes longer than the UART packet */
+       packet_ns = bit_ns * W1_UART_BITS_PER_PACKET;
+       w1cfg->delay_us = 0;
+       if (to_ns(limits->cycle_us) > packet_ns)
+               w1cfg->delay_us =
+                       (to_ns(limits->cycle_us) - packet_ns) / NSEC_PER_USEC;
+
+       /* byte to create 1-Wire pulse */
+       w1cfg->tx_byte = 0xff << bits_low;
+
+       return 0;
+}
+
+/*
+ * Configuration for reset and presence detect
+ * - bit_min_us is 480us, add margin and use 485us
+ * - limits for sample time 60us-75us, use 65us
+ */
+static int w1_uart_set_config_reset(struct w1_uart_device *w1dev)
+{
+       struct serdev_device *serdev = w1dev->serdev;
+       struct device_node *np = serdev->dev.of_node;
+
+       struct w1_uart_limits limits = { .baudrate = 9600,
+                                        .bit_min_us = 485,
+                                        .bit_max_us = 640,
+                                        .sample_us = 65,
+                                        .cycle_us = 960 };
+
+       of_property_read_u32(np, "reset-bps", &limits.baudrate);
+
+       return w1_uart_set_config(serdev, &limits, &w1dev->cfg_reset);
+}
+
+/*
+ * Configuration for write-0 cycle (touch bit 0)
+ * - bit_min_us is 60us, add margin and use 65us
+ * - no sampling required, sample_us = 0
+ */
+static int w1_uart_set_config_touch_0(struct w1_uart_device *w1dev)
+{
+       struct serdev_device *serdev = w1dev->serdev;
+       struct device_node *np = serdev->dev.of_node;
+
+       struct w1_uart_limits limits = { .baudrate = 115200,
+                                        .bit_min_us = 65,
+                                        .bit_max_us = 120,
+                                        .sample_us = 0,
+                                        .cycle_us = 70 };
+
+       of_property_read_u32(np, "write-0-bps", &limits.baudrate);
+
+       return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_0);
+}
+
+/*
+ * Configuration for write-1 and read cycle (touch bit 1)
+ * - bit_min_us is 5us, add margin and use 6us
+ * - limits for sample time 5us-15us, use 15us
+ */
+static int w1_uart_set_config_touch_1(struct w1_uart_device *w1dev)
+{
+       struct serdev_device *serdev = w1dev->serdev;
+       struct device_node *np = serdev->dev.of_node;
+
+       struct w1_uart_limits limits = { .baudrate = 115200,
+                                        .bit_min_us = 6,
+                                        .bit_max_us = 15,
+                                        .sample_us = 15,
+                                        .cycle_us = 70 };
+
+       of_property_read_u32(np, "write-1-bps", &limits.baudrate);
+
+       return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_1);
+}
+
+/*
+ * Configure and open the serial device
+ */
+static int w1_uart_serdev_open(struct w1_uart_device *w1dev)
+{
+       struct serdev_device *serdev = w1dev->serdev;
+       struct device *dev = &serdev->dev;
+       int ret;
+
+       ret = devm_serdev_device_open(dev, serdev);
+       if (ret < 0)
+               return ret;
+
+       ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+       if (ret < 0) {
+               dev_err(dev, "set parity failed\n");
+               return ret;
+       }
+
+       ret = w1_uart_set_config_reset(w1dev);
+       if (ret < 0) {
+               dev_err(dev, "config for reset failed\n");
+               return ret;
+       }
+
+       ret = w1_uart_set_config_touch_0(w1dev);
+       if (ret < 0) {
+               dev_err(dev, "config for touch-0 failed\n");
+               return ret;
+       }
+
+       ret = w1_uart_set_config_touch_1(w1dev);
+       if (ret < 0) {
+               dev_err(dev, "config for touch-1 failed\n");
+               return ret;
+       }
+
+       serdev_device_set_flow_control(serdev, false);
+
+       return 0;
+}
+
+/*
+ * Send one byte (tx_byte) and read one byte (rx_byte) via serdev.
+ */
+static int w1_uart_serdev_tx_rx(struct w1_uart_device *w1dev,
+                               const struct w1_uart_config *w1cfg, u8 *rx_byte)
+{
+       struct serdev_device *serdev = w1dev->serdev;
+       int ret;
+
+       serdev_device_write_flush(serdev);
+       serdev_device_set_baudrate(serdev, w1cfg->baudrate);
+
+       /* write and immediately read one byte */
+       reinit_completion(&w1dev->rx_byte_received);
+       ret = serdev_device_write_buf(serdev, &w1cfg->tx_byte, 1);
+       if (ret != 1)
+               return -EIO;
+       ret = wait_for_completion_interruptible_timeout(
+               &w1dev->rx_byte_received, W1_UART_TIMEOUT);
+       if (ret <= 0)
+               return -EIO;
+
+       /* locking could fail when serdev is unexpectedly receiving. */
+       if (!mutex_trylock(&w1dev->rx_mutex))
+               return -EIO;
+
+       ret = w1dev->rx_err;
+       if (ret == 0)
+               *rx_byte = w1dev->rx_byte;
+
+       mutex_unlock(&w1dev->rx_mutex);
+
+       if (w1cfg->delay_us > 0)
+               fsleep(w1cfg->delay_us);
+
+       return ret;
+}
+
+static size_t w1_uart_serdev_receive_buf(struct serdev_device *serdev,
+                                         const u8 *buf, size_t count)
+{
+       struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev);
+
+       mutex_lock(&w1dev->rx_mutex);
+
+       /* sent a single byte and receive one single byte */
+       if (count == 1) {
+               w1dev->rx_byte = buf[0];
+               w1dev->rx_err = 0;
+       } else {
+               w1dev->rx_err = -EIO;
+       }
+
+       mutex_unlock(&w1dev->rx_mutex);
+       complete(&w1dev->rx_byte_received);
+
+       return count;
+}
+
+static const struct serdev_device_ops w1_uart_serdev_ops = {
+       .receive_buf = w1_uart_serdev_receive_buf,
+       .write_wakeup = serdev_device_write_wakeup,
+};
+
+/*
+ * 1-wire reset and presence detect: A present slave will manipulate
+ * the received byte by pulling the 1-Wire low.
+ */
+static u8 w1_uart_reset_bus(void *data)
+{
+       struct w1_uart_device *w1dev = data;
+       const struct w1_uart_config *w1cfg = &w1dev->cfg_reset;
+       int ret;
+       u8 val;
+
+       ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val);
+       if (ret < 0)
+               return -1;
+
+       /* Device present (0) or no device (1) */
+       return val != w1cfg->tx_byte ? 0 : 1;
+}
+
+/*
+ * 1-Wire read and write cycle: Only the read-0 manipulates the
+ * received byte, all others left the line untouched.
+ */
+static u8 w1_uart_touch_bit(void *data, u8 bit)
+{
+       struct w1_uart_device *w1dev = data;
+       const struct w1_uart_config *w1cfg = bit ? &w1dev->cfg_touch_1 :
+                                                  &w1dev->cfg_touch_0;
+       int ret;
+       u8 val;
+
+       ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val);
+
+       /* return inactive bus state on error */
+       if (ret < 0)
+               return 1;
+
+       return val == w1cfg->tx_byte ? 1 : 0;
+}
+
+static int w1_uart_probe(struct serdev_device *serdev)
+{
+       struct device *dev = &serdev->dev;
+       struct w1_uart_device *w1dev;
+       int ret;
+
+       w1dev = devm_kzalloc(dev, sizeof(*w1dev), GFP_KERNEL);
+       if (!w1dev)
+               return -ENOMEM;
+       w1dev->bus.data = w1dev;
+       w1dev->bus.reset_bus = w1_uart_reset_bus;
+       w1dev->bus.touch_bit = w1_uart_touch_bit;
+       w1dev->serdev = serdev;
+
+       init_completion(&w1dev->rx_byte_received);
+       mutex_init(&w1dev->rx_mutex);
+
+       ret = w1_uart_serdev_open(w1dev);
+       if (ret < 0)
+               return ret;
+       serdev_device_set_drvdata(serdev, w1dev);
+       serdev_device_set_client_ops(serdev, &w1_uart_serdev_ops);
+
+       return w1_add_master_device(&w1dev->bus);
+}
+
+static void w1_uart_remove(struct serdev_device *serdev)
+{
+       struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev);
+
+       /*
+        * Waits until w1-uart callbacks are finished, serdev is closed
+        * and its device data released automatically by devres (waits
+        * until serdev-receive is finished).
+        */
+       w1_remove_master_device(&w1dev->bus);
+}
+
+static const struct of_device_id w1_uart_of_match[] = {
+       { .compatible = "w1-uart" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, w1_uart_of_match);
+
+static struct serdev_device_driver w1_uart_driver = {
+       .driver = {
+               .name           = "w1-uart",
+               .of_match_table = w1_uart_of_match,
+       },
+       .probe  = w1_uart_probe,
+       .remove = w1_uart_remove,
+};
+
+module_serdev_device_driver(w1_uart_driver);
+
+MODULE_DESCRIPTION("UART w1 bus driver");
+MODULE_AUTHOR("Christoph Winklhofer <cj.winklhofer@gmail.com>");
+MODULE_LICENSE("GPL");
index 5353cbd75126c120f4f202038be16c3e27fdef63..afb1cc4606c5230f4c8fb840875976bb4d110b8c 100644 (file)
@@ -167,7 +167,7 @@ static struct w1_family w1_default_family = {
 
 static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env);
 
-static struct bus_type w1_bus_type = {
+static const struct bus_type w1_bus_type = {
        .name = "w1",
        .uevent = w1_uevent,
 };
index 976c6cdf9ee67a598f28e51b7c96f0dc54acace9..aaf2514fcfa4626f70259d467002f497007f8378 100644 (file)
@@ -672,7 +672,6 @@ EXPORT_SYMBOL(xen_free_ballooned_pages);
 
 static void __init balloon_add_regions(void)
 {
-#if defined(CONFIG_XEN_PV)
        unsigned long start_pfn, pages;
        unsigned long pfn, extra_pfn_end;
        unsigned int i;
@@ -696,7 +695,6 @@ static void __init balloon_add_regions(void)
 
                balloon_stats.total_pages += extra_pfn_end - start_pfn;
        }
-#endif
 }
 
 static int __init balloon_init(void)
index 2faa4bf78c7a9d87a0cbfe76358c2ad7538f6b48..81effbd53dc52b58daa51fc4ea7f906e8cc1ca81 100644 (file)
@@ -1190,7 +1190,7 @@ int xen_pirq_from_irq(unsigned irq)
 EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
 
 static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip,
-                                  struct xenbus_device *dev)
+                                  struct xenbus_device *dev, bool shared)
 {
        int ret = -ENOMEM;
        struct irq_info *info;
@@ -1224,7 +1224,8 @@ static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip,
                 */
                bind_evtchn_to_cpu(info, 0, false);
        } else if (!WARN_ON(info->type != IRQT_EVTCHN)) {
-               info->refcnt++;
+               if (shared && !WARN_ON(info->refcnt < 0))
+                       info->refcnt++;
        }
 
        ret = info->irq;
@@ -1237,13 +1238,13 @@ out:
 
 int bind_evtchn_to_irq(evtchn_port_t evtchn)
 {
-       return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip, NULL);
+       return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip, NULL, false);
 }
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
 
 int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
 {
-       return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL);
+       return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip, NULL, false);
 }
 EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
 
@@ -1295,7 +1296,8 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
 
 static int bind_interdomain_evtchn_to_irq_chip(struct xenbus_device *dev,
                                               evtchn_port_t remote_port,
-                                              struct irq_chip *chip)
+                                              struct irq_chip *chip,
+                                              bool shared)
 {
        struct evtchn_bind_interdomain bind_interdomain;
        int err;
@@ -1307,14 +1309,14 @@ static int bind_interdomain_evtchn_to_irq_chip(struct xenbus_device *dev,
                                          &bind_interdomain);
 
        return err ? : bind_evtchn_to_irq_chip(bind_interdomain.local_port,
-                                              chip, dev);
+                                              chip, dev, shared);
 }
 
 int bind_interdomain_evtchn_to_irq_lateeoi(struct xenbus_device *dev,
                                           evtchn_port_t remote_port)
 {
        return bind_interdomain_evtchn_to_irq_chip(dev, remote_port,
-                                                  &xen_lateeoi_chip);
+                                                  &xen_lateeoi_chip, false);
 }
 EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi);
 
@@ -1430,7 +1432,8 @@ static int bind_evtchn_to_irqhandler_chip(evtchn_port_t evtchn,
 {
        int irq, retval;
 
-       irq = bind_evtchn_to_irq_chip(evtchn, chip, NULL);
+       irq = bind_evtchn_to_irq_chip(evtchn, chip, NULL,
+                                     irqflags & IRQF_SHARED);
        if (irq < 0)
                return irq;
        retval = request_irq(irq, handler, irqflags, devname, dev_id);
@@ -1471,7 +1474,8 @@ static int bind_interdomain_evtchn_to_irqhandler_chip(
 {
        int irq, retval;
 
-       irq = bind_interdomain_evtchn_to_irq_chip(dev, remote_port, chip);
+       irq = bind_interdomain_evtchn_to_irq_chip(dev, remote_port, chip,
+                                                 irqflags & IRQF_SHARED);
        if (irq < 0)
                return irq;
 
index 59717628ca42b4d024eb8b070d1ee4a72d30ece9..f6a2216c2c8701e9ffa9a549ea2e40944ab5647e 100644 (file)
@@ -85,6 +85,7 @@ struct user_evtchn {
        struct per_user_data *user;
        evtchn_port_t port;
        bool enabled;
+       bool unbinding;
 };
 
 static void evtchn_free_ring(evtchn_port_t *ring)
@@ -164,6 +165,10 @@ static irqreturn_t evtchn_interrupt(int irq, void *data)
        struct per_user_data *u = evtchn->user;
        unsigned int prod, cons;
 
+       /* Handler might be called when tearing down the IRQ. */
+       if (evtchn->unbinding)
+               return IRQ_HANDLED;
+
        WARN(!evtchn->enabled,
             "Interrupt for port %u, but apparently not enabled; per-user %p\n",
             evtchn->port, u);
@@ -421,6 +426,7 @@ static void evtchn_unbind_from_user(struct per_user_data *u,
 
        BUG_ON(irq < 0);
 
+       evtchn->unbinding = true;
        unbind_from_irqhandler(irq, evtchn);
 
        del_evtchn(u, evtchn);
index 6a9fe02c6bfccdfe1641ab255aa5f95ca5025c1b..2ee750a03c2f7b0463be8eb2ac9bd748692ba080 100644 (file)
@@ -51,14 +51,12 @@ static int grant_dma_iommu_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int grant_dma_iommu_remove(struct platform_device *pdev)
+static void grant_dma_iommu_remove(struct platform_device *pdev)
 {
        struct grant_dma_iommu_device *mmu = platform_get_drvdata(pdev);
 
        platform_set_drvdata(pdev, NULL);
        iommu_device_unregister(&mmu->iommu);
-
-       return 0;
 }
 
 static struct platform_driver grant_dma_iommu_driver = {
@@ -67,7 +65,7 @@ static struct platform_driver grant_dma_iommu_driver = {
                .of_match_table = grant_dma_iommu_of_match,
        },
        .probe = grant_dma_iommu_probe,
-       .remove = grant_dma_iommu_remove,
+       .remove_new = grant_dma_iommu_remove,
 };
 
 static int __init grant_dma_iommu_init(void)
index 8a67fc427e748a0840d9e92c1c0e8e4a3d7c4fdc..67afe68972d5c7e62a5db77f41d5b81916eb432d 100644 (file)
@@ -474,16 +474,6 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode,
                        continue;
                }
 
-               /* Don't expose silly rename entries to userspace. */
-               if (nlen > 6 &&
-                   dire->u.name[0] == '.' &&
-                   ctx->actor != afs_lookup_filldir &&
-                   ctx->actor != afs_lookup_one_filldir &&
-                   memcmp(dire->u.name, ".__afs", 6) == 0) {
-                       ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent);
-                       continue;
-               }
-
                /* found the next entry */
                if (!dir_emit(ctx, dire->u.name, nlen,
                              ntohl(dire->u.vnode),
index 700a27bc8c257e920714359ceb168d7c6d7d6055..ed04bd1eeae89793219aacd1ada6efb61aa6ba03 100644 (file)
@@ -602,6 +602,8 @@ iterate_address:
                goto wait_for_more_probe_results;
 
        alist = op->estate->addresses;
+       best_prio = -1;
+       addr_index = 0;
        for (i = 0; i < alist->nr_addrs; i++) {
                if (alist->addrs[i].prio > best_prio) {
                        addr_index = i;
@@ -609,9 +611,7 @@ iterate_address:
                }
        }
 
-       addr_index = READ_ONCE(alist->preferred);
-       if (!test_bit(addr_index, &set))
-               addr_index = __ffs(set);
+       alist->preferred = addr_index;
 
        op->addr_index = addr_index;
        set_bit(addr_index, &op->addr_tried);
@@ -656,12 +656,6 @@ wait_for_more_probe_results:
 next_server:
        trace_afs_rotate(op, afs_rotate_trace_next_server, 0);
        _debug("next");
-       ASSERT(op->estate);
-       alist = op->estate->addresses;
-       if (op->call_responded &&
-           op->addr_index != READ_ONCE(alist->preferred) &&
-           test_bit(alist->preferred, &op->addr_tried))
-               WRITE_ONCE(alist->preferred, op->addr_index);
        op->estate = NULL;
        goto pick_server;
 
@@ -690,14 +684,7 @@ no_more_servers:
 failed:
        trace_afs_rotate(op, afs_rotate_trace_failed, 0);
        op->flags |= AFS_OPERATION_STOP;
-       if (op->estate) {
-               alist = op->estate->addresses;
-               if (op->call_responded &&
-                   op->addr_index != READ_ONCE(alist->preferred) &&
-                   test_bit(alist->preferred, &op->addr_tried))
-                       WRITE_ONCE(alist->preferred, op->addr_index);
-               op->estate = NULL;
-       }
+       op->estate = NULL;
        _leave(" = f [failed %d]", afs_op_error(op));
        return false;
 }
index 46b37f2cce7d907562ef5014762b5cd37e99775a..32a53fc8dfb26b292c0817155a7c9d387d66064d 100644 (file)
@@ -122,6 +122,9 @@ bool afs_check_validity(const struct afs_vnode *vnode)
        const struct afs_volume *volume = vnode->volume;
        time64_t deadline = ktime_get_real_seconds() + 10;
 
+       if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
+               return true;
+
        if (atomic_read(&volume->cb_v_check) != atomic_read(&volume->cb_v_break) ||
            atomic64_read(&vnode->cb_expires_at)  <= deadline ||
            volume->cb_expires_at <= deadline ||
@@ -389,12 +392,17 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
               key_serial(key));
 
        if (afs_check_validity(vnode))
-               return 0;
+               return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? -ESTALE : 0;
 
        ret = down_write_killable(&vnode->validate_lock);
        if (ret < 0)
                goto error;
 
+       if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
+               ret = -ESTALE;
+               goto error_unlock;
+       }
+
        /* Validate a volume after the v_break has changed or the volume
         * callback expired.  We only want to do this once per volume per
         * v_break change.  The actual work will be done when parsing the
@@ -448,12 +456,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
        vnode->cb_ro_snapshot = cb_ro_snapshot;
        vnode->cb_scrub = cb_scrub;
 
-       if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
-               _debug("file already deleted");
-               ret = -ESTALE;
-               goto error_unlock;
-       }
-
        /* if the vnode's data version number changed then its contents are
         * different */
        zap |= test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
index c47f72f2bd586f6c15bc42e019cc97edc0f6030a..893e38f9db807f4c6d819a470339b6af97f85804 100644 (file)
@@ -532,13 +532,13 @@ int bch2_bucket_gens_init(struct bch_fs *c)
                u8 gen = bch2_alloc_to_v4(k, &a)->gen;
                unsigned offset;
                struct bpos pos = alloc_gens_pos(iter.pos, &offset);
+               int ret2 = 0;
 
                if (have_bucket_gens_key && bkey_cmp(iter.pos, pos)) {
-                       ret = commit_do(trans, NULL, NULL,
-                                       BCH_TRANS_COMMIT_no_enospc,
-                               bch2_btree_insert_trans(trans, BTREE_ID_bucket_gens, &g.k_i, 0));
-                       if (ret)
-                               break;
+                       ret2 =  bch2_btree_insert_trans(trans, BTREE_ID_bucket_gens, &g.k_i, 0) ?:
+                               bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
+                       if (ret2)
+                               goto iter_err;
                        have_bucket_gens_key = false;
                }
 
@@ -549,7 +549,8 @@ int bch2_bucket_gens_init(struct bch_fs *c)
                }
 
                g.v.gens[offset] = gen;
-               0;
+iter_err:
+               ret2;
        }));
 
        if (have_bucket_gens_key && !ret)
@@ -852,7 +853,7 @@ int bch2_trigger_alloc(struct btree_trans *trans,
                                        bucket_journal_seq);
                        if (ret) {
                                bch2_fs_fatal_error(c,
-                                       "error setting bucket_needs_journal_commit: %i", ret);
+                                       "setting bucket_needs_journal_commit: %s", bch2_err_str(ret));
                                return ret;
                        }
                }
index ca58193dd90279b6d6081f06954690f214ba3a42..214b15c84d1f3258d2ba23effacc5ad4e8852783 100644 (file)
@@ -1356,15 +1356,17 @@ retry:
 
                /* Don't retry from all devices if we're out of open buckets: */
                if (bch2_err_matches(ret, BCH_ERR_open_buckets_empty)) {
-                       int ret = open_bucket_add_buckets(trans, &ptrs, wp, devs_have,
+                       int ret2 = open_bucket_add_buckets(trans, &ptrs, wp, devs_have,
                                              target, erasure_code,
                                              nr_replicas, &nr_effective,
                                              &have_cache, watermark,
                                              flags, cl);
-                       if (!ret ||
-                           bch2_err_matches(ret, BCH_ERR_transaction_restart) ||
-                           bch2_err_matches(ret, BCH_ERR_open_buckets_empty))
+                       if (!ret2 ||
+                           bch2_err_matches(ret2, BCH_ERR_transaction_restart) ||
+                           bch2_err_matches(ret2, BCH_ERR_open_buckets_empty)) {
+                               ret = ret2;
                                goto alloc_done;
+                       }
                }
 
                /*
index 339dc3e1dcd39939b5f021db2665190ea07ceee9..799aa32b6b4d990f913b0d5dfb98b6a47af1f0b2 100644 (file)
@@ -849,6 +849,8 @@ struct bch_fs {
        struct workqueue_struct *btree_interior_update_worker;
        struct work_struct      btree_interior_update_work;
 
+       struct workqueue_struct *btree_node_rewrite_worker;
+
        struct list_head        pending_node_rewrites;
        struct mutex            pending_node_rewrites_lock;
 
index 584aee7010deaa79df36edd60e5d7e59bcb7a7e3..bdaed29f084a4d558a160817e6fa6447c8547b0d 100644 (file)
@@ -1392,11 +1392,11 @@ static int bch2_alloc_write_key(struct btree_trans *trans,
                                         *old,
                                         b->data_type);
        gc = *b;
-       percpu_up_read(&c->mark_lock);
 
        if (gc.data_type != old_gc.data_type ||
            gc.dirty_sectors != old_gc.dirty_sectors)
                bch2_dev_usage_update_m(c, ca, &old_gc, &gc);
+       percpu_up_read(&c->mark_lock);
 
        if (metadata_only &&
            gc.data_type != BCH_DATA_sb &&
index 624c8287deb43191d39b130c842875f7aa1a9ff1..34df8ccc5fecc2bfbad874e77f53fa1f5f068251 100644 (file)
@@ -1066,7 +1066,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
 
                        ret = bset_encrypt(c, i, b->written << 9);
                        if (bch2_fs_fatal_err_on(ret, c,
-                                       "error decrypting btree node: %i", ret))
+                                       "decrypting btree node: %s", bch2_err_str(ret)))
                                goto fsck_err;
 
                        btree_err_on(btree_node_type_is_extents(btree_node_type(b)) &&
@@ -1107,7 +1107,7 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
 
                        ret = bset_encrypt(c, i, b->written << 9);
                        if (bch2_fs_fatal_err_on(ret, c,
-                                       "error decrypting btree node: %i\n", ret))
+                                       "decrypting btree node: %s", bch2_err_str(ret)))
                                goto fsck_err;
 
                        sectors = vstruct_sectors(bne, c->block_bits);
@@ -1338,7 +1338,7 @@ start:
        if (saw_error && !btree_node_read_error(b)) {
                printbuf_reset(&buf);
                bch2_bpos_to_text(&buf, b->key.k.p);
-               bch_info(c, "%s: rewriting btree node at btree=%s level=%u %s due to error",
+               bch_err_ratelimited(c, "%s: rewriting btree node at btree=%s level=%u %s due to error",
                         __func__, bch2_btree_id_str(b->c.btree_id), b->c.level, buf.buf);
 
                bch2_btree_node_rewrite_async(c, b);
@@ -1874,8 +1874,8 @@ out:
        return;
 err:
        set_btree_node_noevict(b);
-       if (!bch2_err_matches(ret, EROFS))
-               bch2_fs_fatal_error(c, "fatal error writing btree node: %s", bch2_err_str(ret));
+       bch2_fs_fatal_err_on(!bch2_err_matches(ret, EROFS), c,
+                            "writing btree node: %s", bch2_err_str(ret));
        goto out;
 }
 
@@ -2131,7 +2131,7 @@ do_write:
 
        ret = bset_encrypt(c, i, b->written << 9);
        if (bch2_fs_fatal_err_on(ret, c,
-                       "error encrypting btree node: %i\n", ret))
+                       "encrypting btree node: %s", bch2_err_str(ret)))
                goto err;
 
        nonce = btree_nonce(i, b->written << 9);
index 8a71d43444b9425808ff1db86ec0fd296c9900ff..581edcb0911bfa39e9ec6242686bd213c47f352c 100644 (file)
@@ -676,7 +676,7 @@ static int btree_key_cache_flush_pos(struct btree_trans *trans,
                             !bch2_err_matches(ret, BCH_ERR_transaction_restart) &&
                             !bch2_err_matches(ret, BCH_ERR_journal_reclaim_would_deadlock) &&
                             !bch2_journal_error(j), c,
-                            "error flushing key cache: %s", bch2_err_str(ret));
+                            "flushing key cache: %s", bch2_err_str(ret));
        if (ret)
                goto out;
 
index 642213ef9f798e477bc902e4977be9cb813aab56..b2f5f2e50f7e19ccd59502a1471ee9bb6d14a988 100644 (file)
@@ -646,7 +646,7 @@ static void btree_update_nodes_written(struct btree_update *as)
        bch2_trans_unlock(trans);
 
        bch2_fs_fatal_err_on(ret && !bch2_journal_error(&c->journal), c,
-                            "%s(): error %s", __func__, bch2_err_str(ret));
+                            "%s", bch2_err_str(ret));
 err:
        if (as->b) {
 
@@ -1067,13 +1067,18 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
        flags &= ~BCH_WATERMARK_MASK;
        flags |= watermark;
 
-       if (!(flags & BCH_TRANS_COMMIT_journal_reclaim) &&
-           watermark < c->journal.watermark) {
+       if (watermark < c->journal.watermark) {
                struct journal_res res = { 0 };
+               unsigned journal_flags = watermark|JOURNAL_RES_GET_CHECK;
+
+               if ((flags & BCH_TRANS_COMMIT_journal_reclaim) &&
+                   watermark != BCH_WATERMARK_reclaim)
+                       journal_flags |= JOURNAL_RES_GET_NONBLOCK;
 
                ret = drop_locks_do(trans,
-                       bch2_journal_res_get(&c->journal, &res, 1,
-                                            watermark|JOURNAL_RES_GET_CHECK));
+                       bch2_journal_res_get(&c->journal, &res, 1, journal_flags));
+               if (bch2_err_matches(ret, BCH_ERR_operation_blocked))
+                       ret = -BCH_ERR_journal_reclaim_would_deadlock;
                if (ret)
                        return ERR_PTR(ret);
        }
@@ -1117,6 +1122,7 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
        closure_init(&as->cl, NULL);
        as->c           = c;
        as->start_time  = start_time;
+       as->ip_started  = _RET_IP_;
        as->mode        = BTREE_INTERIOR_NO_UPDATE;
        as->took_gc_lock = true;
        as->btree_id    = path->btree_id;
@@ -1192,7 +1198,8 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path,
 err:
        bch2_btree_update_free(as, trans);
        if (!bch2_err_matches(ret, ENOSPC) &&
-           !bch2_err_matches(ret, EROFS))
+           !bch2_err_matches(ret, EROFS) &&
+           ret != -BCH_ERR_journal_reclaim_would_deadlock)
                bch_err_fn_ratelimited(c, ret);
        return ERR_PTR(ret);
 }
@@ -2114,7 +2121,7 @@ static void async_btree_node_rewrite_work(struct work_struct *work)
 
        ret = bch2_trans_do(c, NULL, NULL, 0,
                      async_btree_node_rewrite_trans(trans, a));
-       bch_err_fn(c, ret);
+       bch_err_fn_ratelimited(c, ret);
        bch2_write_ref_put(c, BCH_WRITE_REF_node_rewrite);
        kfree(a);
 }
@@ -2161,7 +2168,7 @@ void bch2_btree_node_rewrite_async(struct bch_fs *c, struct btree *b)
                bch2_write_ref_get(c, BCH_WRITE_REF_node_rewrite);
        }
 
-       queue_work(c->btree_interior_update_worker, &a->work);
+       queue_work(c->btree_node_rewrite_worker, &a->work);
 }
 
 void bch2_do_pending_node_rewrites(struct bch_fs *c)
@@ -2173,7 +2180,7 @@ void bch2_do_pending_node_rewrites(struct bch_fs *c)
                list_del(&a->list);
 
                bch2_write_ref_get(c, BCH_WRITE_REF_node_rewrite);
-               queue_work(c->btree_interior_update_worker, &a->work);
+               queue_work(c->btree_node_rewrite_worker, &a->work);
        }
        mutex_unlock(&c->pending_node_rewrites_lock);
 }
@@ -2441,12 +2448,12 @@ void bch2_btree_updates_to_text(struct printbuf *out, struct bch_fs *c)
 
        mutex_lock(&c->btree_interior_update_lock);
        list_for_each_entry(as, &c->btree_interior_update_list, list)
-               prt_printf(out, "%p m %u w %u r %u j %llu\n",
-                      as,
-                      as->mode,
-                      as->nodes_written,
-                      closure_nr_remaining(&as->cl),
-                      as->journal.seq);
+               prt_printf(out, "%ps: mode=%u nodes_written=%u cl.remaining=%u journal_seq=%llu\n",
+                          (void *) as->ip_started,
+                          as->mode,
+                          as->nodes_written,
+                          closure_nr_remaining(&as->cl),
+                          as->journal.seq);
        mutex_unlock(&c->btree_interior_update_lock);
 }
 
@@ -2510,6 +2517,8 @@ bch2_btree_roots_to_journal_entries(struct bch_fs *c,
 
 void bch2_fs_btree_interior_update_exit(struct bch_fs *c)
 {
+       if (c->btree_node_rewrite_worker)
+               destroy_workqueue(c->btree_node_rewrite_worker);
        if (c->btree_interior_update_worker)
                destroy_workqueue(c->btree_interior_update_worker);
        mempool_exit(&c->btree_interior_update_pool);
@@ -2534,6 +2543,11 @@ int bch2_fs_btree_interior_update_init(struct bch_fs *c)
        if (!c->btree_interior_update_worker)
                return -BCH_ERR_ENOMEM_btree_interior_update_worker_init;
 
+       c->btree_node_rewrite_worker =
+               alloc_ordered_workqueue("btree_node_rewrite", WQ_UNBOUND);
+       if (!c->btree_node_rewrite_worker)
+               return -BCH_ERR_ENOMEM_btree_interior_update_worker_init;
+
        if (mempool_init_kmalloc_pool(&c->btree_interior_update_pool, 1,
                                      sizeof(struct btree_update)))
                return -BCH_ERR_ENOMEM_btree_interior_update_pool_init;
index 3439b03719c7b505bf43e5f76bf703f6778c9899..f651dd48aaa0496b7cf7c80eb183896b1d418044 100644 (file)
@@ -32,6 +32,7 @@ struct btree_update {
        struct closure                  cl;
        struct bch_fs                   *c;
        u64                             start_time;
+       unsigned long                   ip_started;
 
        struct list_head                list;
        struct list_head                unwritten_list;
index b77e7b382b66660f8b02925c13657118dc28fed1..5cbad8445782c4006074365c13551b1c38b57849 100644 (file)
@@ -378,7 +378,7 @@ static int bch2_btree_write_buffer_flush_locked(struct btree_trans *trans)
                }
        }
 err:
-       bch2_fs_fatal_err_on(ret, c, "%s: insert error %s", __func__, bch2_err_str(ret));
+       bch2_fs_fatal_err_on(ret, c, "%s", bch2_err_str(ret));
        trace_write_buffer_flush(trans, wb->flushing.keys.nr, skipped, fast, 0);
        bch2_journal_pin_drop(j, &wb->flushing.pin);
        wb->flushing.keys.nr = 0;
index c2f46b267b3ad50c796690320f0a700411940931..96edf2c34d433d1c1ad41ec8da0c77b8d40afe9f 100644 (file)
@@ -990,8 +990,8 @@ static int __trigger_extent(struct btree_trans *trans,
                                ret = !gc
                                        ? bch2_update_cached_sectors_list(trans, p.ptr.dev, disk_sectors)
                                        : update_cached_sectors(c, k, p.ptr.dev, disk_sectors, 0, true);
-                               bch2_fs_fatal_err_on(ret && gc, c, "%s(): no replicas entry while updating cached sectors",
-                                                    __func__);
+                               bch2_fs_fatal_err_on(ret && gc, c, "%s: no replicas entry while updating cached sectors",
+                                                    bch2_err_str(ret));
                                if (ret)
                                        return ret;
                        }
@@ -1020,7 +1020,7 @@ static int __trigger_extent(struct btree_trans *trans,
                        struct printbuf buf = PRINTBUF;
 
                        bch2_bkey_val_to_text(&buf, c, k);
-                       bch2_fs_fatal_error(c, "%s(): no replicas entry for %s", __func__, buf.buf);
+                       bch2_fs_fatal_error(c, ": no replicas entry for %s", buf.buf);
                        printbuf_exit(&buf);
                }
                if (ret)
index b1f147e6be4d5cdd0ab491932db9c625b763e29e..208ce6f0fc4317d561582bae51785da2c016a1cd 100644 (file)
@@ -170,7 +170,7 @@ void __bch2_btree_verify(struct bch_fs *c, struct btree *b)
                struct printbuf buf = PRINTBUF;
 
                bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));
-               bch2_fs_fatal_error(c, "btree node verify failed for : %s\n", buf.buf);
+               bch2_fs_fatal_error(c, ": btree node verify failed for: %s\n", buf.buf);
                printbuf_exit(&buf);
        }
 out:
index b98e2c2b8bf06f59fa70cfe23873e51529a917b8..082075244e16aedc824249b239ecec6efb1a07fa 100644 (file)
@@ -448,7 +448,7 @@ int bch2_trigger_stripe(struct btree_trans *trans,
                        struct printbuf buf = PRINTBUF;
 
                        bch2_bkey_val_to_text(&buf, c, new);
-                       bch2_fs_fatal_error(c, "no replicas entry for %s", buf.buf);
+                       bch2_fs_fatal_error(c, "no replicas entry for %s", buf.buf);
                        printbuf_exit(&buf);
                        return ret;
                }
@@ -1868,10 +1868,10 @@ static int __bch2_ec_stripe_head_reuse(struct btree_trans *trans, struct ec_stri
                return -BCH_ERR_stripe_alloc_blocked;
 
        ret = get_stripe_key_trans(trans, idx, &h->s->existing_stripe);
+       bch2_fs_fatal_err_on(ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart), c,
+                            "reading stripe key: %s", bch2_err_str(ret));
        if (ret) {
                bch2_stripe_close(c, h->s);
-               if (!bch2_err_matches(ret, BCH_ERR_transaction_restart))
-                       bch2_fs_fatal_error(c, "error reading stripe key: %s", bch2_err_str(ret));
                return ret;
        }
 
index 94491190e09e9d5085ca1ef87c5764c4192d6a24..ae1d6674c512d44521379f21d5872b2b79993f57 100644 (file)
@@ -191,9 +191,9 @@ do {                                                                        \
 
 void bch2_fatal_error(struct bch_fs *);
 
-#define bch2_fs_fatal_error(c, ...)                                    \
+#define bch2_fs_fatal_error(c, _msg, ...)                              \
 do {                                                                   \
-       bch_err(c, __VA_ARGS__);                                        \
+       bch_err(c, "%s(): fatal error " _msg, __func__, ##__VA_ARGS__); \
        bch2_fatal_error(c);                                            \
 } while (0)
 
index 6219f2c08e4c737abd477588419c0f0dbeecbc38..fd2669cdd76f3b23861a9c0835253d3812a6de10 100644 (file)
@@ -108,17 +108,17 @@ static inline void extent_entry_drop(struct bkey_s k, union bch_extent_entry *en
 
 static inline bool extent_entry_is_ptr(const union bch_extent_entry *e)
 {
-       return extent_entry_type(e) == BCH_EXTENT_ENTRY_ptr;
+       return __extent_entry_type(e) == BCH_EXTENT_ENTRY_ptr;
 }
 
 static inline bool extent_entry_is_stripe_ptr(const union bch_extent_entry *e)
 {
-       return extent_entry_type(e) == BCH_EXTENT_ENTRY_stripe_ptr;
+       return __extent_entry_type(e) == BCH_EXTENT_ENTRY_stripe_ptr;
 }
 
 static inline bool extent_entry_is_crc(const union bch_extent_entry *e)
 {
-       switch (extent_entry_type(e)) {
+       switch (__extent_entry_type(e)) {
        case BCH_EXTENT_ENTRY_crc32:
        case BCH_EXTENT_ENTRY_crc64:
        case BCH_EXTENT_ENTRY_crc128:
index 3f073845bbd77391306a55c6ac7a87771f7e5890..0ccee05f6887b3b0aedf1e7c11f82665c7d38ba5 100644 (file)
@@ -108,7 +108,8 @@ retry:
                goto retry;
 
        bch2_fs_fatal_err_on(bch2_err_matches(ret, ENOENT), c,
-                            "inode %u:%llu not found when updating",
+                            "%s: inode %u:%llu not found when updating",
+                            bch2_err_str(ret),
                             inode_inum(inode).subvol,
                             inode_inum(inode).inum);
 
index f48033be3f6b1fda3da6105b982403b607158c32..47d4eefaba7ba05dc1a610ddc35a27bb10891b5d 100644 (file)
@@ -1114,10 +1114,9 @@ int bch2_check_inodes(struct bch_fs *c)
        return ret;
 }
 
-static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
+static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_walker *w)
 {
        struct bch_fs *c = trans->c;
-       u32 restart_count = trans->restart_count;
        int ret = 0;
        s64 count2;
 
@@ -1149,7 +1148,14 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
        }
 fsck_err:
        bch_err_fn(c, ret);
-       return ret ?: trans_was_restarted(trans, restart_count);
+       return ret;
+}
+
+static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
+{
+       u32 restart_count = trans->restart_count;
+       return check_i_sectors_notnested(trans, w) ?:
+               trans_was_restarted(trans, restart_count);
 }
 
 struct extent_end {
@@ -1533,7 +1539,7 @@ int bch2_check_extents(struct bch_fs *c)
                        check_extent(trans, &iter, k, &w, &s, &extent_ends) ?:
                        check_extent_overbig(trans, &iter, k);
                })) ?:
-               check_i_sectors(trans, &w));
+               check_i_sectors_notnested(trans, &w));
 
        bch2_disk_reservation_put(c, &res);
        extent_ends_exit(&extent_ends);
@@ -1563,10 +1569,9 @@ int bch2_check_indirect_extents(struct bch_fs *c)
        return ret;
 }
 
-static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
+static int check_subdir_count_notnested(struct btree_trans *trans, struct inode_walker *w)
 {
        struct bch_fs *c = trans->c;
-       u32 restart_count = trans->restart_count;
        int ret = 0;
        s64 count2;
 
@@ -1598,7 +1603,14 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
        }
 fsck_err:
        bch_err_fn(c, ret);
-       return ret ?: trans_was_restarted(trans, restart_count);
+       return ret;
+}
+
+static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
+{
+       u32 restart_count = trans->restart_count;
+       return check_subdir_count_notnested(trans, w) ?:
+               trans_was_restarted(trans, restart_count);
 }
 
 static int check_dirent_inode_dirent(struct btree_trans *trans,
@@ -2003,7 +2015,8 @@ int bch2_check_dirents(struct bch_fs *c)
                                k,
                                NULL, NULL,
                                BCH_TRANS_COMMIT_no_enospc,
-                       check_dirent(trans, &iter, k, &hash_info, &dir, &target, &s)));
+                       check_dirent(trans, &iter, k, &hash_info, &dir, &target, &s)) ?:
+               check_subdir_count_notnested(trans, &dir));
 
        snapshots_seen_exit(&s);
        inode_walker_exit(&dir);
@@ -2022,8 +2035,10 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
        int ret;
 
        ret = check_key_has_snapshot(trans, iter, k);
-       if (ret)
+       if (ret < 0)
                return ret;
+       if (ret)
+               return 0;
 
        i = walk_inode(trans, inode, k);
        ret = PTR_ERR_OR_ZERO(i);
index f314b2e78ec368718e671651a99752de374a838f..9c9a25dbd6137a6d51205c80cbf8d931fda918ef 100644 (file)
@@ -511,18 +511,18 @@ retry:
        if (journal_res_get_fast(j, res, flags))
                return 0;
 
+       if (bch2_journal_error(j))
+               return -BCH_ERR_erofs_journal_err;
+
+       if (j->blocked)
+               return -BCH_ERR_journal_res_get_blocked;
+
        if ((flags & BCH_WATERMARK_MASK) < j->watermark) {
                ret = JOURNAL_ERR_journal_full;
                can_discard = j->can_discard;
                goto out;
        }
 
-       if (j->blocked)
-               return -BCH_ERR_journal_res_get_blocked;
-
-       if (bch2_journal_error(j))
-               return -BCH_ERR_erofs_journal_err;
-
        if (nr_unwritten_journal_entries(j) == ARRAY_SIZE(j->buf) && !journal_entry_is_open(j)) {
                ret = JOURNAL_ERR_max_in_flight;
                goto out;
index d76c3c0c203f9eb8e39d391b28bf09430f919f6b..725fcf46f6312c267c2a7c05f1eaa6aed5fb83e7 100644 (file)
@@ -1082,9 +1082,7 @@ reread:
                ret = bch2_encrypt(c, JSET_CSUM_TYPE(j), journal_nonce(j),
                             j->encrypted_start,
                             vstruct_end(j) - (void *) j->encrypted_start);
-               bch2_fs_fatal_err_on(ret, c,
-                               "error decrypting journal entry: %s",
-                               bch2_err_str(ret));
+               bch2_fs_fatal_err_on(ret, c, "decrypting journal entry: %s", bch2_err_str(ret));
 
                mutex_lock(&jlist->lock);
                ret = journal_entry_add(c, ca, (struct journal_ptr) {
@@ -1820,7 +1818,8 @@ static int bch2_journal_write_prep(struct journal *j, struct journal_buf *w)
                        jset_entry_for_each_key(i, k) {
                                ret = bch2_journal_key_to_wb(c, &wb, i->btree_id, k);
                                if (ret) {
-                                       bch2_fs_fatal_error(c, "-ENOMEM flushing journal keys to btree write buffer");
+                                       bch2_fs_fatal_error(c, "flushing journal keys to btree write buffer: %s",
+                                                           bch2_err_str(ret));
                                        bch2_journal_keys_to_write_buffer_end(c, &wb);
                                        return ret;
                                }
@@ -1848,7 +1847,8 @@ static int bch2_journal_write_prep(struct journal *j, struct journal_buf *w)
 
        bch2_journal_super_entries_add_common(c, &end, seq);
        u64s    = (u64 *) end - (u64 *) start;
-       BUG_ON(u64s > j->entry_u64s_reserved);
+
+       WARN_ON(u64s > j->entry_u64s_reserved);
 
        le32_add_cpu(&jset->u64s, u64s);
 
@@ -1856,7 +1856,7 @@ static int bch2_journal_write_prep(struct journal *j, struct journal_buf *w)
        bytes   = vstruct_bytes(jset);
 
        if (sectors > w->sectors) {
-               bch2_fs_fatal_error(c, "aieeee! journal write overran available space, %zu > %u (extra %u reserved %u/%u)",
+               bch2_fs_fatal_error(c, ": journal write overran available space, %zu > %u (extra %u reserved %u/%u)",
                                    vstruct_bytes(jset), w->sectors << 9,
                                    u64s, w->u64s_reserved, j->entry_u64s_reserved);
                return -EINVAL;
@@ -1884,8 +1884,7 @@ static int bch2_journal_write_prep(struct journal *j, struct journal_buf *w)
        ret = bch2_encrypt(c, JSET_CSUM_TYPE(jset), journal_nonce(jset),
                    jset->encrypted_start,
                    vstruct_end(jset) - (void *) jset->encrypted_start);
-       if (bch2_fs_fatal_err_on(ret, c,
-                       "error decrypting journal entry: %i", ret))
+       if (bch2_fs_fatal_err_on(ret, c, "decrypting journal entry: %s", bch2_err_str(ret)))
                return ret;
 
        jset->csum = csum_vstruct(c, JSET_CSUM_TYPE(jset),
index ad598105c587cc0354773b85461293099bbbe36d..9fac838d123e8e40fb836d895afccde634f2d54c 100644 (file)
@@ -101,8 +101,8 @@ void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
                struct printbuf buf = PRINTBUF;
 
                bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k));
-               bch2_fs_fatal_error(c, "%s: error deleting logged operation %s: %s",
-                                    __func__, buf.buf, bch2_err_str(ret));
+               bch2_fs_fatal_error(c, "deleting logged operation %s: %s",
+                                   buf.buf, bch2_err_str(ret));
                printbuf_exit(&buf);
        }
 }
index 69e06a84dad4094847e8c737860d5acc37b25d79..0d2b82d8d11f39efe6a65bee8678e8f2496bdbcf 100644 (file)
@@ -155,8 +155,7 @@ static int bch2_copygc_get_buckets(struct moving_context *ctxt,
        if (bch2_err_matches(ret, EROFS))
                return ret;
 
-       if (bch2_fs_fatal_err_on(ret, c, "%s: error %s from bch2_btree_write_buffer_tryflush()",
-                                __func__, bch2_err_str(ret)))
+       if (bch2_fs_fatal_err_on(ret, c, "%s: from bch2_btree_write_buffer_tryflush()", bch2_err_str(ret)))
                return ret;
 
        ret = for_each_btree_key_upto(trans, iter, BTREE_ID_lru,
index 2af219aedfdbefb36d37fe19423d8e26cabf0cdd..03f9d6afe467889b02a483561277b0d539a836f5 100644 (file)
@@ -90,10 +90,12 @@ static void do_reconstruct_alloc(struct bch_fs *c)
        struct journal_keys *keys = &c->journal_keys;
        size_t src, dst;
 
+       move_gap(keys, keys->nr);
+
        for (src = 0, dst = 0; src < keys->nr; src++)
                if (!btree_id_is_alloc(keys->data[src].btree_id))
                        keys->data[dst++] = keys->data[src];
-       keys->nr = dst;
+       keys->nr = keys->gap = dst;
 }
 
 /*
@@ -203,6 +205,8 @@ static int bch2_journal_replay(struct bch_fs *c)
 
        BUG_ON(!atomic_read(&keys->ref));
 
+       move_gap(keys, keys->nr);
+
        /*
         * First, attempt to replay keys in sorted order. This is more
         * efficient - better locality of btree access -  but some might fail if
index 1361e34d4e64c2939fc0b7af8c9df9e5d9dfc7cf..4959e95e7c74654e8b3a6e78a0ea7778713bd8ba 100644 (file)
  * must never change:
  */
 #define BCH_RECOVERY_PASSES()                                                  \
+       x(check_topology,                        4, 0)                          \
        x(alloc_read,                            0, PASS_ALWAYS)                \
        x(stripes_read,                          1, PASS_ALWAYS)                \
        x(initialize_subvolumes,                 2, 0)                          \
        x(snapshots_read,                        3, PASS_ALWAYS)                \
-       x(check_topology,                        4, 0)                          \
        x(check_allocations,                     5, PASS_FSCK)                  \
        x(trans_mark_dev_sbs,                    6, PASS_ALWAYS|PASS_SILENT)    \
        x(fs_journal_alloc,                      7, PASS_ALWAYS|PASS_SILENT)    \
index ac6ba04d5521714ece2e2cb00400fff60ec05eb6..39debe814bf392acb76c7cebe6752736d6c57cff 100644 (file)
@@ -91,18 +91,20 @@ static int bch2_snapshot_tree_create(struct btree_trans *trans,
 
 /* Snapshot nodes: */
 
-static bool bch2_snapshot_is_ancestor_early(struct bch_fs *c, u32 id, u32 ancestor)
+static bool __bch2_snapshot_is_ancestor_early(struct snapshot_table *t, u32 id, u32 ancestor)
 {
-       struct snapshot_table *t;
-
-       rcu_read_lock();
-       t = rcu_dereference(c->snapshots);
-
        while (id && id < ancestor)
                id = __snapshot_t(t, id)->parent;
+       return id == ancestor;
+}
+
+static bool bch2_snapshot_is_ancestor_early(struct bch_fs *c, u32 id, u32 ancestor)
+{
+       rcu_read_lock();
+       bool ret = __bch2_snapshot_is_ancestor_early(rcu_dereference(c->snapshots), id, ancestor);
        rcu_read_unlock();
 
-       return id == ancestor;
+       return ret;
 }
 
 static inline u32 get_ancestor_below(struct snapshot_table *t, u32 id, u32 ancestor)
@@ -120,13 +122,15 @@ static inline u32 get_ancestor_below(struct snapshot_table *t, u32 id, u32 ances
 
 bool __bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ancestor)
 {
-       struct snapshot_table *t;
        bool ret;
 
-       EBUG_ON(c->recovery_pass_done <= BCH_RECOVERY_PASS_check_snapshots);
-
        rcu_read_lock();
-       t = rcu_dereference(c->snapshots);
+       struct snapshot_table *t = rcu_dereference(c->snapshots);
+
+       if (unlikely(c->recovery_pass_done <= BCH_RECOVERY_PASS_check_snapshots)) {
+               ret = __bch2_snapshot_is_ancestor_early(t, id, ancestor);
+               goto out;
+       }
 
        while (id && id < ancestor - IS_ANCESTOR_BITMAP)
                id = get_ancestor_below(t, id, ancestor);
@@ -134,11 +138,11 @@ bool __bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ancestor)
        if (id && id < ancestor) {
                ret = test_bit(ancestor - id - 1, __snapshot_t(t, id)->is_ancestor);
 
-               EBUG_ON(ret != bch2_snapshot_is_ancestor_early(c, id, ancestor));
+               EBUG_ON(ret != __bch2_snapshot_is_ancestor_early(t, id, ancestor));
        } else {
                ret = id == ancestor;
        }
-
+out:
        rcu_read_unlock();
 
        return ret;
@@ -547,7 +551,7 @@ static int check_snapshot_tree(struct btree_trans *trans,
                        "snapshot tree points to missing subvolume:\n  %s",
                        (printbuf_reset(&buf),
                         bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf)) ||
-           fsck_err_on(!bch2_snapshot_is_ancestor_early(c,
+           fsck_err_on(!bch2_snapshot_is_ancestor(c,
                                                le32_to_cpu(subvol.snapshot),
                                                root_id),
                        c, snapshot_tree_to_wrong_subvol,
index bceac29f3d86272d884c8fa59ad8e7f7c8163318..ad28e370b6404c915ee8bf8743ed535366fc6a55 100644 (file)
@@ -985,7 +985,7 @@ int bch2_write_super(struct bch_fs *c)
                prt_str(&buf, " > ");
                bch2_version_to_text(&buf, bcachefs_metadata_version_current);
                prt_str(&buf, ")");
-               bch2_fs_fatal_error(c, "%s", buf.buf);
+               bch2_fs_fatal_error(c, "%s", buf.buf);
                printbuf_exit(&buf);
                return -BCH_ERR_sb_not_downgraded;
        }
@@ -1005,7 +1005,7 @@ int bch2_write_super(struct bch_fs *c)
 
                if (le64_to_cpu(ca->sb_read_scratch->seq) < ca->disk_sb.seq) {
                        bch2_fs_fatal_error(c,
-                               "Superblock write was silently dropped! (seq %llu expected %llu)",
+                               "Superblock write was silently dropped! (seq %llu expected %llu)",
                                le64_to_cpu(ca->sb_read_scratch->seq),
                                ca->disk_sb.seq);
                        percpu_ref_put(&ca->io_ref);
@@ -1015,7 +1015,7 @@ int bch2_write_super(struct bch_fs *c)
 
                if (le64_to_cpu(ca->sb_read_scratch->seq) > ca->disk_sb.seq) {
                        bch2_fs_fatal_error(c,
-                               "Superblock modified by another process (seq %llu expected %llu)",
+                               "Superblock modified by another process (seq %llu expected %llu)",
                                le64_to_cpu(ca->sb_read_scratch->seq),
                                ca->disk_sb.seq);
                        percpu_ref_put(&ca->io_ref);
@@ -1066,7 +1066,7 @@ int bch2_write_super(struct bch_fs *c)
                                 !can_mount_with_written ||
                                 (can_mount_without_written &&
                                  !can_mount_with_written), c,
-               "Unable to write superblock to sufficient devices (from %ps)",
+               "Unable to write superblock to sufficient devices (from %ps)",
                (void *) _RET_IP_))
                ret = -1;
 out:
index 233f864ed8b07ff321b64993a821d08137b70ecd..1ad6e5cd9476c86f4b905feff6f727b4cdd94a4e 100644 (file)
@@ -87,20 +87,28 @@ const char * const bch2_fs_flag_strs[] = {
        NULL
 };
 
-void bch2_print_opts(struct bch_opts *opts, const char *fmt, ...)
+__printf(2, 0)
+static void bch2_print_maybe_redirect(struct stdio_redirect *stdio, const char *fmt, va_list args)
 {
-       struct stdio_redirect *stdio = (void *)(unsigned long)opts->stdio;
-
-       va_list args;
-       va_start(args, fmt);
-       if (likely(!stdio)) {
-               vprintk(fmt, args);
-       } else {
+#ifdef __KERNEL__
+       if (unlikely(stdio)) {
                if (fmt[0] == KERN_SOH[0])
                        fmt += 2;
 
                bch2_stdio_redirect_vprintf(stdio, true, fmt, args);
+               return;
        }
+#endif
+       vprintk(fmt, args);
+}
+
+void bch2_print_opts(struct bch_opts *opts, const char *fmt, ...)
+{
+       struct stdio_redirect *stdio = (void *)(unsigned long)opts->stdio;
+
+       va_list args;
+       va_start(args, fmt);
+       bch2_print_maybe_redirect(stdio, fmt, args);
        va_end(args);
 }
 
@@ -110,14 +118,7 @@ void __bch2_print(struct bch_fs *c, const char *fmt, ...)
 
        va_list args;
        va_start(args, fmt);
-       if (likely(!stdio)) {
-               vprintk(fmt, args);
-       } else {
-               if (fmt[0] == KERN_SOH[0])
-                       fmt += 2;
-
-               bch2_stdio_redirect_vprintf(stdio, true, fmt, args);
-       }
+       bch2_print_maybe_redirect(stdio, fmt, args);
        va_end(args);
 }
 
index 7ffbddb80400d7aed4bc1479c79cae32427e2595..175aee3074c7d539d40e7ec3ffc072a0e3d2d388 100644 (file)
@@ -683,6 +683,9 @@ static inline void __move_gap(void *array, size_t element_size,
 /* Move the gap in a gap buffer: */
 #define move_gap(_d, _new_gap)                                         \
 do {                                                                   \
+       BUG_ON(_new_gap > (_d)->nr);                                    \
+       BUG_ON((_d)->gap > (_d)->nr);                                   \
+                                                                       \
        __move_gap((_d)->data, sizeof((_d)->data[0]),                   \
                   (_d)->nr, (_d)->size, (_d)->gap, _new_gap);          \
        (_d)->gap = _new_gap;                                           \
index a2d07fa3cfdff4081f34365d121cc7acdf845750..1dc1f1946ae0eb3158a38b2d214746e7cc4a09ee 100644 (file)
@@ -1303,6 +1303,47 @@ int btrfs_forget_devices(dev_t devt)
        return ret;
 }
 
+static bool btrfs_skip_registration(struct btrfs_super_block *disk_super,
+                                   const char *path, dev_t devt,
+                                   bool mount_arg_dev)
+{
+       struct btrfs_fs_devices *fs_devices;
+
+       /*
+        * Do not skip device registration for mounted devices with matching
+        * maj:min but different paths. Booting without initrd relies on
+        * /dev/root initially, later replaced with the actual root device.
+        * A successful scan ensures grub2-probe selects the correct device.
+        */
+       list_for_each_entry(fs_devices, &fs_uuids, fs_list) {
+               struct btrfs_device *device;
+
+               mutex_lock(&fs_devices->device_list_mutex);
+
+               if (!fs_devices->opened) {
+                       mutex_unlock(&fs_devices->device_list_mutex);
+                       continue;
+               }
+
+               list_for_each_entry(device, &fs_devices->devices, dev_list) {
+                       if (device->bdev && (device->bdev->bd_dev == devt) &&
+                           strcmp(device->name->str, path) != 0) {
+                               mutex_unlock(&fs_devices->device_list_mutex);
+
+                               /* Do not skip registration. */
+                               return false;
+                       }
+               }
+               mutex_unlock(&fs_devices->device_list_mutex);
+       }
+
+       if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 &&
+           !(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING))
+               return true;
+
+       return false;
+}
+
 /*
  * Look for a btrfs signature on a device. This may be called out of the mount path
  * and we are not allowed to call set_blocksize during the scan. The superblock
@@ -1320,6 +1361,7 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
        struct btrfs_device *device = NULL;
        struct file *bdev_file;
        u64 bytenr, bytenr_orig;
+       dev_t devt;
        int ret;
 
        lockdep_assert_held(&uuid_mutex);
@@ -1359,19 +1401,13 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, blk_mode_t flags,
                goto error_bdev_put;
        }
 
-       if (!mount_arg_dev && btrfs_super_num_devices(disk_super) == 1 &&
-           !(btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING)) {
-               dev_t devt;
+       devt = file_bdev(bdev_file)->bd_dev;
+       if (btrfs_skip_registration(disk_super, path, devt, mount_arg_dev)) {
+               pr_debug("BTRFS: skip registering single non-seed device %s (%d:%d)\n",
+                         path, MAJOR(devt), MINOR(devt));
 
-               ret = lookup_bdev(path, &devt);
-               if (ret)
-                       btrfs_warn(NULL, "lookup bdev failed for path %s: %d",
-                                  path, ret);
-               else
-                       btrfs_free_stale_devices(devt, NULL);
+               btrfs_free_stale_devices(devt, NULL);
 
-       pr_debug("BTRFS: skip registering single non-seed device %s (%d:%d)\n",
-                       path, MAJOR(devt), MINOR(devt));
                device = NULL;
                goto free_disk_super;
        }
index 7fb4aae97412464c54b42037f75016085d214bd3..55051ad09c19197e9b12d5d17068d20b04d6d3e6 100644 (file)
@@ -4634,6 +4634,14 @@ unsigned long ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
                        iput(inode);
                        spin_lock(&mdsc->cap_delay_lock);
                }
+
+               /*
+                * Make sure too many dirty caps or general
+                * slowness doesn't block mdsc delayed work,
+                * preventing send_renew_caps() from running.
+                */
+               if (jiffies - loop_start >= 5 * HZ)
+                       break;
        }
        spin_unlock(&mdsc->cap_delay_lock);
        doutc(cl, "done\n");
index abe8028d95bf4e3e99091d83cf1784f2b9a249e1..16873d07692f42e96aa76f7042b364a60d8b6cea 100644 (file)
@@ -1138,7 +1138,12 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
                }
 
                idx = 0;
-               left = ret > 0 ? ret : 0;
+               if (ret <= 0)
+                       left = 0;
+               else if (off + ret > i_size)
+                       left = i_size - off;
+               else
+                       left = ret;
                while (left > 0) {
                        size_t plen, copied;
 
@@ -1167,15 +1172,13 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos,
        }
 
        if (ret > 0) {
-               if (off > *ki_pos) {
-                       if (off >= i_size) {
-                               *retry_op = CHECK_EOF;
-                               ret = i_size - *ki_pos;
-                               *ki_pos = i_size;
-                       } else {
-                               ret = off - *ki_pos;
-                               *ki_pos = off;
-                       }
+               if (off >= i_size) {
+                       *retry_op = CHECK_EOF;
+                       ret = i_size - *ki_pos;
+                       *ki_pos = i_size;
+               } else {
+                       ret = off - *ki_pos;
+                       *ki_pos = off;
                }
 
                if (last_objver)
@@ -2126,14 +2129,16 @@ again:
                int statret;
                struct page *page = NULL;
                loff_t i_size;
+               int mask = CEPH_STAT_CAP_SIZE;
                if (retry_op == READ_INLINE) {
                        page = __page_cache_alloc(GFP_KERNEL);
                        if (!page)
                                return -ENOMEM;
+
+                       mask = CEPH_STAT_CAP_INLINE_DATA;
                }
 
-               statret = __ceph_do_getattr(inode, page,
-                                           CEPH_STAT_CAP_INLINE_DATA, !!page);
+               statret = __ceph_do_getattr(inode, page, mask, !!page);
                if (statret < 0) {
                        if (page)
                                __free_page(page);
@@ -2174,7 +2179,7 @@ again:
                /* hit EOF or hole? */
                if (retry_op == CHECK_EOF && iocb->ki_pos < i_size &&
                    ret < len) {
-                       doutc(cl, "hit hole, ppos %lld < size %lld, reading more\n",
+                       doutc(cl, "may hit hole, ppos %lld < size %lld, reading more\n",
                              iocb->ki_pos, i_size);
 
                        read += ret;
index 034a617cb1a5e777d5e254bd3aa81b368c566ed2..a40da006543361c890aa5038a266e0300baaf4ec 100644 (file)
@@ -751,13 +751,28 @@ static void __debugfs_file_removed(struct dentry *dentry)
        if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
                return;
 
-       /* if we hit zero, just wait for all to finish */
-       if (!refcount_dec_and_test(&fsd->active_users)) {
-               wait_for_completion(&fsd->active_users_drained);
+       /* if this was the last reference, we're done */
+       if (refcount_dec_and_test(&fsd->active_users))
                return;
-       }
 
-       /* if we didn't hit zero, try to cancel any we can */
+       /*
+        * If there's still a reference, the code that obtained it can
+        * be in different states:
+        *  - The common case of not using cancellations, or already
+        *    after debugfs_leave_cancellation(), where we just need
+        *    to wait for debugfs_file_put() which signals the completion;
+        *  - inside a cancellation section, i.e. between
+        *    debugfs_enter_cancellation() and debugfs_leave_cancellation(),
+        *    in which case we need to trigger the ->cancel() function,
+        *    and then wait for debugfs_file_put() just like in the
+        *    previous case;
+        *  - before debugfs_enter_cancellation() (but obviously after
+        *    debugfs_file_get()), in which case we may not see the
+        *    cancellation in the list on the first round of the loop,
+        *    but debugfs_enter_cancellation() signals the completion
+        *    after adding it, so this code gets woken up to call the
+        *    ->cancel() function.
+        */
        while (refcount_read(&fsd->active_users)) {
                struct debugfs_cancellation *c;
 
index dfc444dad3298aeb361cc29533278496a81f85da..3b4dbce849f0f268d8b6876f28d90a32e0d9c119 100644 (file)
@@ -246,7 +246,7 @@ struct dlm_lkb {
        int8_t                  lkb_highbast;   /* highest mode bast sent for */
 
        int8_t                  lkb_wait_type;  /* type of reply waiting for */
-       atomic_t                lkb_wait_count;
+       int8_t                  lkb_wait_count;
        int                     lkb_wait_nodeid; /* for debugging */
 
        struct list_head        lkb_statequeue; /* rsb g/c/w list */
index 652c51fbbf7685e0777d61c6142c26350247396e..fd752dd03896348504200202199299b4389eb869 100644 (file)
@@ -1407,7 +1407,6 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype, int to_nodeid)
 {
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
        int error = 0;
-       int wc;
 
        mutex_lock(&ls->ls_waiters_mutex);
 
@@ -1429,17 +1428,20 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype, int to_nodeid)
                        error = -EBUSY;
                        goto out;
                }
-               wc = atomic_inc_return(&lkb->lkb_wait_count);
+               lkb->lkb_wait_count++;
                hold_lkb(lkb);
 
                log_debug(ls, "addwait %x cur %d overlap %d count %d f %x",
-                         lkb->lkb_id, lkb->lkb_wait_type, mstype, wc,
-                         dlm_iflags_val(lkb));
+                         lkb->lkb_id, lkb->lkb_wait_type, mstype,
+                         lkb->lkb_wait_count, dlm_iflags_val(lkb));
                goto out;
        }
 
-       wc = atomic_fetch_inc(&lkb->lkb_wait_count);
-       DLM_ASSERT(!wc, dlm_print_lkb(lkb); printk("wait_count %d\n", wc););
+       DLM_ASSERT(!lkb->lkb_wait_count,
+                  dlm_print_lkb(lkb);
+                  printk("wait_count %d\n", lkb->lkb_wait_count););
+
+       lkb->lkb_wait_count++;
        lkb->lkb_wait_type = mstype;
        lkb->lkb_wait_nodeid = to_nodeid; /* for debugging */
        hold_lkb(lkb);
@@ -1502,7 +1504,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
                log_debug(ls, "remwait %x convert_reply zap overlap_cancel",
                          lkb->lkb_id);
                lkb->lkb_wait_type = 0;
-               atomic_dec(&lkb->lkb_wait_count);
+               lkb->lkb_wait_count--;
                unhold_lkb(lkb);
                goto out_del;
        }
@@ -1529,15 +1531,16 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
        if (overlap_done && lkb->lkb_wait_type) {
                log_error(ls, "remwait error %x reply %d wait_type %d overlap",
                          lkb->lkb_id, mstype, lkb->lkb_wait_type);
-               atomic_dec(&lkb->lkb_wait_count);
+               lkb->lkb_wait_count--;
                unhold_lkb(lkb);
                lkb->lkb_wait_type = 0;
        }
 
-       DLM_ASSERT(atomic_read(&lkb->lkb_wait_count), dlm_print_lkb(lkb););
+       DLM_ASSERT(lkb->lkb_wait_count, dlm_print_lkb(lkb););
 
        clear_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
-       if (atomic_dec_and_test(&lkb->lkb_wait_count))
+       lkb->lkb_wait_count--;
+       if (!lkb->lkb_wait_count)
                list_del_init(&lkb->lkb_wait_reply);
        unhold_lkb(lkb);
        return 0;
@@ -2666,7 +2669,7 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
                        goto out;
 
                /* lock not allowed if there's any op in progress */
-               if (lkb->lkb_wait_type || atomic_read(&lkb->lkb_wait_count))
+               if (lkb->lkb_wait_type || lkb->lkb_wait_count)
                        goto out;
 
                if (is_overlap(lkb))
@@ -2728,7 +2731,7 @@ static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
 
        /* normal unlock not allowed if there's any op in progress */
        if (!(args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) &&
-           (lkb->lkb_wait_type || atomic_read(&lkb->lkb_wait_count)))
+           (lkb->lkb_wait_type || lkb->lkb_wait_count))
                goto out;
 
        /* an lkb may be waiting for an rsb lookup to complete where the
@@ -5011,21 +5014,32 @@ static struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)
        return lkb;
 }
 
-/* Deal with lookups and lkb's marked RESEND from _pre.  We may now be the
-   master or dir-node for r.  Processing the lkb may result in it being placed
-   back on waiters. */
-
-/* We do this after normal locking has been enabled and any saved messages
-   (in requestqueue) have been processed.  We should be confident that at
-   this point we won't get or process a reply to any of these waiting
-   operations.  But, new ops may be coming in on the rsbs/locks here from
-   userspace or remotely. */
-
-/* there may have been an overlap unlock/cancel prior to recovery or after
-   recovery.  if before, the lkb may still have a pos wait_count; if after, the
-   overlap flag would just have been set and nothing new sent.  we can be
-   confident here than any replies to either the initial op or overlap ops
-   prior to recovery have been received. */
+/*
+ * Forced state reset for locks that were in the middle of remote operations
+ * when recovery happened (i.e. lkbs that were on the waiters list, waiting
+ * for a reply from a remote operation.)  The lkbs remaining on the waiters
+ * list need to be reevaluated; some may need resending to a different node
+ * than previously, and some may now need local handling rather than remote.
+ *
+ * First, the lkb state for the voided remote operation is forcibly reset,
+ * equivalent to what remove_from_waiters() would normally do:
+ * . lkb removed from ls_waiters list
+ * . lkb wait_type cleared
+ * . lkb waiters_count cleared
+ * . lkb ref count decremented for each waiters_count (almost always 1,
+ *   but possibly 2 in case of cancel/unlock overlapping, which means
+ *   two remote replies were being expected for the lkb.)
+ *
+ * Second, the lkb is reprocessed like an original operation would be,
+ * by passing it to _request_lock or _convert_lock, which will either
+ * process the lkb operation locally, or send it to a remote node again
+ * and put the lkb back onto the waiters list.
+ *
+ * When reprocessing the lkb, we may find that it's flagged for an overlapping
+ * force-unlock or cancel, either from before recovery began, or after recovery
+ * finished.  If this is the case, the unlock/cancel is done directly, and the
+ * original operation is not initiated again (no _request_lock/_convert_lock.)
+ */
 
 int dlm_recover_waiters_post(struct dlm_ls *ls)
 {
@@ -5040,6 +5054,11 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
                        break;
                }
 
+               /* 
+                * Find an lkb from the waiters list that's been affected by
+                * recovery node changes, and needs to be reprocessed.  Does
+                * hold_lkb(), adding a refcount.
+                */
                lkb = find_resend_waiter(ls);
                if (!lkb)
                        break;
@@ -5048,6 +5067,11 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
                hold_rsb(r);
                lock_rsb(r);
 
+               /*
+                * If the lkb has been flagged for a force unlock or cancel,
+                * then the reprocessing below will be replaced by just doing
+                * the unlock/cancel directly.
+                */
                mstype = lkb->lkb_wait_type;
                oc = test_and_clear_bit(DLM_IFL_OVERLAP_CANCEL_BIT,
                                        &lkb->lkb_iflags);
@@ -5061,22 +5085,40 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
                          r->res_nodeid, lkb->lkb_nodeid, lkb->lkb_wait_nodeid,
                          dlm_dir_nodeid(r), oc, ou);
 
-               /* At this point we assume that we won't get a reply to any
-                  previous op or overlap op on this lock.  First, do a big
-                  remove_from_waiters() for all previous ops. */
+               /*
+                * No reply to the pre-recovery operation will now be received,
+                * so a forced equivalent of remove_from_waiters() is needed to
+                * reset the waiters state that was in place before recovery.
+                */
 
                clear_bit(DLM_IFL_RESEND_BIT, &lkb->lkb_iflags);
+
+               /* Forcibly clear wait_type */
                lkb->lkb_wait_type = 0;
-               /* drop all wait_count references we still
-                * hold a reference for this iteration.
+
+               /*
+                * Forcibly reset wait_count and associated refcount.  The
+                * wait_count will almost always be 1, but in case of an
+                * overlapping unlock/cancel it could be 2: see where
+                * add_to_waiters() finds the lkb is already on the waiters
+                * list and does lkb_wait_count++; hold_lkb().
                 */
-               while (!atomic_dec_and_test(&lkb->lkb_wait_count))
+               while (lkb->lkb_wait_count) {
+                       lkb->lkb_wait_count--;
                        unhold_lkb(lkb);
+               }
 
+               /* Forcibly remove from waiters list */
                mutex_lock(&ls->ls_waiters_mutex);
                list_del_init(&lkb->lkb_wait_reply);
                mutex_unlock(&ls->ls_waiters_mutex);
 
+               /*
+                * The lkb is now clear of all prior waiters state and can be
+                * processed locally, or sent to remote node again, or directly
+                * cancelled/unlocked.
+                */
+
                if (oc || ou) {
                        /* do an unlock or cancel instead of resending */
                        switch (mstype) {
index 695e691b38b318395f241de0a2f28c5e48e30a4f..9f9b68448830ece12fd342e79ef1f2ccf6f9f1ae 100644 (file)
@@ -806,7 +806,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
        struct dlm_lkb *lkb;
        DECLARE_WAITQUEUE(wait, current);
        struct dlm_callback *cb;
-       int rv, copy_lvb = 0;
+       int rv, ret, copy_lvb = 0;
        int old_mode, new_mode;
 
        if (count == sizeof(struct dlm_device_version)) {
@@ -906,9 +906,9 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
                trace_dlm_ast(lkb->lkb_resource->res_ls, lkb);
        }
 
-       rv = copy_result_to_user(lkb->lkb_ua,
-                                test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
-                                cb->flags, cb->mode, copy_lvb, buf, count);
+       ret = copy_result_to_user(lkb->lkb_ua,
+                                 test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
+                                 cb->flags, cb->mode, copy_lvb, buf, count);
 
        kref_put(&cb->ref, dlm_release_callback);
 
@@ -916,7 +916,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
        if (rv == DLM_DEQUEUE_CALLBACK_LAST)
                dlm_put_lkb(lkb);
 
-       return rv;
+       return ret;
 }
 
 static __poll_t device_poll(struct file *file, poll_table *wait)
index 9f9295847a4e6ecfd02fe3662b82e9f80479ada8..077944d3c2c025fa9b74d041f64762ce4c969dcd 100644 (file)
@@ -448,88 +448,34 @@ static void exfat_init_name_entry(struct exfat_dentry *ep,
        }
 }
 
-int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
-               int entry, unsigned int type, unsigned int start_clu,
-               unsigned long long size)
+void exfat_init_dir_entry(struct exfat_entry_set_cache *es,
+               unsigned int type, unsigned int start_clu,
+               unsigned long long size, struct timespec64 *ts)
 {
-       struct super_block *sb = inode->i_sb;
+       struct super_block *sb = es->sb;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct timespec64 ts = current_time(inode);
        struct exfat_dentry *ep;
-       struct buffer_head *bh;
-
-       /*
-        * We cannot use exfat_get_dentry_set here because file ep is not
-        * initialized yet.
-        */
-       ep = exfat_get_dentry(sb, p_dir, entry, &bh);
-       if (!ep)
-               return -EIO;
 
+       ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
        exfat_set_entry_type(ep, type);
-       exfat_set_entry_time(sbi, &ts,
+       exfat_set_entry_time(sbi, ts,
                        &ep->dentry.file.create_tz,
                        &ep->dentry.file.create_time,
                        &ep->dentry.file.create_date,
                        &ep->dentry.file.create_time_cs);
-       exfat_set_entry_time(sbi, &ts,
+       exfat_set_entry_time(sbi, ts,
                        &ep->dentry.file.modify_tz,
                        &ep->dentry.file.modify_time,
                        &ep->dentry.file.modify_date,
                        &ep->dentry.file.modify_time_cs);
-       exfat_set_entry_time(sbi, &ts,
+       exfat_set_entry_time(sbi, ts,
                        &ep->dentry.file.access_tz,
                        &ep->dentry.file.access_time,
                        &ep->dentry.file.access_date,
                        NULL);
 
-       exfat_update_bh(bh, IS_DIRSYNC(inode));
-       brelse(bh);
-
-       ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh);
-       if (!ep)
-               return -EIO;
-
+       ep = exfat_get_dentry_cached(es, ES_IDX_STREAM);
        exfat_init_stream_entry(ep, start_clu, size);
-       exfat_update_bh(bh, IS_DIRSYNC(inode));
-       brelse(bh);
-
-       return 0;
-}
-
-int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
-               int entry)
-{
-       struct super_block *sb = inode->i_sb;
-       int ret = 0;
-       int i, num_entries;
-       u16 chksum;
-       struct exfat_dentry *ep, *fep;
-       struct buffer_head *fbh, *bh;
-
-       fep = exfat_get_dentry(sb, p_dir, entry, &fbh);
-       if (!fep)
-               return -EIO;
-
-       num_entries = fep->dentry.file.num_ext + 1;
-       chksum = exfat_calc_chksum16(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY);
-
-       for (i = 1; i < num_entries; i++) {
-               ep = exfat_get_dentry(sb, p_dir, entry + i, &bh);
-               if (!ep) {
-                       ret = -EIO;
-                       goto release_fbh;
-               }
-               chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum,
-                               CS_DEFAULT);
-               brelse(bh);
-       }
-
-       fep->dentry.file.checksum = cpu_to_le16(chksum);
-       exfat_update_bh(fbh, IS_DIRSYNC(inode));
-release_fbh:
-       brelse(fbh);
-       return ret;
 }
 
 static void exfat_free_benign_secondary_clusters(struct inode *inode,
@@ -551,76 +497,49 @@ static void exfat_free_benign_secondary_clusters(struct inode *inode,
        exfat_free_cluster(inode, &dir);
 }
 
-int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
-               int entry, int num_entries, struct exfat_uni_name *p_uniname)
+void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries,
+               struct exfat_uni_name *p_uniname)
 {
-       struct super_block *sb = inode->i_sb;
        int i;
        unsigned short *uniname = p_uniname->name;
        struct exfat_dentry *ep;
-       struct buffer_head *bh;
-       int sync = IS_DIRSYNC(inode);
-
-       ep = exfat_get_dentry(sb, p_dir, entry, &bh);
-       if (!ep)
-               return -EIO;
 
+       ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
        ep->dentry.file.num_ext = (unsigned char)(num_entries - 1);
-       exfat_update_bh(bh, sync);
-       brelse(bh);
-
-       ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh);
-       if (!ep)
-               return -EIO;
 
+       ep = exfat_get_dentry_cached(es, ES_IDX_STREAM);
        ep->dentry.stream.name_len = p_uniname->name_len;
        ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash);
-       exfat_update_bh(bh, sync);
-       brelse(bh);
-
-       for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) {
-               ep = exfat_get_dentry(sb, p_dir, entry + i, &bh);
-               if (!ep)
-                       return -EIO;
-
-               if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC)
-                       exfat_free_benign_secondary_clusters(inode, ep);
 
+       for (i = ES_IDX_FIRST_FILENAME; i < num_entries; i++) {
+               ep = exfat_get_dentry_cached(es, i);
                exfat_init_name_entry(ep, uniname);
-               exfat_update_bh(bh, sync);
-               brelse(bh);
                uniname += EXFAT_FILE_NAME_LEN;
        }
 
-       exfat_update_dir_chksum(inode, p_dir, entry);
-       return 0;
+       exfat_update_dir_chksum(es);
 }
 
-int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
-               int entry, int order, int num_entries)
+void exfat_remove_entries(struct inode *inode, struct exfat_entry_set_cache *es,
+               int order)
 {
-       struct super_block *sb = inode->i_sb;
        int i;
        struct exfat_dentry *ep;
-       struct buffer_head *bh;
 
-       for (i = order; i < num_entries; i++) {
-               ep = exfat_get_dentry(sb, p_dir, entry + i, &bh);
-               if (!ep)
-                       return -EIO;
+       for (i = order; i < es->num_entries; i++) {
+               ep = exfat_get_dentry_cached(es, i);
 
                if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC)
                        exfat_free_benign_secondary_clusters(inode, ep);
 
                exfat_set_entry_type(ep, TYPE_DELETED);
-               exfat_update_bh(bh, IS_DIRSYNC(inode));
-               brelse(bh);
        }
 
-       return 0;
+       if (order < es->num_entries)
+               es->modified = true;
 }
 
-void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es)
+void exfat_update_dir_chksum(struct exfat_entry_set_cache *es)
 {
        int chksum_type = CS_DIR_ENTRY, i;
        unsigned short chksum = 0;
@@ -775,7 +694,6 @@ struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
 }
 
 enum exfat_validate_dentry_mode {
-       ES_MODE_STARTED,
        ES_MODE_GET_FILE_ENTRY,
        ES_MODE_GET_STRM_ENTRY,
        ES_MODE_GET_NAME_ENTRY,
@@ -790,11 +708,6 @@ static bool exfat_validate_entry(unsigned int type,
                return false;
 
        switch (*mode) {
-       case ES_MODE_STARTED:
-               if  (type != TYPE_FILE && type != TYPE_DIR)
-                       return false;
-               *mode = ES_MODE_GET_FILE_ENTRY;
-               break;
        case ES_MODE_GET_FILE_ENTRY:
                if (type != TYPE_STREAM)
                        return false;
@@ -834,7 +747,7 @@ struct exfat_dentry *exfat_get_dentry_cached(
 }
 
 /*
- * Returns a set of dentries for a file or dir.
+ * Returns a set of dentries.
  *
  * Note It provides a direct pointer to bh->data via exfat_get_dentry_cached().
  * User should call exfat_get_dentry_set() after setting 'modified' to apply
@@ -842,22 +755,24 @@ struct exfat_dentry *exfat_get_dentry_cached(
  *
  * in:
  *   sb+p_dir+entry: indicates a file/dir
- *   type:  specifies how many dentries should be included.
+ *   num_entries: specifies how many dentries should be included.
+ *                It will be set to es->num_entries if it is not 0.
+ *                If num_entries is 0, es->num_entries will be obtained
+ *                from the first dentry.
+ * out:
+ *   es: pointer of entry set on success.
  * return:
- *   pointer of entry set on success,
- *   NULL on failure.
+ *   0 on success
+ *   -error code on failure
  */
-int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
+static int __exfat_get_dentry_set(struct exfat_entry_set_cache *es,
                struct super_block *sb, struct exfat_chain *p_dir, int entry,
-               unsigned int type)
+               unsigned int num_entries)
 {
        int ret, i, num_bh;
        unsigned int off;
        sector_t sec;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct exfat_dentry *ep;
-       int num_entries;
-       enum exfat_validate_dentry_mode mode = ES_MODE_STARTED;
        struct buffer_head *bh;
 
        if (p_dir->dir == DIR_DELETED) {
@@ -880,12 +795,18 @@ int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
                return -EIO;
        es->bh[es->num_bh++] = bh;
 
-       ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
-       if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
-               goto put_es;
+       if (num_entries == ES_ALL_ENTRIES) {
+               struct exfat_dentry *ep;
+
+               ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
+               if (ep->type != EXFAT_FILE) {
+                       brelse(bh);
+                       return -EIO;
+               }
+
+               num_entries = ep->dentry.file.num_ext + 1;
+       }
 
-       num_entries = type == ES_ALL_ENTRIES ?
-               ep->dentry.file.num_ext + 1 : type;
        es->num_entries = num_entries;
 
        num_bh = EXFAT_B_TO_BLK_ROUND_UP(off + num_entries * DENTRY_SIZE, sb);
@@ -918,8 +839,27 @@ int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
                es->bh[es->num_bh++] = bh;
        }
 
+       return 0;
+
+put_es:
+       exfat_put_dentry_set(es, false);
+       return -EIO;
+}
+
+int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
+               struct super_block *sb, struct exfat_chain *p_dir,
+               int entry, unsigned int num_entries)
+{
+       int ret, i;
+       struct exfat_dentry *ep;
+       enum exfat_validate_dentry_mode mode = ES_MODE_GET_FILE_ENTRY;
+
+       ret = __exfat_get_dentry_set(es, sb, p_dir, entry, num_entries);
+       if (ret < 0)
+               return ret;
+
        /* validate cached dentries */
-       for (i = ES_IDX_STREAM; i < num_entries; i++) {
+       for (i = ES_IDX_STREAM; i < es->num_entries; i++) {
                ep = exfat_get_dentry_cached(es, i);
                if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
                        goto put_es;
@@ -931,6 +871,85 @@ put_es:
        return -EIO;
 }
 
+static int exfat_validate_empty_dentry_set(struct exfat_entry_set_cache *es)
+{
+       struct exfat_dentry *ep;
+       struct buffer_head *bh;
+       int i, off;
+       bool unused_hit = false;
+
+       /*
+        * ONLY UNUSED OR DELETED DENTRIES ARE ALLOWED:
+        * Although it violates the specification for a deleted entry to
+        * follow an unused entry, some exFAT implementations could work
+        * like this. Therefore, to improve compatibility, let's allow it.
+        */
+       for (i = 0; i < es->num_entries; i++) {
+               ep = exfat_get_dentry_cached(es, i);
+               if (ep->type == EXFAT_UNUSED) {
+                       unused_hit = true;
+               } else if (!IS_EXFAT_DELETED(ep->type)) {
+                       if (unused_hit)
+                               goto err_used_follow_unused;
+                       i++;
+                       goto count_skip_entries;
+               }
+       }
+
+       return 0;
+
+err_used_follow_unused:
+       off = es->start_off + (i << DENTRY_SIZE_BITS);
+       bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)];
+
+       exfat_fs_error(es->sb,
+               "in sector %lld, dentry %d should be unused, but 0x%x",
+               bh->b_blocknr, off >> DENTRY_SIZE_BITS, ep->type);
+
+       return -EIO;
+
+count_skip_entries:
+       es->num_entries = EXFAT_B_TO_DEN(EXFAT_BLK_TO_B(es->num_bh, es->sb) - es->start_off);
+       for (; i < es->num_entries; i++) {
+               ep = exfat_get_dentry_cached(es, i);
+               if (IS_EXFAT_DELETED(ep->type))
+                       break;
+       }
+
+       return i;
+}
+
+/*
+ * Get an empty dentry set.
+ *
+ * in:
+ *   sb+p_dir+entry: indicates the empty dentry location
+ *   num_entries: specifies how many empty dentries should be included.
+ * out:
+ *   es: pointer of empty dentry set on success.
+ * return:
+ *   0  : on success
+ *   >0 : the dentries are not empty, the return value is the number of
+ *        dentries to be skipped for the next lookup.
+ *   <0 : on failure
+ */
+int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es,
+               struct super_block *sb, struct exfat_chain *p_dir,
+               int entry, unsigned int num_entries)
+{
+       int ret;
+
+       ret = __exfat_get_dentry_set(es, sb, p_dir, entry, num_entries);
+       if (ret < 0)
+               return ret;
+
+       ret = exfat_validate_empty_dentry_set(es);
+       if (ret)
+               exfat_put_dentry_set(es, false);
+
+       return ret;
+}
+
 static inline void exfat_reset_empty_hint(struct exfat_hint_femp *hint_femp)
 {
        hint_femp->eidx = EXFAT_HINT_NONE;
@@ -1187,27 +1206,6 @@ found:
        return dentry - num_ext;
 }
 
-int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir,
-               int entry, struct exfat_dentry *ep)
-{
-       int i, count = 0;
-       unsigned int type;
-       struct exfat_dentry *ext_ep;
-       struct buffer_head *bh;
-
-       for (i = 0, entry++; i < ep->dentry.file.num_ext; i++, entry++) {
-               ext_ep = exfat_get_dentry(sb, p_dir, entry, &bh);
-               if (!ext_ep)
-                       return -EIO;
-
-               type = exfat_get_entry_type(ext_ep);
-               brelse(bh);
-               if (type & TYPE_CRITICAL_SEC || type & TYPE_BENIGN_SEC)
-                       count++;
-       }
-       return count;
-}
-
 int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
 {
        int i, count = 0;
index 361595433480c46562765ad4d5c886a071005c25..ecc5db952deb0ebf703ac7fce10a9a120449e2ee 100644 (file)
@@ -431,8 +431,6 @@ int exfat_ent_get(struct super_block *sb, unsigned int loc,
                unsigned int *content);
 int exfat_ent_set(struct super_block *sb, unsigned int loc,
                unsigned int content);
-int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir,
-               int entry, struct exfat_dentry *p_entry);
 int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
                unsigned int len);
 int exfat_zeroed_cluster(struct inode *dir, unsigned int clu);
@@ -480,16 +478,14 @@ int exfat_get_cluster(struct inode *inode, unsigned int cluster,
 extern const struct inode_operations exfat_dir_inode_operations;
 extern const struct file_operations exfat_dir_operations;
 unsigned int exfat_get_entry_type(struct exfat_dentry *p_entry);
-int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
-               int entry, unsigned int type, unsigned int start_clu,
-               unsigned long long size);
-int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
-               int entry, int num_entries, struct exfat_uni_name *p_uniname);
-int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
-               int entry, int order, int num_entries);
-int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
-               int entry);
-void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
+void exfat_init_dir_entry(struct exfat_entry_set_cache *es,
+               unsigned int type, unsigned int start_clu,
+               unsigned long long size, struct timespec64 *ts);
+void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries,
+               struct exfat_uni_name *p_uniname);
+void exfat_remove_entries(struct inode *inode, struct exfat_entry_set_cache *es,
+               int order);
+void exfat_update_dir_chksum(struct exfat_entry_set_cache *es);
 int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
 int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
                struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
@@ -501,7 +497,10 @@ struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
                int num);
 int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
                struct super_block *sb, struct exfat_chain *p_dir, int entry,
-               unsigned int type);
+               unsigned int num_entries);
+int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es,
+               struct super_block *sb, struct exfat_chain *p_dir, int entry,
+               unsigned int num_entries);
 int exfat_put_dentry_set(struct exfat_entry_set_cache *es, int sync);
 int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir);
 
index 0687f952956c34b6d85e785ee13f231d49679e64..dd894e558c9144a2eed57c90822eca166f127c9b 100644 (file)
@@ -94,7 +94,7 @@ int __exfat_write_inode(struct inode *inode, int sync)
                ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
        }
 
-       exfat_update_dir_chksum_with_entry_set(&es);
+       exfat_update_dir_chksum(&es);
        return exfat_put_dentry_set(&es, sync);
 }
 
index 9c549fd11fc847055a35f7a5872dc044b1576796..631ad9e8e32a913037e468a49585b0dc4006b66f 100644 (file)
@@ -204,21 +204,16 @@ const struct dentry_operations exfat_utf8_dentry_ops = {
        .d_compare      = exfat_utf8_d_cmp,
 };
 
-/* used only in search empty_slot() */
-#define CNT_UNUSED_NOHIT        (-1)
-#define CNT_UNUSED_HIT          (-2)
 /* search EMPTY CONTINUOUS "num_entries" entries */
 static int exfat_search_empty_slot(struct super_block *sb,
                struct exfat_hint_femp *hint_femp, struct exfat_chain *p_dir,
-               int num_entries)
+               int num_entries, struct exfat_entry_set_cache *es)
 {
-       int i, dentry, num_empty = 0;
+       int i, dentry, ret;
        int dentries_per_clu;
-       unsigned int type;
        struct exfat_chain clu;
-       struct exfat_dentry *ep;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct buffer_head *bh;
+       int total_entries = EXFAT_CLU_TO_DEN(p_dir->size, sbi);
 
        dentries_per_clu = sbi->dentries_per_clu;
 
@@ -231,7 +226,7 @@ static int exfat_search_empty_slot(struct super_block *sb,
                 * Otherwise, and if "dentry + hint_famp->count" is also equal
                 * to "p_dir->size * dentries_per_clu", it means ENOSPC.
                 */
-               if (dentry + hint_femp->count == p_dir->size * dentries_per_clu &&
+               if (dentry + hint_femp->count == total_entries &&
                    num_entries > hint_femp->count)
                        return -ENOSPC;
 
@@ -242,69 +237,41 @@ static int exfat_search_empty_slot(struct super_block *sb,
                dentry = 0;
        }
 
-       while (clu.dir != EXFAT_EOF_CLUSTER) {
+       while (dentry + num_entries < total_entries &&
+              clu.dir != EXFAT_EOF_CLUSTER) {
                i = dentry & (dentries_per_clu - 1);
 
-               for (; i < dentries_per_clu; i++, dentry++) {
-                       ep = exfat_get_dentry(sb, &clu, i, &bh);
-                       if (!ep)
-                               return -EIO;
-                       type = exfat_get_entry_type(ep);
-                       brelse(bh);
-
-                       if (type == TYPE_UNUSED || type == TYPE_DELETED) {
-                               num_empty++;
-                               if (hint_femp->eidx == EXFAT_HINT_NONE) {
-                                       hint_femp->eidx = dentry;
-                                       hint_femp->count = CNT_UNUSED_NOHIT;
-                                       exfat_chain_set(&hint_femp->cur,
-                                               clu.dir, clu.size, clu.flags);
-                               }
-
-                               if (type == TYPE_UNUSED &&
-                                   hint_femp->count != CNT_UNUSED_HIT)
-                                       hint_femp->count = CNT_UNUSED_HIT;
+               ret = exfat_get_empty_dentry_set(es, sb, &clu, i, num_entries);
+               if (ret < 0)
+                       return ret;
+               else if (ret == 0)
+                       return dentry;
+
+               dentry += ret;
+               i += ret;
+
+               while (i >= dentries_per_clu) {
+                       if (clu.flags == ALLOC_NO_FAT_CHAIN) {
+                               if (--clu.size > 0)
+                                       clu.dir++;
+                               else
+                                       clu.dir = EXFAT_EOF_CLUSTER;
                        } else {
-                               if (hint_femp->eidx != EXFAT_HINT_NONE &&
-                                   hint_femp->count == CNT_UNUSED_HIT) {
-                                       /* unused empty group means
-                                        * an empty group which includes
-                                        * unused dentry
-                                        */
-                                       exfat_fs_error(sb,
-                                               "found bogus dentry(%d) beyond unused empty group(%d) (start_clu : %u, cur_clu : %u)",
-                                               dentry, hint_femp->eidx,
-                                               p_dir->dir, clu.dir);
+                               if (exfat_get_next_cluster(sb, &clu.dir))
                                        return -EIO;
-                               }
-
-                               num_empty = 0;
-                               hint_femp->eidx = EXFAT_HINT_NONE;
                        }
 
-                       if (num_empty >= num_entries) {
-                               /* found and invalidate hint_femp */
-                               hint_femp->eidx = EXFAT_HINT_NONE;
-                               return (dentry - (num_entries - 1));
-                       }
-               }
-
-               if (clu.flags == ALLOC_NO_FAT_CHAIN) {
-                       if (--clu.size > 0)
-                               clu.dir++;
-                       else
-                               clu.dir = EXFAT_EOF_CLUSTER;
-               } else {
-                       if (exfat_get_next_cluster(sb, &clu.dir))
-                               return -EIO;
+                       i -= dentries_per_clu;
                }
        }
 
-       hint_femp->eidx = p_dir->size * dentries_per_clu - num_empty;
-       hint_femp->count = num_empty;
-       if (num_empty == 0)
+       hint_femp->eidx = dentry;
+       hint_femp->count = 0;
+       if (dentry == total_entries || clu.dir == EXFAT_EOF_CLUSTER)
                exfat_chain_set(&hint_femp->cur, EXFAT_EOF_CLUSTER, 0,
                                clu.flags);
+       else
+               hint_femp->cur = clu;
 
        return -ENOSPC;
 }
@@ -325,7 +292,8 @@ static int exfat_check_max_dentries(struct inode *inode)
  * if there isn't any empty slot, expand cluster chain.
  */
 static int exfat_find_empty_entry(struct inode *inode,
-               struct exfat_chain *p_dir, int num_entries)
+               struct exfat_chain *p_dir, int num_entries,
+               struct exfat_entry_set_cache *es)
 {
        int dentry;
        unsigned int ret, last_clu;
@@ -344,7 +312,7 @@ static int exfat_find_empty_entry(struct inode *inode,
        }
 
        while ((dentry = exfat_search_empty_slot(sb, &hint_femp, p_dir,
-                                       num_entries)) < 0) {
+                                       num_entries, es)) < 0) {
                if (dentry == -EIO)
                        break;
 
@@ -499,6 +467,8 @@ static int exfat_add_entry(struct inode *inode, const char *path,
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
        struct exfat_uni_name uniname;
        struct exfat_chain clu;
+       struct timespec64 ts = current_time(inode);
+       struct exfat_entry_set_cache es;
        int clu_size = 0;
        unsigned int start_clu = EXFAT_FREE_CLUSTER;
 
@@ -513,7 +483,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
        }
 
        /* exfat_find_empty_entry must be called before alloc_cluster() */
-       dentry = exfat_find_empty_entry(inode, p_dir, num_entries);
+       dentry = exfat_find_empty_entry(inode, p_dir, num_entries, &es);
        if (dentry < 0) {
                ret = dentry; /* -EIO or -ENOSPC */
                goto out;
@@ -521,8 +491,10 @@ static int exfat_add_entry(struct inode *inode, const char *path,
 
        if (type == TYPE_DIR && !sbi->options.zero_size_dir) {
                ret = exfat_alloc_new_dir(inode, &clu);
-               if (ret)
+               if (ret) {
+                       exfat_put_dentry_set(&es, false);
                        goto out;
+               }
                start_clu = clu.dir;
                clu_size = sbi->cluster_size;
        }
@@ -531,12 +503,10 @@ static int exfat_add_entry(struct inode *inode, const char *path,
        /* fill the dos name directory entry information of the created file.
         * the first cluster is not determined yet. (0)
         */
-       ret = exfat_init_dir_entry(inode, p_dir, dentry, type,
-               start_clu, clu_size);
-       if (ret)
-               goto out;
+       exfat_init_dir_entry(&es, type, start_clu, clu_size, &ts);
+       exfat_init_ext_entry(&es, num_entries, &uniname);
 
-       ret = exfat_init_ext_entry(inode, p_dir, dentry, num_entries, &uniname);
+       ret = exfat_put_dentry_set(&es, IS_DIRSYNC(inode));
        if (ret)
                goto out;
 
@@ -577,6 +547,7 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
        struct exfat_dir_entry info;
        loff_t i_pos;
        int err;
+       loff_t size = i_size_read(dir);
 
        mutex_lock(&EXFAT_SB(sb)->s_lock);
        exfat_set_volume_dirty(sb);
@@ -587,7 +558,7 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
 
        inode_inc_iversion(dir);
        inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
-       if (IS_DIRSYNC(dir))
+       if (IS_DIRSYNC(dir) && size != i_size_read(dir))
                exfat_sync_inode(dir);
        else
                mark_inode_dirty(dir);
@@ -795,12 +766,11 @@ unlock:
 static int exfat_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct exfat_chain cdir;
-       struct exfat_dentry *ep;
        struct super_block *sb = dir->i_sb;
        struct inode *inode = dentry->d_inode;
        struct exfat_inode_info *ei = EXFAT_I(inode);
-       struct buffer_head *bh;
-       int num_entries, entry, err = 0;
+       struct exfat_entry_set_cache es;
+       int entry, err = 0;
 
        mutex_lock(&EXFAT_SB(sb)->s_lock);
        exfat_chain_dup(&cdir, &ei->dir);
@@ -811,26 +781,20 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
                goto unlock;
        }
 
-       ep = exfat_get_dentry(sb, &cdir, entry, &bh);
-       if (!ep) {
-               err = -EIO;
-               goto unlock;
-       }
-       num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep);
-       if (num_entries < 0) {
+       err = exfat_get_dentry_set(&es, sb, &cdir, entry, ES_ALL_ENTRIES);
+       if (err) {
                err = -EIO;
-               brelse(bh);
                goto unlock;
        }
-       num_entries++;
-       brelse(bh);
 
        exfat_set_volume_dirty(sb);
+
        /* update the directory entry */
-       if (exfat_remove_entries(dir, &cdir, entry, 0, num_entries)) {
-               err = -EIO;
+       exfat_remove_entries(inode, &es, ES_IDX_FILE);
+
+       err = exfat_put_dentry_set(&es, IS_DIRSYNC(inode));
+       if (err)
                goto unlock;
-       }
 
        /* This doesn't modify ei */
        ei->dir.dir = DIR_DELETED;
@@ -838,10 +802,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
        inode_inc_iversion(dir);
        simple_inode_init_ts(dir);
        exfat_truncate_inode_atime(dir);
-       if (IS_DIRSYNC(dir))
-               exfat_sync_inode(dir);
-       else
-               mark_inode_dirty(dir);
+       mark_inode_dirty(dir);
 
        clear_nlink(inode);
        simple_inode_init_ts(inode);
@@ -862,6 +823,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
        struct exfat_chain cdir;
        loff_t i_pos;
        int err;
+       loff_t size = i_size_read(dir);
 
        mutex_lock(&EXFAT_SB(sb)->s_lock);
        exfat_set_volume_dirty(sb);
@@ -872,7 +834,7 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
 
        inode_inc_iversion(dir);
        inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
-       if (IS_DIRSYNC(dir))
+       if (IS_DIRSYNC(dir) && size != i_size_read(dir))
                exfat_sync_inode(dir);
        else
                mark_inode_dirty(dir);
@@ -946,13 +908,12 @@ static int exfat_check_dir_empty(struct super_block *sb,
 static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = dentry->d_inode;
-       struct exfat_dentry *ep;
        struct exfat_chain cdir, clu_to_free;
        struct super_block *sb = inode->i_sb;
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
        struct exfat_inode_info *ei = EXFAT_I(inode);
-       struct buffer_head *bh;
-       int num_entries, entry, err;
+       struct exfat_entry_set_cache es;
+       int entry, err;
 
        mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
 
@@ -976,27 +937,20 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
                goto unlock;
        }
 
-       ep = exfat_get_dentry(sb, &cdir, entry, &bh);
-       if (!ep) {
-               err = -EIO;
-               goto unlock;
-       }
-
-       num_entries = exfat_count_ext_entries(sb, &cdir, entry, ep);
-       if (num_entries < 0) {
+       err = exfat_get_dentry_set(&es, sb, &cdir, entry, ES_ALL_ENTRIES);
+       if (err) {
                err = -EIO;
-               brelse(bh);
                goto unlock;
        }
-       num_entries++;
-       brelse(bh);
 
        exfat_set_volume_dirty(sb);
-       err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries);
-       if (err) {
-               exfat_err(sb, "failed to exfat_remove_entries : err(%d)", err);
+
+       exfat_remove_entries(inode, &es, ES_IDX_FILE);
+
+       err = exfat_put_dentry_set(&es, IS_DIRSYNC(dir));
+       if (err)
                goto unlock;
-       }
+
        ei->dir.dir = DIR_DELETED;
 
        inode_inc_iversion(dir);
@@ -1022,67 +976,52 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
                int oldentry, struct exfat_uni_name *p_uniname,
                struct exfat_inode_info *ei)
 {
-       int ret, num_old_entries, num_new_entries;
+       int ret, num_new_entries;
        struct exfat_dentry *epold, *epnew;
        struct super_block *sb = inode->i_sb;
-       struct buffer_head *new_bh, *old_bh;
+       struct exfat_entry_set_cache old_es, new_es;
        int sync = IS_DIRSYNC(inode);
 
-       epold = exfat_get_dentry(sb, p_dir, oldentry, &old_bh);
-       if (!epold)
-               return -EIO;
-
-       num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, epold);
-       if (num_old_entries < 0)
-               return -EIO;
-       num_old_entries++;
-
        num_new_entries = exfat_calc_num_entries(p_uniname);
        if (num_new_entries < 0)
                return num_new_entries;
 
-       if (num_old_entries < num_new_entries) {
-               int newentry;
+       ret = exfat_get_dentry_set(&old_es, sb, p_dir, oldentry, ES_ALL_ENTRIES);
+       if (ret) {
+               ret = -EIO;
+               return ret;
+       }
 
-               newentry =
-                       exfat_find_empty_entry(inode, p_dir, num_new_entries);
-               if (newentry < 0)
-                       return newentry; /* -EIO or -ENOSPC */
+       epold = exfat_get_dentry_cached(&old_es, ES_IDX_FILE);
 
-               epnew = exfat_get_dentry(sb, p_dir, newentry, &new_bh);
-               if (!epnew)
-                       return -EIO;
+       if (old_es.num_entries < num_new_entries) {
+               int newentry;
 
+               newentry = exfat_find_empty_entry(inode, p_dir, num_new_entries,
+                               &new_es);
+               if (newentry < 0) {
+                       ret = newentry; /* -EIO or -ENOSPC */
+                       goto put_old_es;
+               }
+
+               epnew = exfat_get_dentry_cached(&new_es, ES_IDX_FILE);
                *epnew = *epold;
                if (exfat_get_entry_type(epnew) == TYPE_FILE) {
                        epnew->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
                        ei->attr |= EXFAT_ATTR_ARCHIVE;
                }
-               exfat_update_bh(new_bh, sync);
-               brelse(old_bh);
-               brelse(new_bh);
-
-               epold = exfat_get_dentry(sb, p_dir, oldentry + 1, &old_bh);
-               if (!epold)
-                       return -EIO;
-               epnew = exfat_get_dentry(sb, p_dir, newentry + 1, &new_bh);
-               if (!epnew) {
-                       brelse(old_bh);
-                       return -EIO;
-               }
 
+               epold = exfat_get_dentry_cached(&old_es, ES_IDX_STREAM);
+               epnew = exfat_get_dentry_cached(&new_es, ES_IDX_STREAM);
                *epnew = *epold;
-               exfat_update_bh(new_bh, sync);
-               brelse(old_bh);
-               brelse(new_bh);
 
-               ret = exfat_init_ext_entry(inode, p_dir, newentry,
-                       num_new_entries, p_uniname);
+               exfat_init_ext_entry(&new_es, num_new_entries, p_uniname);
+
+               ret = exfat_put_dentry_set(&new_es, sync);
                if (ret)
-                       return ret;
+                       goto put_old_es;
 
-               exfat_remove_entries(inode, p_dir, oldentry, 0,
-                       num_old_entries);
+               exfat_remove_entries(inode, &old_es, ES_IDX_FILE);
                ei->dir = *p_dir;
                ei->entry = newentry;
        } else {
@@ -1090,85 +1029,72 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
                        epold->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
                        ei->attr |= EXFAT_ATTR_ARCHIVE;
                }
-               exfat_update_bh(old_bh, sync);
-               brelse(old_bh);
-               ret = exfat_init_ext_entry(inode, p_dir, oldentry,
-                       num_new_entries, p_uniname);
-               if (ret)
-                       return ret;
 
-               exfat_remove_entries(inode, p_dir, oldentry, num_new_entries,
-                       num_old_entries);
+               exfat_remove_entries(inode, &old_es, ES_IDX_FIRST_FILENAME + 1);
+               exfat_init_ext_entry(&old_es, num_new_entries, p_uniname);
        }
-       return 0;
+       return exfat_put_dentry_set(&old_es, sync);
+
+put_old_es:
+       exfat_put_dentry_set(&old_es, false);
+       return ret;
 }
 
 static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
                int oldentry, struct exfat_chain *p_newdir,
                struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei)
 {
-       int ret, newentry, num_new_entries, num_old_entries;
+       int ret, newentry, num_new_entries;
        struct exfat_dentry *epmov, *epnew;
        struct super_block *sb = inode->i_sb;
-       struct buffer_head *mov_bh, *new_bh;
-
-       epmov = exfat_get_dentry(sb, p_olddir, oldentry, &mov_bh);
-       if (!epmov)
-               return -EIO;
-
-       num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry,
-               epmov);
-       if (num_old_entries < 0)
-               return -EIO;
-       num_old_entries++;
+       struct exfat_entry_set_cache mov_es, new_es;
 
        num_new_entries = exfat_calc_num_entries(p_uniname);
        if (num_new_entries < 0)
                return num_new_entries;
 
-       newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries);
-       if (newentry < 0)
-               return newentry; /* -EIO or -ENOSPC */
-
-       epnew = exfat_get_dentry(sb, p_newdir, newentry, &new_bh);
-       if (!epnew)
+       ret = exfat_get_dentry_set(&mov_es, sb, p_olddir, oldentry,
+                       ES_ALL_ENTRIES);
+       if (ret)
                return -EIO;
 
+       newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries,
+                       &new_es);
+       if (newentry < 0) {
+               ret = newentry; /* -EIO or -ENOSPC */
+               goto put_mov_es;
+       }
+
+       epmov = exfat_get_dentry_cached(&mov_es, ES_IDX_FILE);
+       epnew = exfat_get_dentry_cached(&new_es, ES_IDX_FILE);
        *epnew = *epmov;
        if (exfat_get_entry_type(epnew) == TYPE_FILE) {
                epnew->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
                ei->attr |= EXFAT_ATTR_ARCHIVE;
        }
-       exfat_update_bh(new_bh, IS_DIRSYNC(inode));
-       brelse(mov_bh);
-       brelse(new_bh);
-
-       epmov = exfat_get_dentry(sb, p_olddir, oldentry + 1, &mov_bh);
-       if (!epmov)
-               return -EIO;
-       epnew = exfat_get_dentry(sb, p_newdir, newentry + 1, &new_bh);
-       if (!epnew) {
-               brelse(mov_bh);
-               return -EIO;
-       }
 
+       epmov = exfat_get_dentry_cached(&mov_es, ES_IDX_STREAM);
+       epnew = exfat_get_dentry_cached(&new_es, ES_IDX_STREAM);
        *epnew = *epmov;
-       exfat_update_bh(new_bh, IS_DIRSYNC(inode));
-       brelse(mov_bh);
-       brelse(new_bh);
-
-       ret = exfat_init_ext_entry(inode, p_newdir, newentry, num_new_entries,
-               p_uniname);
-       if (ret)
-               return ret;
 
-       exfat_remove_entries(inode, p_olddir, oldentry, 0, num_old_entries);
+       exfat_init_ext_entry(&new_es, num_new_entries, p_uniname);
+       exfat_remove_entries(inode, &mov_es, ES_IDX_FILE);
 
        exfat_chain_set(&ei->dir, p_newdir->dir, p_newdir->size,
                p_newdir->flags);
 
        ei->entry = newentry;
-       return 0;
+
+       ret = exfat_put_dentry_set(&new_es, IS_DIRSYNC(inode));
+       if (ret)
+               goto put_mov_es;
+
+       return exfat_put_dentry_set(&mov_es, IS_DIRSYNC(inode));
+
+put_mov_es:
+       exfat_put_dentry_set(&mov_es, false);
+
+       return ret;
 }
 
 /* rename or move a old file into a new file */
@@ -1186,7 +1112,6 @@ static int __exfat_rename(struct inode *old_parent_inode,
        struct exfat_sb_info *sbi = EXFAT_SB(sb);
        const unsigned char *new_path = new_dentry->d_name.name;
        struct inode *new_inode = new_dentry->d_inode;
-       int num_entries;
        struct exfat_inode_info *new_ei = NULL;
        unsigned int new_entry_type = TYPE_UNUSED;
        int new_entry = 0;
@@ -1257,25 +1182,21 @@ static int __exfat_rename(struct inode *old_parent_inode,
                                &newdir, &uni_name, ei);
 
        if (!ret && new_inode) {
+               struct exfat_entry_set_cache es;
+
                /* delete entries of new_dir */
-               ep = exfat_get_dentry(sb, p_dir, new_entry, &new_bh);
-               if (!ep) {
+               ret = exfat_get_dentry_set(&es, sb, p_dir, new_entry,
+                               ES_ALL_ENTRIES);
+               if (ret) {
                        ret = -EIO;
                        goto del_out;
                }
 
-               num_entries = exfat_count_ext_entries(sb, p_dir, new_entry, ep);
-               if (num_entries < 0) {
-                       ret = -EIO;
-                       goto del_out;
-               }
-               brelse(new_bh);
+               exfat_remove_entries(new_inode, &es, ES_IDX_FILE);
 
-               if (exfat_remove_entries(new_inode, p_dir, new_entry, 0,
-                               num_entries + 1)) {
-                       ret = -EIO;
+               ret = exfat_put_dentry_set(&es, IS_DIRSYNC(new_inode));
+               if (ret)
                        goto del_out;
-               }
 
                /* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
                if (new_entry_type == TYPE_DIR &&
@@ -1317,6 +1238,7 @@ static int exfat_rename(struct mnt_idmap *idmap,
        struct super_block *sb = old_dir->i_sb;
        loff_t i_pos;
        int err;
+       loff_t size = i_size_read(new_dir);
 
        /*
         * The VFS already checks for existence, so for local filesystems
@@ -1338,7 +1260,7 @@ static int exfat_rename(struct mnt_idmap *idmap,
        simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
        EXFAT_I(new_dir)->i_crtime = current_time(new_dir);
        exfat_truncate_inode_atime(new_dir);
-       if (IS_DIRSYNC(new_dir))
+       if (IS_DIRSYNC(new_dir) && size != i_size_read(new_dir))
                exfat_sync_inode(new_dir);
        else
                mark_inode_dirty(new_dir);
@@ -1359,9 +1281,7 @@ static int exfat_rename(struct mnt_idmap *idmap,
        }
 
        inode_inc_iversion(old_dir);
-       if (IS_DIRSYNC(old_dir))
-               exfat_sync_inode(old_dir);
-       else
+       if (new_dir != old_dir)
                mark_inode_dirty(old_dir);
 
        if (new_inode) {
index b0597a539fc54842922714c74f893452296164e2..eac698b8dd3877a1a00cedd9d6f17d11adb199ca 100644 (file)
@@ -154,49 +154,47 @@ static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
        if (unlikely(f2fs_cp_error(sbi)))
                return exist;
 
-       if (exist && type == DATA_GENERIC_ENHANCE_UPDATE) {
-               f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d",
-                        blkaddr, exist);
-               set_sbi_flag(sbi, SBI_NEED_FSCK);
-               return exist;
-       }
+       if ((exist && type == DATA_GENERIC_ENHANCE_UPDATE) ||
+               (!exist && type == DATA_GENERIC_ENHANCE))
+               goto out_err;
+       if (!exist && type != DATA_GENERIC_ENHANCE_UPDATE)
+               goto out_handle;
+       return exist;
 
-       if (!exist && type == DATA_GENERIC_ENHANCE) {
-               f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d",
-                        blkaddr, exist);
-               set_sbi_flag(sbi, SBI_NEED_FSCK);
-               dump_stack();
-       }
+out_err:
+       f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d",
+                blkaddr, exist);
+       set_sbi_flag(sbi, SBI_NEED_FSCK);
+       dump_stack();
+out_handle:
+       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
        return exist;
 }
 
-bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+static bool __f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type)
 {
-       if (time_to_inject(sbi, FAULT_BLKADDR))
-               return false;
-
        switch (type) {
        case META_NAT:
                break;
        case META_SIT:
                if (unlikely(blkaddr >= SIT_BLK_CNT(sbi)))
-                       return false;
+                       goto err;
                break;
        case META_SSA:
                if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) ||
                        blkaddr < SM_I(sbi)->ssa_blkaddr))
-                       return false;
+                       goto err;
                break;
        case META_CP:
                if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr ||
                        blkaddr < __start_cp_addr(sbi)))
-                       return false;
+                       goto err;
                break;
        case META_POR:
                if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
                        blkaddr < MAIN_BLKADDR(sbi)))
-                       return false;
+                       goto err;
                break;
        case DATA_GENERIC:
        case DATA_GENERIC_ENHANCE:
@@ -213,7 +211,7 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                  blkaddr);
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        dump_stack();
-                       return false;
+                       goto err;
                } else {
                        return __is_bitmap_valid(sbi, blkaddr, type);
                }
@@ -221,13 +219,30 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
        case META_GENERIC:
                if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
                        blkaddr >= MAIN_BLKADDR(sbi)))
-                       return false;
+                       goto err;
                break;
        default:
                BUG();
        }
 
        return true;
+err:
+       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
+       return false;
+}
+
+bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+                                       block_t blkaddr, int type)
+{
+       if (time_to_inject(sbi, FAULT_BLKADDR_VALIDITY))
+               return false;
+       return __f2fs_is_valid_blkaddr(sbi, blkaddr, type);
+}
+
+bool f2fs_is_valid_blkaddr_raw(struct f2fs_sb_info *sbi,
+                                       block_t blkaddr, int type)
+{
+       return __f2fs_is_valid_blkaddr(sbi, blkaddr, type);
 }
 
 /*
@@ -889,7 +904,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
 
        cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count);
 
-       if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) {
+       if (cp_blocks > BLKS_PER_SEG(sbi) || cp_blocks <= F2FS_CP_PACKS) {
                f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u",
                          le32_to_cpu(cp_block->cp_pack_total_block_count));
                goto invalid_cp;
@@ -1324,7 +1339,7 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        if (cpc->reason & CP_UMOUNT) {
                if (le32_to_cpu(ckpt->cp_pack_total_block_count) +
-                       NM_I(sbi)->nat_bits_blocks > sbi->blocks_per_seg) {
+                       NM_I(sbi)->nat_bits_blocks > BLKS_PER_SEG(sbi)) {
                        clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG);
                        f2fs_notice(sbi, "Disable nat_bits due to no space");
                } else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) &&
@@ -1527,7 +1542,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                cp_ver |= ((__u64)crc32 << 32);
                *(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver);
 
-               blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks;
+               blk = start_blk + BLKS_PER_SEG(sbi) - nm_i->nat_bits_blocks;
                for (i = 0; i < nm_i->nat_bits_blocks; i++)
                        f2fs_update_meta_page(sbi, nm_i->nat_bits +
                                        (i << F2FS_BLKSIZE_BITS), blk + i);
@@ -1587,8 +1602,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
         */
        if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi) ||
                f2fs_sb_has_compression(sbi))
-               invalidate_mapping_pages(META_MAPPING(sbi),
-                               MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1);
+               f2fs_bug_on(sbi,
+                       invalidate_inode_pages2_range(META_MAPPING(sbi),
+                               MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1));
 
        f2fs_release_ino_entry(sbi, false);
 
@@ -1730,9 +1746,9 @@ void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi)
                im->ino_num = 0;
        }
 
-       sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
+       sbi->max_orphans = (BLKS_PER_SEG(sbi) - F2FS_CP_PACKS -
                        NR_CURSEG_PERSIST_TYPE - __cp_payload(sbi)) *
-                               F2FS_ORPHANS_PER_BLOCK;
+                       F2FS_ORPHANS_PER_BLOCK;
 }
 
 int __init f2fs_create_checkpoint_caches(void)
index 531517dac07967c72daf289cb5e7bd9fc70b3942..8892c82621414602e50b070d2187d9f66c0e23a5 100644 (file)
@@ -512,8 +512,8 @@ static int lzorle_compress_pages(struct compress_ctx *cc)
        ret = lzorle1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata,
                                        &cc->clen, cc->private);
        if (ret != LZO_E_OK) {
-               printk_ratelimited("%sF2FS-fs (%s): lzo-rle compress failed, ret:%d\n",
-                               KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret);
+               f2fs_err_ratelimited(F2FS_I_SB(cc->inode),
+                               "lzo-rle compress failed, ret:%d", ret);
                return -EIO;
        }
        return 0;
@@ -780,9 +780,9 @@ void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task)
                if (provided != calculated) {
                        if (!is_inode_flag_set(dic->inode, FI_COMPRESS_CORRUPT)) {
                                set_inode_flag(dic->inode, FI_COMPRESS_CORRUPT);
-                               printk_ratelimited(
-                                       "%sF2FS-fs (%s): checksum invalid, nid = %lu, %x vs %x",
-                                       KERN_INFO, sbi->sb->s_id, dic->inode->i_ino,
+                               f2fs_info_ratelimited(sbi,
+                                       "checksum invalid, nid = %lu, %x vs %x",
+                                       dic->inode->i_ino,
                                        provided, calculated);
                        }
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
@@ -1418,6 +1418,8 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
        struct f2fs_sb_info *sbi = bio->bi_private;
        struct compress_io_ctx *cic =
                        (struct compress_io_ctx *)page_private(page);
+       enum count_type type = WB_DATA_TYPE(page,
+                               f2fs_is_compressed_page(page));
        int i;
 
        if (unlikely(bio->bi_status))
@@ -1425,7 +1427,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
 
        f2fs_compress_free_page(page);
 
-       dec_page_count(sbi, F2FS_WB_DATA);
+       dec_page_count(sbi, type);
 
        if (atomic_dec_return(&cic->pending_pages))
                return;
@@ -1441,12 +1443,14 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
 }
 
 static int f2fs_write_raw_pages(struct compress_ctx *cc,
-                                       int *submitted,
+                                       int *submitted_p,
                                        struct writeback_control *wbc,
                                        enum iostat_type io_type)
 {
        struct address_space *mapping = cc->inode->i_mapping;
-       int _submitted, compr_blocks, ret, i;
+       struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
+       int submitted, compr_blocks, i;
+       int ret = 0;
 
        compr_blocks = f2fs_compressed_blocks(cc);
 
@@ -1461,6 +1465,10 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
        if (compr_blocks < 0)
                return compr_blocks;
 
+       /* overwrite compressed cluster w/ normal cluster */
+       if (compr_blocks > 0)
+               f2fs_lock_op(sbi);
+
        for (i = 0; i < cc->cluster_size; i++) {
                if (!cc->rpages[i])
                        continue;
@@ -1485,7 +1493,7 @@ continue_unlock:
                if (!clear_page_dirty_for_io(cc->rpages[i]))
                        goto continue_unlock;
 
-               ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted,
+               ret = f2fs_write_single_data_page(cc->rpages[i], &submitted,
                                                NULL, NULL, wbc, io_type,
                                                compr_blocks, false);
                if (ret) {
@@ -1493,26 +1501,29 @@ continue_unlock:
                                unlock_page(cc->rpages[i]);
                                ret = 0;
                        } else if (ret == -EAGAIN) {
+                               ret = 0;
                                /*
                                 * for quota file, just redirty left pages to
                                 * avoid deadlock caused by cluster update race
                                 * from foreground operation.
                                 */
                                if (IS_NOQUOTA(cc->inode))
-                                       return 0;
-                               ret = 0;
+                                       goto out;
                                f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
                                goto retry_write;
                        }
-                       return ret;
+                       goto out;
                }
 
-               *submitted += _submitted;
+               *submitted_p += submitted;
        }
 
-       f2fs_balance_fs(F2FS_M_SB(mapping), true);
+out:
+       if (compr_blocks > 0)
+               f2fs_unlock_op(sbi);
 
-       return 0;
+       f2fs_balance_fs(sbi, true);
+       return ret;
 }
 
 int f2fs_write_multi_pages(struct compress_ctx *cc,
@@ -1806,16 +1817,18 @@ void f2fs_put_page_dic(struct page *page, bool in_task)
  * check whether cluster blocks are contiguous, and add extent cache entry
  * only if cluster blocks are logically and physically contiguous.
  */
-unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn)
+unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn,
+                                               unsigned int ofs_in_node)
 {
-       bool compressed = f2fs_data_blkaddr(dn) == COMPRESS_ADDR;
+       bool compressed = data_blkaddr(dn->inode, dn->node_page,
+                                       ofs_in_node) == COMPRESS_ADDR;
        int i = compressed ? 1 : 0;
        block_t first_blkaddr = data_blkaddr(dn->inode, dn->node_page,
-                                               dn->ofs_in_node + i);
+                                                       ofs_in_node + i);
 
        for (i += 1; i < F2FS_I(dn->inode)->i_cluster_size; i++) {
                block_t blkaddr = data_blkaddr(dn->inode, dn->node_page,
-                                               dn->ofs_in_node + i);
+                                                       ofs_in_node + i);
 
                if (!__is_valid_data_blkaddr(blkaddr))
                        break;
@@ -1878,12 +1891,8 @@ void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page,
 
        set_page_private_data(cpage, ino);
 
-       if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE_READ))
-               goto out;
-
        memcpy(page_address(cpage), page_address(page), PAGE_SIZE);
        SetPageUptodate(cpage);
-out:
        f2fs_put_page(cpage, 1);
 }
 
index 26e317696b3389d9291f84756b82a126137ce215..d9494b5fc7c185e5088dd12885a5e9758cfd4011 100644 (file)
@@ -48,7 +48,7 @@ void f2fs_destroy_bioset(void)
        bioset_exit(&f2fs_bioset);
 }
 
-static bool __is_cp_guaranteed(struct page *page)
+bool f2fs_is_cp_guaranteed(struct page *page)
 {
        struct address_space *mapping = page->mapping;
        struct inode *inode;
@@ -65,8 +65,6 @@ static bool __is_cp_guaranteed(struct page *page)
                        S_ISDIR(inode->i_mode))
                return true;
 
-       if (f2fs_is_compressed_page(page))
-               return false;
        if ((S_ISREG(inode->i_mode) && IS_NOQUOTA(inode)) ||
                        page_private_gcing(page))
                return true;
@@ -338,18 +336,7 @@ static void f2fs_write_end_io(struct bio *bio)
 
        bio_for_each_segment_all(bvec, bio, iter_all) {
                struct page *page = bvec->bv_page;
-               enum count_type type = WB_DATA_TYPE(page);
-
-               if (page_private_dummy(page)) {
-                       clear_page_private_dummy(page);
-                       unlock_page(page);
-                       mempool_free(page, sbi->write_io_dummy);
-
-                       if (unlikely(bio->bi_status))
-                               f2fs_stop_checkpoint(sbi, true,
-                                               STOP_CP_REASON_WRITE_FAIL);
-                       continue;
-               }
+               enum count_type type = WB_DATA_TYPE(page, false);
 
                fscrypt_finalize_bounce_page(&page);
 
@@ -524,50 +511,13 @@ void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio,
        submit_bio(bio);
 }
 
-static void f2fs_align_write_bio(struct f2fs_sb_info *sbi, struct bio *bio)
-{
-       unsigned int start =
-               (bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS) % F2FS_IO_SIZE(sbi);
-
-       if (start == 0)
-               return;
-
-       /* fill dummy pages */
-       for (; start < F2FS_IO_SIZE(sbi); start++) {
-               struct page *page =
-                       mempool_alloc(sbi->write_io_dummy,
-                                     GFP_NOIO | __GFP_NOFAIL);
-               f2fs_bug_on(sbi, !page);
-
-               lock_page(page);
-
-               zero_user_segment(page, 0, PAGE_SIZE);
-               set_page_private_dummy(page);
-
-               if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
-                       f2fs_bug_on(sbi, 1);
-       }
-}
-
 static void f2fs_submit_write_bio(struct f2fs_sb_info *sbi, struct bio *bio,
                                  enum page_type type)
 {
        WARN_ON_ONCE(is_read_io(bio_op(bio)));
 
-       if (type == DATA || type == NODE) {
-               if (f2fs_lfs_mode(sbi) && current->plug)
-                       blk_finish_plug(current->plug);
-
-               if (F2FS_IO_ALIGNED(sbi)) {
-                       f2fs_align_write_bio(sbi, bio);
-                       /*
-                        * In the NODE case, we lose next block address chain.
-                        * So, we need to do checkpoint in f2fs_sync_file.
-                        */
-                       if (type == NODE)
-                               set_sbi_flag(sbi, SBI_NEED_CP);
-               }
-       }
+       if (f2fs_lfs_mode(sbi) && current->plug && PAGE_TYPE_ON_MAIN(type))
+               blk_finish_plug(current->plug);
 
        trace_f2fs_submit_write_bio(sbi->sb, type, bio);
        iostat_update_submit_ctx(bio, type);
@@ -740,10 +690,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
 
        if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
                        fio->is_por ? META_POR : (__is_meta_io(fio) ?
-                       META_GENERIC : DATA_GENERIC_ENHANCE))) {
-               f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);
+                       META_GENERIC : DATA_GENERIC_ENHANCE)))
                return -EFSCORRUPTED;
-       }
 
        trace_f2fs_submit_page_bio(page, fio);
 
@@ -762,7 +710,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
                wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE);
 
        inc_page_count(fio->sbi, is_read_io(fio->op) ?
-                       __read_io_type(page) : WB_DATA_TYPE(fio->page));
+                       __read_io_type(page) : WB_DATA_TYPE(fio->page, false));
 
        if (is_read_io(bio_op(bio)))
                f2fs_submit_read_bio(fio->sbi, bio, fio->type);
@@ -796,16 +744,6 @@ static bool io_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio,
                                        block_t last_blkaddr,
                                        block_t cur_blkaddr)
 {
-       if (F2FS_IO_ALIGNED(sbi) && (fio->type == DATA || fio->type == NODE)) {
-               unsigned int filled_blocks =
-                               F2FS_BYTES_TO_BLK(bio->bi_iter.bi_size);
-               unsigned int io_size = F2FS_IO_SIZE(sbi);
-               unsigned int left_vecs = bio->bi_max_vecs - bio->bi_vcnt;
-
-               /* IOs in bio is aligned and left space of vectors is not enough */
-               if (!(filled_blocks % io_size) && left_vecs < io_size)
-                       return false;
-       }
        if (!page_is_mergeable(sbi, bio, last_blkaddr, cur_blkaddr))
                return false;
        return io_type_is_mergeable(io, fio);
@@ -948,10 +886,8 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
                        fio->encrypted_page : fio->page;
 
        if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
-                       __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)) {
-               f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);
+                       __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
                return -EFSCORRUPTED;
-       }
 
        trace_f2fs_submit_page_bio(page, fio);
 
@@ -973,7 +909,7 @@ alloc_new:
        if (fio->io_wbc)
                wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE);
 
-       inc_page_count(fio->sbi, WB_DATA_TYPE(page));
+       inc_page_count(fio->sbi, WB_DATA_TYPE(page, false));
 
        *fio->last_block = fio->new_blkaddr;
        *fio->bio = bio;
@@ -1007,11 +943,12 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
        enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
        struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
        struct page *bio_page;
+       enum count_type type;
 
        f2fs_bug_on(sbi, is_read_io(fio->op));
 
        f2fs_down_write(&io->io_rwsem);
-
+next:
 #ifdef CONFIG_BLK_DEV_ZONED
        if (f2fs_sb_has_blkzoned(sbi) && btype < META && io->zone_pending_bio) {
                wait_for_completion_io(&io->zone_wait);
@@ -1021,7 +958,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
        }
 #endif
 
-next:
        if (fio->in_list) {
                spin_lock(&io->io_lock);
                if (list_empty(&io->io_list)) {
@@ -1046,7 +982,8 @@ next:
        /* set submitted = true as a return value */
        fio->submitted = 1;
 
-       inc_page_count(sbi, WB_DATA_TYPE(bio_page));
+       type = WB_DATA_TYPE(bio_page, fio->compressed_page);
+       inc_page_count(sbi, type);
 
        if (io->bio &&
            (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio,
@@ -1056,13 +993,6 @@ next:
                __submit_merged_bio(io);
 alloc_new:
        if (io->bio == NULL) {
-               if (F2FS_IO_ALIGNED(sbi) &&
-                               (fio->type == DATA || fio->type == NODE) &&
-                               fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) {
-                       dec_page_count(sbi, WB_DATA_TYPE(bio_page));
-                       fio->retry = 1;
-                       goto skip;
-               }
                io->bio = __bio_alloc(fio, BIO_MAX_VECS);
                f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host,
                                       bio_page->index, fio, GFP_NOIO);
@@ -1080,10 +1010,6 @@ alloc_new:
        io->last_block_in_bio = fio->new_blkaddr;
 
        trace_f2fs_submit_page_write(fio->page, fio);
-skip:
-       if (fio->in_list)
-               goto next;
-out:
 #ifdef CONFIG_BLK_DEV_ZONED
        if (f2fs_sb_has_blkzoned(sbi) && btype < META &&
                        is_end_zone_blkaddr(sbi, fio->new_blkaddr)) {
@@ -1096,6 +1022,9 @@ out:
                __submit_merged_bio(io);
        }
 #endif
+       if (fio->in_list)
+               goto next;
+out:
        if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) ||
                                !f2fs_is_checkpoint_ready(sbi))
                __submit_merged_bio(io);
@@ -1218,7 +1147,8 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
 
        if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
                return -EPERM;
-       if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count))))
+       err = inc_valid_block_count(sbi, dn->inode, &count, true);
+       if (unlikely(err))
                return err;
 
        trace_f2fs_reserve_new_blocks(dn->inode, dn->nid,
@@ -1285,8 +1215,6 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
                if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE_READ)) {
                        err = -EFSCORRUPTED;
-                       f2fs_handle_error(F2FS_I_SB(inode),
-                                               ERROR_INVALID_BLKADDR);
                        goto put_err;
                }
                goto got_it;
@@ -1312,8 +1240,6 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
                                                dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE)) {
                err = -EFSCORRUPTED;
-               f2fs_handle_error(F2FS_I_SB(inode),
-                                       ERROR_INVALID_BLKADDR);
                goto put_err;
        }
 got_it:
@@ -1475,15 +1401,18 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
 
        dn->data_blkaddr = f2fs_data_blkaddr(dn);
        if (dn->data_blkaddr == NULL_ADDR) {
-               err = inc_valid_block_count(sbi, dn->inode, &count);
+               err = inc_valid_block_count(sbi, dn->inode, &count, true);
                if (unlikely(err))
                        return err;
        }
 
        set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
        old_blkaddr = dn->data_blkaddr;
-       f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
-                               &sum, seg_type, NULL);
+       err = f2fs_allocate_data_block(sbi, NULL, old_blkaddr,
+                               &dn->data_blkaddr, &sum, seg_type, NULL);
+       if (err)
+               return err;
+
        if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
                f2fs_invalidate_internal_cache(sbi, old_blkaddr);
 
@@ -1641,7 +1570,6 @@ next_block:
        if (!is_hole &&
            !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
                err = -EFSCORRUPTED;
-               f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                goto sync_out;
        }
 
@@ -2165,8 +2093,6 @@ got_it:
                if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
                                                DATA_GENERIC_ENHANCE_READ)) {
                        ret = -EFSCORRUPTED;
-                       f2fs_handle_error(F2FS_I_SB(inode),
-                                               ERROR_INVALID_BLKADDR);
                        goto out;
                }
        } else {
@@ -2668,8 +2594,6 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
        if (fio) {
                if (page_private_gcing(fio->page))
                        return true;
-               if (page_private_dummy(fio->page))
-                       return true;
                if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
                        f2fs_is_checkpointed_data(sbi, fio->old_blkaddr)))
                        return true;
@@ -2706,11 +2630,8 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
            f2fs_lookup_read_extent_cache_block(inode, page->index,
                                                &fio->old_blkaddr)) {
                if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
-                                               DATA_GENERIC_ENHANCE)) {
-                       f2fs_handle_error(fio->sbi,
-                                               ERROR_INVALID_BLKADDR);
+                                               DATA_GENERIC_ENHANCE))
                        return -EFSCORRUPTED;
-               }
 
                ipu_force = true;
                fio->need_lock = LOCK_DONE;
@@ -2738,7 +2659,6 @@ got_it:
                !f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
                                                DATA_GENERIC_ENHANCE)) {
                err = -EFSCORRUPTED;
-               f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);
                goto out_writepage;
        }
 
@@ -2838,7 +2758,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
                .encrypted_page = NULL,
                .submitted = 0,
                .compr_blocks = compr_blocks,
-               .need_lock = LOCK_RETRY,
+               .need_lock = compr_blocks ? LOCK_DONE : LOCK_RETRY,
                .post_read = f2fs_post_read_required(inode) ? 1 : 0,
                .io_type = io_type,
                .io_wbc = wbc,
@@ -2919,6 +2839,7 @@ write:
        if (err == -EAGAIN) {
                err = f2fs_do_write_data_page(&fio);
                if (err == -EAGAIN) {
+                       f2fs_bug_on(sbi, compr_blocks);
                        fio.need_lock = LOCK_REQ;
                        err = f2fs_do_write_data_page(&fio);
                }
@@ -3704,7 +3625,6 @@ repeat:
                if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
                                DATA_GENERIC_ENHANCE_READ)) {
                        err = -EFSCORRUPTED;
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                        goto fail;
                }
                err = f2fs_submit_page_read(use_cow ?
@@ -3905,26 +3825,36 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        unsigned int blkofs;
        unsigned int blk_per_sec = BLKS_PER_SEC(sbi);
+       unsigned int end_blk = start_blk + blkcnt - 1;
        unsigned int secidx = start_blk / blk_per_sec;
-       unsigned int end_sec = secidx + blkcnt / blk_per_sec;
+       unsigned int end_sec;
        int ret = 0;
 
+       if (!blkcnt)
+               return 0;
+       end_sec = end_blk / blk_per_sec;
+
        f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
        filemap_invalidate_lock(inode->i_mapping);
 
        set_inode_flag(inode, FI_ALIGNED_WRITE);
        set_inode_flag(inode, FI_OPU_WRITE);
 
-       for (; secidx < end_sec; secidx++) {
+       for (; secidx <= end_sec; secidx++) {
+               unsigned int blkofs_end = secidx == end_sec ?
+                               end_blk % blk_per_sec : blk_per_sec - 1;
+
                f2fs_down_write(&sbi->pin_sem);
 
-               f2fs_lock_op(sbi);
-               f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
-               f2fs_unlock_op(sbi);
+               ret = f2fs_allocate_pinning_section(sbi);
+               if (ret) {
+                       f2fs_up_write(&sbi->pin_sem);
+                       break;
+               }
 
                set_inode_flag(inode, FI_SKIP_WRITES);
 
-               for (blkofs = 0; blkofs < blk_per_sec; blkofs++) {
+               for (blkofs = 0; blkofs <= blkofs_end; blkofs++) {
                        struct page *page;
                        unsigned int blkidx = secidx * blk_per_sec + blkofs;
 
@@ -4013,27 +3943,34 @@ retry:
                nr_pblocks = map.m_len;
 
                if ((pblock - SM_I(sbi)->main_blkaddr) & sec_blks_mask ||
-                               nr_pblocks & sec_blks_mask) {
+                               nr_pblocks & sec_blks_mask ||
+                               !f2fs_valid_pinned_area(sbi, pblock)) {
+                       bool last_extent = false;
+
                        not_aligned++;
 
                        nr_pblocks = roundup(nr_pblocks, blks_per_sec);
                        if (cur_lblock + nr_pblocks > sis->max)
                                nr_pblocks -= blks_per_sec;
 
+                       /* this extent is last one */
                        if (!nr_pblocks) {
-                               /* this extent is last one */
-                               nr_pblocks = map.m_len;
-                               f2fs_warn(sbi, "Swapfile: last extent is not aligned to section");
-                               goto next;
+                               nr_pblocks = last_lblock - cur_lblock;
+                               last_extent = true;
                        }
 
                        ret = f2fs_migrate_blocks(inode, cur_lblock,
                                                        nr_pblocks);
-                       if (ret)
+                       if (ret) {
+                               if (ret == -ENOENT)
+                                       ret = -EINVAL;
                                goto out;
-                       goto retry;
+                       }
+
+                       if (!last_extent)
+                               goto retry;
                }
-next:
+
                if (cur_lblock + nr_pblocks >= sis->max)
                        nr_pblocks = sis->max - cur_lblock;
 
@@ -4071,17 +4008,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
                                sector_t *span)
 {
        struct inode *inode = file_inode(file);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        int ret;
 
        if (!S_ISREG(inode->i_mode))
                return -EINVAL;
 
-       if (f2fs_readonly(F2FS_I_SB(inode)->sb))
+       if (f2fs_readonly(sbi->sb))
                return -EROFS;
 
-       if (f2fs_lfs_mode(F2FS_I_SB(inode))) {
-               f2fs_err(F2FS_I_SB(inode),
-                       "Swapfile not supported in LFS mode");
+       if (f2fs_lfs_mode(sbi) && !f2fs_sb_has_blkzoned(sbi)) {
+               f2fs_err(sbi, "Swapfile not supported in LFS mode");
                return -EINVAL;
        }
 
@@ -4092,6 +4029,10 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
        if (!f2fs_disable_compressed_file(inode))
                return -EINVAL;
 
+       ret = filemap_fdatawrite(inode->i_mapping);
+       if (ret < 0)
+               return ret;
+
        f2fs_precache_extents(inode);
 
        ret = check_swap_activate(sis, file, span);
@@ -4100,7 +4041,7 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
 
        stat_inc_swapfile_inode(inode);
        set_inode_flag(inode, FI_PIN_FILE);
-       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+       f2fs_update_time(sbi, REQ_TIME);
        return ret;
 }
 
index fdbf994f12718c566ef03d22fae9a7050a2ba5ee..8b0e1e71b667448afce3cb7b094fc2bc4644a892 100644 (file)
@@ -41,7 +41,7 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi)
        total_vblocks = 0;
        blks_per_sec = CAP_BLKS_PER_SEC(sbi);
        hblks_per_sec = blks_per_sec / 2;
-       for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
+       for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) {
                vblocks = get_valid_blocks(sbi, segno, true);
                dist = abs(vblocks - hblks_per_sec);
                bimodal += dist * dist;
@@ -135,7 +135,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
        si->cur_ckpt_time = sbi->cprc_info.cur_time;
        si->peak_ckpt_time = sbi->cprc_info.peak_time;
        spin_unlock(&sbi->cprc_info.stat_lock);
-       si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
+       si->total_count = BLKS_TO_SEGS(sbi, (int)sbi->user_block_count);
        si->rsvd_segs = reserved_segments(sbi);
        si->overp_segs = overprovision_segments(sbi);
        si->valid_count = valid_user_blocks(sbi);
@@ -176,11 +176,10 @@ static void update_general_status(struct f2fs_sb_info *sbi)
        si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID];
        si->io_skip_bggc = sbi->io_skip_bggc;
        si->other_skip_bggc = sbi->other_skip_bggc;
-       si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
+       si->util_free = (int)(BLKS_TO_SEGS(sbi, free_user_blocks(sbi)))
                * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
                / 2;
-       si->util_valid = (int)(written_block_count(sbi) >>
-                                               sbi->log_blocks_per_seg)
+       si->util_valid = (int)(BLKS_TO_SEGS(sbi, written_block_count(sbi)))
                * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
                / 2;
        si->util_invalid = 50 - si->util_free - si->util_valid;
@@ -208,7 +207,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
                if (!blks)
                        continue;
 
-               if (blks == sbi->blocks_per_seg)
+               if (blks == BLKS_PER_SEG(sbi))
                        si->full_seg[type]++;
                else
                        si->dirty_seg[type]++;
index 042593aed1ec0a79cdae8846d0e79c06674d97ca..02c9355176d3b55f467d0bd6948c7e5db600b519 100644 (file)
@@ -830,13 +830,14 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
        return err;
 }
 
-int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
+int f2fs_do_tmpfile(struct inode *inode, struct inode *dir,
+                                       struct f2fs_filename *fname)
 {
        struct page *page;
        int err = 0;
 
        f2fs_down_write(&F2FS_I(inode)->i_sem);
-       page = f2fs_init_inode_metadata(inode, dir, NULL, NULL);
+       page = f2fs_init_inode_metadata(inode, dir, fname, NULL);
        if (IS_ERR(page)) {
                err = PTR_ERR(page);
                goto fail;
@@ -995,9 +996,8 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
                de = &d->dentry[bit_pos];
                if (de->name_len == 0) {
                        if (found_valid_dirent || !bit_pos) {
-                               printk_ratelimited(
-                                       "%sF2FS-fs (%s): invalid namelen(0), ino:%u, run fsck to fix.",
-                                       KERN_WARNING, sbi->sb->s_id,
+                               f2fs_warn_ratelimited(sbi,
+                                       "invalid namelen(0), ino:%u, run fsck to fix.",
                                        le32_to_cpu(de->ino));
                                set_sbi_flag(sbi, SBI_NEED_FSCK);
                        }
index ad8dfac73bd4461d95d92e965a079d3968d1a229..48048fa3642766d5176e175ee445f5a26aea8a6b 100644 (file)
@@ -43,7 +43,6 @@ bool sanity_check_extent_cache(struct inode *inode)
        if (!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC_ENHANCE) ||
            !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
                                        DATA_GENERIC_ENHANCE)) {
-               set_sbi_flag(sbi, SBI_NEED_FSCK);
                f2fs_warn(sbi, "%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix",
                          __func__, inode->i_ino,
                          ei->blk, ei->fofs, ei->len);
@@ -856,10 +855,8 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei,
                goto out;
 
        if (__is_valid_data_blkaddr(blkaddr) &&
-           !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
-               f2fs_bug_on(sbi, 1);
+           !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE))
                return -EINVAL;
-       }
 out:
        /*
         * init block age with zero, this can happen when the block age extent
index 3ff428bee958cbd25f16e0e74e8ebc9e43be1a3a..fced2b7652f40a1acf202043dc3c3fdd82c46177 100644 (file)
@@ -61,7 +61,9 @@ enum {
        FAULT_SLAB_ALLOC,
        FAULT_DQUOT_INIT,
        FAULT_LOCK_OP,
-       FAULT_BLKADDR,
+       FAULT_BLKADDR_VALIDITY,
+       FAULT_BLKADDR_CONSISTENCE,
+       FAULT_NO_SEGMENT,
        FAULT_MAX,
 };
 
@@ -76,6 +78,11 @@ struct f2fs_fault_info {
 
 extern const char *f2fs_fault_name[FAULT_MAX];
 #define IS_FAULT_SET(fi, type) ((fi)->inject_type & BIT(type))
+
+/* maximum retry count for injected failure */
+#define DEFAULT_FAILURE_RETRY_COUNT            8
+#else
+#define DEFAULT_FAILURE_RETRY_COUNT            1
 #endif
 
 /*
@@ -143,7 +150,6 @@ struct f2fs_rwsem {
 
 struct f2fs_mount_info {
        unsigned int opt;
-       int write_io_size_bits;         /* Write IO size bits */
        block_t root_reserved_blocks;   /* root reserved blocks */
        kuid_t s_resuid;                /* reserved blocks for uid */
        kgid_t s_resgid;                /* reserved blocks for gid */
@@ -1081,7 +1087,8 @@ struct f2fs_sm_info {
  * f2fs monitors the number of several block types such as on-writeback,
  * dirty dentry blocks, dirty node blocks, and dirty meta blocks.
  */
-#define WB_DATA_TYPE(p)        (__is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA)
+#define WB_DATA_TYPE(p, f)                     \
+       (f || f2fs_is_cp_guaranteed(p) ? F2FS_WB_CP_DATA : F2FS_WB_DATA)
 enum count_type {
        F2FS_DIRTY_DENTS,
        F2FS_DIRTY_DATA,
@@ -1111,6 +1118,7 @@ enum count_type {
  * ...                 Only can be used with META.
  */
 #define PAGE_TYPE_OF_BIO(type) ((type) > META ? META : (type))
+#define PAGE_TYPE_ON_MAIN(type)        ((type) == DATA || (type) == NODE)
 enum page_type {
        DATA = 0,
        NODE = 1,       /* should not change this */
@@ -1205,7 +1213,6 @@ struct f2fs_io_info {
        unsigned int submitted:1;       /* indicate IO submission */
        unsigned int in_list:1;         /* indicate fio is in io_list */
        unsigned int is_por:1;          /* indicate IO is from recovery or not */
-       unsigned int retry:1;           /* need to reallocate block address */
        unsigned int encrypted:1;       /* indicate file is encrypted */
        unsigned int post_read:1;       /* require post read */
        enum iostat_type io_type;       /* io type */
@@ -1407,18 +1414,16 @@ static inline void f2fs_clear_bit(unsigned int nr, char *addr);
  * Layout A: lowest bit should be 1
  * | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... |
  * bit 0       PAGE_PRIVATE_NOT_POINTER
- * bit 1       PAGE_PRIVATE_DUMMY_WRITE
- * bit 2       PAGE_PRIVATE_ONGOING_MIGRATION
- * bit 3       PAGE_PRIVATE_INLINE_INODE
- * bit 4       PAGE_PRIVATE_REF_RESOURCE
- * bit 5-      f2fs private data
+ * bit 1       PAGE_PRIVATE_ONGOING_MIGRATION
+ * bit 2       PAGE_PRIVATE_INLINE_INODE
+ * bit 3       PAGE_PRIVATE_REF_RESOURCE
+ * bit 4-      f2fs private data
  *
  * Layout B: lowest bit should be 0
  * page.private is a wrapped pointer.
  */
 enum {
        PAGE_PRIVATE_NOT_POINTER,               /* private contains non-pointer data */
-       PAGE_PRIVATE_DUMMY_WRITE,               /* data page for padding aligned IO */
        PAGE_PRIVATE_ONGOING_MIGRATION,         /* data page which is on-going migrating */
        PAGE_PRIVATE_INLINE_INODE,              /* inode page contains inline data */
        PAGE_PRIVATE_REF_RESOURCE,              /* dirty page has referenced resources */
@@ -1565,7 +1570,6 @@ struct f2fs_sb_info {
        struct f2fs_bio_info *write_io[NR_PAGE_TYPE];   /* for write bios */
        /* keep migration IO order for LFS mode */
        struct f2fs_rwsem io_order_lock;
-       mempool_t *write_io_dummy;              /* Dummy pages */
        pgoff_t page_eio_ofs[NR_PAGE_TYPE];     /* EIO page offset */
        int page_eio_cnt[NR_PAGE_TYPE];         /* EIO count */
 
@@ -1811,6 +1815,37 @@ struct f2fs_sb_info {
 #endif
 };
 
+/* Definitions to access f2fs_sb_info */
+#define SEGS_TO_BLKS(sbi, segs)                                        \
+               ((segs) << (sbi)->log_blocks_per_seg)
+#define BLKS_TO_SEGS(sbi, blks)                                        \
+               ((blks) >> (sbi)->log_blocks_per_seg)
+
+#define BLKS_PER_SEG(sbi)      ((sbi)->blocks_per_seg)
+#define BLKS_PER_SEC(sbi)      (SEGS_TO_BLKS(sbi, (sbi)->segs_per_sec))
+#define SEGS_PER_SEC(sbi)      ((sbi)->segs_per_sec)
+
+__printf(3, 4)
+void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate, const char *fmt, ...);
+
+#define f2fs_err(sbi, fmt, ...)                                                \
+       f2fs_printk(sbi, false, KERN_ERR fmt, ##__VA_ARGS__)
+#define f2fs_warn(sbi, fmt, ...)                                       \
+       f2fs_printk(sbi, false, KERN_WARNING fmt, ##__VA_ARGS__)
+#define f2fs_notice(sbi, fmt, ...)                                     \
+       f2fs_printk(sbi, false, KERN_NOTICE fmt, ##__VA_ARGS__)
+#define f2fs_info(sbi, fmt, ...)                                       \
+       f2fs_printk(sbi, false, KERN_INFO fmt, ##__VA_ARGS__)
+#define f2fs_debug(sbi, fmt, ...)                                      \
+       f2fs_printk(sbi, false, KERN_DEBUG fmt, ##__VA_ARGS__)
+
+#define f2fs_err_ratelimited(sbi, fmt, ...)                            \
+       f2fs_printk(sbi, true, KERN_ERR fmt, ##__VA_ARGS__)
+#define f2fs_warn_ratelimited(sbi, fmt, ...)                           \
+       f2fs_printk(sbi, true, KERN_WARNING fmt, ##__VA_ARGS__)
+#define f2fs_info_ratelimited(sbi, fmt, ...)                           \
+       f2fs_printk(sbi, true, KERN_INFO fmt, ##__VA_ARGS__)
+
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 #define time_to_inject(sbi, type) __time_to_inject(sbi, type, __func__,        \
                                                                        __builtin_return_address(0))
@@ -1828,9 +1863,8 @@ static inline bool __time_to_inject(struct f2fs_sb_info *sbi, int type,
        atomic_inc(&ffi->inject_ops);
        if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) {
                atomic_set(&ffi->inject_ops, 0);
-               printk_ratelimited("%sF2FS-fs (%s) : inject %s in %s of %pS\n",
-                       KERN_INFO, sbi->sb->s_id, f2fs_fault_name[type],
-                       func, parent_func);
+               f2fs_info_ratelimited(sbi, "inject %s in %s of %pS",
+                               f2fs_fault_name[type], func, parent_func);
                return true;
        }
        return false;
@@ -2250,9 +2284,30 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi,
        return false;
 }
 
+static inline unsigned int get_available_block_count(struct f2fs_sb_info *sbi,
+                                               struct inode *inode, bool cap)
+{
+       block_t avail_user_block_count;
+
+       avail_user_block_count = sbi->user_block_count -
+                                       sbi->current_reserved_blocks;
+
+       if (!__allow_reserved_blocks(sbi, inode, cap))
+               avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
+
+       if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
+               if (avail_user_block_count > sbi->unusable_block_count)
+                       avail_user_block_count -= sbi->unusable_block_count;
+               else
+                       avail_user_block_count = 0;
+       }
+
+       return avail_user_block_count;
+}
+
 static inline void f2fs_i_blocks_write(struct inode *, block_t, bool, bool);
 static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
-                                struct inode *inode, blkcnt_t *count)
+                                struct inode *inode, blkcnt_t *count, bool partial)
 {
        blkcnt_t diff = 0, release = 0;
        block_t avail_user_block_count;
@@ -2275,23 +2330,14 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
 
        spin_lock(&sbi->stat_lock);
        sbi->total_valid_block_count += (block_t)(*count);
-       avail_user_block_count = sbi->user_block_count -
-                                       sbi->current_reserved_blocks;
-
-       if (!__allow_reserved_blocks(sbi, inode, true))
-               avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
-
-       if (F2FS_IO_ALIGNED(sbi))
-               avail_user_block_count -= sbi->blocks_per_seg *
-                               SM_I(sbi)->additional_reserved_segments;
+       avail_user_block_count = get_available_block_count(sbi, inode, true);
 
-       if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
-               if (avail_user_block_count > sbi->unusable_block_count)
-                       avail_user_block_count -= sbi->unusable_block_count;
-               else
-                       avail_user_block_count = 0;
-       }
        if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
+               if (!partial) {
+                       spin_unlock(&sbi->stat_lock);
+                       goto enospc;
+               }
+
                diff = sbi->total_valid_block_count - avail_user_block_count;
                if (diff > *count)
                        diff = *count;
@@ -2319,20 +2365,6 @@ release_quota:
        return -ENOSPC;
 }
 
-__printf(2, 3)
-void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...);
-
-#define f2fs_err(sbi, fmt, ...)                                                \
-       f2fs_printk(sbi, KERN_ERR fmt, ##__VA_ARGS__)
-#define f2fs_warn(sbi, fmt, ...)                                       \
-       f2fs_printk(sbi, KERN_WARNING fmt, ##__VA_ARGS__)
-#define f2fs_notice(sbi, fmt, ...)                                     \
-       f2fs_printk(sbi, KERN_NOTICE fmt, ##__VA_ARGS__)
-#define f2fs_info(sbi, fmt, ...)                                       \
-       f2fs_printk(sbi, KERN_INFO fmt, ##__VA_ARGS__)
-#define f2fs_debug(sbi, fmt, ...)                                      \
-       f2fs_printk(sbi, KERN_DEBUG fmt, ##__VA_ARGS__)
-
 #define PAGE_PRIVATE_GET_FUNC(name, flagname) \
 static inline bool page_private_##name(struct page *page) \
 { \
@@ -2361,17 +2393,14 @@ static inline void clear_page_private_##name(struct page *page) \
 PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER);
 PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE);
 PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION);
-PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE);
 
 PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE);
 PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE);
 PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION);
-PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE);
 
 PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE);
 PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE);
 PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION);
-PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE);
 
 static inline unsigned long get_page_private_data(struct page *page)
 {
@@ -2505,11 +2534,8 @@ static inline int get_dirty_pages(struct inode *inode)
 
 static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type)
 {
-       unsigned int pages_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg;
-       unsigned int segs = (get_pages(sbi, block_type) + pages_per_sec - 1) >>
-                                               sbi->log_blocks_per_seg;
-
-       return segs / sbi->segs_per_sec;
+       return div_u64(get_pages(sbi, block_type) + BLKS_PER_SEC(sbi) - 1,
+                                                       BLKS_PER_SEC(sbi));
 }
 
 static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi)
@@ -2573,7 +2599,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
        block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
 
        if (sbi->cur_cp_pack == 2)
-               start_addr += sbi->blocks_per_seg;
+               start_addr += BLKS_PER_SEG(sbi);
        return start_addr;
 }
 
@@ -2582,7 +2608,7 @@ static inline block_t __start_cp_next_addr(struct f2fs_sb_info *sbi)
        block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
 
        if (sbi->cur_cp_pack == 1)
-               start_addr += sbi->blocks_per_seg;
+               start_addr += BLKS_PER_SEG(sbi);
        return start_addr;
 }
 
@@ -2601,7 +2627,8 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
                                        struct inode *inode, bool is_inode)
 {
        block_t valid_block_count;
-       unsigned int valid_node_count, user_block_count;
+       unsigned int valid_node_count;
+       unsigned int avail_user_block_count;
        int err;
 
        if (is_inode) {
@@ -2621,21 +2648,10 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
 
        spin_lock(&sbi->stat_lock);
 
-       valid_block_count = sbi->total_valid_block_count +
-                                       sbi->current_reserved_blocks + 1;
-
-       if (!__allow_reserved_blocks(sbi, inode, false))
-               valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
+       valid_block_count = sbi->total_valid_block_count + 1;
+       avail_user_block_count = get_available_block_count(sbi, inode, false);
 
-       if (F2FS_IO_ALIGNED(sbi))
-               valid_block_count += sbi->blocks_per_seg *
-                               SM_I(sbi)->additional_reserved_segments;
-
-       user_block_count = sbi->user_block_count;
-       if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
-               user_block_count -= sbi->unusable_block_count;
-
-       if (unlikely(valid_block_count > user_block_count)) {
+       if (unlikely(valid_block_count > avail_user_block_count)) {
                spin_unlock(&sbi->stat_lock);
                goto enospc;
        }
@@ -3022,6 +3038,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
        case FI_INLINE_DOTS:
        case FI_PIN_FILE:
        case FI_COMPRESS_RELEASED:
+       case FI_ATOMIC_COMMITTED:
                f2fs_mark_inode_dirty_sync(inode, true);
        }
 }
@@ -3445,7 +3462,7 @@ static inline __le32 *get_dnode_addr(struct inode *inode,
                sizeof((f2fs_inode)->field))                    \
                <= (F2FS_OLD_ATTRIBUTE_SIZE + (extra_isize)))   \
 
-#define __is_large_section(sbi)                ((sbi)->segs_per_sec > 1)
+#define __is_large_section(sbi)                (SEGS_PER_SEC(sbi) > 1)
 
 #define __is_meta_io(fio) (PAGE_TYPE_OF_BIO((fio)->type) == META)
 
@@ -3454,11 +3471,9 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
 static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type)
 {
-       if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
+       if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type))
                f2fs_err(sbi, "invalid blkaddr: %u, type: %d, run fsck to fix.",
                         blkaddr, type);
-               f2fs_bug_on(sbi, 1);
-       }
 }
 
 static inline bool __is_valid_data_blkaddr(block_t blkaddr)
@@ -3560,7 +3575,8 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
                        struct inode *inode, nid_t ino, umode_t mode);
 void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                        struct inode *dir, struct inode *inode);
-int f2fs_do_tmpfile(struct inode *inode, struct inode *dir);
+int f2fs_do_tmpfile(struct inode *inode, struct inode *dir,
+                                       struct f2fs_filename *fname);
 bool f2fs_empty_dir(struct inode *dir);
 
 static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
@@ -3675,15 +3691,14 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable);
 void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi);
 int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra);
 bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno);
-void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi);
+int f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi);
 void f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi);
 void f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi);
-void f2fs_get_new_segment(struct f2fs_sb_info *sbi,
-                       unsigned int *newseg, bool new_sec, int dir);
-void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
+int f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
                                        unsigned int start, unsigned int end);
-void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force);
-void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi);
+int f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force);
+int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi);
+int f2fs_allocate_new_segments(struct f2fs_sb_info *sbi);
 int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range);
 bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
                                        struct cp_control *cpc);
@@ -3704,7 +3719,7 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
                        block_t old_addr, block_t new_addr,
                        unsigned char version, bool recover_curseg,
                        bool recover_newaddr);
-void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
+int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
                        block_t old_blkaddr, block_t *new_blkaddr,
                        struct f2fs_summary *sum, int type,
                        struct f2fs_io_info *fio);
@@ -3754,6 +3769,8 @@ struct page *f2fs_get_meta_page_retry(struct f2fs_sb_info *sbi, pgoff_t index);
 struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
 bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type);
+bool f2fs_is_valid_blkaddr_raw(struct f2fs_sb_info *sbi,
+                                       block_t blkaddr, int type);
 int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
                        int type, bool sync);
 void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index,
@@ -3794,6 +3811,7 @@ void f2fs_init_ckpt_req_control(struct f2fs_sb_info *sbi);
  */
 int __init f2fs_init_bioset(void);
 void f2fs_destroy_bioset(void);
+bool f2fs_is_cp_guaranteed(struct page *page);
 int f2fs_init_bio_entry_cache(void);
 void f2fs_destroy_bio_entry_cache(void);
 void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio,
@@ -3857,6 +3875,9 @@ void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi);
 block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode);
 int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control);
 void f2fs_build_gc_manager(struct f2fs_sb_info *sbi);
+int f2fs_gc_range(struct f2fs_sb_info *sbi,
+               unsigned int start_seg, unsigned int end_seg,
+               bool dry_run, unsigned int dry_run_sections);
 int f2fs_resize_fs(struct file *filp, __u64 block_count);
 int __init f2fs_create_garbage_collection_cache(void);
 void f2fs_destroy_garbage_collection_cache(void);
@@ -4277,7 +4298,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc);
 void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
                                bool in_task);
 void f2fs_put_page_dic(struct page *page, bool in_task);
-unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn);
+unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn,
+                                               unsigned int ofs_in_node);
 int f2fs_init_compress_ctx(struct compress_ctx *cc);
 void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse);
 void f2fs_init_compress_info(struct f2fs_sb_info *sbi);
@@ -4334,7 +4356,8 @@ static inline void f2fs_put_page_dic(struct page *page, bool in_task)
 {
        WARN_ON_ONCE(1);
 }
-static inline unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn) { return 0; }
+static inline unsigned int f2fs_cluster_blocks_are_contiguous(
+                       struct dnode_of_data *dn, unsigned int ofs_in_node) { return 0; }
 static inline bool f2fs_sanity_check_cluster(struct dnode_of_data *dn) { return false; }
 static inline int f2fs_init_compress_inode(struct f2fs_sb_info *sbi) { return 0; }
 static inline void f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi) { }
@@ -4391,15 +4414,24 @@ static inline bool f2fs_disable_compressed_file(struct inode *inode)
 {
        struct f2fs_inode_info *fi = F2FS_I(inode);
 
-       if (!f2fs_compressed_file(inode))
+       f2fs_down_write(&F2FS_I(inode)->i_sem);
+
+       if (!f2fs_compressed_file(inode)) {
+               f2fs_up_write(&F2FS_I(inode)->i_sem);
                return true;
-       if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))
+       }
+       if (f2fs_is_mmap_file(inode) ||
+               (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))) {
+               f2fs_up_write(&F2FS_I(inode)->i_sem);
                return false;
+       }
 
        fi->i_flags &= ~F2FS_COMPR_FL;
        stat_dec_compr_inode(inode);
        clear_inode_flag(inode, FI_COMPRESSED_FILE);
        f2fs_mark_inode_dirty_sync(inode, true);
+
+       f2fs_up_write(&F2FS_I(inode)->i_sem);
        return true;
 }
 
@@ -4502,6 +4534,17 @@ static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi)
        return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS;
 }
 
+static inline bool f2fs_valid_pinned_area(struct f2fs_sb_info *sbi,
+                                         block_t blkaddr)
+{
+       if (f2fs_sb_has_blkzoned(sbi)) {
+               int devi = f2fs_target_device_index(sbi, blkaddr);
+
+               return !bdev_is_zoned(FDEV(devi).bdev);
+       }
+       return true;
+}
+
 static inline bool f2fs_low_mem_mode(struct f2fs_sb_info *sbi)
 {
        return F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW;
@@ -4603,10 +4646,36 @@ static inline bool f2fs_is_readonly(struct f2fs_sb_info *sbi)
        return f2fs_sb_has_readonly(sbi) || f2fs_readonly(sbi->sb);
 }
 
+static inline void f2fs_truncate_meta_inode_pages(struct f2fs_sb_info *sbi,
+                                       block_t blkaddr, unsigned int cnt)
+{
+       bool need_submit = false;
+       int i = 0;
+
+       do {
+               struct page *page;
+
+               page = find_get_page(META_MAPPING(sbi), blkaddr + i);
+               if (page) {
+                       if (PageWriteback(page))
+                               need_submit = true;
+                       f2fs_put_page(page, 0);
+               }
+       } while (++i < cnt && !need_submit);
+
+       if (need_submit)
+               f2fs_submit_merged_write_cond(sbi, sbi->meta_inode,
+                                                       NULL, 0, DATA);
+
+       truncate_inode_pages_range(META_MAPPING(sbi),
+                       F2FS_BLK_TO_BYTES((loff_t)blkaddr),
+                       F2FS_BLK_END_BYTES((loff_t)(blkaddr + cnt - 1)));
+}
+
 static inline void f2fs_invalidate_internal_cache(struct f2fs_sb_info *sbi,
                                                                block_t blkaddr)
 {
-       invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr);
+       f2fs_truncate_meta_inode_pages(sbi, blkaddr, 1);
        f2fs_invalidate_compress_page(sbi, blkaddr);
 }
 
index b58ab1157b7ef27724ed46be6527439c76975e9a..1761ad125f97a37ebb7bb9ce5c35ff9decf8a130 100644 (file)
@@ -39,6 +39,7 @@
 static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
 {
        struct inode *inode = file_inode(vmf->vma->vm_file);
+       vm_flags_t flags = vmf->vma->vm_flags;
        vm_fault_t ret;
 
        ret = filemap_fault(vmf);
@@ -46,7 +47,7 @@ static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
                f2fs_update_iostat(F2FS_I_SB(inode), inode,
                                        APP_MAPPED_READ_IO, F2FS_BLKSIZE);
 
-       trace_f2fs_filemap_fault(inode, vmf->pgoff, vmf->vma->vm_flags, ret);
+       trace_f2fs_filemap_fault(inode, vmf->pgoff, flags, ret);
 
        return ret;
 }
@@ -394,9 +395,20 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        return f2fs_do_sync_file(file, start, end, datasync, false);
 }
 
-static bool __found_offset(struct address_space *mapping, block_t blkaddr,
-                               pgoff_t index, int whence)
+static bool __found_offset(struct address_space *mapping,
+               struct dnode_of_data *dn, pgoff_t index, int whence)
 {
+       block_t blkaddr = f2fs_data_blkaddr(dn);
+       struct inode *inode = mapping->host;
+       bool compressed_cluster = false;
+
+       if (f2fs_compressed_file(inode)) {
+               block_t first_blkaddr = data_blkaddr(dn->inode, dn->node_page,
+                   ALIGN_DOWN(dn->ofs_in_node, F2FS_I(inode)->i_cluster_size));
+
+               compressed_cluster = first_blkaddr == COMPRESS_ADDR;
+       }
+
        switch (whence) {
        case SEEK_DATA:
                if (__is_valid_data_blkaddr(blkaddr))
@@ -404,8 +416,12 @@ static bool __found_offset(struct address_space *mapping, block_t blkaddr,
                if (blkaddr == NEW_ADDR &&
                    xa_get_mark(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY))
                        return true;
+               if (compressed_cluster)
+                       return true;
                break;
        case SEEK_HOLE:
+               if (compressed_cluster)
+                       return false;
                if (blkaddr == NULL_ADDR)
                        return true;
                break;
@@ -474,7 +490,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
                                goto fail;
                        }
 
-                       if (__found_offset(file->f_mapping, blkaddr,
+                       if (__found_offset(file->f_mapping, &dn,
                                                        pgofs, whence)) {
                                f2fs_put_dnode(&dn);
                                goto found;
@@ -590,8 +606,10 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
                f2fs_set_data_blkaddr(dn, NULL_ADDR);
 
                if (__is_valid_data_blkaddr(blkaddr)) {
-                       if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
-                                       DATA_GENERIC_ENHANCE))
+                       if (time_to_inject(sbi, FAULT_BLKADDR_CONSISTENCE))
+                               continue;
+                       if (!f2fs_is_valid_blkaddr_raw(sbi, blkaddr,
+                                               DATA_GENERIC_ENHANCE))
                                continue;
                        if (compressed_cluster)
                                valid_blocks++;
@@ -818,8 +836,6 @@ static bool f2fs_force_buffered_io(struct inode *inode, int rw)
         */
        if (f2fs_sb_has_blkzoned(sbi) && (rw == WRITE))
                return true;
-       if (f2fs_lfs_mode(sbi) && rw == WRITE && F2FS_IO_ALIGNED(sbi))
-               return true;
        if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
                return true;
 
@@ -1192,7 +1208,6 @@ next_dnode:
                        !f2fs_is_valid_blkaddr(sbi, *blkaddr,
                                        DATA_GENERIC_ENHANCE)) {
                        f2fs_put_dnode(&dn);
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                        return -EFSCORRUPTED;
                }
 
@@ -1478,7 +1493,6 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
                if (!f2fs_is_valid_blkaddr(sbi, dn->data_blkaddr,
                                        DATA_GENERIC_ENHANCE)) {
                        ret = -EFSCORRUPTED;
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                        break;
                }
 
@@ -1662,10 +1676,12 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
        }
        filemap_invalidate_unlock(mapping);
        f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
+       if (ret)
+               return ret;
 
        /* write out all moved pages, if possible */
        filemap_invalidate_lock(mapping);
-       filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
+       ret = filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
        truncate_pagecache(inode, offset);
        filemap_invalidate_unlock(mapping);
 
@@ -1731,9 +1747,11 @@ next_alloc:
 
                f2fs_down_write(&sbi->pin_sem);
 
-               f2fs_lock_op(sbi);
-               f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
-               f2fs_unlock_op(sbi);
+               err = f2fs_allocate_pinning_section(sbi);
+               if (err) {
+                       f2fs_up_write(&sbi->pin_sem);
+                       goto out_err;
+               }
 
                map.m_seg_type = CURSEG_COLD_DATA_PINNED;
                err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO);
@@ -2066,7 +2084,8 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
 
        inode_lock(inode);
 
-       if (!f2fs_disable_compressed_file(inode)) {
+       if (!f2fs_disable_compressed_file(inode) ||
+                       f2fs_is_pinned_file(inode)) {
                ret = -EINVAL;
                goto out;
        }
@@ -2243,8 +2262,11 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
        case F2FS_GOING_DOWN_METASYNC:
                /* do checkpoint only */
                ret = f2fs_sync_fs(sb, 1);
-               if (ret)
+               if (ret) {
+                       if (ret == -EIO)
+                               ret = 0;
                        goto out;
+               }
                f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
                break;
        case F2FS_GOING_DOWN_NOSYNC:
@@ -2260,6 +2282,8 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
                set_sbi_flag(sbi, SBI_IS_DIRTY);
                /* do checkpoint only */
                ret = f2fs_sync_fs(sb, 1);
+               if (ret == -EIO)
+                       ret = 0;
                goto out;
        default:
                ret = -EINVAL;
@@ -2578,7 +2602,6 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
                                        .m_may_create = false };
        struct extent_info ei = {};
        pgoff_t pg_start, pg_end, next_pgofs;
-       unsigned int blk_per_seg = sbi->blocks_per_seg;
        unsigned int total = 0, sec_num;
        block_t blk_end = 0;
        bool fragmented = false;
@@ -2687,7 +2710,8 @@ do_map:
                set_inode_flag(inode, FI_SKIP_WRITES);
 
                idx = map.m_lblk;
-               while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
+               while (idx < map.m_lblk + map.m_len &&
+                                               cnt < BLKS_PER_SEG(sbi)) {
                        struct page *page;
 
                        page = f2fs_get_lock_data_page(inode, idx, true);
@@ -2707,7 +2731,7 @@ do_map:
 
                map.m_lblk = idx;
 check:
-               if (map.m_lblk < pg_end && cnt < blk_per_seg)
+               if (map.m_lblk < pg_end && cnt < BLKS_PER_SEG(sbi))
                        goto do_map;
 
                clear_inode_flag(inode, FI_SKIP_WRITES);
@@ -2976,8 +3000,8 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
 
        if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
                        __is_large_section(sbi)) {
-               f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1",
-                         range.dev_num, sbi->s_ndevs, sbi->segs_per_sec);
+               f2fs_warn(sbi, "Can't flush %u in %d for SEGS_PER_SEC %u != 1",
+                         range.dev_num, sbi->s_ndevs, SEGS_PER_SEC(sbi));
                return -EINVAL;
        }
 
@@ -3183,6 +3207,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc)
 static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        __u32 pin;
        int ret = 0;
 
@@ -3192,7 +3217,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
        if (!S_ISREG(inode->i_mode))
                return -EINVAL;
 
-       if (f2fs_readonly(F2FS_I_SB(inode)->sb))
+       if (f2fs_readonly(sbi->sb))
                return -EROFS;
 
        ret = mnt_want_write_file(filp);
@@ -3205,9 +3230,18 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
                clear_inode_flag(inode, FI_PIN_FILE);
                f2fs_i_gc_failures_write(inode, 0);
                goto done;
+       } else if (f2fs_is_pinned_file(inode)) {
+               goto done;
        }
 
-       if (f2fs_should_update_outplace(inode, NULL)) {
+       if (f2fs_sb_has_blkzoned(sbi) && F2FS_HAS_BLOCKS(inode)) {
+               ret = -EFBIG;
+               goto out;
+       }
+
+       /* Let's allow file pinning on zoned device. */
+       if (!f2fs_sb_has_blkzoned(sbi) &&
+           f2fs_should_update_outplace(inode, NULL)) {
                ret = -EINVAL;
                goto out;
        }
@@ -3229,7 +3263,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
        set_inode_flag(inode, FI_PIN_FILE);
        ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
 done:
-       f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
+       f2fs_update_time(sbi, REQ_TIME);
 out:
        inode_unlock(inode);
        mnt_drop_write_file(filp);
@@ -3438,10 +3472,8 @@ static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
                if (!__is_valid_data_blkaddr(blkaddr))
                        continue;
                if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
-                                       DATA_GENERIC_ENHANCE))) {
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
+                                       DATA_GENERIC_ENHANCE)))
                        return -EFSCORRUPTED;
-               }
        }
 
        while (count) {
@@ -3588,10 +3620,10 @@ out:
        return ret;
 }
 
-static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
+static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count,
+               unsigned int *reserved_blocks)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
-       unsigned int reserved_blocks = 0;
        int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
        block_t blkaddr;
        int i;
@@ -3603,10 +3635,8 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
                if (!__is_valid_data_blkaddr(blkaddr))
                        continue;
                if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
-                                       DATA_GENERIC_ENHANCE))) {
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
+                                       DATA_GENERIC_ENHANCE)))
                        return -EFSCORRUPTED;
-               }
        }
 
        while (count) {
@@ -3614,40 +3644,53 @@ static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
                blkcnt_t reserved;
                int ret;
 
-               for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
-                       blkaddr = f2fs_data_blkaddr(dn);
+               for (i = 0; i < cluster_size; i++) {
+                       blkaddr = data_blkaddr(dn->inode, dn->node_page,
+                                               dn->ofs_in_node + i);
 
                        if (i == 0) {
-                               if (blkaddr == COMPRESS_ADDR)
-                                       continue;
-                               dn->ofs_in_node += cluster_size;
-                               goto next;
+                               if (blkaddr != COMPRESS_ADDR) {
+                                       dn->ofs_in_node += cluster_size;
+                                       goto next;
+                               }
+                               continue;
                        }
 
-                       if (__is_valid_data_blkaddr(blkaddr)) {
+                       /*
+                        * compressed cluster was not released due to it
+                        * fails in release_compress_blocks(), so NEW_ADDR
+                        * is a possible case.
+                        */
+                       if (blkaddr == NEW_ADDR ||
+                               __is_valid_data_blkaddr(blkaddr)) {
                                compr_blocks++;
                                continue;
                        }
-
-                       f2fs_set_data_blkaddr(dn, NEW_ADDR);
                }
 
                reserved = cluster_size - compr_blocks;
-               ret = inc_valid_block_count(sbi, dn->inode, &reserved);
-               if (ret)
+
+               /* for the case all blocks in cluster were reserved */
+               if (reserved == 1)
+                       goto next;
+
+               ret = inc_valid_block_count(sbi, dn->inode, &reserved, false);
+               if (unlikely(ret))
                        return ret;
 
-               if (reserved != cluster_size - compr_blocks)
-                       return -ENOSPC;
+               for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
+                       if (f2fs_data_blkaddr(dn) == NULL_ADDR)
+                               f2fs_set_data_blkaddr(dn, NEW_ADDR);
+               }
 
                f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
 
-               reserved_blocks += reserved;
+               *reserved_blocks += reserved;
 next:
                count -= cluster_size;
        }
 
-       return reserved_blocks;
+       return 0;
 }
 
 static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
@@ -3671,9 +3714,6 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
        if (ret)
                return ret;
 
-       if (atomic_read(&F2FS_I(inode)->i_compr_blocks))
-               goto out;
-
        f2fs_balance_fs(sbi, true);
 
        inode_lock(inode);
@@ -3683,6 +3723,9 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
                goto unlock_inode;
        }
 
+       if (atomic_read(&F2FS_I(inode)->i_compr_blocks))
+               goto unlock_inode;
+
        f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
        filemap_invalidate_lock(inode->i_mapping);
 
@@ -3708,7 +3751,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
                count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
                count = round_up(count, F2FS_I(inode)->i_cluster_size);
 
-               ret = reserve_compress_blocks(&dn, count);
+               ret = reserve_compress_blocks(&dn, count, &reserved_blocks);
 
                f2fs_put_dnode(&dn);
 
@@ -3716,23 +3759,21 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
                        break;
 
                page_idx += count;
-               reserved_blocks += ret;
        }
 
        filemap_invalidate_unlock(inode->i_mapping);
        f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 
-       if (ret >= 0) {
+       if (!ret) {
                clear_inode_flag(inode, FI_COMPRESS_RELEASED);
                inode_set_ctime_current(inode);
                f2fs_mark_inode_dirty_sync(inode, true);
        }
 unlock_inode:
        inode_unlock(inode);
-out:
        mnt_drop_write_file(filp);
 
-       if (ret >= 0) {
+       if (!ret) {
                ret = put_user(reserved_blocks, (u64 __user *)arg);
        } else if (reserved_blocks &&
                        atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
@@ -3877,8 +3918,6 @@ static int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
                                                DATA_GENERIC_ENHANCE)) {
                                ret = -EFSCORRUPTED;
                                f2fs_put_dnode(&dn);
-                               f2fs_handle_error(sbi,
-                                               ERROR_INVALID_BLKADDR);
                                goto out;
                        }
 
@@ -3981,16 +4020,20 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
                                sizeof(option)))
                return -EFAULT;
 
-       if (!f2fs_compressed_file(inode) ||
-                       option.log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
-                       option.log_cluster_size > MAX_COMPRESS_LOG_SIZE ||
-                       option.algorithm >= COMPRESS_MAX)
+       if (option.log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
+               option.log_cluster_size > MAX_COMPRESS_LOG_SIZE ||
+               option.algorithm >= COMPRESS_MAX)
                return -EINVAL;
 
        file_start_write(filp);
        inode_lock(inode);
 
        f2fs_down_write(&F2FS_I(inode)->i_sem);
+       if (!f2fs_compressed_file(inode)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) {
                ret = -EBUSY;
                goto out;
@@ -4066,7 +4109,6 @@ static int f2fs_ioc_decompress_file(struct file *filp)
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct f2fs_inode_info *fi = F2FS_I(inode);
        pgoff_t page_idx = 0, last_idx;
-       unsigned int blk_per_seg = sbi->blocks_per_seg;
        int cluster_size = fi->i_cluster_size;
        int count, ret;
 
@@ -4110,7 +4152,7 @@ static int f2fs_ioc_decompress_file(struct file *filp)
                if (ret < 0)
                        break;
 
-               if (get_dirty_pages(inode) >= blk_per_seg) {
+               if (get_dirty_pages(inode) >= BLKS_PER_SEG(sbi)) {
                        ret = filemap_fdatawrite(inode->i_mapping);
                        if (ret < 0)
                                break;
@@ -4145,7 +4187,6 @@ static int f2fs_ioc_compress_file(struct file *filp)
        struct inode *inode = file_inode(filp);
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        pgoff_t page_idx = 0, last_idx;
-       unsigned int blk_per_seg = sbi->blocks_per_seg;
        int cluster_size = F2FS_I(inode)->i_cluster_size;
        int count, ret;
 
@@ -4188,7 +4229,7 @@ static int f2fs_ioc_compress_file(struct file *filp)
                if (ret < 0)
                        break;
 
-               if (get_dirty_pages(inode) >= blk_per_seg) {
+               if (get_dirty_pages(inode) >= BLKS_PER_SEG(sbi)) {
                        ret = filemap_fdatawrite(inode->i_mapping);
                        if (ret < 0)
                                break;
index a079eebfb080beba723be99e0db95203d6815c8f..8852814dab7f625a9e01032892ed586ad86f26f5 100644 (file)
@@ -259,7 +259,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
                p->ofs_unit = 1;
        } else {
                p->gc_mode = select_gc_type(sbi, gc_type);
-               p->ofs_unit = sbi->segs_per_sec;
+               p->ofs_unit = SEGS_PER_SEC(sbi);
                if (__is_large_section(sbi)) {
                        p->dirty_bitmap = dirty_i->dirty_secmap;
                        p->max_search = count_bits(p->dirty_bitmap,
@@ -280,11 +280,11 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
                        p->max_search > sbi->max_victim_search)
                p->max_search = sbi->max_victim_search;
 
-       /* let's select beginning hot/small space first in no_heap mode*/
+       /* let's select beginning hot/small space first*/
        if (f2fs_need_rand_seg(sbi))
-               p->offset = get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec);
-       else if (test_opt(sbi, NOHEAP) &&
-               (type == CURSEG_HOT_DATA || IS_NODESEG(type)))
+               p->offset = get_random_u32_below(MAIN_SECS(sbi) *
+                                               SEGS_PER_SEC(sbi));
+       else if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
                p->offset = 0;
        else
                p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
@@ -295,13 +295,13 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
 {
        /* SSR allocates in a segment unit */
        if (p->alloc_mode == SSR)
-               return sbi->blocks_per_seg;
+               return BLKS_PER_SEG(sbi);
        else if (p->alloc_mode == AT_SSR)
                return UINT_MAX;
 
        /* LFS */
        if (p->gc_mode == GC_GREEDY)
-               return 2 * sbi->blocks_per_seg * p->ofs_unit;
+               return SEGS_TO_BLKS(sbi, 2 * p->ofs_unit);
        else if (p->gc_mode == GC_CB)
                return UINT_MAX;
        else if (p->gc_mode == GC_AT)
@@ -348,7 +348,7 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
        mtime = div_u64(mtime, usable_segs_per_sec);
        vblocks = div_u64(vblocks, usable_segs_per_sec);
 
-       u = (vblocks * 100) >> sbi->log_blocks_per_seg;
+       u = BLKS_TO_SEGS(sbi, vblocks * 100);
 
        /* Handle if the system time has changed by the user */
        if (mtime < sit_i->min_mtime)
@@ -496,9 +496,9 @@ static void add_victim_entry(struct f2fs_sb_info *sbi,
                        return;
        }
 
-       for (i = 0; i < sbi->segs_per_sec; i++)
+       for (i = 0; i < SEGS_PER_SEC(sbi); i++)
                mtime += get_seg_entry(sbi, start + i)->mtime;
-       mtime = div_u64(mtime, sbi->segs_per_sec);
+       mtime = div_u64(mtime, SEGS_PER_SEC(sbi));
 
        /* Handle if the system time has changed by the user */
        if (mtime < sit_i->min_mtime)
@@ -599,7 +599,6 @@ static void atssr_lookup_victim(struct f2fs_sb_info *sbi,
        unsigned long long age;
        unsigned long long max_mtime = sit_i->dirty_max_mtime;
        unsigned long long min_mtime = sit_i->dirty_min_mtime;
-       unsigned int seg_blocks = sbi->blocks_per_seg;
        unsigned int vblocks;
        unsigned int dirty_threshold = max(am->max_candidate_count,
                                        am->candidate_ratio *
@@ -629,7 +628,7 @@ next_node:
        f2fs_bug_on(sbi, !vblocks);
 
        /* rare case */
-       if (vblocks == seg_blocks)
+       if (vblocks == BLKS_PER_SEG(sbi))
                goto skip_node;
 
        iter++;
@@ -755,7 +754,7 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,
        int ret = 0;
 
        mutex_lock(&dirty_i->seglist_lock);
-       last_segment = MAIN_SECS(sbi) * sbi->segs_per_sec;
+       last_segment = MAIN_SECS(sbi) * SEGS_PER_SEC(sbi);
 
        p.alloc_mode = alloc_mode;
        p.age = age;
@@ -896,7 +895,7 @@ next:
                        else
                                sm->last_victim[p.gc_mode] = segno + p.ofs_unit;
                        sm->last_victim[p.gc_mode] %=
-                               (MAIN_SECS(sbi) * sbi->segs_per_sec);
+                               (MAIN_SECS(sbi) * SEGS_PER_SEC(sbi));
                        break;
                }
        }
@@ -1184,7 +1183,6 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
                .op_flags = 0,
                .encrypted_page = NULL,
                .in_list = 0,
-               .retry = 0,
        };
        int err;
 
@@ -1197,7 +1195,6 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
                if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE_READ))) {
                        err = -EFSCORRUPTED;
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                        goto put_page;
                }
                goto got_it;
@@ -1216,7 +1213,6 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
        if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
                                                DATA_GENERIC_ENHANCE))) {
                err = -EFSCORRUPTED;
-               f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                goto put_page;
        }
 got_it:
@@ -1273,7 +1269,6 @@ static int move_data_block(struct inode *inode, block_t bidx,
                .op_flags = 0,
                .encrypted_page = NULL,
                .in_list = 0,
-               .retry = 0,
        };
        struct dnode_of_data dn;
        struct f2fs_summary sum;
@@ -1364,8 +1359,13 @@ static int move_data_block(struct inode *inode, block_t bidx,
        set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
 
        /* allocate block address */
-       f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
+       err = f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
                                &sum, type, NULL);
+       if (err) {
+               f2fs_put_page(mpage, 1);
+               /* filesystem should shutdown, no need to recovery block */
+               goto up_out;
+       }
 
        fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
                                newaddr, FGP_LOCK | FGP_CREAT, GFP_NOFS);
@@ -1393,18 +1393,12 @@ static int move_data_block(struct inode *inode, block_t bidx,
        fio.op_flags = REQ_SYNC;
        fio.new_blkaddr = newaddr;
        f2fs_submit_page_write(&fio);
-       if (fio.retry) {
-               err = -EAGAIN;
-               if (PageWriteback(fio.encrypted_page))
-                       end_page_writeback(fio.encrypted_page);
-               goto put_page_out;
-       }
 
        f2fs_update_iostat(fio.sbi, NULL, FS_GC_DATA_IO, F2FS_BLKSIZE);
 
        f2fs_update_data_blkaddr(&dn, newaddr);
        set_inode_flag(inode, FI_APPEND_WRITE);
-put_page_out:
+
        f2fs_put_page(fio.encrypted_page, 1);
 recover_block:
        if (err)
@@ -1678,7 +1672,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
        struct f2fs_summary_block *sum;
        struct blk_plug plug;
        unsigned int segno = start_segno;
-       unsigned int end_segno = start_segno + sbi->segs_per_sec;
+       unsigned int end_segno = start_segno + SEGS_PER_SEC(sbi);
        int seg_freed = 0, migrated = 0;
        unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
                                                SUM_TYPE_DATA : SUM_TYPE_NODE;
@@ -1686,7 +1680,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
        int submitted = 0;
 
        if (__is_large_section(sbi))
-               end_segno = rounddown(end_segno, sbi->segs_per_sec);
+               end_segno = rounddown(end_segno, SEGS_PER_SEC(sbi));
 
        /*
         * zone-capacity can be less than zone-size in zoned devices,
@@ -1694,7 +1688,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
         * calculate the end segno in the zone which can be garbage collected
         */
        if (f2fs_sb_has_blkzoned(sbi))
-               end_segno -= sbi->segs_per_sec -
+               end_segno -= SEGS_PER_SEC(sbi) -
                                        f2fs_usable_segs_in_sec(sbi, segno);
 
        sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type);
@@ -1983,10 +1977,43 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi)
        init_atgc_management(sbi);
 }
 
+int f2fs_gc_range(struct f2fs_sb_info *sbi,
+               unsigned int start_seg, unsigned int end_seg,
+               bool dry_run, unsigned int dry_run_sections)
+{
+       unsigned int segno;
+       unsigned int gc_secs = dry_run_sections;
+
+       if (unlikely(f2fs_cp_error(sbi)))
+               return -EIO;
+
+       for (segno = start_seg; segno <= end_seg; segno += SEGS_PER_SEC(sbi)) {
+               struct gc_inode_list gc_list = {
+                       .ilist = LIST_HEAD_INIT(gc_list.ilist),
+                       .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS),
+               };
+
+               do_garbage_collect(sbi, segno, &gc_list, FG_GC,
+                                               dry_run_sections == 0);
+               put_gc_inode(&gc_list);
+
+               if (!dry_run && get_valid_blocks(sbi, segno, true))
+                       return -EAGAIN;
+               if (dry_run && dry_run_sections &&
+                   !get_valid_blocks(sbi, segno, true) && --gc_secs == 0)
+                       break;
+
+               if (fatal_signal_pending(current))
+                       return -ERESTARTSYS;
+       }
+
+       return 0;
+}
+
 static int free_segment_range(struct f2fs_sb_info *sbi,
-                               unsigned int secs, bool gc_only)
+                               unsigned int secs, bool dry_run)
 {
-       unsigned int segno, next_inuse, start, end;
+       unsigned int next_inuse, start, end;
        struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
        int gc_mode, gc_type;
        int err = 0;
@@ -1994,7 +2021,7 @@ static int free_segment_range(struct f2fs_sb_info *sbi,
 
        /* Force block allocation for GC */
        MAIN_SECS(sbi) -= secs;
-       start = MAIN_SECS(sbi) * sbi->segs_per_sec;
+       start = MAIN_SECS(sbi) * SEGS_PER_SEC(sbi);
        end = MAIN_SEGS(sbi) - 1;
 
        mutex_lock(&DIRTY_I(sbi)->seglist_lock);
@@ -2008,29 +2035,15 @@ static int free_segment_range(struct f2fs_sb_info *sbi,
        mutex_unlock(&DIRTY_I(sbi)->seglist_lock);
 
        /* Move out cursegs from the target range */
-       for (type = CURSEG_HOT_DATA; type < NR_CURSEG_PERSIST_TYPE; type++)
-               f2fs_allocate_segment_for_resize(sbi, type, start, end);
-
-       /* do GC to move out valid blocks in the range */
-       for (segno = start; segno <= end; segno += sbi->segs_per_sec) {
-               struct gc_inode_list gc_list = {
-                       .ilist = LIST_HEAD_INIT(gc_list.ilist),
-                       .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS),
-               };
-
-               do_garbage_collect(sbi, segno, &gc_list, FG_GC, true);
-               put_gc_inode(&gc_list);
-
-               if (!gc_only && get_valid_blocks(sbi, segno, true)) {
-                       err = -EAGAIN;
-                       goto out;
-               }
-               if (fatal_signal_pending(current)) {
-                       err = -ERESTARTSYS;
+       for (type = CURSEG_HOT_DATA; type < NR_CURSEG_PERSIST_TYPE; type++) {
+               err = f2fs_allocate_segment_for_resize(sbi, type, start, end);
+               if (err)
                        goto out;
-               }
        }
-       if (gc_only)
+
+       /* do GC to move out valid blocks in the range */
+       err = f2fs_gc_range(sbi, start, end, dry_run, 0);
+       if (err || dry_run)
                goto out;
 
        stat_inc_cp_call_count(sbi, TOTAL_CALL);
@@ -2056,7 +2069,7 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs)
        int segment_count;
        int segment_count_main;
        long long block_count;
-       int segs = secs * sbi->segs_per_sec;
+       int segs = secs * SEGS_PER_SEC(sbi);
 
        f2fs_down_write(&sbi->sb_lock);
 
@@ -2069,7 +2082,7 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs)
        raw_sb->segment_count = cpu_to_le32(segment_count + segs);
        raw_sb->segment_count_main = cpu_to_le32(segment_count_main + segs);
        raw_sb->block_count = cpu_to_le64(block_count +
-                                       (long long)segs * sbi->blocks_per_seg);
+                       (long long)SEGS_TO_BLKS(sbi, segs));
        if (f2fs_is_multi_device(sbi)) {
                int last_dev = sbi->s_ndevs - 1;
                int dev_segs =
@@ -2084,8 +2097,8 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs)
 
 static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs)
 {
-       int segs = secs * sbi->segs_per_sec;
-       long long blks = (long long)segs * sbi->blocks_per_seg;
+       int segs = secs * SEGS_PER_SEC(sbi);
+       long long blks = SEGS_TO_BLKS(sbi, segs);
        long long user_block_count =
                                le64_to_cpu(F2FS_CKPT(sbi)->user_block_count);
 
@@ -2127,7 +2140,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
                int last_dev = sbi->s_ndevs - 1;
                __u64 last_segs = FDEV(last_dev).total_segments;
 
-               if (block_count + last_segs * sbi->blocks_per_seg <=
+               if (block_count + SEGS_TO_BLKS(sbi, last_segs) <=
                                                                old_block_count)
                        return -EINVAL;
        }
index 28a00942802c216cc77ad3d5910f14329e3e2b60..9c0d06c4d19a91f61757c4d9a5babbeb4a07729d 100644 (file)
@@ -96,7 +96,7 @@ static inline block_t free_segs_blk_count(struct f2fs_sb_info *sbi)
        if (f2fs_sb_has_blkzoned(sbi))
                return free_segs_blk_count_zoned(sbi);
 
-       return free_segments(sbi) << sbi->log_blocks_per_seg;
+       return SEGS_TO_BLKS(sbi, free_segments(sbi));
 }
 
 static inline block_t free_user_blocks(struct f2fs_sb_info *sbi)
@@ -104,7 +104,7 @@ static inline block_t free_user_blocks(struct f2fs_sb_info *sbi)
        block_t free_blks, ovp_blks;
 
        free_blks = free_segs_blk_count(sbi);
-       ovp_blks = overprovision_segments(sbi) << sbi->log_blocks_per_seg;
+       ovp_blks = SEGS_TO_BLKS(sbi, overprovision_segments(sbi));
 
        if (free_blks < ovp_blks)
                return 0;
index f7f63a567d869d66e024b0334a06e1cc83c8b6f4..e54f8c08bda832b2b25c93495b796fa943a13d8e 100644 (file)
@@ -851,7 +851,7 @@ out:
 
 static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
                          struct file *file, umode_t mode, bool is_whiteout,
-                         struct inode **new_inode)
+                         struct inode **new_inode, struct f2fs_filename *fname)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
        struct inode *inode;
@@ -879,7 +879,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
        if (err)
                goto out;
 
-       err = f2fs_do_tmpfile(inode, dir);
+       err = f2fs_do_tmpfile(inode, dir, fname);
        if (err)
                goto release_out;
 
@@ -930,22 +930,24 @@ static int f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
        if (!f2fs_is_checkpoint_ready(sbi))
                return -ENOSPC;
 
-       err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL);
+       err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL, NULL);
 
        return finish_open_simple(file, err);
 }
 
 static int f2fs_create_whiteout(struct mnt_idmap *idmap,
-                               struct inode *dir, struct inode **whiteout)
+                               struct inode *dir, struct inode **whiteout,
+                               struct f2fs_filename *fname)
 {
-       return __f2fs_tmpfile(idmap, dir, NULL,
-                               S_IFCHR | WHITEOUT_MODE, true, whiteout);
+       return __f2fs_tmpfile(idmap, dir, NULL, S_IFCHR | WHITEOUT_MODE,
+                                               true, whiteout, fname);
 }
 
 int f2fs_get_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
                     struct inode **new_inode)
 {
-       return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG, false, new_inode);
+       return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG,
+                               false, new_inode, NULL);
 }
 
 static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
@@ -989,7 +991,14 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
        }
 
        if (flags & RENAME_WHITEOUT) {
-               err = f2fs_create_whiteout(idmap, old_dir, &whiteout);
+               struct f2fs_filename fname;
+
+               err = f2fs_setup_filename(old_dir, &old_dentry->d_name,
+                                                       0, &fname);
+               if (err)
+                       return err;
+
+               err = f2fs_create_whiteout(idmap, old_dir, &whiteout, &fname);
                if (err)
                        return err;
        }
@@ -1104,14 +1113,11 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
                iput(whiteout);
        }
 
-       if (old_is_dir) {
-               if (old_dir_entry)
-                       f2fs_set_link(old_inode, old_dir_entry,
-                                               old_dir_page, new_dir);
-               else
-                       f2fs_put_page(old_dir_page, 0);
+       if (old_dir_entry)
+               f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir);
+       if (old_is_dir)
                f2fs_i_links_write(old_dir, false);
-       }
+
        if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
                f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
                if (S_ISDIR(old_inode->i_mode))
index 9b546fd2101004c306d83bb5a33a11e53a88b7c7..b3de6d6cdb02199c13808bfaabbc8e742b52a067 100644 (file)
@@ -852,21 +852,29 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
 
        if (is_inode_flag_set(dn->inode, FI_COMPRESSED_FILE) &&
                                        f2fs_sb_has_readonly(sbi)) {
-               unsigned int c_len = f2fs_cluster_blocks_are_contiguous(dn);
+               unsigned int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
+               unsigned int ofs_in_node = dn->ofs_in_node;
+               pgoff_t fofs = index;
+               unsigned int c_len;
                block_t blkaddr;
 
+               /* should align fofs and ofs_in_node to cluster_size */
+               if (fofs % cluster_size) {
+                       fofs = round_down(fofs, cluster_size);
+                       ofs_in_node = round_down(ofs_in_node, cluster_size);
+               }
+
+               c_len = f2fs_cluster_blocks_are_contiguous(dn, ofs_in_node);
                if (!c_len)
                        goto out;
 
-               blkaddr = f2fs_data_blkaddr(dn);
+               blkaddr = data_blkaddr(dn->inode, dn->node_page, ofs_in_node);
                if (blkaddr == COMPRESS_ADDR)
                        blkaddr = data_blkaddr(dn->inode, dn->node_page,
-                                               dn->ofs_in_node + 1);
+                                               ofs_in_node + 1);
 
                f2fs_update_read_extent_tree_range_compressed(dn->inode,
-                                       index, blkaddr,
-                                       F2FS_I(dn->inode)->i_cluster_size,
-                                       c_len);
+                                       fofs, blkaddr, cluster_size, c_len);
        }
 out:
        return 0;
@@ -1919,7 +1927,7 @@ void f2fs_flush_inline_data(struct f2fs_sb_info *sbi)
                for (i = 0; i < nr_folios; i++) {
                        struct page *page = &fbatch.folios[i]->page;
 
-                       if (!IS_DNODE(page))
+                       if (!IS_INODE(page))
                                continue;
 
                        lock_page(page);
@@ -2841,7 +2849,7 @@ int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
        int i, idx, last_offset, nrpages;
 
        /* scan the node segment */
-       last_offset = sbi->blocks_per_seg;
+       last_offset = BLKS_PER_SEG(sbi);
        addr = START_BLOCK(sbi, segno);
        sum_entry = &sum->entries[0];
 
@@ -3158,7 +3166,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
        if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG))
                return 0;
 
-       nat_bits_addr = __start_cp_addr(sbi) + sbi->blocks_per_seg -
+       nat_bits_addr = __start_cp_addr(sbi) + BLKS_PER_SEG(sbi) -
                                                nm_i->nat_bits_blocks;
        for (i = 0; i < nm_i->nat_bits_blocks; i++) {
                struct page *page;
index 5bd16a95eef8f13bb5465faa166c2e74d7bc838c..6aea13024ac1659f83fe412849bbb64cb0ec2abd 100644 (file)
@@ -208,10 +208,10 @@ static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
 
        block_addr = (pgoff_t)(nm_i->nat_blkaddr +
                (block_off << 1) -
-               (block_off & (sbi->blocks_per_seg - 1)));
+               (block_off & (BLKS_PER_SEG(sbi) - 1)));
 
        if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
-               block_addr += sbi->blocks_per_seg;
+               block_addr += BLKS_PER_SEG(sbi);
 
        return block_addr;
 }
index d0f24ccbd1ac6e99d2b67ec2f6529c274ee583c4..e7bf15b8240ae613ec82f8b2be4049c77dccdce9 100644 (file)
@@ -354,7 +354,7 @@ static unsigned int adjust_por_ra_blocks(struct f2fs_sb_info *sbi,
        if (blkaddr + 1 == next_blkaddr)
                ra_blocks = min_t(unsigned int, RECOVERY_MAX_RA_BLOCKS,
                                                        ra_blocks * 2);
-       else if (next_blkaddr % sbi->blocks_per_seg)
+       else if (next_blkaddr % BLKS_PER_SEG(sbi))
                ra_blocks = max_t(unsigned int, RECOVERY_MIN_RA_BLOCKS,
                                                        ra_blocks / 2);
        return ra_blocks;
@@ -611,6 +611,19 @@ truncate_out:
        return 0;
 }
 
+static int f2fs_reserve_new_block_retry(struct dnode_of_data *dn)
+{
+       int i, err = 0;
+
+       for (i = DEFAULT_FAILURE_RETRY_COUNT; i > 0; i--) {
+               err = f2fs_reserve_new_block(dn);
+               if (!err)
+                       break;
+       }
+
+       return err;
+}
+
 static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                                        struct page *page)
 {
@@ -680,14 +693,12 @@ retry_dn:
                if (__is_valid_data_blkaddr(src) &&
                        !f2fs_is_valid_blkaddr(sbi, src, META_POR)) {
                        err = -EFSCORRUPTED;
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                        goto err;
                }
 
                if (__is_valid_data_blkaddr(dest) &&
                        !f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
                        err = -EFSCORRUPTED;
-                       f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
                        goto err;
                }
 
@@ -712,14 +723,8 @@ retry_dn:
                 */
                if (dest == NEW_ADDR) {
                        f2fs_truncate_data_blocks_range(&dn, 1);
-                       do {
-                               err = f2fs_reserve_new_block(&dn);
-                               if (err == -ENOSPC) {
-                                       f2fs_bug_on(sbi, 1);
-                                       break;
-                               }
-                       } while (err &&
-                               IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION));
+
+                       err = f2fs_reserve_new_block_retry(&dn);
                        if (err)
                                goto err;
                        continue;
@@ -727,16 +732,8 @@ retry_dn:
 
                /* dest is valid block, try to recover from src to dest */
                if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
-
                        if (src == NULL_ADDR) {
-                               do {
-                                       err = f2fs_reserve_new_block(&dn);
-                                       if (err == -ENOSPC) {
-                                               f2fs_bug_on(sbi, 1);
-                                               break;
-                                       }
-                               } while (err &&
-                                       IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION));
+                               err = f2fs_reserve_new_block_retry(&dn);
                                if (err)
                                        goto err;
                        }
@@ -756,8 +753,6 @@ retry_prev:
                                f2fs_err(sbi, "Inconsistent dest blkaddr:%u, ino:%lu, ofs:%u",
                                        dest, inode->i_ino, dn.ofs_in_node);
                                err = -EFSCORRUPTED;
-                               f2fs_handle_error(sbi,
-                                               ERROR_INVALID_BLKADDR);
                                goto err;
                        }
 
@@ -852,7 +847,7 @@ next:
                f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks);
        }
        if (!err)
-               f2fs_allocate_new_segments(sbi);
+               err = f2fs_allocate_new_segments(sbi);
        return err;
 }
 
@@ -864,7 +859,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
        int ret = 0;
        unsigned long s_flags = sbi->sb->s_flags;
        bool need_writecp = false;
-       bool fix_curseg_write_pointer = false;
 
        if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE))
                f2fs_info(sbi, "recover fsync data on readonly fs");
@@ -895,8 +889,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
        else
                f2fs_bug_on(sbi, sbi->sb->s_flags & SB_ACTIVE);
 skip:
-       fix_curseg_write_pointer = !check_only || list_empty(&inode_list);
-
        destroy_fsync_dnodes(&inode_list, err);
        destroy_fsync_dnodes(&tmp_inode_list, err);
 
@@ -914,11 +906,13 @@ skip:
         * and the f2fs is not read only, check and fix zoned block devices'
         * write pointer consistency.
         */
-       if (!err && fix_curseg_write_pointer && !f2fs_readonly(sbi->sb) &&
-                       f2fs_sb_has_blkzoned(sbi)) {
-               err = f2fs_fix_curseg_write_pointer(sbi);
-               if (!err)
-                       err = f2fs_check_write_pointer(sbi);
+       if (f2fs_sb_has_blkzoned(sbi) && !f2fs_readonly(sbi->sb)) {
+               int err2 = f2fs_fix_curseg_write_pointer(sbi);
+
+               if (!err2)
+                       err2 = f2fs_check_write_pointer(sbi);
+               if (err2)
+                       err = err2;
                ret = err;
        }
 
index e1065ba702076131067091fe173b19edab41b5d1..4fd76e867e0a2efa772fda10e9f01a870c2edcd2 100644 (file)
@@ -192,6 +192,9 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
        if (!f2fs_is_atomic_file(inode))
                return;
 
+       if (clean)
+               truncate_inode_pages_final(inode->i_mapping);
+
        release_atomic_write_cnt(inode);
        clear_inode_flag(inode, FI_ATOMIC_COMMITTED);
        clear_inode_flag(inode, FI_ATOMIC_REPLACE);
@@ -201,7 +204,6 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
        F2FS_I(inode)->atomic_write_task = NULL;
 
        if (clean) {
-               truncate_inode_pages_final(inode->i_mapping);
                f2fs_i_size_write(inode, fi->original_i_size);
                fi->original_i_size = 0;
        }
@@ -248,7 +250,7 @@ retry:
        } else {
                blkcnt_t count = 1;
 
-               err = inc_valid_block_count(sbi, inode, &count);
+               err = inc_valid_block_count(sbi, inode, &count, true);
                if (err) {
                        f2fs_put_dnode(&dn);
                        return err;
@@ -334,8 +336,6 @@ static int __f2fs_commit_atomic_write(struct inode *inode)
                                        DATA_GENERIC_ENHANCE)) {
                                f2fs_put_dnode(&dn);
                                ret = -EFSCORRUPTED;
-                               f2fs_handle_error(sbi,
-                                               ERROR_INVALID_BLKADDR);
                                goto out;
                        }
 
@@ -400,6 +400,9 @@ int f2fs_commit_atomic_write(struct inode *inode)
  */
 void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
 {
+       if (f2fs_cp_error(sbi))
+               return;
+
        if (time_to_inject(sbi, FAULT_CHECKPOINT))
                f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT);
 
@@ -448,8 +451,8 @@ static inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi)
        unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES);
        unsigned int meta = get_pages(sbi, F2FS_DIRTY_META);
        unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
-       unsigned int threshold = sbi->blocks_per_seg * factor *
-                                       DEFAULT_DIRTY_THRESHOLD;
+       unsigned int threshold =
+               SEGS_TO_BLKS(sbi, (factor * DEFAULT_DIRTY_THRESHOLD));
        unsigned int global_threshold = threshold * 3 / 2;
 
        if (dents >= threshold || qdata >= threshold ||
@@ -872,7 +875,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
 {
        int ovp_hole_segs =
                (overprovision_segments(sbi) - reserved_segments(sbi));
-       block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg;
+       block_t ovp_holes = SEGS_TO_BLKS(sbi, ovp_hole_segs);
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        block_t holes[2] = {0, 0};      /* DATA and NODE */
        block_t unusable;
@@ -901,11 +904,16 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable)
 {
        int ovp_hole_segs =
                (overprovision_segments(sbi) - reserved_segments(sbi));
+
+       if (F2FS_OPTION(sbi).unusable_cap_perc == 100)
+               return 0;
        if (unusable > F2FS_OPTION(sbi).unusable_cap)
                return -EAGAIN;
        if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) &&
                dirty_segments(sbi) > ovp_hole_segs)
                return -EAGAIN;
+       if (has_not_enough_free_secs(sbi, 0, 0))
+               return -EAGAIN;
        return 0;
 }
 
@@ -1132,8 +1140,7 @@ static void __check_sit_bitmap(struct f2fs_sb_info *sbi,
        struct seg_entry *sentry;
        unsigned int segno;
        block_t blk = start;
-       unsigned long offset, size, max_blocks = sbi->blocks_per_seg;
-       unsigned long *map;
+       unsigned long offset, size, *map;
 
        while (blk < end) {
                segno = GET_SEGNO(sbi, blk);
@@ -1143,7 +1150,7 @@ static void __check_sit_bitmap(struct f2fs_sb_info *sbi,
                if (end < START_BLOCK(sbi, segno + 1))
                        size = GET_BLKOFF_FROM_SEG0(sbi, end);
                else
-                       size = max_blocks;
+                       size = BLKS_PER_SEG(sbi);
                map = (unsigned long *)(sentry->cur_valid_map);
                offset = __find_rev_next_bit(map, size, offset);
                f2fs_bug_on(sbi, offset != size);
@@ -2048,7 +2055,6 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
                                                        bool check_only)
 {
        int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
-       int max_blocks = sbi->blocks_per_seg;
        struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start);
        unsigned long *cur_map = (unsigned long *)se->cur_valid_map;
        unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map;
@@ -2060,8 +2066,9 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
        struct list_head *head = &SM_I(sbi)->dcc_info->entry_list;
        int i;
 
-       if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi) ||
-                       !f2fs_block_unit_discard(sbi))
+       if (se->valid_blocks == BLKS_PER_SEG(sbi) ||
+           !f2fs_hw_support_discard(sbi) ||
+           !f2fs_block_unit_discard(sbi))
                return false;
 
        if (!force) {
@@ -2078,13 +2085,14 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
 
        while (force || SM_I(sbi)->dcc_info->nr_discards <=
                                SM_I(sbi)->dcc_info->max_discards) {
-               start = __find_rev_next_bit(dmap, max_blocks, end + 1);
-               if (start >= max_blocks)
+               start = __find_rev_next_bit(dmap, BLKS_PER_SEG(sbi), end + 1);
+               if (start >= BLKS_PER_SEG(sbi))
                        break;
 
-               end = __find_rev_next_zero_bit(dmap, max_blocks, start + 1);
-               if (force && start && end != max_blocks
-                                       && (end - start) < cpc->trim_minlen)
+               end = __find_rev_next_zero_bit(dmap,
+                                               BLKS_PER_SEG(sbi), start + 1);
+               if (force && start && end != BLKS_PER_SEG(sbi) &&
+                   (end - start) < cpc->trim_minlen)
                        continue;
 
                if (check_only)
@@ -2166,8 +2174,8 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
                                                                start + 1);
 
                if (section_alignment) {
-                       start = rounddown(start, sbi->segs_per_sec);
-                       end = roundup(end, sbi->segs_per_sec);
+                       start = rounddown(start, SEGS_PER_SEC(sbi));
+                       end = roundup(end, SEGS_PER_SEC(sbi));
                }
 
                for (i = start; i < end; i++) {
@@ -2186,7 +2194,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
                if (!f2fs_sb_has_blkzoned(sbi) &&
                    (!f2fs_lfs_mode(sbi) || !__is_large_section(sbi))) {
                        f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
-                               (end - start) << sbi->log_blocks_per_seg);
+                               SEGS_TO_BLKS(sbi, end - start));
                        continue;
                }
 next:
@@ -2195,9 +2203,9 @@ next:
                if (!IS_CURSEC(sbi, secno) &&
                        !get_valid_blocks(sbi, start, true))
                        f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno),
-                               sbi->segs_per_sec << sbi->log_blocks_per_seg);
+                                               BLKS_PER_SEC(sbi));
 
-               start = start_segno + sbi->segs_per_sec;
+               start = start_segno + SEGS_PER_SEC(sbi);
                if (start < end)
                        goto next;
                else
@@ -2216,7 +2224,7 @@ next:
 find_next:
                if (is_valid) {
                        next_pos = find_next_zero_bit_le(entry->discard_map,
-                                       sbi->blocks_per_seg, cur_pos);
+                                               BLKS_PER_SEG(sbi), cur_pos);
                        len = next_pos - cur_pos;
 
                        if (f2fs_sb_has_blkzoned(sbi) ||
@@ -2228,13 +2236,13 @@ find_next:
                        total_len += len;
                } else {
                        next_pos = find_next_bit_le(entry->discard_map,
-                                       sbi->blocks_per_seg, cur_pos);
+                                               BLKS_PER_SEG(sbi), cur_pos);
                }
 skip:
                cur_pos = next_pos;
                is_valid = !is_valid;
 
-               if (cur_pos < sbi->blocks_per_seg)
+               if (cur_pos < BLKS_PER_SEG(sbi))
                        goto find_next;
 
                release_discard_addr(entry);
@@ -2251,6 +2259,12 @@ int f2fs_start_discard_thread(struct f2fs_sb_info *sbi)
        struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
        int err = 0;
 
+       if (f2fs_sb_has_readonly(sbi)) {
+               f2fs_info(sbi,
+                       "Skip to start discard thread for readonly image");
+               return 0;
+       }
+
        if (!f2fs_realtime_discard_enable(sbi))
                return 0;
 
@@ -2283,7 +2297,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
        dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY;
        dcc->discard_io_aware = DPOLICY_IO_AWARE_ENABLE;
        if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
-               dcc->discard_granularity = sbi->blocks_per_seg;
+               dcc->discard_granularity = BLKS_PER_SEG(sbi);
        else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
                dcc->discard_granularity = BLKS_PER_SEC(sbi);
 
@@ -2297,7 +2311,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
        atomic_set(&dcc->queued_discard, 0);
        atomic_set(&dcc->discard_cmd_cnt, 0);
        dcc->nr_discards = 0;
-       dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;
+       dcc->max_discards = SEGS_TO_BLKS(sbi, MAIN_SEGS(sbi));
        dcc->max_discard_request = DEF_MAX_DISCARD_REQUEST;
        dcc->min_discard_issue_time = DEF_MIN_DISCARD_ISSUE_TIME;
        dcc->mid_discard_issue_time = DEF_MID_DISCARD_ISSUE_TIME;
@@ -2405,6 +2419,8 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
 #endif
 
        segno = GET_SEGNO(sbi, blkaddr);
+       if (segno == NULL_SEGNO)
+               return;
 
        se = get_seg_entry(sbi, segno);
        new_vblocks = se->valid_blocks + del;
@@ -2546,7 +2562,7 @@ static unsigned short f2fs_curseg_valid_blocks(struct f2fs_sb_info *sbi, int typ
        struct curseg_info *curseg = CURSEG_I(sbi, type);
 
        if (sbi->ckpt->alloc_type[type] == SSR)
-               return sbi->blocks_per_seg;
+               return BLKS_PER_SEG(sbi);
        return curseg->next_blkoff;
 }
 
@@ -2634,7 +2650,7 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi,
        unsigned int segno = curseg->segno + 1;
        struct free_segmap_info *free_i = FREE_I(sbi);
 
-       if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec)
+       if (segno < MAIN_SEGS(sbi) && segno % SEGS_PER_SEC(sbi))
                return !test_bit(segno, free_i->free_segmap);
        return 0;
 }
@@ -2643,54 +2659,51 @@ static int is_next_segment_free(struct f2fs_sb_info *sbi,
  * Find a new segment from the free segments bitmap to right order
  * This function should be returned with success, otherwise BUG
  */
-static void get_new_segment(struct f2fs_sb_info *sbi,
-                       unsigned int *newseg, bool new_sec, int dir)
+static int get_new_segment(struct f2fs_sb_info *sbi,
+                       unsigned int *newseg, bool new_sec, bool pinning)
 {
        struct free_segmap_info *free_i = FREE_I(sbi);
        unsigned int segno, secno, zoneno;
        unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone;
        unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg);
        unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg);
-       unsigned int left_start = hint;
        bool init = true;
-       int go_left = 0;
        int i;
+       int ret = 0;
 
        spin_lock(&free_i->segmap_lock);
 
-       if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
+       if (time_to_inject(sbi, FAULT_NO_SEGMENT)) {
+               ret = -ENOSPC;
+               goto out_unlock;
+       }
+
+       if (!new_sec && ((*newseg + 1) % SEGS_PER_SEC(sbi))) {
                segno = find_next_zero_bit(free_i->free_segmap,
                        GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1);
                if (segno < GET_SEG_FROM_SEC(sbi, hint + 1))
                        goto got_it;
        }
+
+       /*
+        * If we format f2fs on zoned storage, let's try to get pinned sections
+        * from beginning of the storage, which should be a conventional one.
+        */
+       if (f2fs_sb_has_blkzoned(sbi)) {
+               segno = pinning ? 0 : max(first_zoned_segno(sbi), *newseg);
+               hint = GET_SEC_FROM_SEG(sbi, segno);
+       }
+
 find_other_zone:
        secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint);
        if (secno >= MAIN_SECS(sbi)) {
-               if (dir == ALLOC_RIGHT) {
-                       secno = find_first_zero_bit(free_i->free_secmap,
+               secno = find_first_zero_bit(free_i->free_secmap,
                                                        MAIN_SECS(sbi));
-                       f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi));
-               } else {
-                       go_left = 1;
-                       left_start = hint - 1;
+               if (secno >= MAIN_SECS(sbi)) {
+                       ret = -ENOSPC;
+                       goto out_unlock;
                }
        }
-       if (go_left == 0)
-               goto skip_left;
-
-       while (test_bit(left_start, free_i->free_secmap)) {
-               if (left_start > 0) {
-                       left_start--;
-                       continue;
-               }
-               left_start = find_first_zero_bit(free_i->free_secmap,
-                                                       MAIN_SECS(sbi));
-               f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi));
-               break;
-       }
-       secno = left_start;
-skip_left:
        segno = GET_SEG_FROM_SEC(sbi, secno);
        zoneno = GET_ZONE_FROM_SEC(sbi, secno);
 
@@ -2701,21 +2714,13 @@ skip_left:
                goto got_it;
        if (zoneno == old_zoneno)
                goto got_it;
-       if (dir == ALLOC_LEFT) {
-               if (!go_left && zoneno + 1 >= total_zones)
-                       goto got_it;
-               if (go_left && zoneno == 0)
-                       goto got_it;
-       }
        for (i = 0; i < NR_CURSEG_TYPE; i++)
                if (CURSEG_I(sbi, i)->zone == zoneno)
                        break;
 
        if (i < NR_CURSEG_TYPE) {
                /* zone is in user, try another */
-               if (go_left)
-                       hint = zoneno * sbi->secs_per_zone - 1;
-               else if (zoneno + 1 >= total_zones)
+               if (zoneno + 1 >= total_zones)
                        hint = 0;
                else
                        hint = (zoneno + 1) * sbi->secs_per_zone;
@@ -2725,9 +2730,23 @@ skip_left:
 got_it:
        /* set it as dirty segment in free segmap */
        f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap));
+
+       /* no free section in conventional zone */
+       if (new_sec && pinning &&
+               !f2fs_valid_pinned_area(sbi, START_BLOCK(sbi, segno))) {
+               ret = -EAGAIN;
+               goto out_unlock;
+       }
        __set_inuse(sbi, segno);
        *newseg = segno;
+out_unlock:
        spin_unlock(&free_i->segmap_lock);
+
+       if (ret == -ENOSPC) {
+               f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_NO_SEGMENT);
+               f2fs_bug_on(sbi, 1);
+       }
+       return ret;
 }
 
 static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
@@ -2736,6 +2755,10 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
        struct summary_footer *sum_footer;
        unsigned short seg_type = curseg->seg_type;
 
+       /* only happen when get_new_segment() fails */
+       if (curseg->next_segno == NULL_SEGNO)
+               return;
+
        curseg->inited = true;
        curseg->segno = curseg->next_segno;
        curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
@@ -2761,9 +2784,8 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
 
        sanity_check_seg_type(sbi, seg_type);
        if (f2fs_need_rand_seg(sbi))
-               return get_random_u32_below(MAIN_SECS(sbi) * sbi->segs_per_sec);
+               return get_random_u32_below(MAIN_SECS(sbi) * SEGS_PER_SEC(sbi));
 
-       /* if segs_per_sec is large than 1, we need to keep original policy. */
        if (__is_large_section(sbi))
                return curseg->segno;
 
@@ -2774,8 +2796,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
        if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
                return 0;
 
-       if (test_opt(sbi, NOHEAP) &&
-               (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type)))
+       if (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type))
                return 0;
 
        if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
@@ -2792,30 +2813,31 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
  * Allocate a current working segment.
  * This function always allocates a free segment in LFS manner.
  */
-static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
+static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, type);
-       unsigned short seg_type = curseg->seg_type;
        unsigned int segno = curseg->segno;
-       int dir = ALLOC_LEFT;
+       bool pinning = type == CURSEG_COLD_DATA_PINNED;
+       int ret;
 
        if (curseg->inited)
-               write_sum_page(sbi, curseg->sum_blk,
-                               GET_SUM_BLOCK(sbi, segno));
-       if (seg_type == CURSEG_WARM_DATA || seg_type == CURSEG_COLD_DATA)
-               dir = ALLOC_RIGHT;
-
-       if (test_opt(sbi, NOHEAP))
-               dir = ALLOC_RIGHT;
+               write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, segno));
 
        segno = __get_next_segno(sbi, type);
-       get_new_segment(sbi, &segno, new_sec, dir);
+       ret = get_new_segment(sbi, &segno, new_sec, pinning);
+       if (ret) {
+               if (ret == -ENOSPC)
+                       curseg->segno = NULL_SEGNO;
+               return ret;
+       }
+
        curseg->next_segno = segno;
        reset_curseg(sbi, type, 1);
        curseg->alloc_type = LFS;
        if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
                curseg->fragment_remained_chunk =
                                get_random_u32_inclusive(1, sbi->max_fragment_chunk);
+       return 0;
 }
 
 static int __next_free_blkoff(struct f2fs_sb_info *sbi,
@@ -2831,7 +2853,7 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi,
        for (i = 0; i < entries; i++)
                target_map[i] = ckpt_map[i] | cur_map[i];
 
-       return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);
+       return __find_rev_next_zero_bit(target_map, BLKS_PER_SEG(sbi), start);
 }
 
 static int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi,
@@ -2842,14 +2864,14 @@ static int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi,
 
 bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
 {
-       return __next_free_blkoff(sbi, segno, 0) < sbi->blocks_per_seg;
+       return __next_free_blkoff(sbi, segno, 0) < BLKS_PER_SEG(sbi);
 }
 
 /*
  * This function always allocates a used segment(from dirty seglist) by SSR
  * manner, so it should recover the existing segment information of valid blocks
  */
-static void change_curseg(struct f2fs_sb_info *sbi, int type)
+static int change_curseg(struct f2fs_sb_info *sbi, int type)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, type);
@@ -2874,21 +2896,23 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type)
        if (IS_ERR(sum_page)) {
                /* GC won't be able to use stale summary pages by cp_error */
                memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE);
-               return;
+               return PTR_ERR(sum_page);
        }
        sum_node = (struct f2fs_summary_block *)page_address(sum_page);
        memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
        f2fs_put_page(sum_page, 1);
+       return 0;
 }
 
 static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
                                int alloc_mode, unsigned long long age);
 
-static void get_atssr_segment(struct f2fs_sb_info *sbi, int type,
+static int get_atssr_segment(struct f2fs_sb_info *sbi, int type,
                                        int target_type, int alloc_mode,
                                        unsigned long long age)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, type);
+       int ret = 0;
 
        curseg->seg_type = target_type;
 
@@ -2896,38 +2920,41 @@ static void get_atssr_segment(struct f2fs_sb_info *sbi, int type,
                struct seg_entry *se = get_seg_entry(sbi, curseg->next_segno);
 
                curseg->seg_type = se->type;
-               change_curseg(sbi, type);
+               ret = change_curseg(sbi, type);
        } else {
                /* allocate cold segment by default */
                curseg->seg_type = CURSEG_COLD_DATA;
-               new_curseg(sbi, type, true);
+               ret = new_curseg(sbi, type, true);
        }
        stat_inc_seg_type(sbi, curseg);
+       return ret;
 }
 
-static void __f2fs_init_atgc_curseg(struct f2fs_sb_info *sbi)
+static int __f2fs_init_atgc_curseg(struct f2fs_sb_info *sbi)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC);
+       int ret = 0;
 
        if (!sbi->am.atgc_enabled)
-               return;
+               return 0;
 
        f2fs_down_read(&SM_I(sbi)->curseg_lock);
 
        mutex_lock(&curseg->curseg_mutex);
        down_write(&SIT_I(sbi)->sentry_lock);
 
-       get_atssr_segment(sbi, CURSEG_ALL_DATA_ATGC, CURSEG_COLD_DATA, SSR, 0);
+       ret = get_atssr_segment(sbi, CURSEG_ALL_DATA_ATGC,
+                                       CURSEG_COLD_DATA, SSR, 0);
 
        up_write(&SIT_I(sbi)->sentry_lock);
        mutex_unlock(&curseg->curseg_mutex);
 
        f2fs_up_read(&SM_I(sbi)->curseg_lock);
-
+       return ret;
 }
-void f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi)
+int f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi)
 {
-       __f2fs_init_atgc_curseg(sbi);
+       return __f2fs_init_atgc_curseg(sbi);
 }
 
 static void __f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi, int type)
@@ -3055,11 +3082,12 @@ static bool need_new_seg(struct f2fs_sb_info *sbi, int type)
        return false;
 }
 
-void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
+int f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
                                        unsigned int start, unsigned int end)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, type);
        unsigned int segno;
+       int ret = 0;
 
        f2fs_down_read(&SM_I(sbi)->curseg_lock);
        mutex_lock(&curseg->curseg_mutex);
@@ -3070,9 +3098,9 @@ void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
                goto unlock;
 
        if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0))
-               change_curseg(sbi, type);
+               ret = change_curseg(sbi, type);
        else
-               new_curseg(sbi, type, true);
+               ret = new_curseg(sbi, type, true);
 
        stat_inc_seg_type(sbi, curseg);
 
@@ -3086,45 +3114,84 @@ unlock:
 
        mutex_unlock(&curseg->curseg_mutex);
        f2fs_up_read(&SM_I(sbi)->curseg_lock);
+       return ret;
 }
 
-static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
+static int __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
                                                bool new_sec, bool force)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, type);
        unsigned int old_segno;
+       int err = 0;
+
+       if (type == CURSEG_COLD_DATA_PINNED && !curseg->inited)
+               goto allocate;
 
        if (!force && curseg->inited &&
            !curseg->next_blkoff &&
            !get_valid_blocks(sbi, curseg->segno, new_sec) &&
            !get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))
-               return;
+               return 0;
 
+allocate:
        old_segno = curseg->segno;
-       new_curseg(sbi, type, true);
+       err = new_curseg(sbi, type, true);
+       if (err)
+               return err;
        stat_inc_seg_type(sbi, curseg);
        locate_dirty_segment(sbi, old_segno);
+       return 0;
 }
 
-void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force)
+int f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force)
 {
+       int ret;
+
        f2fs_down_read(&SM_I(sbi)->curseg_lock);
        down_write(&SIT_I(sbi)->sentry_lock);
-       __allocate_new_segment(sbi, type, true, force);
+       ret = __allocate_new_segment(sbi, type, true, force);
        up_write(&SIT_I(sbi)->sentry_lock);
        f2fs_up_read(&SM_I(sbi)->curseg_lock);
+
+       return ret;
 }
 
-void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
+int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi)
+{
+       int err;
+       bool gc_required = true;
+
+retry:
+       f2fs_lock_op(sbi);
+       err = f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
+       f2fs_unlock_op(sbi);
+
+       if (f2fs_sb_has_blkzoned(sbi) && err == -EAGAIN && gc_required) {
+               f2fs_down_write(&sbi->gc_lock);
+               err = f2fs_gc_range(sbi, 0, GET_SEGNO(sbi, FDEV(0).end_blk), true, 1);
+               f2fs_up_write(&sbi->gc_lock);
+
+               gc_required = false;
+               if (!err)
+                       goto retry;
+       }
+
+       return err;
+}
+
+int f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
 {
        int i;
+       int err = 0;
 
        f2fs_down_read(&SM_I(sbi)->curseg_lock);
        down_write(&SIT_I(sbi)->sentry_lock);
        for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++)
-               __allocate_new_segment(sbi, i, false, false);
+               err += __allocate_new_segment(sbi, i, false, false);
        up_write(&SIT_I(sbi)->sentry_lock);
        f2fs_up_read(&SM_I(sbi)->curseg_lock);
+
+       return err;
 }
 
 bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
@@ -3242,8 +3309,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
        end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 :
                                                GET_SEGNO(sbi, end);
        if (need_align) {
-               start_segno = rounddown(start_segno, sbi->segs_per_sec);
-               end_segno = roundup(end_segno + 1, sbi->segs_per_sec) - 1;
+               start_segno = rounddown(start_segno, SEGS_PER_SEC(sbi));
+               end_segno = roundup(end_segno + 1, SEGS_PER_SEC(sbi)) - 1;
        }
 
        cpc.reason = CP_DISCARD;
@@ -3416,7 +3483,14 @@ static void f2fs_randomize_chunk(struct f2fs_sb_info *sbi,
                get_random_u32_inclusive(1, sbi->max_fragment_hole);
 }
 
-void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
+static void reset_curseg_fields(struct curseg_info *curseg)
+{
+       curseg->inited = false;
+       curseg->segno = NULL_SEGNO;
+       curseg->next_segno = 0;
+}
+
+int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
                block_t old_blkaddr, block_t *new_blkaddr,
                struct f2fs_summary *sum, int type,
                struct f2fs_io_info *fio)
@@ -3427,12 +3501,18 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
        bool from_gc = (type == CURSEG_ALL_DATA_ATGC);
        struct seg_entry *se = NULL;
        bool segment_full = false;
+       int ret = 0;
 
        f2fs_down_read(&SM_I(sbi)->curseg_lock);
 
        mutex_lock(&curseg->curseg_mutex);
        down_write(&sit_i->sentry_lock);
 
+       if (curseg->segno == NULL_SEGNO) {
+               ret = -ENOSPC;
+               goto out_err;
+       }
+
        if (from_gc) {
                f2fs_bug_on(sbi, GET_SEGNO(sbi, old_blkaddr) == NULL_SEGNO);
                se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr));
@@ -3441,7 +3521,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
        }
        *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
 
-       f2fs_bug_on(sbi, curseg->next_blkoff >= sbi->blocks_per_seg);
+       f2fs_bug_on(sbi, curseg->next_blkoff >= BLKS_PER_SEG(sbi));
 
        f2fs_wait_discard_bio(sbi, *new_blkaddr);
 
@@ -3470,25 +3550,35 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
         * since SSR needs latest valid block information.
         */
        update_sit_entry(sbi, *new_blkaddr, 1);
-       if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
-               update_sit_entry(sbi, old_blkaddr, -1);
+       update_sit_entry(sbi, old_blkaddr, -1);
 
        /*
         * If the current segment is full, flush it out and replace it with a
         * new segment.
         */
        if (segment_full) {
+               if (type == CURSEG_COLD_DATA_PINNED &&
+                   !((curseg->segno + 1) % sbi->segs_per_sec)) {
+                       reset_curseg_fields(curseg);
+                       goto skip_new_segment;
+               }
+
                if (from_gc) {
-                       get_atssr_segment(sbi, type, se->type,
+                       ret = get_atssr_segment(sbi, type, se->type,
                                                AT_SSR, se->mtime);
                } else {
                        if (need_new_seg(sbi, type))
-                               new_curseg(sbi, type, false);
+                               ret = new_curseg(sbi, type, false);
                        else
-                               change_curseg(sbi, type);
+                               ret = change_curseg(sbi, type);
                        stat_inc_seg_type(sbi, curseg);
                }
+
+               if (ret)
+                       goto out_err;
        }
+
+skip_new_segment:
        /*
         * segment dirty status should be updated after segment allocation,
         * so we just need to update status only one time after previous
@@ -3497,12 +3587,12 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
        locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
        locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
 
-       if (IS_DATASEG(type))
+       if (IS_DATASEG(curseg->seg_type))
                atomic64_inc(&sbi->allocated_data_blocks);
 
        up_write(&sit_i->sentry_lock);
 
-       if (page && IS_NODESEG(type)) {
+       if (page && IS_NODESEG(curseg->seg_type)) {
                fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
 
                f2fs_inode_chksum_set(sbi, page);
@@ -3511,9 +3601,6 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
        if (fio) {
                struct f2fs_bio_info *io;
 
-               if (F2FS_IO_ALIGNED(sbi))
-                       fio->retry = 0;
-
                INIT_LIST_HEAD(&fio->list);
                fio->in_list = 1;
                io = sbi->write_io[fio->type] + fio->temp;
@@ -3523,8 +3610,15 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
        }
 
        mutex_unlock(&curseg->curseg_mutex);
-
        f2fs_up_read(&SM_I(sbi)->curseg_lock);
+       return 0;
+out_err:
+       *new_blkaddr = NULL_ADDR;
+       up_write(&sit_i->sentry_lock);
+       mutex_unlock(&curseg->curseg_mutex);
+       f2fs_up_read(&SM_I(sbi)->curseg_lock);
+       return ret;
+
 }
 
 void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
@@ -3561,21 +3655,25 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
 
        if (keep_order)
                f2fs_down_read(&fio->sbi->io_order_lock);
-reallocate:
-       f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
-                       &fio->new_blkaddr, sum, type, fio);
+
+       if (f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
+                       &fio->new_blkaddr, sum, type, fio)) {
+               if (fscrypt_inode_uses_fs_layer_crypto(fio->page->mapping->host))
+                       fscrypt_finalize_bounce_page(&fio->encrypted_page);
+               if (PageWriteback(fio->page))
+                       end_page_writeback(fio->page);
+               if (f2fs_in_warm_node_list(fio->sbi, fio->page))
+                       f2fs_del_fsync_node_entry(fio->sbi, fio->page);
+               goto out;
+       }
        if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)
                f2fs_invalidate_internal_cache(fio->sbi, fio->old_blkaddr);
 
        /* writeout dirty page into bdev */
        f2fs_submit_page_write(fio);
-       if (fio->retry) {
-               fio->old_blkaddr = fio->new_blkaddr;
-               goto reallocate;
-       }
 
        f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1);
-
+out:
        if (keep_order)
                f2fs_up_read(&fio->sbi->io_order_lock);
 }
@@ -3659,8 +3757,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
        }
 
        if (fio->post_read)
-               invalidate_mapping_pages(META_MAPPING(sbi),
-                               fio->new_blkaddr, fio->new_blkaddr);
+               f2fs_truncate_meta_inode_pages(sbi, fio->new_blkaddr, 1);
 
        stat_inc_inplace_blocks(fio->sbi);
 
@@ -3749,7 +3846,8 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
        /* change the current segment */
        if (segno != curseg->segno) {
                curseg->next_segno = segno;
-               change_curseg(sbi, type);
+               if (change_curseg(sbi, type))
+                       goto out_unlock;
        }
 
        curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
@@ -3775,12 +3873,14 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
        if (recover_curseg) {
                if (old_cursegno != curseg->segno) {
                        curseg->next_segno = old_cursegno;
-                       change_curseg(sbi, type);
+                       if (change_curseg(sbi, type))
+                               goto out_unlock;
                }
                curseg->next_blkoff = old_blkoff;
                curseg->alloc_type = old_alloc_type;
        }
 
+out_unlock:
        up_write(&sit_i->sentry_lock);
        mutex_unlock(&curseg->curseg_mutex);
        f2fs_up_write(&SM_I(sbi)->curseg_lock);
@@ -3850,7 +3950,7 @@ void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
        for (i = 0; i < len; i++)
                f2fs_wait_on_block_writeback(inode, blkaddr + i);
 
-       invalidate_mapping_pages(META_MAPPING(sbi), blkaddr, blkaddr + len - 1);
+       f2fs_truncate_meta_inode_pages(sbi, blkaddr, len);
 }
 
 static int read_compacted_summaries(struct f2fs_sb_info *sbi)
@@ -3892,7 +3992,7 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
                seg_i->next_blkoff = blk_off;
 
                if (seg_i->alloc_type == SSR)
-                       blk_off = sbi->blocks_per_seg;
+                       blk_off = BLKS_PER_SEG(sbi);
 
                for (j = 0; j < blk_off; j++) {
                        struct f2fs_summary *s;
@@ -3960,7 +4060,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
                        struct f2fs_summary *ns = &sum->entries[0];
                        int i;
 
-                       for (i = 0; i < sbi->blocks_per_seg; i++, ns++) {
+                       for (i = 0; i < BLKS_PER_SEG(sbi); i++, ns++) {
                                ns->version = 0;
                                ns->ofs_in_node = 0;
                        }
@@ -4466,7 +4566,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
 #endif
 
        sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
-       sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
+       sit_i->sit_blocks = SEGS_TO_BLKS(sbi, sit_segs);
        sit_i->written_valid_blocks = 0;
        sit_i->bitmap_size = sit_bitmap_size;
        sit_i->dirty_sentries = 0;
@@ -4539,9 +4639,7 @@ static int build_curseg(struct f2fs_sb_info *sbi)
                        array[i].seg_type = CURSEG_COLD_DATA;
                else if (i == CURSEG_ALL_DATA_ATGC)
                        array[i].seg_type = CURSEG_COLD_DATA;
-               array[i].segno = NULL_SEGNO;
-               array[i].next_blkoff = 0;
-               array[i].inited = false;
+               reset_curseg_fields(&array[i]);
        }
        return restore_curseg_summaries(sbi);
 }
@@ -4593,21 +4691,20 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
 
                        sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
 
-                       if (f2fs_block_unit_discard(sbi)) {
-                               /* build discard map only one time */
-                               if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
-                                       memset(se->discard_map, 0xff,
+                       if (!f2fs_block_unit_discard(sbi))
+                               goto init_discard_map_done;
+
+                       /* build discard map only one time */
+                       if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+                               memset(se->discard_map, 0xff,
                                                SIT_VBLOCK_MAP_SIZE);
-                               } else {
-                                       memcpy(se->discard_map,
-                                               se->cur_valid_map,
+                               goto init_discard_map_done;
+                       }
+                       memcpy(se->discard_map, se->cur_valid_map,
                                                SIT_VBLOCK_MAP_SIZE);
-                                       sbi->discard_blks +=
-                                               sbi->blocks_per_seg -
+                       sbi->discard_blks += BLKS_PER_SEG(sbi) -
                                                se->valid_blocks;
-                               }
-                       }
-
+init_discard_map_done:
                        if (__is_large_section(sbi))
                                get_sec_entry(sbi, start)->valid_blocks +=
                                                        se->valid_blocks;
@@ -4747,7 +4844,7 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)
                return;
 
        mutex_lock(&dirty_i->seglist_lock);
-       for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
+       for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) {
                valid_blocks = get_valid_blocks(sbi, segno, true);
                secno = GET_SEC_FROM_SEG(sbi, segno);
 
@@ -4846,7 +4943,7 @@ static int sanity_check_curseg(struct f2fs_sb_info *sbi)
                if (curseg->alloc_type == SSR)
                        continue;
 
-               for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
+               for (blkofs += 1; blkofs < BLKS_PER_SEG(sbi); blkofs++) {
                        if (!f2fs_test_bit(blkofs, se->cur_valid_map))
                                continue;
 out:
@@ -4862,6 +4959,16 @@ out:
 }
 
 #ifdef CONFIG_BLK_DEV_ZONED
+static const char *f2fs_zone_status[BLK_ZONE_COND_OFFLINE + 1] = {
+       [BLK_ZONE_COND_NOT_WP]          = "NOT_WP",
+       [BLK_ZONE_COND_EMPTY]           = "EMPTY",
+       [BLK_ZONE_COND_IMP_OPEN]        = "IMPLICIT_OPEN",
+       [BLK_ZONE_COND_EXP_OPEN]        = "EXPLICIT_OPEN",
+       [BLK_ZONE_COND_CLOSED]          = "CLOSED",
+       [BLK_ZONE_COND_READONLY]        = "READONLY",
+       [BLK_ZONE_COND_FULL]            = "FULL",
+       [BLK_ZONE_COND_OFFLINE]         = "OFFLINE",
+};
 
 static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
                                    struct f2fs_dev_info *fdev,
@@ -4883,14 +4990,19 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
         * Skip check of zones cursegs point to, since
         * fix_curseg_write_pointer() checks them.
         */
-       if (zone_segno >= MAIN_SEGS(sbi) ||
-           IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno)))
+       if (zone_segno >= MAIN_SEGS(sbi))
                return 0;
 
        /*
         * Get # of valid block of the zone.
         */
        valid_block_cnt = get_valid_blocks(sbi, zone_segno, true);
+       if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno))) {
+               f2fs_notice(sbi, "Open zones: valid block[0x%x,0x%x] cond[%s]",
+                               zone_segno, valid_block_cnt,
+                               f2fs_zone_status[zone->cond]);
+               return 0;
+       }
 
        if ((!valid_block_cnt && zone->cond == BLK_ZONE_COND_EMPTY) ||
            (valid_block_cnt && zone->cond == BLK_ZONE_COND_FULL))
@@ -4898,8 +5010,8 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
 
        if (!valid_block_cnt) {
                f2fs_notice(sbi, "Zone without valid block has non-zero write "
-                           "pointer. Reset the write pointer: cond[0x%x]",
-                           zone->cond);
+                           "pointer. Reset the write pointer: cond[%s]",
+                           f2fs_zone_status[zone->cond]);
                ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block,
                                        zone->len >> log_sectors_per_block);
                if (ret)
@@ -4916,8 +5028,8 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
         * selected for write operation until it get discarded.
         */
        f2fs_notice(sbi, "Valid blocks are not aligned with write "
-                   "pointer: valid block[0x%x,0x%x] cond[0x%x]",
-                   zone_segno, valid_block_cnt, zone->cond);
+                   "pointer: valid block[0x%x,0x%x] cond[%s]",
+                   zone_segno, valid_block_cnt, f2fs_zone_status[zone->cond]);
 
        nofs_flags = memalloc_nofs_save();
        ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH,
@@ -5128,7 +5240,7 @@ static inline unsigned int f2fs_usable_zone_blks_in_seg(
        unsigned int secno;
 
        if (!sbi->unusable_blocks_per_sec)
-               return sbi->blocks_per_seg;
+               return BLKS_PER_SEG(sbi);
 
        secno = GET_SEC_FROM_SEG(sbi, segno);
        seg_start = START_BLOCK(sbi, segno);
@@ -5143,10 +5255,10 @@ static inline unsigned int f2fs_usable_zone_blks_in_seg(
         */
        if (seg_start >= sec_cap_blkaddr)
                return 0;
-       if (seg_start + sbi->blocks_per_seg > sec_cap_blkaddr)
+       if (seg_start + BLKS_PER_SEG(sbi) > sec_cap_blkaddr)
                return sec_cap_blkaddr - seg_start;
 
-       return sbi->blocks_per_seg;
+       return BLKS_PER_SEG(sbi);
 }
 #else
 int f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi)
@@ -5172,7 +5284,7 @@ unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,
        if (f2fs_sb_has_blkzoned(sbi))
                return f2fs_usable_zone_blks_in_seg(sbi, segno);
 
-       return sbi->blocks_per_seg;
+       return BLKS_PER_SEG(sbi);
 }
 
 unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
@@ -5181,7 +5293,7 @@ unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
        if (f2fs_sb_has_blkzoned(sbi))
                return CAP_SEGS_PER_SEC(sbi);
 
-       return sbi->segs_per_sec;
+       return SEGS_PER_SEC(sbi);
 }
 
 /*
@@ -5196,14 +5308,14 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi)
 
        sit_i->min_mtime = ULLONG_MAX;
 
-       for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
+       for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) {
                unsigned int i;
                unsigned long long mtime = 0;
 
-               for (i = 0; i < sbi->segs_per_sec; i++)
+               for (i = 0; i < SEGS_PER_SEC(sbi); i++)
                        mtime += get_seg_entry(sbi, segno + i)->mtime;
 
-               mtime = div_u64(mtime, sbi->segs_per_sec);
+               mtime = div_u64(mtime, SEGS_PER_SEC(sbi));
 
                if (sit_i->min_mtime > mtime)
                        sit_i->min_mtime = mtime;
@@ -5242,7 +5354,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
                sm_info->ipu_policy = BIT(F2FS_IPU_FSYNC);
        sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
        sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
-       sm_info->min_seq_blocks = sbi->blocks_per_seg;
+       sm_info->min_seq_blocks = BLKS_PER_SEG(sbi);
        sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;
        sm_info->min_ssr_sections = reserved_sections(sbi);
 
index 8129be788bd5615b99a666f6a240b16c315a0cc0..e1c0f418aa11f6b2495c5cd24d409f1434560ea4 100644 (file)
@@ -48,21 +48,21 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
 
 #define IS_CURSEC(sbi, secno)                                          \
        (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno /            \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno /           \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno /           \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno /            \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno /           \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno /           \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA_PINNED)->segno /    \
-         (sbi)->segs_per_sec) ||       \
+         SEGS_PER_SEC(sbi)) || \
         ((secno) == CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC)->segno /       \
-         (sbi)->segs_per_sec))
+         SEGS_PER_SEC(sbi)))
 
 #define MAIN_BLKADDR(sbi)                                              \
        (SM_I(sbi) ? SM_I(sbi)->main_blkaddr :                          \
@@ -77,40 +77,37 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
 #define TOTAL_SEGS(sbi)                                                        \
        (SM_I(sbi) ? SM_I(sbi)->segment_count :                                 \
                le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
-#define TOTAL_BLKS(sbi)        (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg)
+#define TOTAL_BLKS(sbi)        (SEGS_TO_BLKS(sbi, TOTAL_SEGS(sbi)))
 
 #define MAX_BLKADDR(sbi)       (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
 #define SEGMENT_SIZE(sbi)      (1ULL << ((sbi)->log_blocksize +        \
                                        (sbi)->log_blocks_per_seg))
 
 #define START_BLOCK(sbi, segno)        (SEG0_BLKADDR(sbi) +                    \
-        (GET_R2L_SEGNO(FREE_I(sbi), segno) << (sbi)->log_blocks_per_seg))
+        (SEGS_TO_BLKS(sbi, GET_R2L_SEGNO(FREE_I(sbi), segno))))
 
 #define NEXT_FREE_BLKADDR(sbi, curseg)                                 \
        (START_BLOCK(sbi, (curseg)->segno) + (curseg)->next_blkoff)
 
 #define GET_SEGOFF_FROM_SEG0(sbi, blk_addr)    ((blk_addr) - SEG0_BLKADDR(sbi))
 #define GET_SEGNO_FROM_SEG0(sbi, blk_addr)                             \
-       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> (sbi)->log_blocks_per_seg)
+       (BLKS_TO_SEGS(sbi, GET_SEGOFF_FROM_SEG0(sbi, blk_addr)))
 #define GET_BLKOFF_FROM_SEG0(sbi, blk_addr)                            \
-       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
+       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (BLKS_PER_SEG(sbi) - 1))
 
 #define GET_SEGNO(sbi, blk_addr)                                       \
        ((!__is_valid_data_blkaddr(blk_addr)) ?                 \
        NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
                GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
-#define BLKS_PER_SEC(sbi)                                      \
-       ((sbi)->segs_per_sec * (sbi)->blocks_per_seg)
 #define CAP_BLKS_PER_SEC(sbi)                                  \
-       ((sbi)->segs_per_sec * (sbi)->blocks_per_seg -          \
-        (sbi)->unusable_blocks_per_sec)
+       (BLKS_PER_SEC(sbi) - (sbi)->unusable_blocks_per_sec)
 #define CAP_SEGS_PER_SEC(sbi)                                  \
-       ((sbi)->segs_per_sec - ((sbi)->unusable_blocks_per_sec >>\
-       (sbi)->log_blocks_per_seg))
+       (SEGS_PER_SEC(sbi) -                                    \
+       BLKS_TO_SEGS(sbi, (sbi)->unusable_blocks_per_sec))
 #define GET_SEC_FROM_SEG(sbi, segno)                           \
-       (((segno) == -1) ? -1 : (segno) / (sbi)->segs_per_sec)
+       (((segno) == -1) ? -1 : (segno) / SEGS_PER_SEC(sbi))
 #define GET_SEG_FROM_SEC(sbi, secno)                           \
-       ((secno) * (sbi)->segs_per_sec)
+       ((secno) * SEGS_PER_SEC(sbi))
 #define GET_ZONE_FROM_SEC(sbi, secno)                          \
        (((secno) == -1) ? -1 : (secno) / (sbi)->secs_per_zone)
 #define GET_ZONE_FROM_SEG(sbi, segno)                          \
@@ -138,16 +135,6 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
 #define SECTOR_TO_BLOCK(sectors)                                       \
        ((sectors) >> F2FS_LOG_SECTORS_PER_BLOCK)
 
-/*
- * indicate a block allocation direction: RIGHT and LEFT.
- * RIGHT means allocating new sections towards the end of volume.
- * LEFT means the opposite direction.
- */
-enum {
-       ALLOC_RIGHT = 0,
-       ALLOC_LEFT
-};
-
 /*
  * In the victim_sel_policy->alloc_mode, there are three block allocation modes.
  * LFS writes data sequentially with cleaning operations.
@@ -364,7 +351,7 @@ static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi,
                unsigned int blocks = 0;
                int i;
 
-               for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) {
+               for (i = 0; i < SEGS_PER_SEC(sbi); i++, start_segno++) {
                        struct seg_entry *se = get_seg_entry(sbi, start_segno);
 
                        blocks += se->ckpt_valid_blocks;
@@ -449,7 +436,7 @@ static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno)
        free_i->free_segments++;
 
        next = find_next_bit(free_i->free_segmap,
-                       start_segno + sbi->segs_per_sec, start_segno);
+                       start_segno + SEGS_PER_SEC(sbi), start_segno);
        if (next >= start_segno + usable_segs) {
                clear_bit(secno, free_i->free_secmap);
                free_i->free_sections++;
@@ -485,7 +472,7 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi,
                if (!inmem && IS_CURSEC(sbi, secno))
                        goto skip_free;
                next = find_next_bit(free_i->free_segmap,
-                               start_segno + sbi->segs_per_sec, start_segno);
+                               start_segno + SEGS_PER_SEC(sbi), start_segno);
                if (next >= start_segno + usable_segs) {
                        if (test_and_clear_bit(secno, free_i->free_secmap))
                                free_i->free_sections++;
@@ -573,23 +560,22 @@ static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
                        unsigned int node_blocks, unsigned int dent_blocks)
 {
 
-       unsigned int segno, left_blocks;
+       unsigned segno, left_blocks;
        int i;
 
-       /* check current node segment */
+       /* check current node sections in the worst case. */
        for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) {
                segno = CURSEG_I(sbi, i)->segno;
-               left_blocks = f2fs_usable_blks_in_seg(sbi, segno) -
-                               get_seg_entry(sbi, segno)->ckpt_valid_blocks;
-
+               left_blocks = CAP_BLKS_PER_SEC(sbi) -
+                               get_ckpt_valid_blocks(sbi, segno, true);
                if (node_blocks > left_blocks)
                        return false;
        }
 
-       /* check current data segment */
+       /* check current data section for dentry blocks. */
        segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno;
-       left_blocks = f2fs_usable_blks_in_seg(sbi, segno) -
-                       get_seg_entry(sbi, segno)->ckpt_valid_blocks;
+       left_blocks = CAP_BLKS_PER_SEC(sbi) -
+                       get_ckpt_valid_blocks(sbi, segno, true);
        if (dent_blocks > left_blocks)
                return false;
        return true;
@@ -638,7 +624,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
 
        if (free_secs > upper_secs)
                return false;
-       else if (free_secs <= lower_secs)
+       if (free_secs <= lower_secs)
                return true;
        return !curseg_space;
 }
@@ -793,10 +779,10 @@ static inline int check_block_count(struct f2fs_sb_info *sbi,
                return -EFSCORRUPTED;
        }
 
-       if (usable_blks_per_seg < sbi->blocks_per_seg)
+       if (usable_blks_per_seg < BLKS_PER_SEG(sbi))
                f2fs_bug_on(sbi, find_next_bit_le(&raw_sit->valid_map,
-                               sbi->blocks_per_seg,
-                               usable_blks_per_seg) != sbi->blocks_per_seg);
+                               BLKS_PER_SEG(sbi),
+                               usable_blks_per_seg) != BLKS_PER_SEG(sbi));
 
        /* check segment usage, and check boundary of a given segment number */
        if (unlikely(GET_SIT_VBLOCKS(raw_sit) > usable_blks_per_seg
@@ -915,9 +901,9 @@ static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
                return 0;
 
        if (type == DATA)
-               return sbi->blocks_per_seg;
+               return BLKS_PER_SEG(sbi);
        else if (type == NODE)
-               return 8 * sbi->blocks_per_seg;
+               return SEGS_TO_BLKS(sbi, 8);
        else if (type == META)
                return 8 * BIO_MAX_VECS;
        else
@@ -969,3 +955,13 @@ wake_up:
        dcc->discard_wake = true;
        wake_up_interruptible_all(&dcc->discard_wait_queue);
 }
+
+static inline unsigned int first_zoned_segno(struct f2fs_sb_info *sbi)
+{
+       int devi;
+
+       for (devi = 0; devi < sbi->s_ndevs; devi++)
+               if (bdev_is_zoned(FDEV(devi).bdev))
+                       return GET_SEGNO(sbi, FDEV(devi).start_blk);
+       return 0;
+}
index f6ffbfe75653cf0de1741bf5094f4a6340faa659..a6867f26f141836dcd4a4f0136dd67a9de6c3c74 100644 (file)
@@ -44,24 +44,26 @@ static struct kmem_cache *f2fs_inode_cachep;
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 
 const char *f2fs_fault_name[FAULT_MAX] = {
-       [FAULT_KMALLOC]         = "kmalloc",
-       [FAULT_KVMALLOC]        = "kvmalloc",
-       [FAULT_PAGE_ALLOC]      = "page alloc",
-       [FAULT_PAGE_GET]        = "page get",
-       [FAULT_ALLOC_NID]       = "alloc nid",
-       [FAULT_ORPHAN]          = "orphan",
-       [FAULT_BLOCK]           = "no more block",
-       [FAULT_DIR_DEPTH]       = "too big dir depth",
-       [FAULT_EVICT_INODE]     = "evict_inode fail",
-       [FAULT_TRUNCATE]        = "truncate fail",
-       [FAULT_READ_IO]         = "read IO error",
-       [FAULT_CHECKPOINT]      = "checkpoint error",
-       [FAULT_DISCARD]         = "discard error",
-       [FAULT_WRITE_IO]        = "write IO error",
-       [FAULT_SLAB_ALLOC]      = "slab alloc",
-       [FAULT_DQUOT_INIT]      = "dquot initialize",
-       [FAULT_LOCK_OP]         = "lock_op",
-       [FAULT_BLKADDR]         = "invalid blkaddr",
+       [FAULT_KMALLOC]                 = "kmalloc",
+       [FAULT_KVMALLOC]                = "kvmalloc",
+       [FAULT_PAGE_ALLOC]              = "page alloc",
+       [FAULT_PAGE_GET]                = "page get",
+       [FAULT_ALLOC_NID]               = "alloc nid",
+       [FAULT_ORPHAN]                  = "orphan",
+       [FAULT_BLOCK]                   = "no more block",
+       [FAULT_DIR_DEPTH]               = "too big dir depth",
+       [FAULT_EVICT_INODE]             = "evict_inode fail",
+       [FAULT_TRUNCATE]                = "truncate fail",
+       [FAULT_READ_IO]                 = "read IO error",
+       [FAULT_CHECKPOINT]              = "checkpoint error",
+       [FAULT_DISCARD]                 = "discard error",
+       [FAULT_WRITE_IO]                = "write IO error",
+       [FAULT_SLAB_ALLOC]              = "slab alloc",
+       [FAULT_DQUOT_INIT]              = "dquot initialize",
+       [FAULT_LOCK_OP]                 = "lock_op",
+       [FAULT_BLKADDR_VALIDITY]        = "invalid blkaddr",
+       [FAULT_BLKADDR_CONSISTENCE]     = "inconsistent blkaddr",
+       [FAULT_NO_SEGMENT]              = "no free segment",
 };
 
 void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
@@ -137,7 +139,6 @@ enum {
        Opt_resgid,
        Opt_resuid,
        Opt_mode,
-       Opt_io_size_bits,
        Opt_fault_injection,
        Opt_fault_type,
        Opt_lazytime,
@@ -216,7 +217,6 @@ static match_table_t f2fs_tokens = {
        {Opt_resgid, "resgid=%u"},
        {Opt_resuid, "resuid=%u"},
        {Opt_mode, "mode=%s"},
-       {Opt_io_size_bits, "io_bits=%u"},
        {Opt_fault_injection, "fault_injection=%u"},
        {Opt_fault_type, "fault_type=%u"},
        {Opt_lazytime, "lazytime"},
@@ -263,7 +263,8 @@ static match_table_t f2fs_tokens = {
        {Opt_err, NULL},
 };
 
-void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
+void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate,
+                                               const char *fmt, ...)
 {
        struct va_format vaf;
        va_list args;
@@ -274,8 +275,12 @@ void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...)
        level = printk_get_level(fmt);
        vaf.fmt = printk_skip_level(fmt);
        vaf.va = &args;
-       printk("%c%cF2FS-fs (%s): %pV\n",
-              KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf);
+       if (limit_rate)
+               printk_ratelimited("%c%cF2FS-fs (%s): %pV\n",
+                       KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf);
+       else
+               printk("%c%cF2FS-fs (%s): %pV\n",
+                       KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf);
 
        va_end(args);
 }
@@ -343,46 +348,6 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
                                           F2FS_OPTION(sbi).s_resgid));
 }
 
-static inline int adjust_reserved_segment(struct f2fs_sb_info *sbi)
-{
-       unsigned int sec_blks = sbi->blocks_per_seg * sbi->segs_per_sec;
-       unsigned int avg_vblocks;
-       unsigned int wanted_reserved_segments;
-       block_t avail_user_block_count;
-
-       if (!F2FS_IO_ALIGNED(sbi))
-               return 0;
-
-       /* average valid block count in section in worst case */
-       avg_vblocks = sec_blks / F2FS_IO_SIZE(sbi);
-
-       /*
-        * we need enough free space when migrating one section in worst case
-        */
-       wanted_reserved_segments = (F2FS_IO_SIZE(sbi) / avg_vblocks) *
-                                               reserved_segments(sbi);
-       wanted_reserved_segments -= reserved_segments(sbi);
-
-       avail_user_block_count = sbi->user_block_count -
-                               sbi->current_reserved_blocks -
-                               F2FS_OPTION(sbi).root_reserved_blocks;
-
-       if (wanted_reserved_segments * sbi->blocks_per_seg >
-                                       avail_user_block_count) {
-               f2fs_err(sbi, "IO align feature can't grab additional reserved segment: %u, available segments: %u",
-                       wanted_reserved_segments,
-                       avail_user_block_count >> sbi->log_blocks_per_seg);
-               return -ENOSPC;
-       }
-
-       SM_I(sbi)->additional_reserved_segments = wanted_reserved_segments;
-
-       f2fs_info(sbi, "IO align feature needs additional reserved segment: %u",
-                        wanted_reserved_segments);
-
-       return 0;
-}
-
 static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
 {
        if (!F2FS_OPTION(sbi).unusable_cap_perc)
@@ -663,7 +628,7 @@ static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str)
 #ifdef CONFIG_F2FS_FS_ZSTD
 static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
 {
-       unsigned int level;
+       int level;
        int len = 4;
 
        if (strlen(str) == len) {
@@ -677,9 +642,15 @@ static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
                f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>");
                return -EINVAL;
        }
-       if (kstrtouint(str + 1, 10, &level))
+       if (kstrtoint(str + 1, 10, &level))
                return -EINVAL;
 
+       /* f2fs does not support negative compress level now */
+       if (level < 0) {
+               f2fs_info(sbi, "do not support negative compress level: %d", level);
+               return -ERANGE;
+       }
+
        if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) {
                f2fs_info(sbi, "invalid zstd compress level: %d", level);
                return -EINVAL;
@@ -763,10 +734,8 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                        clear_opt(sbi, DISCARD);
                        break;
                case Opt_noheap:
-                       set_opt(sbi, NOHEAP);
-                       break;
                case Opt_heap:
-                       clear_opt(sbi, NOHEAP);
+                       f2fs_warn(sbi, "heap/no_heap options were deprecated");
                        break;
 #ifdef CONFIG_F2FS_FS_XATTR
                case Opt_user_xattr:
@@ -913,16 +882,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                        }
                        kfree(name);
                        break;
-               case Opt_io_size_bits:
-                       if (args->from && match_int(args, &arg))
-                               return -EINVAL;
-                       if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_VECS)) {
-                               f2fs_warn(sbi, "Not support %ld, larger than %d",
-                                       BIT(arg), BIO_MAX_VECS);
-                               return -EINVAL;
-                       }
-                       F2FS_OPTION(sbi).write_io_size_bits = arg;
-                       break;
 #ifdef CONFIG_F2FS_FAULT_INJECTION
                case Opt_fault_injection:
                        if (args->from && match_int(args, &arg))
@@ -1392,12 +1351,6 @@ default_check:
        }
 #endif
 
-       if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) {
-               f2fs_err(sbi, "Should set mode=lfs with %luKB-sized IO",
-                        F2FS_IO_SIZE_KB(sbi));
-               return -EINVAL;
-       }
-
        if (test_opt(sbi, INLINE_XATTR_SIZE)) {
                int min_size, max_size;
 
@@ -1718,7 +1671,6 @@ static void f2fs_put_super(struct super_block *sb)
 
        f2fs_destroy_page_array_cache(sbi);
        f2fs_destroy_xattr_caches(sbi);
-       mempool_destroy(sbi->write_io_dummy);
 #ifdef CONFIG_QUOTA
        for (i = 0; i < MAXQUOTAS; i++)
                kfree(F2FS_OPTION(sbi).s_qf_names[i]);
@@ -2009,10 +1961,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
        } else {
                seq_puts(seq, ",nodiscard");
        }
-       if (test_opt(sbi, NOHEAP))
-               seq_puts(seq, ",no_heap");
-       else
-               seq_puts(seq, ",heap");
 #ifdef CONFIG_F2FS_FS_XATTR
        if (test_opt(sbi, XATTR_USER))
                seq_puts(seq, ",user_xattr");
@@ -2078,9 +2026,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                                        F2FS_OPTION(sbi).s_resuid),
                                from_kgid_munged(&init_user_ns,
                                        F2FS_OPTION(sbi).s_resgid));
-       if (F2FS_IO_SIZE_BITS(sbi))
-               seq_printf(seq, ",io_bits=%u",
-                               F2FS_OPTION(sbi).write_io_size_bits);
 #ifdef CONFIG_F2FS_FAULT_INJECTION
        if (test_opt(sbi, FAULT_INJECTION)) {
                seq_printf(seq, ",fault_injection=%u",
@@ -2192,7 +2137,6 @@ static void default_options(struct f2fs_sb_info *sbi, bool remount)
        set_opt(sbi, INLINE_XATTR);
        set_opt(sbi, INLINE_DATA);
        set_opt(sbi, INLINE_DENTRY);
-       set_opt(sbi, NOHEAP);
        set_opt(sbi, MERGE_CHECKPOINT);
        F2FS_OPTION(sbi).unusable_cap = 0;
        sbi->sb->s_flags |= SB_LAZYTIME;
@@ -2247,6 +2191,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
                        .init_gc_type = FG_GC,
                        .should_migrate_blocks = false,
                        .err_gc_skipped = true,
+                       .no_bg_gc = true,
                        .nr_free_secs = 1 };
 
                f2fs_down_write(&sbi->gc_lock);
@@ -2332,7 +2277,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        bool no_read_extent_cache = !test_opt(sbi, READ_EXTENT_CACHE);
        bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE);
        bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT);
-       bool no_io_align = !F2FS_IO_ALIGNED(sbi);
        bool no_atgc = !test_opt(sbi, ATGC);
        bool no_discard = !test_opt(sbi, DISCARD);
        bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE);
@@ -2440,12 +2384,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
                goto restore_opts;
        }
 
-       if (no_io_align == !!F2FS_IO_ALIGNED(sbi)) {
-               err = -EINVAL;
-               f2fs_warn(sbi, "switch io_bits option is not allowed");
-               goto restore_opts;
-       }
-
        if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) {
                err = -EINVAL;
                f2fs_warn(sbi, "switch compress_cache option is not allowed");
@@ -3706,7 +3644,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        }
 
        main_segs = le32_to_cpu(raw_super->segment_count_main);
-       blocks_per_seg = sbi->blocks_per_seg;
+       blocks_per_seg = BLKS_PER_SEG(sbi);
 
        for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
                if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
@@ -3818,9 +3756,9 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
        sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
        sbi->total_sections = le32_to_cpu(raw_super->section_count);
-       sbi->total_node_count =
-               (le32_to_cpu(raw_super->segment_count_nat) / 2)
-                       * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK;
+       sbi->total_node_count = SEGS_TO_BLKS(sbi,
+                       ((le32_to_cpu(raw_super->segment_count_nat) / 2) *
+                       NAT_ENTRY_PER_BLOCK));
        F2FS_ROOT_INO(sbi) = le32_to_cpu(raw_super->root_ino);
        F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino);
        F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino);
@@ -3829,7 +3767,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->next_victim_seg[BG_GC] = NULL_SEGNO;
        sbi->next_victim_seg[FG_GC] = NULL_SEGNO;
        sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH;
-       sbi->migration_granularity = sbi->segs_per_sec;
+       sbi->migration_granularity = SEGS_PER_SEC(sbi);
        sbi->seq_file_ra_mul = MIN_RA_MUL;
        sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
        sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
@@ -3930,11 +3868,6 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
                return 0;
 
        zone_sectors = bdev_zone_sectors(bdev);
-       if (!is_power_of_2(zone_sectors)) {
-               f2fs_err(sbi, "F2FS does not support non power of 2 zone sizes\n");
-               return -EINVAL;
-       }
-
        if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
                                SECTOR_TO_BLOCK(zone_sectors))
                return -EINVAL;
@@ -4090,7 +4023,9 @@ static void f2fs_record_stop_reason(struct f2fs_sb_info *sbi)
 
        f2fs_up_write(&sbi->sb_lock);
        if (err)
-               f2fs_err(sbi, "f2fs_commit_super fails to record err:%d", err);
+               f2fs_err_ratelimited(sbi,
+                       "f2fs_commit_super fails to record stop_reason, err:%d",
+                       err);
 }
 
 void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag)
@@ -4133,8 +4068,9 @@ static void f2fs_record_errors(struct f2fs_sb_info *sbi, unsigned char error)
 
        err = f2fs_commit_super(sbi, false);
        if (err)
-               f2fs_err(sbi, "f2fs_commit_super fails to record errors:%u, err:%d",
-                                                               error, err);
+               f2fs_err_ratelimited(sbi,
+                       "f2fs_commit_super fails to record errors:%u, err:%d",
+                       error, err);
 out_unlock:
        f2fs_up_write(&sbi->sb_lock);
 }
@@ -4259,14 +4195,14 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                        if (i == 0) {
                                FDEV(i).start_blk = 0;
                                FDEV(i).end_blk = FDEV(i).start_blk +
-                                   (FDEV(i).total_segments <<
-                                   sbi->log_blocks_per_seg) - 1 +
-                                   le32_to_cpu(raw_super->segment0_blkaddr);
+                                       SEGS_TO_BLKS(sbi,
+                                       FDEV(i).total_segments) - 1 +
+                                       le32_to_cpu(raw_super->segment0_blkaddr);
                        } else {
                                FDEV(i).start_blk = FDEV(i - 1).end_blk + 1;
                                FDEV(i).end_blk = FDEV(i).start_blk +
-                                       (FDEV(i).total_segments <<
-                                       sbi->log_blocks_per_seg) - 1;
+                                               SEGS_TO_BLKS(sbi,
+                                               FDEV(i).total_segments) - 1;
                                FDEV(i).bdev_file = bdev_file_open_by_path(
                                        FDEV(i).path, mode, sbi->sb, NULL);
                        }
@@ -4305,8 +4241,6 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                          FDEV(i).total_segments,
                          FDEV(i).start_blk, FDEV(i).end_blk);
        }
-       f2fs_info(sbi,
-                 "IO Block Size: %8ld KB", F2FS_IO_SIZE_KB(sbi));
        return 0;
 }
 
@@ -4519,19 +4453,10 @@ try_onemore:
        if (err)
                goto free_iostat;
 
-       if (F2FS_IO_ALIGNED(sbi)) {
-               sbi->write_io_dummy =
-                       mempool_create_page_pool(2 * (F2FS_IO_SIZE(sbi) - 1), 0);
-               if (!sbi->write_io_dummy) {
-                       err = -ENOMEM;
-                       goto free_percpu;
-               }
-       }
-
        /* init per sbi slab cache */
        err = f2fs_init_xattr_caches(sbi);
        if (err)
-               goto free_io_dummy;
+               goto free_percpu;
        err = f2fs_init_page_array_cache(sbi);
        if (err)
                goto free_xattr_cache;
@@ -4619,10 +4544,6 @@ try_onemore:
                goto free_nm;
        }
 
-       err = adjust_reserved_segment(sbi);
-       if (err)
-               goto free_nm;
-
        /* For write statistics */
        sbi->sectors_written_start = f2fs_get_sectors_written(sbi);
 
@@ -4749,13 +4670,20 @@ reset_checkpoint:
         * If the f2fs is not readonly and fsync data recovery succeeds,
         * check zoned block devices' write pointer consistency.
         */
-       if (!err && !f2fs_readonly(sb) && f2fs_sb_has_blkzoned(sbi)) {
-               err = f2fs_check_write_pointer(sbi);
-               if (err)
-                       goto free_meta;
+       if (f2fs_sb_has_blkzoned(sbi) && !f2fs_readonly(sb)) {
+               int err2;
+
+               f2fs_notice(sbi, "Checking entire write pointers");
+               err2 = f2fs_check_write_pointer(sbi);
+               if (err2)
+                       err = err2;
        }
+       if (err)
+               goto free_meta;
 
-       f2fs_init_inmem_curseg(sbi);
+       err = f2fs_init_inmem_curseg(sbi);
+       if (err)
+               goto sync_free_meta;
 
        /* f2fs_recover_fsync_data() cleared this already */
        clear_sbi_flag(sbi, SBI_POR_DOING);
@@ -4854,8 +4782,6 @@ free_page_array_cache:
        f2fs_destroy_page_array_cache(sbi);
 free_xattr_cache:
        f2fs_destroy_xattr_caches(sbi);
-free_io_dummy:
-       mempool_destroy(sbi->write_io_dummy);
 free_percpu:
        destroy_percpu_info(sbi);
 free_iostat:
index a7ec55c7bb20ce136d41ac91cdea0c618062c9bb..a568ce96cf563130654333ccae5a69049050aae7 100644 (file)
@@ -493,8 +493,8 @@ out:
                spin_lock(&sbi->stat_lock);
                if (t > (unsigned long)(sbi->user_block_count -
                                F2FS_OPTION(sbi).root_reserved_blocks -
-                               sbi->blocks_per_seg *
-                               SM_I(sbi)->additional_reserved_segments)) {
+                               SEGS_TO_BLKS(sbi,
+                               SM_I(sbi)->additional_reserved_segments))) {
                        spin_unlock(&sbi->stat_lock);
                        return -EINVAL;
                }
@@ -551,7 +551,7 @@ out:
        }
 
        if (!strcmp(a->attr.name, "migration_granularity")) {
-               if (t == 0 || t > sbi->segs_per_sec)
+               if (t == 0 || t > SEGS_PER_SEC(sbi))
                        return -EINVAL;
        }
 
@@ -1492,6 +1492,50 @@ static int __maybe_unused discard_plist_seq_show(struct seq_file *seq,
        return 0;
 }
 
+static int __maybe_unused disk_map_seq_show(struct seq_file *seq,
+                                               void *offset)
+{
+       struct super_block *sb = seq->private;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       int i;
+
+       seq_printf(seq, "Address Layout   : %5luB Block address (# of Segments)\n",
+                                       F2FS_BLKSIZE);
+       seq_printf(seq, " SB            : %12s\n", "0/1024B");
+       seq_printf(seq, " seg0_blkaddr  : 0x%010x\n", SEG0_BLKADDR(sbi));
+       seq_printf(seq, " Checkpoint    : 0x%010x (%10d)\n",
+                       le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr), 2);
+       seq_printf(seq, " SIT           : 0x%010x (%10d)\n",
+                       SIT_I(sbi)->sit_base_addr,
+                       le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_sit));
+       seq_printf(seq, " NAT           : 0x%010x (%10d)\n",
+                       NM_I(sbi)->nat_blkaddr,
+                       le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_nat));
+       seq_printf(seq, " SSA           : 0x%010x (%10d)\n",
+                       SM_I(sbi)->ssa_blkaddr,
+                       le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_ssa));
+       seq_printf(seq, " Main          : 0x%010x (%10d)\n",
+                       SM_I(sbi)->main_blkaddr,
+                       le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_main));
+       seq_printf(seq, " # of Sections : %12d\n",
+                       le32_to_cpu(F2FS_RAW_SUPER(sbi)->section_count));
+       seq_printf(seq, " Segs/Sections : %12d\n",
+                       SEGS_PER_SEC(sbi));
+       seq_printf(seq, " Section size  : %12d MB\n",
+                       SEGS_PER_SEC(sbi) << 1);
+
+       if (!f2fs_is_multi_device(sbi))
+               return 0;
+
+       seq_puts(seq, "\nDisk Map for multi devices:\n");
+       for (i = 0; i < sbi->s_ndevs; i++)
+               seq_printf(seq, "Disk:%2d (zoned=%d): 0x%010x - 0x%010x on %s\n",
+                       i, bdev_is_zoned(FDEV(i).bdev),
+                       FDEV(i).start_blk, FDEV(i).end_blk,
+                       FDEV(i).path);
+       return 0;
+}
+
 int __init f2fs_init_sysfs(void)
 {
        int ret;
@@ -1573,6 +1617,8 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
                                victim_bits_seq_show, sb);
        proc_create_single_data("discard_plist_info", 0444, sbi->s_proc,
                                discard_plist_seq_show, sb);
+       proc_create_single_data("disk_map", 0444, sbi->s_proc,
+                               disk_map_seq_show, sb);
        return 0;
 put_feature_list_kobj:
        kobject_put(&sbi->s_feature_list_kobj);
index 4fc95f353a7a96c6cc67c6ea5dfabea0cc591e9c..f7bb0c54502c8d57981ffe9f41850b5c196e9f2c 100644 (file)
@@ -258,21 +258,23 @@ static struct page *f2fs_read_merkle_tree_page(struct inode *inode,
                                               pgoff_t index,
                                               unsigned long num_ra_pages)
 {
-       struct page *page;
+       struct folio *folio;
 
        index += f2fs_verity_metadata_pos(inode) >> PAGE_SHIFT;
 
-       page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED);
-       if (!page || !PageUptodate(page)) {
+       folio = __filemap_get_folio(inode->i_mapping, index, FGP_ACCESSED, 0);
+       if (IS_ERR(folio) || !folio_test_uptodate(folio)) {
                DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index);
 
-               if (page)
-                       put_page(page);
+               if (!IS_ERR(folio))
+                       folio_put(folio);
                else if (num_ra_pages > 1)
                        page_cache_ra_unbounded(&ractl, num_ra_pages, 0);
-               page = read_mapping_page(inode->i_mapping, index, NULL);
+               folio = read_mapping_folio(inode->i_mapping, index, NULL);
+               if (IS_ERR(folio))
+                       return ERR_CAST(folio);
        }
-       return page;
+       return folio_file_page(folio, index);
 }
 
 static int f2fs_write_merkle_tree_block(struct inode *inode, const void *buf,
index bce1d7ac95caaa6ae48ba62c094d43c9da27298e..458519e416fe75e97cc454a716d29c06b3586b56 100644 (file)
@@ -529,6 +529,20 @@ void kernfs_get(struct kernfs_node *kn)
 }
 EXPORT_SYMBOL_GPL(kernfs_get);
 
+static void kernfs_free_rcu(struct rcu_head *rcu)
+{
+       struct kernfs_node *kn = container_of(rcu, struct kernfs_node, rcu);
+
+       kfree_const(kn->name);
+
+       if (kn->iattr) {
+               simple_xattrs_free(&kn->iattr->xattrs, NULL);
+               kmem_cache_free(kernfs_iattrs_cache, kn->iattr);
+       }
+
+       kmem_cache_free(kernfs_node_cache, kn);
+}
+
 /**
  * kernfs_put - put a reference count on a kernfs_node
  * @kn: the target kernfs_node
@@ -557,16 +571,11 @@ void kernfs_put(struct kernfs_node *kn)
        if (kernfs_type(kn) == KERNFS_LINK)
                kernfs_put(kn->symlink.target_kn);
 
-       kfree_const(kn->name);
-
-       if (kn->iattr) {
-               simple_xattrs_free(&kn->iattr->xattrs, NULL);
-               kmem_cache_free(kernfs_iattrs_cache, kn->iattr);
-       }
        spin_lock(&kernfs_idr_lock);
        idr_remove(&root->ino_idr, (u32)kernfs_ino(kn));
        spin_unlock(&kernfs_idr_lock);
-       kmem_cache_free(kernfs_node_cache, kn);
+
+       call_rcu(&kn->rcu, kernfs_free_rcu);
 
        kn = parent;
        if (kn) {
@@ -575,7 +584,7 @@ void kernfs_put(struct kernfs_node *kn)
        } else {
                /* just released the root kn, free @root too */
                idr_destroy(&root->ino_idr);
-               kfree(root);
+               kfree_rcu(root, rcu);
        }
 }
 EXPORT_SYMBOL_GPL(kernfs_put);
@@ -715,7 +724,7 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
        ino_t ino = kernfs_id_ino(id);
        u32 gen = kernfs_id_gen(id);
 
-       spin_lock(&kernfs_idr_lock);
+       rcu_read_lock();
 
        kn = idr_find(&root->ino_idr, (u32)ino);
        if (!kn)
@@ -739,10 +748,10 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
        if (unlikely(!__kernfs_active(kn) || !atomic_inc_not_zero(&kn->count)))
                goto err_unlock;
 
-       spin_unlock(&kernfs_idr_lock);
+       rcu_read_unlock();
        return kn;
 err_unlock:
-       spin_unlock(&kernfs_idr_lock);
+       rcu_read_unlock();
        return NULL;
 }
 
index ffa4565c275a7a1f9dfeb5075ccc82261c971c29..e9df2f87072c687073abe9625e66886934497a02 100644 (file)
@@ -483,9 +483,11 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
                goto out_put;
 
        rc = 0;
-       of->mmapped = true;
-       of_on(of)->nr_mmapped++;
-       of->vm_ops = vma->vm_ops;
+       if (!of->mmapped) {
+               of->mmapped = true;
+               of_on(of)->nr_mmapped++;
+               of->vm_ops = vma->vm_ops;
+       }
        vma->vm_ops = &kernfs_vm_ops;
 out_put:
        kernfs_put_active(of->kn);
index 237f2764b9412d65f2db6be01329d5565169a327..b42ee6547cdc1cfb1be7bb30ff890ce2d91e0777 100644 (file)
@@ -49,6 +49,8 @@ struct kernfs_root {
        struct rw_semaphore     kernfs_rwsem;
        struct rw_semaphore     kernfs_iattr_rwsem;
        struct rw_semaphore     kernfs_supers_rwsem;
+
+       struct rcu_head         rcu;
 };
 
 /* +1 to avoid triggering overflow warning when negating it */
index ad572f7ee897b9d26d2439a6a1178332d2a2e547..43a651ed826413d8ea60dcb240950e2a074aca28 100644 (file)
@@ -83,8 +83,10 @@ static int fscache_begin_operation(struct netfs_cache_resources *cres,
        cres->debug_id          = cookie->debug_id;
        cres->inval_counter     = cookie->inval_counter;
 
-       if (!fscache_begin_cookie_access(cookie, why))
+       if (!fscache_begin_cookie_access(cookie, why)) {
+               cres->cache_priv = NULL;
                return -ENOBUFS;
+       }
 
 again:
        spin_lock(&cookie->lock);
index e545e92c440809c1dfdbea094d9746f34faf25fc..1cd2076210b14a770d440c9c2ddee18f4d6d4eea 100644 (file)
@@ -104,7 +104,7 @@ TRACE_EVENT(nfsd_compound,
        TP_fast_assign(
                __entry->xid = be32_to_cpu(rqst->rq_xid);
                __entry->opcnt = opcnt;
-               __assign_str_len(tag, tag, taglen);
+               __assign_str(tag, tag);
        ),
        TP_printk("xid=0x%08x opcnt=%u tag=%s",
                __entry->xid, __entry->opcnt, __get_str(tag)
@@ -485,7 +485,7 @@ TRACE_EVENT(nfsd_dirent,
        TP_fast_assign(
                __entry->fh_hash = fhp ? knfsd_fh_hash(&fhp->fh_handle) : 0;
                __entry->ino = ino;
-               __assign_str_len(name, name, namlen)
+               __assign_str(name, name);
        ),
        TP_printk("fh_hash=0x%08x ino=%llu name=%s",
                __entry->fh_hash, __entry->ino, __get_str(name)
@@ -896,7 +896,7 @@ DECLARE_EVENT_CLASS(nfsd_clid_class,
                __array(unsigned char, addr, sizeof(struct sockaddr_in6))
                __field(unsigned long, flavor)
                __array(unsigned char, verifier, NFS4_VERIFIER_SIZE)
-               __string_len(name, name, clp->cl_name.len)
+               __string_len(name, clp->cl_name.data, clp->cl_name.len)
        ),
        TP_fast_assign(
                __entry->cl_boot = clp->cl_clientid.cl_boot;
@@ -906,7 +906,7 @@ DECLARE_EVENT_CLASS(nfsd_clid_class,
                __entry->flavor = clp->cl_cred.cr_flavor;
                memcpy(__entry->verifier, (void *)&clp->cl_verifier,
                       NFS4_VERIFIER_SIZE);
-               __assign_str_len(name, clp->cl_name.data, clp->cl_name.len);
+               __assign_str(name, clp->cl_name.data);
        ),
        TP_printk("addr=%pISpc name='%s' verifier=0x%s flavor=%s client=%08x:%08x",
                __entry->addr, __get_str(name),
@@ -1976,7 +1976,7 @@ TRACE_EVENT(nfsd_ctl_time,
        TP_fast_assign(
                __entry->netns_ino = net->ns.inum;
                __entry->time = time;
-               __assign_str_len(name, name, namelen);
+               __assign_str(name, name);
        ),
        TP_printk("file=%s time=%d\n",
                __get_str(name), __entry->time
index 3b6982bf6bcf3ecd64f36fa118d4ec551f080acf..e75e173a918622b1c213c4e3862631fb29a2fa9a 100644 (file)
@@ -22,7 +22,7 @@ int op_cache_initialize(void)
        op_cache = kmem_cache_create("orangefs_op_cache",
                                     sizeof(struct orangefs_kernel_op_s),
                                     0,
-                                    ORANGEFS_CACHE_CREATE_FLAGS,
+                                    0,
                                     NULL);
 
        if (!op_cache) {
index 926d9c0a428a2d4977c6d68d644d9d449495df48..e2df7eeadc7aa2bb6d15ff6b3c363655bd333469 100644 (file)
@@ -93,16 +93,6 @@ enum orangefs_vfs_op_states {
        OP_VFS_STATE_GIVEN_UP = 16,
 };
 
-/*
- * orangefs kernel memory related flags
- */
-
-#if (defined CONFIG_DEBUG_SLAB)
-#define ORANGEFS_CACHE_CREATE_FLAGS SLAB_RED_ZONE
-#else
-#define ORANGEFS_CACHE_CREATE_FLAGS 0
-#endif
-
 extern const struct xattr_handler * const orangefs_xattr_handlers[];
 
 extern struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu);
index 5254256a224d7a0a78f9673a42dc7df386370a4a..34849b4a3243ca5a2d27114d8a6f5f0a6074d329 100644 (file)
@@ -527,7 +527,7 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
        sb->s_fs_info = kzalloc(sizeof(struct orangefs_sb_info_s), GFP_KERNEL);
        if (!ORANGEFS_SB(sb)) {
                d = ERR_PTR(-ENOMEM);
-               goto free_sb_and_op;
+               goto free_op;
        }
 
        ret = orangefs_fill_sb(sb,
@@ -644,7 +644,7 @@ int orangefs_inode_cache_initialize(void)
                                        "orangefs_inode_cache",
                                        sizeof(struct orangefs_inode_s),
                                        0,
-                                       ORANGEFS_CACHE_CREATE_FLAGS,
+                                       0,
                                        offsetof(struct orangefs_inode_s,
                                                link_target),
                                        sizeof_field(struct orangefs_inode_s,
index 8586e2f5d24390c91263ea1ee48e7c3b22199cd2..0762575a1e7080b30ba29fbdf69958eff27aea42 100644 (file)
@@ -234,11 +234,11 @@ static int ovl_verify_area(loff_t pos, loff_t pos2, loff_t len, loff_t totlen)
 {
        loff_t tmp;
 
-       if (WARN_ON_ONCE(pos != pos2))
+       if (pos != pos2)
                return -EIO;
-       if (WARN_ON_ONCE(pos < 0 || len < 0 || totlen < 0))
+       if (pos < 0 || len < 0 || totlen < 0)
                return -EIO;
-       if (WARN_ON_ONCE(check_add_overflow(pos, len, &tmp)))
+       if (check_add_overflow(pos, len, &tmp))
                return -EIO;
        return 0;
 }
index 3de5047a7ff988c2049350e464771e912b12894e..a0017724d5239312c14644bd15d2867880337d91 100644 (file)
@@ -239,7 +239,8 @@ replay_again:
                .tcon = tcon,
                .path = path,
                .create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
-               .desired_access =  FILE_READ_DATA | FILE_READ_ATTRIBUTES,
+               .desired_access =  FILE_READ_DATA | FILE_READ_ATTRIBUTES |
+                                  FILE_READ_EA,
                .disposition = FILE_OPEN,
                .fid = pfid,
                .replay = !!(retries),
index 81d9aafd2210afb64e7fbcb58a1da901048dc34d..aa6f1ecb7c0e8fc11f9b1fb830d8c0ca8071b631 100644 (file)
@@ -151,10 +151,6 @@ MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be "
                                  "vers=1.0 (CIFS/SMB1) and vers=2.0 are weaker"
                                  " and less secure. Default: n/N/0");
 
-extern mempool_t *cifs_sm_req_poolp;
-extern mempool_t *cifs_req_poolp;
-extern mempool_t *cifs_mid_poolp;
-
 struct workqueue_struct        *cifsiod_wq;
 struct workqueue_struct        *decrypt_wq;
 struct workqueue_struct        *fileinfo_put_wq;
index 8be62ed053a25e4c56018641553d10314d0f1563..7ed9d05f6890b4d40cb11a7b8d7384c6e0111461 100644 (file)
@@ -355,6 +355,9 @@ struct smb_version_operations {
        /* informational QFS call */
        void (*qfs_tcon)(const unsigned int, struct cifs_tcon *,
                         struct cifs_sb_info *);
+       /* query for server interfaces */
+       int (*query_server_interfaces)(const unsigned int, struct cifs_tcon *,
+                                      bool);
        /* check if a path is accessible or not */
        int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
                                  struct cifs_sb_info *, const char *);
@@ -2104,6 +2107,8 @@ extern struct workqueue_struct *cifsoplockd_wq;
 extern struct workqueue_struct *deferredclose_wq;
 extern __u32 cifs_lock_secret;
 
+extern mempool_t *cifs_sm_req_poolp;
+extern mempool_t *cifs_req_poolp;
 extern mempool_t *cifs_mid_poolp;
 
 /* Operations for different SMB versions */
index 86ae578904a269be0fd17c7d110dc1548ef2f203..9b85b5341822e73d9a4746a027f50121f01873c3 100644 (file)
@@ -52,9 +52,6 @@
 #include "fs_context.h"
 #include "cifs_swn.h"
 
-extern mempool_t *cifs_req_poolp;
-extern bool disable_legacy_dialects;
-
 /* FIXME: should these be tunable? */
 #define TLINK_ERROR_EXPIRE     (1 * HZ)
 #define TLINK_IDLE_EXPIRE      (600 * HZ)
@@ -123,12 +120,16 @@ static void smb2_query_server_interfaces(struct work_struct *work)
        struct cifs_tcon *tcon = container_of(work,
                                        struct cifs_tcon,
                                        query_interfaces.work);
+       struct TCP_Server_Info *server = tcon->ses->server;
 
        /*
         * query server network interfaces, in case they change
         */
+       if (!server->ops->query_server_interfaces)
+               return;
+
        xid = get_xid();
-       rc = SMB3_request_interfaces(xid, tcon, false);
+       rc = server->ops->query_server_interfaces(xid, tcon, false);
        free_xid(xid);
 
        if (rc) {
index ec25d3c3e1ee3985152bec6c8e66a801917d9c0e..16aadce492b2ec67b973c8726e7cefd4857197d5 100644 (file)
@@ -486,7 +486,6 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
        cfile->uid = current_fsuid();
        cfile->dentry = dget(dentry);
        cfile->f_flags = file->f_flags;
-       cfile->status_file_deleted = false;
        cfile->invalidHandle = false;
        cfile->deferred_close_scheduled = false;
        cfile->tlink = cifs_get_tlink(tlink);
@@ -1073,6 +1072,19 @@ void smb2_deferred_work_close(struct work_struct *work)
        _cifsFileInfo_put(cfile, true, false);
 }
 
+static bool
+smb2_can_defer_close(struct inode *inode, struct cifs_deferred_close *dclose)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsInodeInfo *cinode = CIFS_I(inode);
+
+       return (cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose &&
+                       (cinode->oplock == CIFS_CACHE_RHW_FLG ||
+                        cinode->oplock == CIFS_CACHE_RH_FLG) &&
+                       !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags));
+
+}
+
 int cifs_close(struct inode *inode, struct file *file)
 {
        struct cifsFileInfo *cfile;
@@ -1086,10 +1098,8 @@ int cifs_close(struct inode *inode, struct file *file)
                cfile = file->private_data;
                file->private_data = NULL;
                dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
-               if ((cifs_sb->ctx->closetimeo && cinode->oplock == CIFS_CACHE_RHW_FLG)
-                   && cinode->lease_granted &&
-                   !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags) &&
-                   dclose && !(cfile->status_file_deleted)) {
+               if ((cfile->status_file_deleted == false) &&
+                   (smb2_can_defer_close(inode, dclose))) {
                        if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
                                inode_set_mtime_to_ts(inode,
                                                      inode_set_ctime_current(inode));
index 8177ec59afeef6bfbb9df666836bb9496de4b6c4..d28ab0af60493623f3d209c4f36b5ccea14973bb 100644 (file)
@@ -401,7 +401,6 @@ cifs_get_file_info_unix(struct file *filp)
                cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
        } else if (rc == -EREMOTE) {
                cifs_create_junction_fattr(&fattr, inode->i_sb);
-               rc = 0;
        } else
                goto cifs_gfiunix_out;
 
@@ -820,8 +819,10 @@ cifs_get_file_info(struct file *filp)
        void *page = alloc_dentry_path();
        const unsigned char *path;
 
-       if (!server->ops->query_file_info)
+       if (!server->ops->query_file_info) {
+               free_dentry_path(page);
                return -ENOSYS;
+       }
 
        xid = get_xid();
        rc = server->ops->query_file_info(xid, tcon, cfile, &data);
@@ -835,8 +836,8 @@ cifs_get_file_info(struct file *filp)
                }
                path = build_path_from_dentry(dentry, page);
                if (IS_ERR(path)) {
-                       free_dentry_path(page);
-                       return PTR_ERR(path);
+                       rc = PTR_ERR(path);
+                       goto cgfi_exit;
                }
                cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
                if (fattr.cf_flags & CIFS_FATTR_DELETE_PENDING)
@@ -844,7 +845,6 @@ cifs_get_file_info(struct file *filp)
                break;
        case -EREMOTE:
                cifs_create_junction_fattr(&fattr, inode->i_sb);
-               rc = 0;
                break;
        case -EOPNOTSUPP:
        case -EINVAL:
@@ -1009,7 +1009,6 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
        struct kvec rsp_iov, *iov = NULL;
        int rsp_buftype = CIFS_NO_BUFFER;
        u32 tag = data->reparse.tag;
-       struct inode *inode = NULL;
        int rc = 0;
 
        if (!tag && server->ops->query_reparse_point) {
@@ -1049,12 +1048,8 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
 
        if (tcon->posix_extensions)
                smb311_posix_info_to_fattr(fattr, data, sb);
-       else {
+       else
                cifs_open_info_to_fattr(fattr, data, sb);
-               inode = cifs_iget(sb, fattr);
-               if (inode && fattr->cf_flags & CIFS_FATTR_DELETE_PENDING)
-                       cifs_mark_open_handles_for_deleted_file(inode, full_path);
-       }
 out:
        fattr->cf_cifstag = data->reparse.tag;
        free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
@@ -1109,9 +1104,9 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
                                                   full_path, fattr);
                } else {
                        cifs_open_info_to_fattr(fattr, data, sb);
-                       if (fattr->cf_flags & CIFS_FATTR_DELETE_PENDING)
-                               cifs_mark_open_handles_for_deleted_file(*inode, full_path);
                }
+               if (!rc && fattr->cf_flags & CIFS_FATTR_DELETE_PENDING)
+                       cifs_mark_open_handles_for_deleted_file(*inode, full_path);
                break;
        case -EREMOTE:
                /* DFS link, no metadata available on this server */
@@ -1340,6 +1335,8 @@ int smb311_posix_get_inode_info(struct inode **inode,
                goto out;
 
        rc = update_inode_info(sb, &fattr, inode);
+       if (!rc && fattr.cf_flags & CIFS_FATTR_DELETE_PENDING)
+               cifs_mark_open_handles_for_deleted_file(*inode, full_path);
 out:
        kfree(fattr.cf_symlink_target);
        return rc;
@@ -1501,6 +1498,9 @@ iget_root:
                goto out;
        }
 
+       if (!rc && fattr.cf_flags & CIFS_FATTR_DELETE_PENDING)
+               cifs_mark_open_handles_for_deleted_file(inode, path);
+
        if (rc && tcon->pipe) {
                cifs_dbg(FYI, "ipc connection - fake read inode\n");
                spin_lock(&inode->i_lock);
index 9428a0db77183ffc4ab7cc4164d19f7c5409449a..c3771fc81328ff12d7d075cadab77c97b16b7e05 100644 (file)
@@ -27,9 +27,6 @@
 #include "fs_context.h"
 #include "cached_dir.h"
 
-extern mempool_t *cifs_sm_req_poolp;
-extern mempool_t *cifs_req_poolp;
-
 /* The xid serves as a useful identifier for each incoming vfs request,
    in a similar way to the mid which is useful to track each sent smb,
    and CurrentXid can also provide a running counter (although it
index 8f37373fd33344bacbf4d492f6115d9396573379..3216f786908fbb2ac8345cf5929fadf8ec6920d4 100644 (file)
@@ -230,7 +230,7 @@ int cifs_try_adding_channels(struct cifs_ses *ses)
                spin_lock(&ses->iface_lock);
                if (!ses->iface_count) {
                        spin_unlock(&ses->iface_lock);
-                       cifs_dbg(VFS, "server %s does not advertise interfaces\n",
+                       cifs_dbg(ONCE, "server %s does not advertise interfaces\n",
                                      ses->server->hostname);
                        break;
                }
@@ -396,7 +396,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
        spin_lock(&ses->iface_lock);
        if (!ses->iface_count) {
                spin_unlock(&ses->iface_lock);
-               cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname);
+               cifs_dbg(ONCE, "server %s does not advertise interfaces\n", ses->server->hostname);
                return;
        }
 
index 6ee22d0dbc006112c23ce6fea483a4db9cd00cf5..2ed456948f34ca0cd88dbe626429694456a681e2 100644 (file)
@@ -5290,6 +5290,7 @@ struct smb_version_operations smb30_operations = {
        .tree_connect = SMB2_tcon,
        .tree_disconnect = SMB2_tdis,
        .qfs_tcon = smb3_qfs_tcon,
+       .query_server_interfaces = SMB3_request_interfaces,
        .is_path_accessible = smb2_is_path_accessible,
        .can_echo = smb2_can_echo,
        .echo = SMB2_echo,
@@ -5405,6 +5406,7 @@ struct smb_version_operations smb311_operations = {
        .tree_connect = SMB2_tcon,
        .tree_disconnect = SMB2_tdis,
        .qfs_tcon = smb3_qfs_tcon,
+       .query_server_interfaces = SMB3_request_interfaces,
        .is_path_accessible = smb2_is_path_accessible,
        .can_echo = smb2_can_echo,
        .echo = SMB2_echo,
index e5e6b14f8cae37bb6ac470c457e34fcf437458a1..3ea688558e6c9b96f454e29197023ec74f274e2a 100644 (file)
@@ -409,14 +409,15 @@ skip_sess_setup:
        spin_unlock(&ses->ses_lock);
 
        if (!rc &&
-           (server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
+           (server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL) &&
+           server->ops->query_server_interfaces) {
                mutex_unlock(&ses->session_mutex);
 
                /*
                 * query server network interfaces, in case they change
                 */
                xid = get_xid();
-               rc = SMB3_request_interfaces(xid, tcon, false);
+               rc = server->ops->query_server_interfaces(xid, tcon, false);
                free_xid(xid);
 
                if (rc == -EOPNOTSUPP && ses->chan_count > 1) {
index 20784f76a60455504e6febd6bd3d22f9ce43bee2..1b594307c9d5a01e0b9d62b47b331dbd31c6dfaf 100644 (file)
@@ -227,7 +227,7 @@ struct smb2_compression_hdr {
        __le32 OriginalCompressedSegmentSize;
        __le16 CompressionAlgorithm;
        __le16 Flags;
-       __le16 Offset; /* this is the size of the uncompressed SMB2 header below */
+       __le32 Offset; /* this is the size of the uncompressed SMB2 header below */
        /* uncompressed SMB2 header (READ or WRITE) goes here */
        /* compressed data goes here */
 } __packed;
@@ -280,15 +280,16 @@ struct smb3_blob_data {
 #define SE_GROUP_RESOURCE              0x20000000
 #define SE_GROUP_LOGON_ID              0xC0000000
 
-/* struct sid_attr_data is SidData array in BlobData format then le32 Attr */
-
 struct sid_array_data {
        __le16 SidAttrCount;
        /* SidAttrList - array of sid_attr_data structs */
 } __packed;
 
-struct luid_attr_data {
-
+/* struct sid_attr_data is SidData array in BlobData format then le32 Attr */
+struct sid_attr_data {
+       __le16 BlobSize;
+       __u8 BlobData[];
+       /* __le32 Attr */
 } __packed;
 
 /*
@@ -502,6 +503,7 @@ struct smb2_encryption_neg_context {
 #define SMB3_COMPRESS_LZ77_HUFF        cpu_to_le16(0x0003)
 /* Pattern scanning algorithm See MS-SMB2 3.1.4.4.1 */
 #define SMB3_COMPRESS_PATTERN  cpu_to_le16(0x0004) /* Pattern_V1 */
+#define SMB3_COMPRESS_LZ4      cpu_to_le16(0x0005)
 
 /* Compression Flags */
 #define SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE                cpu_to_le32(0x00000000)
index 5b8f3e0ebdb36aef86f79c1ca475e646fa300f87..d528b20b37a85f6fab7dad4088247940d8616efc 100644 (file)
@@ -12,8 +12,6 @@
 #include "unicode.h"
 #include "vfs_cache.h"
 
-#define KSMBD_VERSION  "3.4.2"
-
 extern int ksmbd_debug_types;
 
 #define KSMBD_DEBUG_SMB                BIT(0)
index 0ebf91ffa2361c0940aba0fc301d1a65bf1612e5..8ca8a45c4c621c5dabf56664bec27e5df0db8356 100644 (file)
@@ -75,6 +75,7 @@ struct ksmbd_heartbeat {
 #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION      BIT(1)
 #define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL    BIT(2)
 #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF  BIT(3)
+#define KSMBD_GLOBAL_FLAG_DURABLE_HANDLE       BIT(4)
 
 /*
  * IPC request for ksmbd server startup
index 15f68ee0508946843983b7d773dc6837f12b3bf0..aec0a7a124052a43700e331d93acaafa76bc4392 100644 (file)
@@ -156,7 +156,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
        kfree(sess);
 }
 
-static struct ksmbd_session *__session_lookup(unsigned long long id)
+struct ksmbd_session *__session_lookup(unsigned long long id)
 {
        struct ksmbd_session *sess;
 
@@ -305,6 +305,32 @@ struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
        return sess;
 }
 
+void destroy_previous_session(struct ksmbd_conn *conn,
+                             struct ksmbd_user *user, u64 id)
+{
+       struct ksmbd_session *prev_sess;
+       struct ksmbd_user *prev_user;
+
+       down_write(&sessions_table_lock);
+       down_write(&conn->session_lock);
+       prev_sess = __session_lookup(id);
+       if (!prev_sess || prev_sess->state == SMB2_SESSION_EXPIRED)
+               goto out;
+
+       prev_user = prev_sess->user;
+       if (!prev_user ||
+           strcmp(user->name, prev_user->name) ||
+           user->passkey_sz != prev_user->passkey_sz ||
+           memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
+               goto out;
+
+       ksmbd_destroy_file_table(&prev_sess->file_table);
+       prev_sess->state = SMB2_SESSION_EXPIRED;
+out:
+       up_write(&conn->session_lock);
+       up_write(&sessions_table_lock);
+}
+
 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
                                           unsigned long long id)
 {
index 63cb08fffde84c4a5f03b936577fe02288885b6e..dc9fded2cd4379a66342e3c3f87aa1423400ac1f 100644 (file)
@@ -88,8 +88,11 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
 int ksmbd_session_register(struct ksmbd_conn *conn,
                           struct ksmbd_session *sess);
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
+struct ksmbd_session *__session_lookup(unsigned long long id);
 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
                                               unsigned long long id);
+void destroy_previous_session(struct ksmbd_conn *conn,
+                             struct ksmbd_user *user, u64 id);
 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
                                                    u64 sess_id);
 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
index 53dfaac425c68dc5f2192924b546b4f9fb71f6c8..4978edfb15f9d7fe452e14c7ffd03b820d2165e9 100644 (file)
@@ -159,7 +159,8 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
        opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,
                                        op_entry);
        if (opinfo) {
-               if (!atomic_inc_not_zero(&opinfo->refcount))
+               if (opinfo->conn == NULL ||
+                   !atomic_inc_not_zero(&opinfo->refcount))
                        opinfo = NULL;
                else {
                        atomic_inc(&opinfo->conn->r_count);
@@ -527,7 +528,7 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
         */
        read_lock(&ci->m_lock);
        list_for_each_entry(opinfo, &ci->m_op_list, op_entry) {
-               if (!opinfo->is_lease)
+               if (!opinfo->is_lease || !opinfo->conn)
                        continue;
                read_unlock(&ci->m_lock);
                lease = opinfo->o_lease;
@@ -641,7 +642,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
        struct smb2_hdr *rsp_hdr;
        struct ksmbd_file *fp;
 
-       fp = ksmbd_lookup_durable_fd(br_info->fid);
+       fp = ksmbd_lookup_global_fd(br_info->fid);
        if (!fp)
                goto out;
 
@@ -1106,7 +1107,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
 
        read_lock(&p_ci->m_lock);
        list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
-               if (!opinfo->is_lease)
+               if (opinfo->conn == NULL || !opinfo->is_lease)
                        continue;
 
                if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE &&
@@ -1142,7 +1143,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
        opinfo = rcu_dereference(fp->f_opinfo);
        rcu_read_unlock();
 
-       if (!opinfo->is_lease || opinfo->o_lease->version != 2)
+       if (!opinfo || !opinfo->is_lease || opinfo->o_lease->version != 2)
                return;
 
        p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);
@@ -1151,7 +1152,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
 
        read_lock(&p_ci->m_lock);
        list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
-               if (!opinfo->is_lease)
+               if (opinfo->conn == NULL || !opinfo->is_lease)
                        continue;
 
                if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE) {
@@ -1361,6 +1362,9 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
 
        rcu_read_lock();
        list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {
+               if (brk_op->conn == NULL)
+                       continue;
+
                if (!atomic_inc_not_zero(&brk_op->refcount))
                        continue;
 
@@ -1496,11 +1500,10 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
 /**
  * parse_lease_state() - parse lease context containted in file open request
  * @open_req:  buffer containing smb2 file open(create) request
- * @is_dir:    whether leasing file is directory
  *
  * Return:  oplock state, -ENOENT if create lease context not found
  */
-struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir)
+struct lease_ctx_info *parse_lease_state(void *open_req)
 {
        struct create_context *cc;
        struct smb2_create_req *req = (struct smb2_create_req *)open_req;
@@ -1518,12 +1521,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir)
                struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
 
                memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
-               if (is_dir) {
-                       lreq->req_state = lc->lcontext.LeaseState &
-                               ~SMB2_LEASE_WRITE_CACHING_LE;
-                       lreq->is_dir = true;
-               } else
-                       lreq->req_state = lc->lcontext.LeaseState;
+               lreq->req_state = lc->lcontext.LeaseState;
                lreq->flags = lc->lcontext.LeaseFlags;
                lreq->epoch = lc->lcontext.Epoch;
                lreq->duration = lc->lcontext.LeaseDuration;
@@ -1646,6 +1644,8 @@ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp)
        buf->Name[3] = 'Q';
 
        buf->Timeout = cpu_to_le32(fp->durable_timeout);
+       if (fp->is_persistent)
+               buf->Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
 }
 
 /**
@@ -1813,3 +1813,71 @@ out:
        read_unlock(&lease_list_lock);
        return ret_op;
 }
+
+int smb2_check_durable_oplock(struct ksmbd_conn *conn,
+                             struct ksmbd_share_config *share,
+                             struct ksmbd_file *fp,
+                             struct lease_ctx_info *lctx,
+                             char *name)
+{
+       struct oplock_info *opinfo = opinfo_get(fp);
+       int ret = 0;
+
+       if (!opinfo)
+               return 0;
+
+       if (opinfo->is_lease == false) {
+               if (lctx) {
+                       pr_err("create context include lease\n");
+                       ret = -EBADF;
+                       goto out;
+               }
+
+               if (opinfo->level != SMB2_OPLOCK_LEVEL_BATCH) {
+                       pr_err("oplock level is not equal to SMB2_OPLOCK_LEVEL_BATCH\n");
+                       ret = -EBADF;
+               }
+
+               goto out;
+       }
+
+       if (memcmp(conn->ClientGUID, fp->client_guid,
+                               SMB2_CLIENT_GUID_SIZE)) {
+               ksmbd_debug(SMB, "Client guid of fp is not equal to the one of connection\n");
+               ret = -EBADF;
+               goto out;
+       }
+
+       if (!lctx) {
+               ksmbd_debug(SMB, "create context does not include lease\n");
+               ret = -EBADF;
+               goto out;
+       }
+
+       if (memcmp(opinfo->o_lease->lease_key, lctx->lease_key,
+                               SMB2_LEASE_KEY_SIZE)) {
+               ksmbd_debug(SMB,
+                           "lease key of fp does not match lease key in create context\n");
+               ret = -EBADF;
+               goto out;
+       }
+
+       if (!(opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE)) {
+               ksmbd_debug(SMB, "lease state does not contain SMB2_LEASE_HANDLE_CACHING\n");
+               ret = -EBADF;
+               goto out;
+       }
+
+       if (opinfo->o_lease->version != lctx->version) {
+               ksmbd_debug(SMB,
+                           "lease version of fp does not match the one in create context\n");
+               ret = -EBADF;
+               goto out;
+       }
+
+       if (!ksmbd_inode_pending_delete(fp))
+               ret = ksmbd_validate_name_reconnect(share, fp, name);
+out:
+       opinfo_put(opinfo);
+       return ret;
+}
index 5b93ea9196c013d0b757add55db43c143cd9706b..e9da63f25b2061d495b924ecdeede7b4de428d68 100644 (file)
@@ -111,7 +111,7 @@ void opinfo_put(struct oplock_info *opinfo);
 
 /* Lease related functions */
 void create_lease_buf(u8 *rbuf, struct lease *lease);
-struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir);
+struct lease_ctx_info *parse_lease_state(void *open_req);
 __u8 smb2_map_lease_to_oplock(__le32 lease_state);
 int lease_read_to_write(struct oplock_info *opinfo);
 
@@ -130,4 +130,9 @@ void destroy_lease_table(struct ksmbd_conn *conn);
 void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
                                      struct lease_ctx_info *lctx);
 void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp);
+int smb2_check_durable_oplock(struct ksmbd_conn *conn,
+                             struct ksmbd_share_config *share,
+                             struct ksmbd_file *fp,
+                             struct lease_ctx_info *lctx,
+                             char *name);
 #endif /* __KSMBD_OPLOCK_H */
index 3079e607c5fe6db71e3cc70a76bcb26d90f813c3..c0788188aa82fa39211f0be694a13f925408580c 100644 (file)
@@ -625,7 +625,6 @@ static void __exit ksmbd_server_exit(void)
 }
 
 MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>");
-MODULE_VERSION(KSMBD_VERSION);
 MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
 MODULE_LICENSE("GPL");
 MODULE_SOFTDEP("pre: ecb");
index 03dded29a9804205f7f96802d99beb28a1c8eaf9..727cb49926ee52b7c12e9b784fe4a53432ab51a2 100644 (file)
@@ -101,13 +101,17 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
                *len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength);
                break;
        case SMB2_TREE_CONNECT:
-               *off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset);
+               *off = max_t(unsigned short int,
+                            le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset),
+                            offsetof(struct smb2_tree_connect_req, Buffer));
                *len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength);
                break;
        case SMB2_CREATE:
        {
                unsigned short int name_off =
-                       le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset);
+                       max_t(unsigned short int,
+                             le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset),
+                             offsetof(struct smb2_create_req, Buffer));
                unsigned short int name_len =
                        le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength);
 
@@ -128,11 +132,15 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
                break;
        }
        case SMB2_QUERY_INFO:
-               *off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset);
+               *off = max_t(unsigned int,
+                            le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset),
+                            offsetof(struct smb2_query_info_req, Buffer));
                *len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength);
                break;
        case SMB2_SET_INFO:
-               *off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset);
+               *off = max_t(unsigned int,
+                            le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset),
+                            offsetof(struct smb2_set_info_req, Buffer));
                *len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength);
                break;
        case SMB2_READ:
@@ -142,7 +150,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
        case SMB2_WRITE:
                if (((struct smb2_write_req *)hdr)->DataOffset ||
                    ((struct smb2_write_req *)hdr)->Length) {
-                       *off = max_t(unsigned int,
+                       *off = max_t(unsigned short int,
                                     le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),
                                     offsetof(struct smb2_write_req, Buffer));
                        *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);
@@ -153,7 +161,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
                *len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength);
                break;
        case SMB2_QUERY_DIRECTORY:
-               *off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset);
+               *off = max_t(unsigned short int,
+                            le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset),
+                            offsetof(struct smb2_query_directory_req, Buffer));
                *len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength);
                break;
        case SMB2_LOCK:
@@ -168,7 +178,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
                break;
        }
        case SMB2_IOCTL:
-               *off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset);
+               *off = max_t(unsigned int,
+                            le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset),
+                            offsetof(struct smb2_ioctl_req, Buffer));
                *len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount);
                break;
        default:
index 27a9dce3e03abe4673ac7241aa828943d22754d8..a45f7dca482e01897720cd69d90291cbaf3ff388 100644 (file)
@@ -256,6 +256,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
 
        if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
                conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
+
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE)
+               conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES;
 }
 
 /**
@@ -283,6 +286,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
        if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
                conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
 
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE)
+               conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES;
+
        INIT_LIST_HEAD(&conn->preauth_sess_table);
        return 0;
 }
index 089527a8b4ff42211c7bccdd4aa8adba9b984436..d478fa0c57abdbc7b8478624edf5133e202c85bf 100644 (file)
@@ -607,30 +607,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
        return -ENOENT;
 }
 
-static void destroy_previous_session(struct ksmbd_conn *conn,
-                                    struct ksmbd_user *user, u64 id)
-{
-       struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
-       struct ksmbd_user *prev_user;
-       struct channel *chann;
-       long index;
-
-       if (!prev_sess)
-               return;
-
-       prev_user = prev_sess->user;
-
-       if (!prev_user ||
-           strcmp(user->name, prev_user->name) ||
-           user->passkey_sz != prev_user->passkey_sz ||
-           memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
-               return;
-
-       prev_sess->state = SMB2_SESSION_EXPIRED;
-       xa_for_each(&prev_sess->ksmbd_chann_list, index, chann)
-               ksmbd_conn_set_exiting(chann->conn);
-}
-
 /**
  * smb2_get_name() - get filename string from on the wire smb format
  * @src:       source buffer
@@ -1951,7 +1927,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
 
        WORK_BUFFERS(work, req, rsp);
 
-       treename = smb_strndup_from_utf16(req->Buffer,
+       treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset),
                                          le16_to_cpu(req->PathLength), true,
                                          conn->local_nls);
        if (IS_ERR(treename)) {
@@ -2642,6 +2618,165 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr,
        }
 }
 
+enum {
+       DURABLE_RECONN_V2 = 1,
+       DURABLE_RECONN,
+       DURABLE_REQ_V2,
+       DURABLE_REQ,
+};
+
+struct durable_info {
+       struct ksmbd_file *fp;
+       unsigned short int type;
+       bool persistent;
+       bool reconnected;
+       unsigned int timeout;
+       char *CreateGuid;
+};
+
+static int parse_durable_handle_context(struct ksmbd_work *work,
+                                       struct smb2_create_req *req,
+                                       struct lease_ctx_info *lc,
+                                       struct durable_info *dh_info)
+{
+       struct ksmbd_conn *conn = work->conn;
+       struct create_context *context;
+       int dh_idx, err = 0;
+       u64 persistent_id = 0;
+       int req_op_level;
+       static const char * const durable_arr[] = {"DH2C", "DHnC", "DH2Q", "DHnQ"};
+
+       req_op_level = req->RequestedOplockLevel;
+       for (dh_idx = DURABLE_RECONN_V2; dh_idx <= ARRAY_SIZE(durable_arr);
+            dh_idx++) {
+               context = smb2_find_context_vals(req, durable_arr[dh_idx - 1], 4);
+               if (IS_ERR(context)) {
+                       err = PTR_ERR(context);
+                       goto out;
+               }
+               if (!context)
+                       continue;
+
+               switch (dh_idx) {
+               case DURABLE_RECONN_V2:
+               {
+                       struct create_durable_reconn_v2_req *recon_v2;
+
+                       if (dh_info->type == DURABLE_RECONN ||
+                           dh_info->type == DURABLE_REQ_V2) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+
+                       recon_v2 = (struct create_durable_reconn_v2_req *)context;
+                       persistent_id = recon_v2->Fid.PersistentFileId;
+                       dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
+                       if (!dh_info->fp) {
+                               ksmbd_debug(SMB, "Failed to get durable handle state\n");
+                               err = -EBADF;
+                               goto out;
+                       }
+
+                       if (memcmp(dh_info->fp->create_guid, recon_v2->CreateGuid,
+                                  SMB2_CREATE_GUID_SIZE)) {
+                               err = -EBADF;
+                               ksmbd_put_durable_fd(dh_info->fp);
+                               goto out;
+                       }
+
+                       dh_info->type = dh_idx;
+                       dh_info->reconnected = true;
+                       ksmbd_debug(SMB,
+                               "reconnect v2 Persistent-id from reconnect = %llu\n",
+                                       persistent_id);
+                       break;
+               }
+               case DURABLE_RECONN:
+               {
+                       struct create_durable_reconn_req *recon;
+
+                       if (dh_info->type == DURABLE_RECONN_V2 ||
+                           dh_info->type == DURABLE_REQ_V2) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+
+                       recon = (struct create_durable_reconn_req *)context;
+                       persistent_id = recon->Data.Fid.PersistentFileId;
+                       dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
+                       if (!dh_info->fp) {
+                               ksmbd_debug(SMB, "Failed to get durable handle state\n");
+                               err = -EBADF;
+                               goto out;
+                       }
+
+                       dh_info->type = dh_idx;
+                       dh_info->reconnected = true;
+                       ksmbd_debug(SMB, "reconnect Persistent-id from reconnect = %llu\n",
+                                   persistent_id);
+                       break;
+               }
+               case DURABLE_REQ_V2:
+               {
+                       struct create_durable_req_v2 *durable_v2_blob;
+
+                       if (dh_info->type == DURABLE_RECONN ||
+                           dh_info->type == DURABLE_RECONN_V2) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+
+                       durable_v2_blob =
+                               (struct create_durable_req_v2 *)context;
+                       ksmbd_debug(SMB, "Request for durable v2 open\n");
+                       dh_info->fp = ksmbd_lookup_fd_cguid(durable_v2_blob->CreateGuid);
+                       if (dh_info->fp) {
+                               if (!memcmp(conn->ClientGUID, dh_info->fp->client_guid,
+                                           SMB2_CLIENT_GUID_SIZE)) {
+                                       if (!(req->hdr.Flags & SMB2_FLAGS_REPLAY_OPERATION)) {
+                                               err = -ENOEXEC;
+                                               goto out;
+                                       }
+
+                                       dh_info->fp->conn = conn;
+                                       dh_info->reconnected = true;
+                                       goto out;
+                               }
+                       }
+
+                       if (((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||
+                            req_op_level == SMB2_OPLOCK_LEVEL_BATCH)) {
+                               dh_info->CreateGuid =
+                                       durable_v2_blob->CreateGuid;
+                               dh_info->persistent =
+                                       le32_to_cpu(durable_v2_blob->Flags);
+                               dh_info->timeout =
+                                       le32_to_cpu(durable_v2_blob->Timeout);
+                               dh_info->type = dh_idx;
+                       }
+                       break;
+               }
+               case DURABLE_REQ:
+                       if (dh_info->type == DURABLE_RECONN)
+                               goto out;
+                       if (dh_info->type == DURABLE_RECONN_V2 ||
+                           dh_info->type == DURABLE_REQ_V2) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+
+                       if (((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||
+                            req_op_level == SMB2_OPLOCK_LEVEL_BATCH)) {
+                               ksmbd_debug(SMB, "Request for durable open\n");
+                               dh_info->type = dh_idx;
+                       }
+               }
+       }
+
+out:
+       return err;
+}
+
 /**
  * smb2_open() - handler for smb file open request
  * @work:      smb work containing request buffer
@@ -2665,6 +2800,7 @@ int smb2_open(struct ksmbd_work *work)
        struct lease_ctx_info *lc = NULL;
        struct create_ea_buf_req *ea_buf = NULL;
        struct oplock_info *opinfo;
+       struct durable_info dh_info = {0};
        __le32 *next_ptr = NULL;
        int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0;
        int rc = 0;
@@ -2704,7 +2840,7 @@ int smb2_open(struct ksmbd_work *work)
                        goto err_out2;
                }
 
-               name = smb2_get_name(req->Buffer,
+               name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset),
                                     le16_to_cpu(req->NameLength),
                                     work->conn->local_nls);
                if (IS_ERR(name)) {
@@ -2745,6 +2881,49 @@ int smb2_open(struct ksmbd_work *work)
                }
        }
 
+       req_op_level = req->RequestedOplockLevel;
+
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE &&
+           req->CreateContextsOffset) {
+               lc = parse_lease_state(req);
+               rc = parse_durable_handle_context(work, req, lc, &dh_info);
+               if (rc) {
+                       ksmbd_debug(SMB, "error parsing durable handle context\n");
+                       goto err_out2;
+               }
+
+               if (dh_info.reconnected == true) {
+                       rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, name);
+                       if (rc) {
+                               ksmbd_put_durable_fd(dh_info.fp);
+                               goto err_out2;
+                       }
+
+                       rc = ksmbd_reopen_durable_fd(work, dh_info.fp);
+                       if (rc) {
+                               ksmbd_put_durable_fd(dh_info.fp);
+                               goto err_out2;
+                       }
+
+                       if (ksmbd_override_fsids(work)) {
+                               rc = -ENOMEM;
+                               ksmbd_put_durable_fd(dh_info.fp);
+                               goto err_out2;
+                       }
+
+                       fp = dh_info.fp;
+                       file_info = FILE_OPENED;
+
+                       rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat);
+                       if (rc)
+                               goto err_out2;
+
+                       ksmbd_put_durable_fd(fp);
+                       goto reconnected_fp;
+               }
+       } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
+               lc = parse_lease_state(req);
+
        if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) {
                pr_err("Invalid impersonationlevel : 0x%x\n",
                       le32_to_cpu(req->ImpersonationLevel));
@@ -3207,10 +3386,6 @@ int smb2_open(struct ksmbd_work *work)
                need_truncate = 1;
        }
 
-       req_op_level = req->RequestedOplockLevel;
-       if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
-               lc = parse_lease_state(req, S_ISDIR(file_inode(filp)->i_mode));
-
        share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
        if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||
            (req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&
@@ -3221,6 +3396,11 @@ int smb2_open(struct ksmbd_work *work)
                }
        } else {
                if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
+                       if (S_ISDIR(file_inode(filp)->i_mode)) {
+                               lc->req_state &= ~SMB2_LEASE_WRITE_CACHING_LE;
+                               lc->is_dir = true;
+                       }
+
                        /*
                         * Compare parent lease using parent key. If there is no
                         * a lease that has same parent key, Send lease break
@@ -3317,6 +3497,24 @@ int smb2_open(struct ksmbd_work *work)
 
        memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
 
+       if (dh_info.type == DURABLE_REQ_V2 || dh_info.type == DURABLE_REQ) {
+               if (dh_info.type == DURABLE_REQ_V2 && dh_info.persistent)
+                       fp->is_persistent = true;
+               else
+                       fp->is_durable = true;
+
+               if (dh_info.type == DURABLE_REQ_V2) {
+                       memcpy(fp->create_guid, dh_info.CreateGuid,
+                                       SMB2_CREATE_GUID_SIZE);
+                       if (dh_info.timeout)
+                               fp->durable_timeout = min(dh_info.timeout,
+                                               300000);
+                       else
+                               fp->durable_timeout = 60;
+               }
+       }
+
+reconnected_fp:
        rsp->StructureSize = cpu_to_le16(89);
        rcu_read_lock();
        opinfo = rcu_dereference(fp->f_opinfo);
@@ -3403,6 +3601,33 @@ int smb2_open(struct ksmbd_work *work)
                next_off = conn->vals->create_disk_id_size;
        }
 
+       if (dh_info.type == DURABLE_REQ || dh_info.type == DURABLE_REQ_V2) {
+               struct create_context *durable_ccontext;
+
+               durable_ccontext = (struct create_context *)(rsp->Buffer +
+                               le32_to_cpu(rsp->CreateContextsLength));
+               contxt_cnt++;
+               if (dh_info.type == DURABLE_REQ) {
+                       create_durable_rsp_buf(rsp->Buffer +
+                                       le32_to_cpu(rsp->CreateContextsLength));
+                       le32_add_cpu(&rsp->CreateContextsLength,
+                                       conn->vals->create_durable_size);
+                       iov_len += conn->vals->create_durable_size;
+               } else {
+                       create_durable_v2_rsp_buf(rsp->Buffer +
+                                       le32_to_cpu(rsp->CreateContextsLength),
+                                       fp);
+                       le32_add_cpu(&rsp->CreateContextsLength,
+                                       conn->vals->create_durable_v2_size);
+                       iov_len += conn->vals->create_durable_v2_size;
+               }
+
+               if (next_ptr)
+                       *next_ptr = cpu_to_le32(next_off);
+               next_ptr = &durable_ccontext->Next;
+               next_off = conn->vals->create_durable_size;
+       }
+
        if (posix_ctxt) {
                contxt_cnt++;
                create_posix_rsp_buf(rsp->Buffer +
@@ -3828,11 +4053,16 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv)
                }
 
                ksmbd_kstat.kstat = &kstat;
-               if (priv->info_level != FILE_NAMES_INFORMATION)
-                       ksmbd_vfs_fill_dentry_attrs(priv->work,
-                                                   idmap,
-                                                   dent,
-                                                   &ksmbd_kstat);
+               if (priv->info_level != FILE_NAMES_INFORMATION) {
+                       rc = ksmbd_vfs_fill_dentry_attrs(priv->work,
+                                                        idmap,
+                                                        dent,
+                                                        &ksmbd_kstat);
+                       if (rc) {
+                               dput(dent);
+                               continue;
+                       }
+               }
 
                rc = smb2_populate_readdir_entry(priv->work->conn,
                                                 priv->info_level,
@@ -4075,7 +4305,7 @@ int smb2_query_dir(struct ksmbd_work *work)
        }
 
        srch_flag = req->Flags;
-       srch_ptr = smb_strndup_from_utf16(req->Buffer,
+       srch_ptr = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->FileNameOffset),
                                          le16_to_cpu(req->FileNameLength), 1,
                                          conn->local_nls);
        if (IS_ERR(srch_ptr)) {
@@ -4335,7 +4565,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
                    sizeof(struct smb2_ea_info_req))
                        return -EINVAL;
 
-               ea_req = (struct smb2_ea_info_req *)req->Buffer;
+               ea_req = (struct smb2_ea_info_req *)((char *)req +
+                                                    le16_to_cpu(req->InputBufferOffset));
        } else {
                /* need to send all EAs, if no specific EA is requested*/
                if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY)
@@ -4480,6 +4711,7 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
        struct smb2_file_basic_info *basic_info;
        struct kstat stat;
        u64 time;
+       int ret;
 
        if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
                pr_err("no right to read the attributes : 0x%x\n",
@@ -4487,9 +4719,12 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
                return -EACCES;
        }
 
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
+
        basic_info = (struct smb2_file_basic_info *)rsp->Buffer;
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
-                        file_inode(fp->filp), &stat);
        basic_info->CreationTime = cpu_to_le64(fp->create_time);
        time = ksmbd_UnixTimeToNT(stat.atime);
        basic_info->LastAccessTime = cpu_to_le64(time);
@@ -4504,27 +4739,31 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
        return 0;
 }
 
-static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
-                                  struct ksmbd_file *fp, void *rsp_org)
+static int get_file_standard_info(struct smb2_query_info_rsp *rsp,
+                                 struct ksmbd_file *fp, void *rsp_org)
 {
        struct smb2_file_standard_info *sinfo;
        unsigned int delete_pending;
-       struct inode *inode;
        struct kstat stat;
+       int ret;
 
-       inode = file_inode(fp->filp);
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
        sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
        delete_pending = ksmbd_inode_pending_delete(fp);
 
-       sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
+       sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
        sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
        sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
        sinfo->DeletePending = delete_pending;
        sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;
        rsp->OutputBufferLength =
                cpu_to_le32(sizeof(struct smb2_file_standard_info));
+
+       return 0;
 }
 
 static void get_file_alignment_info(struct smb2_query_info_rsp *rsp,
@@ -4546,11 +4785,11 @@ static int get_file_all_info(struct ksmbd_work *work,
        struct ksmbd_conn *conn = work->conn;
        struct smb2_file_all_info *file_info;
        unsigned int delete_pending;
-       struct inode *inode;
        struct kstat stat;
        int conv_len;
        char *filename;
        u64 time;
+       int ret;
 
        if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
                ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n",
@@ -4562,8 +4801,10 @@ static int get_file_all_info(struct ksmbd_work *work,
        if (IS_ERR(filename))
                return PTR_ERR(filename);
 
-       inode = file_inode(fp->filp);
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
        ksmbd_debug(SMB, "filename = %s\n", filename);
        delete_pending = ksmbd_inode_pending_delete(fp);
@@ -4579,7 +4820,7 @@ static int get_file_all_info(struct ksmbd_work *work,
        file_info->Attributes = fp->f_ci->m_fattr;
        file_info->Pad1 = 0;
        file_info->AllocationSize =
-               cpu_to_le64(inode->i_blocks << 9);
+               cpu_to_le64(stat.blocks << 9);
        file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
        file_info->NumberOfLinks =
                        cpu_to_le32(get_nlink(&stat) - delete_pending);
@@ -4623,10 +4864,10 @@ static void get_file_alternate_info(struct ksmbd_work *work,
                cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len);
 }
 
-static void get_file_stream_info(struct ksmbd_work *work,
-                                struct smb2_query_info_rsp *rsp,
-                                struct ksmbd_file *fp,
-                                void *rsp_org)
+static int get_file_stream_info(struct ksmbd_work *work,
+                               struct smb2_query_info_rsp *rsp,
+                               struct ksmbd_file *fp,
+                               void *rsp_org)
 {
        struct ksmbd_conn *conn = work->conn;
        struct smb2_file_stream_info *file_info;
@@ -4637,9 +4878,13 @@ static void get_file_stream_info(struct ksmbd_work *work,
        int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
        int buf_free_len;
        struct smb2_query_info_req *req = ksmbd_req_buf_next(work);
+       int ret;
+
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
-                        file_inode(fp->filp), &stat);
        file_info = (struct smb2_file_stream_info *)rsp->Buffer;
 
        buf_free_len =
@@ -4720,29 +4965,37 @@ out:
        kvfree(xattr_list);
 
        rsp->OutputBufferLength = cpu_to_le32(nbytes);
+
+       return 0;
 }
 
-static void get_file_internal_info(struct smb2_query_info_rsp *rsp,
-                                  struct ksmbd_file *fp, void *rsp_org)
+static int get_file_internal_info(struct smb2_query_info_rsp *rsp,
+                                 struct ksmbd_file *fp, void *rsp_org)
 {
        struct smb2_file_internal_info *file_info;
        struct kstat stat;
+       int ret;
+
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
-                        file_inode(fp->filp), &stat);
        file_info = (struct smb2_file_internal_info *)rsp->Buffer;
        file_info->IndexNumber = cpu_to_le64(stat.ino);
        rsp->OutputBufferLength =
                cpu_to_le32(sizeof(struct smb2_file_internal_info));
+
+       return 0;
 }
 
 static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
                                      struct ksmbd_file *fp, void *rsp_org)
 {
        struct smb2_file_ntwrk_info *file_info;
-       struct inode *inode;
        struct kstat stat;
        u64 time;
+       int ret;
 
        if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) {
                pr_err("no right to read the attributes : 0x%x\n",
@@ -4750,10 +5003,12 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
                return -EACCES;
        }
 
-       file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
-       inode = file_inode(fp->filp);
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat);
+       file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer;
 
        file_info->CreationTime = cpu_to_le64(fp->create_time);
        time = ksmbd_UnixTimeToNT(stat.atime);
@@ -4763,8 +5018,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
        time = ksmbd_UnixTimeToNT(stat.ctime);
        file_info->ChangeTime = cpu_to_le64(time);
        file_info->Attributes = fp->f_ci->m_fattr;
-       file_info->AllocationSize =
-               cpu_to_le64(inode->i_blocks << 9);
+       file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
        file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
        file_info->Reserved = cpu_to_le32(0);
        rsp->OutputBufferLength =
@@ -4804,14 +5058,17 @@ static void get_file_mode_info(struct smb2_query_info_rsp *rsp,
                cpu_to_le32(sizeof(struct smb2_file_mode_info));
 }
 
-static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
-                                     struct ksmbd_file *fp, void *rsp_org)
+static int get_file_compression_info(struct smb2_query_info_rsp *rsp,
+                                    struct ksmbd_file *fp, void *rsp_org)
 {
        struct smb2_file_comp_info *file_info;
        struct kstat stat;
+       int ret;
 
-       generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS,
-                        file_inode(fp->filp), &stat);
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
        file_info = (struct smb2_file_comp_info *)rsp->Buffer;
        file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9);
@@ -4823,6 +5080,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp,
 
        rsp->OutputBufferLength =
                cpu_to_le32(sizeof(struct smb2_file_comp_info));
+
+       return 0;
 }
 
 static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
@@ -4844,7 +5103,7 @@ static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp,
        return 0;
 }
 
-static void find_file_posix_info(struct smb2_query_info_rsp *rsp,
+static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
                                struct ksmbd_file *fp, void *rsp_org)
 {
        struct smb311_posix_qinfo *file_info;
@@ -4852,24 +5111,31 @@ static void find_file_posix_info(struct smb2_query_info_rsp *rsp,
        struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);
        vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);
        vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
+       struct kstat stat;
        u64 time;
        int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32;
+       int ret;
+
+       ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                         AT_STATX_SYNC_AS_STAT);
+       if (ret)
+               return ret;
 
        file_info = (struct smb311_posix_qinfo *)rsp->Buffer;
        file_info->CreationTime = cpu_to_le64(fp->create_time);
-       time = ksmbd_UnixTimeToNT(inode_get_atime(inode));
+       time = ksmbd_UnixTimeToNT(stat.atime);
        file_info->LastAccessTime = cpu_to_le64(time);
-       time = ksmbd_UnixTimeToNT(inode_get_mtime(inode));
+       time = ksmbd_UnixTimeToNT(stat.mtime);
        file_info->LastWriteTime = cpu_to_le64(time);
-       time = ksmbd_UnixTimeToNT(inode_get_ctime(inode));
+       time = ksmbd_UnixTimeToNT(stat.ctime);
        file_info->ChangeTime = cpu_to_le64(time);
        file_info->DosAttributes = fp->f_ci->m_fattr;
-       file_info->Inode = cpu_to_le64(inode->i_ino);
-       file_info->EndOfFile = cpu_to_le64(inode->i_size);
-       file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
-       file_info->HardLinks = cpu_to_le32(inode->i_nlink);
-       file_info->Mode = cpu_to_le32(inode->i_mode & 0777);
-       file_info->DeviceId = cpu_to_le32(inode->i_rdev);
+       file_info->Inode = cpu_to_le64(stat.ino);
+       file_info->EndOfFile = cpu_to_le64(stat.size);
+       file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
+       file_info->HardLinks = cpu_to_le32(stat.nlink);
+       file_info->Mode = cpu_to_le32(stat.mode & 0777);
+       file_info->DeviceId = cpu_to_le32(stat.rdev);
 
        /*
         * Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)).
@@ -4882,6 +5148,8 @@ static void find_file_posix_info(struct smb2_query_info_rsp *rsp,
                  SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]);
 
        rsp->OutputBufferLength = cpu_to_le32(out_buf_len);
+
+       return 0;
 }
 
 static int smb2_get_info_file(struct ksmbd_work *work,
@@ -4930,7 +5198,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
                break;
 
        case FILE_STANDARD_INFORMATION:
-               get_file_standard_info(rsp, fp, work->response_buf);
+               rc = get_file_standard_info(rsp, fp, work->response_buf);
                break;
 
        case FILE_ALIGNMENT_INFORMATION:
@@ -4946,11 +5214,11 @@ static int smb2_get_info_file(struct ksmbd_work *work,
                break;
 
        case FILE_STREAM_INFORMATION:
-               get_file_stream_info(work, rsp, fp, work->response_buf);
+               rc = get_file_stream_info(work, rsp, fp, work->response_buf);
                break;
 
        case FILE_INTERNAL_INFORMATION:
-               get_file_internal_info(rsp, fp, work->response_buf);
+               rc = get_file_internal_info(rsp, fp, work->response_buf);
                break;
 
        case FILE_NETWORK_OPEN_INFORMATION:
@@ -4974,7 +5242,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
                break;
 
        case FILE_COMPRESSION_INFORMATION:
-               get_file_compression_info(rsp, fp, work->response_buf);
+               rc = get_file_compression_info(rsp, fp, work->response_buf);
                break;
 
        case FILE_ATTRIBUTE_TAG_INFORMATION:
@@ -4985,7 +5253,7 @@ static int smb2_get_info_file(struct ksmbd_work *work,
                        pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n");
                        rc = -EOPNOTSUPP;
                } else {
-                       find_file_posix_info(rsp, fp, work->response_buf);
+                       rc = find_file_posix_info(rsp, fp, work->response_buf);
                }
                break;
        default:
@@ -5398,7 +5666,6 @@ int smb2_close(struct ksmbd_work *work)
        struct smb2_close_rsp *rsp;
        struct ksmbd_conn *conn = work->conn;
        struct ksmbd_file *fp;
-       struct inode *inode;
        u64 time;
        int err = 0;
 
@@ -5453,24 +5720,33 @@ int smb2_close(struct ksmbd_work *work)
        rsp->Reserved = 0;
 
        if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) {
+               struct kstat stat;
+               int ret;
+
                fp = ksmbd_lookup_fd_fast(work, volatile_id);
                if (!fp) {
                        err = -ENOENT;
                        goto out;
                }
 
-               inode = file_inode(fp->filp);
+               ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                                 AT_STATX_SYNC_AS_STAT);
+               if (ret) {
+                       ksmbd_fd_put(work, fp);
+                       goto out;
+               }
+
                rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
-               rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 :
-                       cpu_to_le64(inode->i_blocks << 9);
-               rsp->EndOfFile = cpu_to_le64(inode->i_size);
+               rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :
+                       cpu_to_le64(stat.blocks << 9);
+               rsp->EndOfFile = cpu_to_le64(stat.size);
                rsp->Attributes = fp->f_ci->m_fattr;
                rsp->CreationTime = cpu_to_le64(fp->create_time);
-               time = ksmbd_UnixTimeToNT(inode_get_atime(inode));
+               time = ksmbd_UnixTimeToNT(stat.atime);
                rsp->LastAccessTime = cpu_to_le64(time);
-               time = ksmbd_UnixTimeToNT(inode_get_mtime(inode));
+               time = ksmbd_UnixTimeToNT(stat.mtime);
                rsp->LastWriteTime = cpu_to_le64(time);
-               time = ksmbd_UnixTimeToNT(inode_get_ctime(inode));
+               time = ksmbd_UnixTimeToNT(stat.ctime);
                rsp->ChangeTime = cpu_to_le64(time);
                ksmbd_fd_put(work, fp);
        } else {
@@ -5759,15 +6035,21 @@ static int set_file_allocation_info(struct ksmbd_work *work,
 
        loff_t alloc_blks;
        struct inode *inode;
+       struct kstat stat;
        int rc;
 
        if (!(fp->daccess & FILE_WRITE_DATA_LE))
                return -EACCES;
 
+       rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
+                        AT_STATX_SYNC_AS_STAT);
+       if (rc)
+               return rc;
+
        alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9;
        inode = file_inode(fp->filp);
 
-       if (alloc_blks > inode->i_blocks) {
+       if (alloc_blks > stat.blocks) {
                smb_break_all_levII_oplock(work, fp, 1);
                rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
                                   alloc_blks * 512);
@@ -5775,7 +6057,7 @@ static int set_file_allocation_info(struct ksmbd_work *work,
                        pr_err("vfs_fallocate is failed : %d\n", rc);
                        return rc;
                }
-       } else if (alloc_blks < inode->i_blocks) {
+       } else if (alloc_blks < stat.blocks) {
                loff_t size;
 
                /*
@@ -5930,6 +6212,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                              struct ksmbd_share_config *share)
 {
        unsigned int buf_len = le32_to_cpu(req->BufferLength);
+       char *buffer = (char *)req + le16_to_cpu(req->BufferOffset);
 
        switch (req->FileInfoClass) {
        case FILE_BASIC_INFORMATION:
@@ -5937,7 +6220,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                if (buf_len < sizeof(struct smb2_file_basic_info))
                        return -EINVAL;
 
-               return set_file_basic_info(fp, (struct smb2_file_basic_info *)req->Buffer, share);
+               return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share);
        }
        case FILE_ALLOCATION_INFORMATION:
        {
@@ -5945,7 +6228,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                        return -EINVAL;
 
                return set_file_allocation_info(work, fp,
-                                               (struct smb2_file_alloc_info *)req->Buffer);
+                                               (struct smb2_file_alloc_info *)buffer);
        }
        case FILE_END_OF_FILE_INFORMATION:
        {
@@ -5953,7 +6236,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                        return -EINVAL;
 
                return set_end_of_file_info(work, fp,
-                                           (struct smb2_file_eof_info *)req->Buffer);
+                                           (struct smb2_file_eof_info *)buffer);
        }
        case FILE_RENAME_INFORMATION:
        {
@@ -5961,7 +6244,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                        return -EINVAL;
 
                return set_rename_info(work, fp,
-                                      (struct smb2_file_rename_info *)req->Buffer,
+                                      (struct smb2_file_rename_info *)buffer,
                                       buf_len);
        }
        case FILE_LINK_INFORMATION:
@@ -5970,7 +6253,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                        return -EINVAL;
 
                return smb2_create_link(work, work->tcon->share_conf,
-                                       (struct smb2_file_link_info *)req->Buffer,
+                                       (struct smb2_file_link_info *)buffer,
                                        buf_len, fp->filp,
                                        work->conn->local_nls);
        }
@@ -5980,7 +6263,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                        return -EINVAL;
 
                return set_file_disposition_info(fp,
-                                                (struct smb2_file_disposition_info *)req->Buffer);
+                                                (struct smb2_file_disposition_info *)buffer);
        }
        case FILE_FULL_EA_INFORMATION:
        {
@@ -5993,7 +6276,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                if (buf_len < sizeof(struct smb2_ea_info))
                        return -EINVAL;
 
-               return smb2_set_ea((struct smb2_ea_info *)req->Buffer,
+               return smb2_set_ea((struct smb2_ea_info *)buffer,
                                   buf_len, &fp->filp->f_path, true);
        }
        case FILE_POSITION_INFORMATION:
@@ -6001,14 +6284,14 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
                if (buf_len < sizeof(struct smb2_file_pos_info))
                        return -EINVAL;
 
-               return set_file_position_info(fp, (struct smb2_file_pos_info *)req->Buffer);
+               return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer);
        }
        case FILE_MODE_INFORMATION:
        {
                if (buf_len < sizeof(struct smb2_file_mode_info))
                        return -EINVAL;
 
-               return set_file_mode_info(fp, (struct smb2_file_mode_info *)req->Buffer);
+               return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer);
        }
        }
 
@@ -6089,7 +6372,7 @@ int smb2_set_info(struct ksmbd_work *work)
                }
                rc = smb2_set_info_sec(fp,
                                       le32_to_cpu(req->AdditionalInformation),
-                                      req->Buffer,
+                                      (char *)req + le16_to_cpu(req->BufferOffset),
                                       le32_to_cpu(req->BufferLength));
                ksmbd_revert_fsids(work);
                break;
@@ -7535,7 +7818,7 @@ static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id,
                                 struct smb2_ioctl_rsp *rsp)
 {
        struct ksmbd_rpc_command *rpc_resp;
-       char *data_buf = (char *)&req->Buffer[0];
+       char *data_buf = (char *)req + le32_to_cpu(req->InputOffset);
        int nbytes = 0;
 
        rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf,
@@ -7648,6 +7931,7 @@ int smb2_ioctl(struct ksmbd_work *work)
        u64 id = KSMBD_NO_FID;
        struct ksmbd_conn *conn = work->conn;
        int ret = 0;
+       char *buffer;
 
        if (work->next_smb2_rcv_hdr_off) {
                req = ksmbd_req_buf_next(work);
@@ -7670,6 +7954,8 @@ int smb2_ioctl(struct ksmbd_work *work)
                goto out;
        }
 
+       buffer = (char *)req + le32_to_cpu(req->InputOffset);
+
        cnt_code = le32_to_cpu(req->CtlCode);
        ret = smb2_calc_max_out_buf_len(work, 48,
                                        le32_to_cpu(req->MaxOutputResponse));
@@ -7727,7 +8013,7 @@ int smb2_ioctl(struct ksmbd_work *work)
                }
 
                ret = fsctl_validate_negotiate_info(conn,
-                       (struct validate_negotiate_info_req *)&req->Buffer[0],
+                       (struct validate_negotiate_info_req *)buffer,
                        (struct validate_negotiate_info_rsp *)&rsp->Buffer[0],
                        in_buf_len);
                if (ret < 0)
@@ -7780,7 +8066,7 @@ int smb2_ioctl(struct ksmbd_work *work)
                rsp->VolatileFileId = req->VolatileFileId;
                rsp->PersistentFileId = req->PersistentFileId;
                fsctl_copychunk(work,
-                               (struct copychunk_ioctl_req *)&req->Buffer[0],
+                               (struct copychunk_ioctl_req *)buffer,
                                le32_to_cpu(req->CtlCode),
                                le32_to_cpu(req->InputCount),
                                req->VolatileFileId,
@@ -7793,8 +8079,7 @@ int smb2_ioctl(struct ksmbd_work *work)
                        goto out;
                }
 
-               ret = fsctl_set_sparse(work, id,
-                                      (struct file_sparse *)&req->Buffer[0]);
+               ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer);
                if (ret < 0)
                        goto out;
                break;
@@ -7817,7 +8102,7 @@ int smb2_ioctl(struct ksmbd_work *work)
                }
 
                zero_data =
-                       (struct file_zero_data_information *)&req->Buffer[0];
+                       (struct file_zero_data_information *)buffer;
 
                off = le64_to_cpu(zero_data->FileOffset);
                bfz = le64_to_cpu(zero_data->BeyondFinalZero);
@@ -7848,7 +8133,7 @@ int smb2_ioctl(struct ksmbd_work *work)
                }
 
                ret = fsctl_query_allocated_ranges(work, id,
-                       (struct file_allocated_range_buffer *)&req->Buffer[0],
+                       (struct file_allocated_range_buffer *)buffer,
                        (struct file_allocated_range_buffer *)&rsp->Buffer[0],
                        out_buf_len /
                        sizeof(struct file_allocated_range_buffer), &nbytes);
@@ -7892,7 +8177,7 @@ int smb2_ioctl(struct ksmbd_work *work)
                        goto out;
                }
 
-               dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0];
+               dup_ext = (struct duplicate_extents_to_file *)buffer;
 
                fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle,
                                             dup_ext->PersistentFileHandle);
index d12cfd3b09278ebb61c59b9590d022f1e126f47f..bd1d2a0e9203a4b5cb5f6509f738b736e578d91c 100644 (file)
@@ -72,6 +72,18 @@ struct create_durable_req_v2 {
        __u8 CreateGuid[16];
 } __packed;
 
+struct create_durable_reconn_req {
+       struct create_context ccontext;
+       __u8   Name[8];
+       union {
+               __u8  Reserved[16];
+               struct {
+                       __u64 PersistentFileId;
+                       __u64 VolatileFileId;
+               } Fid;
+       } Data;
+} __packed;
+
 struct create_durable_reconn_v2_req {
        struct create_context ccontext;
        __u8   Name[8];
@@ -98,6 +110,9 @@ struct create_durable_rsp {
        } Data;
 } __packed;
 
+/* See MS-SMB2 2.2.13.2.11 */
+/* Flags */
+#define SMB2_DHANDLE_FLAG_PERSISTENT   0x00000002
 struct create_durable_v2_rsp {
        struct create_context ccontext;
        __u8   Name[8];
index 7c98bf699772f23271504ae2c1b354615111b4b1..fcaf373cc008044c52bcc9414e53f50af1b98569 100644 (file)
@@ -457,10 +457,13 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
                        }
 
                        ksmbd_kstat.kstat = &kstat;
-                       ksmbd_vfs_fill_dentry_attrs(work,
-                                                   idmap,
-                                                   dentry,
-                                                   &ksmbd_kstat);
+                       rc = ksmbd_vfs_fill_dentry_attrs(work,
+                                                        idmap,
+                                                        dentry,
+                                                        &ksmbd_kstat);
+                       if (rc)
+                               break;
+
                        rc = fn(conn, info_level, d_info, &ksmbd_kstat);
                        if (rc)
                                break;
index c487e834331aa61962b22d94c677289ec6e72067..22f0f3db3ac92df2447e6b62646447d5ca1895a0 100644 (file)
@@ -1682,11 +1682,19 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
                                struct dentry *dentry,
                                struct ksmbd_kstat *ksmbd_kstat)
 {
+       struct ksmbd_share_config *share_conf = work->tcon->share_conf;
        u64 time;
        int rc;
+       struct path path = {
+               .mnt = share_conf->vfs_path.mnt,
+               .dentry = dentry,
+       };
 
-       generic_fillattr(idmap, STATX_BASIC_STATS, d_inode(dentry),
-                        ksmbd_kstat->kstat);
+       rc = vfs_getattr(&path, ksmbd_kstat->kstat,
+                        STATX_BASIC_STATS | STATX_BTIME,
+                        AT_STATX_SYNC_AS_STAT);
+       if (rc)
+               return rc;
 
        time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime);
        ksmbd_kstat->create_time = time;
index 4e82ff627d1224d7972534a1233b0f952e94f9e4..030f70700036c17b65f8f16f595ad605e32f8721 100644 (file)
@@ -305,7 +305,8 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
 
        fd_limit_close();
        __ksmbd_remove_durable_fd(fp);
-       __ksmbd_remove_fd(ft, fp);
+       if (ft)
+               __ksmbd_remove_fd(ft, fp);
 
        close_id_del_oplock(fp);
        filp = fp->filp;
@@ -465,11 +466,32 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
        return fp;
 }
 
-struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
+struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id)
 {
        return __ksmbd_lookup_fd(&global_ft, id);
 }
 
+struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
+{
+       struct ksmbd_file *fp;
+
+       fp = __ksmbd_lookup_fd(&global_ft, id);
+       if (fp && fp->conn) {
+               ksmbd_put_durable_fd(fp);
+               fp = NULL;
+       }
+
+       return fp;
+}
+
+void ksmbd_put_durable_fd(struct ksmbd_file *fp)
+{
+       if (!atomic_dec_and_test(&fp->refcount))
+               return;
+
+       __ksmbd_close_fd(NULL, fp);
+}
+
 struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid)
 {
        struct ksmbd_file       *fp = NULL;
@@ -639,6 +661,32 @@ __close_file_table_ids(struct ksmbd_file_table *ft,
        return num;
 }
 
+static inline bool is_reconnectable(struct ksmbd_file *fp)
+{
+       struct oplock_info *opinfo = opinfo_get(fp);
+       bool reconn = false;
+
+       if (!opinfo)
+               return false;
+
+       if (opinfo->op_state != OPLOCK_STATE_NONE) {
+               opinfo_put(opinfo);
+               return false;
+       }
+
+       if (fp->is_resilient || fp->is_persistent)
+               reconn = true;
+       else if (fp->is_durable && opinfo->is_lease &&
+                opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE)
+               reconn = true;
+
+       else if (fp->is_durable && opinfo->level == SMB2_OPLOCK_LEVEL_BATCH)
+               reconn = true;
+
+       opinfo_put(opinfo);
+       return reconn;
+}
+
 static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
                               struct ksmbd_file *fp)
 {
@@ -648,7 +696,28 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
 static bool session_fd_check(struct ksmbd_tree_connect *tcon,
                             struct ksmbd_file *fp)
 {
-       return false;
+       struct ksmbd_inode *ci;
+       struct oplock_info *op;
+       struct ksmbd_conn *conn;
+
+       if (!is_reconnectable(fp))
+               return false;
+
+       conn = fp->conn;
+       ci = fp->f_ci;
+       write_lock(&ci->m_lock);
+       list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
+               if (op->conn != conn)
+                       continue;
+               op->conn = NULL;
+       }
+       write_unlock(&ci->m_lock);
+
+       fp->conn = NULL;
+       fp->tcon = NULL;
+       fp->volatile_id = KSMBD_NO_FID;
+
+       return true;
 }
 
 void ksmbd_close_tree_conn_fds(struct ksmbd_work *work)
@@ -687,6 +756,68 @@ void ksmbd_free_global_file_table(void)
        ksmbd_destroy_file_table(&global_ft);
 }
 
+int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
+                                 struct ksmbd_file *fp, char *name)
+{
+       char *pathname, *ab_pathname;
+       int ret = 0;
+
+       pathname = kmalloc(PATH_MAX, GFP_KERNEL);
+       if (!pathname)
+               return -EACCES;
+
+       ab_pathname = d_path(&fp->filp->f_path, pathname, PATH_MAX);
+       if (IS_ERR(ab_pathname)) {
+               kfree(pathname);
+               return -EACCES;
+       }
+
+       if (name && strcmp(&ab_pathname[share->path_sz + 1], name)) {
+               ksmbd_debug(SMB, "invalid name reconnect %s\n", name);
+               ret = -EINVAL;
+       }
+
+       kfree(pathname);
+
+       return ret;
+}
+
+int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
+{
+       struct ksmbd_inode *ci;
+       struct oplock_info *op;
+
+       if (!fp->is_durable || fp->conn || fp->tcon) {
+               pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon);
+               return -EBADF;
+       }
+
+       if (has_file_id(fp->volatile_id)) {
+               pr_err("Still in use durable fd: %llu\n", fp->volatile_id);
+               return -EBADF;
+       }
+
+       fp->conn = work->conn;
+       fp->tcon = work->tcon;
+
+       ci = fp->f_ci;
+       write_lock(&ci->m_lock);
+       list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
+               if (op->conn)
+                       continue;
+               op->conn = fp->conn;
+       }
+       write_unlock(&ci->m_lock);
+
+       __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
+       if (!has_file_id(fp->volatile_id)) {
+               fp->conn = NULL;
+               fp->tcon = NULL;
+               return -EBADF;
+       }
+       return 0;
+}
+
 int ksmbd_init_file_table(struct ksmbd_file_table *ft)
 {
        ft->idr = kzalloc(sizeof(struct idr), GFP_KERNEL);
index a528f0cc775ae0b6c60e05dfef3c2484fa92af3c..ed44fb4e18e79c1b87367bfe234767ca99925083 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/workqueue.h>
 
 #include "vfs.h"
+#include "mgmt/share_config.h"
 
 /* Windows style file permissions for extended response */
 #define        FILE_GENERIC_ALL        0x1F01FF
@@ -106,6 +107,9 @@ struct ksmbd_file {
        int                             dot_dotdot[2];
        unsigned int                    f_state;
        bool                            reserve_lease_break;
+       bool                            is_durable;
+       bool                            is_persistent;
+       bool                            is_resilient;
 };
 
 static inline void set_ctx_actor(struct dir_context *ctx,
@@ -141,7 +145,9 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
 void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
 struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d);
 void ksmbd_inode_put(struct ksmbd_inode *ci);
+struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id);
 struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
+void ksmbd_put_durable_fd(struct ksmbd_file *fp);
 struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
 struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
 unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
@@ -173,6 +179,9 @@ void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp);
 void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp);
 void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
                                  int file_info);
+int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp);
+int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
+                                 struct ksmbd_file *fp, char *name);
 int ksmbd_init_file_cache(void);
 void ksmbd_exit_file_cache(void);
 #endif /* __VFS_CACHE_H__ */
index ee05ab6b37e769a16a3b1e40cd820c17e0b76d85..71d9779c42b10aca8bd4e0b7b667fc62386e2305 100644 (file)
@@ -1515,11 +1515,29 @@ static int fs_bdev_thaw(struct block_device *bdev)
        return error;
 }
 
+static void fs_bdev_super_get(void *data)
+{
+       struct super_block *sb = data;
+
+       spin_lock(&sb_lock);
+       sb->s_count++;
+       spin_unlock(&sb_lock);
+}
+
+static void fs_bdev_super_put(void *data)
+{
+       struct super_block *sb = data;
+
+       put_super(sb);
+}
+
 const struct blk_holder_ops fs_holder_ops = {
        .mark_dead              = fs_bdev_mark_dead,
        .sync                   = fs_bdev_sync,
        .freeze                 = fs_bdev_freeze,
        .thaw                   = fs_bdev_thaw,
+       .get_holder             = fs_bdev_super_get,
+       .put_holder             = fs_bdev_super_put,
 };
 EXPORT_SYMBOL_GPL(fs_holder_ops);
 
index 138676463336c7db9398748a2a516033afa141cc..d22ad67a0f3291f4702f494939528d5d13c31fae 100644 (file)
@@ -31,6 +31,17 @@ static void remove_files(struct kernfs_node *parent,
                        kernfs_remove_by_name(parent, (*bin_attr)->attr.name);
 }
 
+static umode_t __first_visible(const struct attribute_group *grp, struct kobject *kobj)
+{
+       if (grp->attrs && grp->attrs[0] && grp->is_visible)
+               return grp->is_visible(kobj, grp->attrs[0], 0);
+
+       if (grp->bin_attrs && grp->bin_attrs[0] && grp->is_bin_visible)
+               return grp->is_bin_visible(kobj, grp->bin_attrs[0], 0);
+
+       return 0;
+}
+
 static int create_files(struct kernfs_node *parent, struct kobject *kobj,
                        kuid_t uid, kgid_t gid,
                        const struct attribute_group *grp, int update)
@@ -52,6 +63,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
                                kernfs_remove_by_name(parent, (*attr)->name);
                        if (grp->is_visible) {
                                mode = grp->is_visible(kobj, *attr, i);
+                               mode &= ~SYSFS_GROUP_INVISIBLE;
                                if (!mode)
                                        continue;
                        }
@@ -81,6 +93,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
                                                (*bin_attr)->attr.name);
                        if (grp->is_bin_visible) {
                                mode = grp->is_bin_visible(kobj, *bin_attr, i);
+                               mode &= ~SYSFS_GROUP_INVISIBLE;
                                if (!mode)
                                        continue;
                        }
@@ -127,16 +140,31 @@ static int internal_create_group(struct kobject *kobj, int update,
 
        kobject_get_ownership(kobj, &uid, &gid);
        if (grp->name) {
+               umode_t mode = __first_visible(grp, kobj);
+
+               if (mode & SYSFS_GROUP_INVISIBLE)
+                       mode = 0;
+               else
+                       mode = S_IRWXU | S_IRUGO | S_IXUGO;
+
                if (update) {
                        kn = kernfs_find_and_get(kobj->sd, grp->name);
                        if (!kn) {
-                               pr_warn("Can't update unknown attr grp name: %s/%s\n",
-                                       kobj->name, grp->name);
-                               return -EINVAL;
+                               pr_debug("attr grp %s/%s not created yet\n",
+                                        kobj->name, grp->name);
+                               /* may have been invisible prior to this update */
+                               update = 0;
+                       } else if (!mode) {
+                               sysfs_remove_group(kobj, grp);
+                               kernfs_put(kn);
+                               return 0;
                        }
-               } else {
-                       kn = kernfs_create_dir_ns(kobj->sd, grp->name,
-                                                 S_IRWXU | S_IRUGO | S_IXUGO,
+               }
+
+               if (!update) {
+                       if (!mode)
+                               return 0;
+                       kn = kernfs_create_dir_ns(kobj->sd, grp->name, mode,
                                                  uid, gid, kobj, NULL);
                        if (IS_ERR(kn)) {
                                if (PTR_ERR(kn) == -EEXIST)
@@ -279,9 +307,8 @@ void sysfs_remove_group(struct kobject *kobj,
        if (grp->name) {
                kn = kernfs_find_and_get(parent, grp->name);
                if (!kn) {
-                       WARN(!kn, KERN_WARNING
-                            "sysfs group '%s' not found for kobject '%s'\n",
-                            grp->name, kobject_name(kobj));
+                       pr_debug("sysfs group '%s' not found for kobject '%s'\n",
+                                grp->name, kobject_name(kobj));
                        return;
                }
        } else {
@@ -318,13 +345,13 @@ void sysfs_remove_groups(struct kobject *kobj,
 EXPORT_SYMBOL_GPL(sysfs_remove_groups);
 
 /**
- * sysfs_merge_group - merge files into a pre-existing attribute group.
+ * sysfs_merge_group - merge files into a pre-existing named attribute group.
  * @kobj:      The kobject containing the group.
  * @grp:       The files to create and the attribute group they belong to.
  *
- * This function returns an error if the group doesn't exist or any of the
- * files already exist in that group, in which case none of the new files
- * are created.
+ * This function returns an error if the group doesn't exist, the .name field is
+ * NULL or any of the files already exist in that group, in which case none of
+ * the new files are created.
  */
 int sysfs_merge_group(struct kobject *kobj,
                       const struct attribute_group *grp)
@@ -356,7 +383,7 @@ int sysfs_merge_group(struct kobject *kobj,
 EXPORT_SYMBOL_GPL(sysfs_merge_group);
 
 /**
- * sysfs_unmerge_group - remove files from a pre-existing attribute group.
+ * sysfs_unmerge_group - remove files from a pre-existing named attribute group.
  * @kobj:      The kobject containing the group.
  * @grp:       The files to remove and the attribute group they belong to.
  */
index 110e8a27218900756f3af6cd515d6e8cf33e9514..dc067eeb638744b72be8487102498e9d010b2945 100644 (file)
@@ -35,6 +35,17 @@ static DEFINE_MUTEX(eventfs_mutex);
 /* Choose something "unique" ;-) */
 #define EVENTFS_FILE_INODE_INO         0x12c4e37
 
+struct eventfs_root_inode {
+       struct eventfs_inode            ei;
+       struct dentry                   *events_dir;
+};
+
+static struct eventfs_root_inode *get_root_inode(struct eventfs_inode *ei)
+{
+       WARN_ON_ONCE(!ei->is_events);
+       return container_of(ei, struct eventfs_root_inode, ei);
+}
+
 /* Just try to make something consistent and unique */
 static int eventfs_dir_ino(struct eventfs_inode *ei)
 {
@@ -73,12 +84,18 @@ enum {
 static void release_ei(struct kref *ref)
 {
        struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref);
+       struct eventfs_root_inode *rei;
 
        WARN_ON_ONCE(!ei->is_freed);
 
        kfree(ei->entry_attrs);
        kfree_const(ei->name);
-       kfree_rcu(ei, rcu);
+       if (ei->is_events) {
+               rei = get_root_inode(ei);
+               kfree_rcu(rei, ei.rcu);
+       } else {
+               kfree_rcu(ei, rcu);
+       }
 }
 
 static inline void put_ei(struct eventfs_inode *ei)
@@ -408,19 +425,43 @@ static struct dentry *lookup_dir_entry(struct dentry *dentry,
        return NULL;
 }
 
+static inline struct eventfs_inode *init_ei(struct eventfs_inode *ei, const char *name)
+{
+       ei->name = kstrdup_const(name, GFP_KERNEL);
+       if (!ei->name)
+               return NULL;
+       kref_init(&ei->kref);
+       return ei;
+}
+
 static inline struct eventfs_inode *alloc_ei(const char *name)
 {
        struct eventfs_inode *ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+       struct eventfs_inode *result;
 
        if (!ei)
                return NULL;
 
-       ei->name = kstrdup_const(name, GFP_KERNEL);
-       if (!ei->name) {
+       result = init_ei(ei, name);
+       if (!result)
                kfree(ei);
+
+       return result;
+}
+
+static inline struct eventfs_inode *alloc_root_ei(const char *name)
+{
+       struct eventfs_root_inode *rei = kzalloc(sizeof(*rei), GFP_KERNEL);
+       struct eventfs_inode *ei;
+
+       if (!rei)
                return NULL;
-       }
-       kref_init(&ei->kref);
+
+       rei->ei.is_events = 1;
+       ei = init_ei(&rei->ei, name);
+       if (!ei)
+               kfree(rei);
+
        return ei;
 }
 
@@ -483,7 +524,7 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
        struct dentry *result = NULL;
 
        ti = get_tracefs(dir);
-       if (!(ti->flags & TRACEFS_EVENT_INODE))
+       if (WARN_ON_ONCE(!(ti->flags & TRACEFS_EVENT_INODE)))
                return ERR_PTR(-EIO);
 
        mutex_lock(&eventfs_mutex);
@@ -495,7 +536,8 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
        list_for_each_entry(ei_child, &ei->children, list) {
                if (strcmp(ei_child->name, name) != 0)
                        continue;
-               if (ei_child->is_freed)
+               /* A child is freed and removed from the list at the same time */
+               if (WARN_ON_ONCE(ei_child->is_freed))
                        goto out;
                result = lookup_dir_entry(dentry, ei, ei_child);
                goto out;
@@ -709,6 +751,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
                                                int size, void *data)
 {
        struct dentry *dentry = tracefs_start_creating(name, parent);
+       struct eventfs_root_inode *rei;
        struct eventfs_inode *ei;
        struct tracefs_inode *ti;
        struct inode *inode;
@@ -721,7 +764,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
        if (IS_ERR(dentry))
                return ERR_CAST(dentry);
 
-       ei = alloc_ei(name);
+       ei = alloc_root_ei(name);
        if (!ei)
                goto fail;
 
@@ -730,10 +773,11 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
                goto fail;
 
        // Note: we have a ref to the dentry from tracefs_start_creating()
-       ei->events_dir = dentry;
+       rei = get_root_inode(ei);
+       rei->events_dir = dentry;
+
        ei->entries = entries;
        ei->nr_entries = size;
-       ei->is_events = 1;
        ei->data = data;
 
        /* Save the ownership of this directory */
@@ -844,13 +888,15 @@ void eventfs_remove_dir(struct eventfs_inode *ei)
  */
 void eventfs_remove_events_dir(struct eventfs_inode *ei)
 {
+       struct eventfs_root_inode *rei;
        struct dentry *dentry;
 
-       dentry = ei->events_dir;
+       rei = get_root_inode(ei);
+       dentry = rei->events_dir;
        if (!dentry)
                return;
 
-       ei->events_dir = NULL;
+       rei->events_dir = NULL;
        eventfs_remove_dir(ei);
 
        /*
index beb3dcd0e434207c882bcfe6ec027b6ca3e43526..15c26f9aaad4df1fe3d509061ba6cd3b437ae76e 100644 (file)
@@ -36,7 +36,6 @@ struct eventfs_attr {
  * @children:  link list into the child eventfs_inode
  * @entries:   the array of entries representing the files in the directory
  * @name:      the name of the directory to create
- * @events_dir: the dentry of the events directory
  * @entry_attrs: Saved mode and ownership of the @d_children
  * @data:      The private data to pass to the callbacks
  * @attr:      Saved mode and ownership of eventfs_inode itself
@@ -54,7 +53,6 @@ struct eventfs_inode {
        struct list_head                children;
        const struct eventfs_entry      *entries;
        const char                      *name;
-       struct dentry                   *events_dir;
        struct eventfs_attr             *entry_attrs;
        void                            *data;
        struct eventfs_attr             attr;
index d013c5b3f1edaeb3d17b351dc61286331a4b6161..ac77ac1fd73e351863c0d7ab98f86c1f12a82b9f 100644 (file)
@@ -1742,17 +1742,22 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
        err = dbg_walk_index(c, NULL, add_size, &calc);
        if (err) {
                ubifs_err(c, "error %d while walking the index", err);
-               return err;
+               goto out_err;
        }
 
        if (calc != idx_size) {
                ubifs_err(c, "index size check failed: calculated size is %lld, should be %lld",
                          calc, idx_size);
                dump_stack();
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_err;
        }
 
        return 0;
+
+out_err:
+       ubifs_destroy_tnc_tree(c);
+       return err;
 }
 
 /**
index 551148de66cd86dbf76484d73c4c3acdc5969a1c..eac0fef801f1433df255713591c12a1e849b1385 100644 (file)
@@ -1133,6 +1133,8 @@ out_cancel:
        dir_ui->ui_size = dir->i_size;
        mutex_unlock(&dir_ui->ui_mutex);
 out_inode:
+       /* Free inode->i_link before inode is marked as bad. */
+       fscrypt_free_inode(inode);
        make_bad_inode(inode);
        iput(inode);
 out_fname:
index 5029eb3390a5607892b7eabdb9a862ea10938519..a1f46919934c7d02f1d5f68e84dfdd0d860f8d86 100644 (file)
@@ -96,36 +96,36 @@ dump:
        return -EINVAL;
 }
 
-static int do_readpage(struct page *page)
+static int do_readpage(struct folio *folio)
 {
        void *addr;
        int err = 0, i;
        unsigned int block, beyond;
-       struct ubifs_data_node *dn;
-       struct inode *inode = page->mapping->host;
+       struct ubifs_data_node *dn = NULL;
+       struct inode *inode = folio->mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        loff_t i_size = i_size_read(inode);
 
        dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
-               inode->i_ino, page->index, i_size, page->flags);
-       ubifs_assert(c, !PageChecked(page));
-       ubifs_assert(c, !PagePrivate(page));
+               inode->i_ino, folio->index, i_size, folio->flags);
+       ubifs_assert(c, !folio_test_checked(folio));
+       ubifs_assert(c, !folio->private);
 
-       addr = kmap(page);
+       addr = kmap_local_folio(folio, 0);
 
-       block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
        beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
        if (block >= beyond) {
                /* Reading beyond inode */
-               SetPageChecked(page);
-               memset(addr, 0, PAGE_SIZE);
+               folio_set_checked(folio);
+               addr = folio_zero_tail(folio, 0, addr);
                goto out;
        }
 
        dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
        if (!dn) {
                err = -ENOMEM;
-               goto error;
+               goto out;
        }
 
        i = 0;
@@ -150,39 +150,35 @@ static int do_readpage(struct page *page)
                                        memset(addr + ilen, 0, dlen - ilen);
                        }
                }
-               if (++i >= UBIFS_BLOCKS_PER_PAGE)
+               if (++i >= (UBIFS_BLOCKS_PER_PAGE << folio_order(folio)))
                        break;
                block += 1;
                addr += UBIFS_BLOCK_SIZE;
+               if (folio_test_highmem(folio) && (offset_in_page(addr) == 0)) {
+                       kunmap_local(addr - UBIFS_BLOCK_SIZE);
+                       addr = kmap_local_folio(folio, i * UBIFS_BLOCK_SIZE);
+               }
        }
+
        if (err) {
                struct ubifs_info *c = inode->i_sb->s_fs_info;
                if (err == -ENOENT) {
                        /* Not found, so it must be a hole */
-                       SetPageChecked(page);
+                       folio_set_checked(folio);
                        dbg_gen("hole");
-                       goto out_free;
+                       err = 0;
+               } else {
+                       ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
+                                 folio->index, inode->i_ino, err);
                }
-               ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
-                         page->index, inode->i_ino, err);
-               goto error;
        }
 
-out_free:
-       kfree(dn);
 out:
-       SetPageUptodate(page);
-       ClearPageError(page);
-       flush_dcache_page(page);
-       kunmap(page);
-       return 0;
-
-error:
        kfree(dn);
-       ClearPageUptodate(page);
-       SetPageError(page);
-       flush_dcache_page(page);
-       kunmap(page);
+       if (!err)
+               folio_mark_uptodate(folio);
+       flush_dcache_folio(folio);
+       kunmap_local(addr);
        return err;
 }
 
@@ -222,16 +218,16 @@ static int write_begin_slow(struct address_space *mapping,
        pgoff_t index = pos >> PAGE_SHIFT;
        struct ubifs_budget_req req = { .new_page = 1 };
        int err, appending = !!(pos + len > inode->i_size);
-       struct page *page;
+       struct folio *folio;
 
        dbg_gen("ino %lu, pos %llu, len %u, i_size %lld",
                inode->i_ino, pos, len, inode->i_size);
 
        /*
-        * At the slow path we have to budget before locking the page, because
-        * budgeting may force write-back, which would wait on locked pages and
-        * deadlock if we had the page locked. At this point we do not know
-        * anything about the page, so assume that this is a new page which is
+        * At the slow path we have to budget before locking the folio, because
+        * budgeting may force write-back, which would wait on locked folios and
+        * deadlock if we had the folio locked. At this point we do not know
+        * anything about the folio, so assume that this is a new folio which is
         * written to a hole. This corresponds to largest budget. Later the
         * budget will be amended if this is not true.
         */
@@ -243,45 +239,43 @@ static int write_begin_slow(struct address_space *mapping,
        if (unlikely(err))
                return err;
 
-       page = grab_cache_page_write_begin(mapping, index);
-       if (unlikely(!page)) {
+       folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
+                       mapping_gfp_mask(mapping));
+       if (IS_ERR(folio)) {
                ubifs_release_budget(c, &req);
-               return -ENOMEM;
+               return PTR_ERR(folio);
        }
 
-       if (!PageUptodate(page)) {
-               if (!(pos & ~PAGE_MASK) && len == PAGE_SIZE)
-                       SetPageChecked(page);
+       if (!folio_test_uptodate(folio)) {
+               if (pos == folio_pos(folio) && len >= folio_size(folio))
+                       folio_set_checked(folio);
                else {
-                       err = do_readpage(page);
+                       err = do_readpage(folio);
                        if (err) {
-                               unlock_page(page);
-                               put_page(page);
+                               folio_unlock(folio);
+                               folio_put(folio);
                                ubifs_release_budget(c, &req);
                                return err;
                        }
                }
-
-               SetPageUptodate(page);
-               ClearPageError(page);
        }
 
-       if (PagePrivate(page))
+       if (folio->private)
                /*
-                * The page is dirty, which means it was budgeted twice:
+                * The folio is dirty, which means it was budgeted twice:
                 *   o first time the budget was allocated by the task which
-                *     made the page dirty and set the PG_private flag;
+                *     made the folio dirty and set the private field;
                 *   o and then we budgeted for it for the second time at the
                 *     very beginning of this function.
                 *
-                * So what we have to do is to release the page budget we
+                * So what we have to do is to release the folio budget we
                 * allocated.
                 */
                release_new_page_budget(c);
-       else if (!PageChecked(page))
+       else if (!folio_test_checked(folio))
                /*
-                * We are changing a page which already exists on the media.
-                * This means that changing the page does not make the amount
+                * We are changing a folio which already exists on the media.
+                * This means that changing the folio does not make the amount
                 * of indexing information larger, and this part of the budget
                 * which we have already acquired may be released.
                 */
@@ -304,14 +298,14 @@ static int write_begin_slow(struct address_space *mapping,
                        ubifs_release_dirty_inode_budget(c, ui);
        }
 
-       *pagep = page;
+       *pagep = &folio->page;
        return 0;
 }
 
 /**
  * allocate_budget - allocate budget for 'ubifs_write_begin()'.
  * @c: UBIFS file-system description object
- * @page: page to allocate budget for
+ * @folio: folio to allocate budget for
  * @ui: UBIFS inode object the page belongs to
  * @appending: non-zero if the page is appended
  *
@@ -322,15 +316,15 @@ static int write_begin_slow(struct address_space *mapping,
  *
  * Returns: %0 in case of success and %-ENOSPC in case of failure.
  */
-static int allocate_budget(struct ubifs_info *c, struct page *page,
+static int allocate_budget(struct ubifs_info *c, struct folio *folio,
                           struct ubifs_inode *ui, int appending)
 {
        struct ubifs_budget_req req = { .fast = 1 };
 
-       if (PagePrivate(page)) {
+       if (folio->private) {
                if (!appending)
                        /*
-                        * The page is dirty and we are not appending, which
+                        * The folio is dirty and we are not appending, which
                         * means no budget is needed at all.
                         */
                        return 0;
@@ -354,11 +348,11 @@ static int allocate_budget(struct ubifs_info *c, struct page *page,
                 */
                req.dirtied_ino = 1;
        } else {
-               if (PageChecked(page))
+               if (folio_test_checked(folio))
                        /*
                         * The page corresponds to a hole and does not
                         * exist on the media. So changing it makes
-                        * make the amount of indexing information
+                        * the amount of indexing information
                         * larger, and we have to budget for a new
                         * page.
                         */
@@ -428,7 +422,7 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index = pos >> PAGE_SHIFT;
        int err, appending = !!(pos + len > inode->i_size);
        int skipped_read = 0;
-       struct page *page;
+       struct folio *folio;
 
        ubifs_assert(c, ubifs_inode(inode)->ui_size == inode->i_size);
        ubifs_assert(c, !c->ro_media && !c->ro_mount);
@@ -437,13 +431,14 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
                return -EROFS;
 
        /* Try out the fast-path part first */
-       page = grab_cache_page_write_begin(mapping, index);
-       if (unlikely(!page))
-               return -ENOMEM;
+       folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
+                       mapping_gfp_mask(mapping));
+       if (IS_ERR(folio))
+               return PTR_ERR(folio);
 
-       if (!PageUptodate(page)) {
+       if (!folio_test_uptodate(folio)) {
                /* The page is not loaded from the flash */
-               if (!(pos & ~PAGE_MASK) && len == PAGE_SIZE) {
+               if (pos == folio_pos(folio) && len >= folio_size(folio)) {
                        /*
                         * We change whole page so no need to load it. But we
                         * do not know whether this page exists on the media or
@@ -453,32 +448,27 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
                         * media. Thus, we are setting the @PG_checked flag
                         * here.
                         */
-                       SetPageChecked(page);
+                       folio_set_checked(folio);
                        skipped_read = 1;
                } else {
-                       err = do_readpage(page);
+                       err = do_readpage(folio);
                        if (err) {
-                               unlock_page(page);
-                               put_page(page);
+                               folio_unlock(folio);
+                               folio_put(folio);
                                return err;
                        }
                }
-
-               SetPageUptodate(page);
-               ClearPageError(page);
        }
 
-       err = allocate_budget(c, page, ui, appending);
+       err = allocate_budget(c, folio, ui, appending);
        if (unlikely(err)) {
                ubifs_assert(c, err == -ENOSPC);
                /*
                 * If we skipped reading the page because we were going to
                 * write all of it, then it is not up to date.
                 */
-               if (skipped_read) {
-                       ClearPageChecked(page);
-                       ClearPageUptodate(page);
-               }
+               if (skipped_read)
+                       folio_clear_checked(folio);
                /*
                 * Budgeting failed which means it would have to force
                 * write-back but didn't, because we set the @fast flag in the
@@ -490,8 +480,8 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
                        ubifs_assert(c, mutex_is_locked(&ui->ui_mutex));
                        mutex_unlock(&ui->ui_mutex);
                }
-               unlock_page(page);
-               put_page(page);
+               folio_unlock(folio);
+               folio_put(folio);
 
                return write_begin_slow(mapping, pos, len, pagep);
        }
@@ -502,22 +492,21 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
         * with @ui->ui_mutex locked if we are appending pages, and unlocked
         * otherwise. This is an optimization (slightly hacky though).
         */
-       *pagep = page;
+       *pagep = &folio->page;
        return 0;
-
 }
 
 /**
  * cancel_budget - cancel budget.
  * @c: UBIFS file-system description object
- * @page: page to cancel budget for
+ * @folio: folio to cancel budget for
  * @ui: UBIFS inode object the page belongs to
  * @appending: non-zero if the page is appended
  *
  * This is a helper function for a page write operation. It unlocks the
  * @ui->ui_mutex in case of appending.
  */
-static void cancel_budget(struct ubifs_info *c, struct page *page,
+static void cancel_budget(struct ubifs_info *c, struct folio *folio,
                          struct ubifs_inode *ui, int appending)
 {
        if (appending) {
@@ -525,8 +514,8 @@ static void cancel_budget(struct ubifs_info *c, struct page *page,
                        ubifs_release_dirty_inode_budget(c, ui);
                mutex_unlock(&ui->ui_mutex);
        }
-       if (!PagePrivate(page)) {
-               if (PageChecked(page))
+       if (!folio->private) {
+               if (folio_test_checked(folio))
                        release_new_page_budget(c);
                else
                        release_existing_page_budget(c);
@@ -537,6 +526,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
                           loff_t pos, unsigned len, unsigned copied,
                           struct page *page, void *fsdata)
 {
+       struct folio *folio = page_folio(page);
        struct inode *inode = mapping->host;
        struct ubifs_inode *ui = ubifs_inode(inode);
        struct ubifs_info *c = inode->i_sb->s_fs_info;
@@ -544,44 +534,47 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
        int appending = !!(end_pos > inode->i_size);
 
        dbg_gen("ino %lu, pos %llu, pg %lu, len %u, copied %d, i_size %lld",
-               inode->i_ino, pos, page->index, len, copied, inode->i_size);
+               inode->i_ino, pos, folio->index, len, copied, inode->i_size);
 
-       if (unlikely(copied < len && len == PAGE_SIZE)) {
+       if (unlikely(copied < len && !folio_test_uptodate(folio))) {
                /*
-                * VFS copied less data to the page that it intended and
+                * VFS copied less data to the folio than it intended and
                 * declared in its '->write_begin()' call via the @len
-                * argument. If the page was not up-to-date, and @len was
-                * @PAGE_SIZE, the 'ubifs_write_begin()' function did
+                * argument. If the folio was not up-to-date,
+                * the 'ubifs_write_begin()' function did
                 * not load it from the media (for optimization reasons). This
-                * means that part of the page contains garbage. So read the
-                * page now.
+                * means that part of the folio contains garbage. So read the
+                * folio now.
                 */
                dbg_gen("copied %d instead of %d, read page and repeat",
                        copied, len);
-               cancel_budget(c, page, ui, appending);
-               ClearPageChecked(page);
+               cancel_budget(c, folio, ui, appending);
+               folio_clear_checked(folio);
 
                /*
                 * Return 0 to force VFS to repeat the whole operation, or the
                 * error code if 'do_readpage()' fails.
                 */
-               copied = do_readpage(page);
+               copied = do_readpage(folio);
                goto out;
        }
 
-       if (!PagePrivate(page)) {
-               attach_page_private(page, (void *)1);
+       if (len == folio_size(folio))
+               folio_mark_uptodate(folio);
+
+       if (!folio->private) {
+               folio_attach_private(folio, (void *)1);
                atomic_long_inc(&c->dirty_pg_cnt);
-               __set_page_dirty_nobuffers(page);
+               filemap_dirty_folio(mapping, folio);
        }
 
        if (appending) {
                i_size_write(inode, end_pos);
                ui->ui_size = end_pos;
                /*
-                * Note, we do not set @I_DIRTY_PAGES (which means that the
-                * inode has dirty pages), this has been done in
-                * '__set_page_dirty_nobuffers()'.
+                * We do not set @I_DIRTY_PAGES (which means that
+                * the inode has dirty pages), this was done in
+                * filemap_dirty_folio().
                 */
                __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
                ubifs_assert(c, mutex_is_locked(&ui->ui_mutex));
@@ -589,43 +582,43 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
        }
 
 out:
-       unlock_page(page);
-       put_page(page);
+       folio_unlock(folio);
+       folio_put(folio);
        return copied;
 }
 
 /**
  * populate_page - copy data nodes into a page for bulk-read.
  * @c: UBIFS file-system description object
- * @page: page
+ * @folio: folio
  * @bu: bulk-read information
  * @n: next zbranch slot
  *
  * Returns: %0 on success and a negative error code on failure.
  */
-static int populate_page(struct ubifs_info *c, struct page *page,
+static int populate_page(struct ubifs_info *c, struct folio *folio,
                         struct bu_info *bu, int *n)
 {
        int i = 0, nn = *n, offs = bu->zbranch[0].offs, hole = 0, read = 0;
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = folio->mapping->host;
        loff_t i_size = i_size_read(inode);
        unsigned int page_block;
        void *addr, *zaddr;
        pgoff_t end_index;
 
        dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx",
-               inode->i_ino, page->index, i_size, page->flags);
+               inode->i_ino, folio->index, i_size, folio->flags);
 
-       addr = zaddr = kmap(page);
+       addr = zaddr = kmap_local_folio(folio, 0);
 
        end_index = (i_size - 1) >> PAGE_SHIFT;
-       if (!i_size || page->index > end_index) {
+       if (!i_size || folio->index > end_index) {
                hole = 1;
-               memset(addr, 0, PAGE_SIZE);
+               addr = folio_zero_tail(folio, 0, addr);
                goto out_hole;
        }
 
-       page_block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       page_block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
        while (1) {
                int err, len, out_len, dlen;
 
@@ -674,9 +667,13 @@ static int populate_page(struct ubifs_info *c, struct page *page,
                        break;
                addr += UBIFS_BLOCK_SIZE;
                page_block += 1;
+               if (folio_test_highmem(folio) && (offset_in_page(addr) == 0)) {
+                       kunmap_local(addr - UBIFS_BLOCK_SIZE);
+                       addr = kmap_local_folio(folio, i * UBIFS_BLOCK_SIZE);
+               }
        }
 
-       if (end_index == page->index) {
+       if (end_index == folio->index) {
                int len = i_size & (PAGE_SIZE - 1);
 
                if (len && len < read)
@@ -685,22 +682,19 @@ static int populate_page(struct ubifs_info *c, struct page *page,
 
 out_hole:
        if (hole) {
-               SetPageChecked(page);
+               folio_set_checked(folio);
                dbg_gen("hole");
        }
 
-       SetPageUptodate(page);
-       ClearPageError(page);
-       flush_dcache_page(page);
-       kunmap(page);
+       folio_mark_uptodate(folio);
+       flush_dcache_folio(folio);
+       kunmap_local(addr);
        *n = nn;
        return 0;
 
 out_err:
-       ClearPageUptodate(page);
-       SetPageError(page);
-       flush_dcache_page(page);
-       kunmap(page);
+       flush_dcache_folio(folio);
+       kunmap_local(addr);
        ubifs_err(c, "bad data node (block %u, inode %lu)",
                  page_block, inode->i_ino);
        return -EINVAL;
@@ -710,15 +704,15 @@ out_err:
  * ubifs_do_bulk_read - do bulk-read.
  * @c: UBIFS file-system description object
  * @bu: bulk-read information
- * @page1: first page to read
+ * @folio1: first folio to read
  *
  * Returns: %1 if the bulk-read is done, otherwise %0 is returned.
  */
 static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
-                             struct page *page1)
+                             struct folio *folio1)
 {
-       pgoff_t offset = page1->index, end_index;
-       struct address_space *mapping = page1->mapping;
+       pgoff_t offset = folio1->index, end_index;
+       struct address_space *mapping = folio1->mapping;
        struct inode *inode = mapping->host;
        struct ubifs_inode *ui = ubifs_inode(inode);
        int err, page_idx, page_cnt, ret = 0, n = 0;
@@ -768,11 +762,11 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
                        goto out_warn;
        }
 
-       err = populate_page(c, page1, bu, &n);
+       err = populate_page(c, folio1, bu, &n);
        if (err)
                goto out_warn;
 
-       unlock_page(page1);
+       folio_unlock(folio1);
        ret = 1;
 
        isize = i_size_read(inode);
@@ -782,19 +776,19 @@ static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
 
        for (page_idx = 1; page_idx < page_cnt; page_idx++) {
                pgoff_t page_offset = offset + page_idx;
-               struct page *page;
+               struct folio *folio;
 
                if (page_offset > end_index)
                        break;
-               page = pagecache_get_page(mapping, page_offset,
+               folio = __filemap_get_folio(mapping, page_offset,
                                 FGP_LOCK|FGP_ACCESSED|FGP_CREAT|FGP_NOWAIT,
                                 ra_gfp_mask);
-               if (!page)
+               if (IS_ERR(folio))
                        break;
-               if (!PageUptodate(page))
-                       err = populate_page(c, page, bu, &n);
-               unlock_page(page);
-               put_page(page);
+               if (!folio_test_uptodate(folio))
+                       err = populate_page(c, folio, bu, &n);
+               folio_unlock(folio);
+               folio_put(folio);
                if (err)
                        break;
        }
@@ -817,7 +811,7 @@ out_bu_off:
 
 /**
  * ubifs_bulk_read - determine whether to bulk-read and, if so, do it.
- * @page: page from which to start bulk-read.
+ * @folio: folio from which to start bulk-read.
  *
  * Some flash media are capable of reading sequentially at faster rates. UBIFS
  * bulk-read facility is designed to take advantage of that, by reading in one
@@ -826,12 +820,12 @@ out_bu_off:
  *
  * Returns: %1 if a bulk-read is done and %0 otherwise.
  */
-static int ubifs_bulk_read(struct page *page)
+static int ubifs_bulk_read(struct folio *folio)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = folio->mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        struct ubifs_inode *ui = ubifs_inode(inode);
-       pgoff_t index = page->index, last_page_read = ui->last_page_read;
+       pgoff_t index = folio->index, last_page_read = ui->last_page_read;
        struct bu_info *bu;
        int err = 0, allocated = 0;
 
@@ -879,8 +873,8 @@ static int ubifs_bulk_read(struct page *page)
 
        bu->buf_len = c->max_bu_buf_len;
        data_key_init(c, &bu->key, inode->i_ino,
-                     page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT);
-       err = ubifs_do_bulk_read(c, bu, page);
+                     folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT);
+       err = ubifs_do_bulk_read(c, bu, folio);
 
        if (!allocated)
                mutex_unlock(&c->bu_mutex);
@@ -894,69 +888,71 @@ out_unlock:
 
 static int ubifs_read_folio(struct file *file, struct folio *folio)
 {
-       struct page *page = &folio->page;
-
-       if (ubifs_bulk_read(page))
+       if (ubifs_bulk_read(folio))
                return 0;
-       do_readpage(page);
+       do_readpage(folio);
        folio_unlock(folio);
        return 0;
 }
 
-static int do_writepage(struct page *page, int len)
+static int do_writepage(struct folio *folio, size_t len)
 {
-       int err = 0, i, blen;
+       int err = 0, blen;
        unsigned int block;
        void *addr;
+       size_t offset = 0;
        union ubifs_key key;
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = folio->mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
 
 #ifdef UBIFS_DEBUG
        struct ubifs_inode *ui = ubifs_inode(inode);
        spin_lock(&ui->ui_lock);
-       ubifs_assert(c, page->index <= ui->synced_i_size >> PAGE_SHIFT);
+       ubifs_assert(c, folio->index <= ui->synced_i_size >> PAGE_SHIFT);
        spin_unlock(&ui->ui_lock);
 #endif
 
-       /* Update radix tree tags */
-       set_page_writeback(page);
+       folio_start_writeback(folio);
 
-       addr = kmap(page);
-       block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
-       i = 0;
-       while (len) {
-               blen = min_t(int, len, UBIFS_BLOCK_SIZE);
+       addr = kmap_local_folio(folio, offset);
+       block = folio->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       for (;;) {
+               blen = min_t(size_t, len, UBIFS_BLOCK_SIZE);
                data_key_init(c, &key, inode->i_ino, block);
                err = ubifs_jnl_write_data(c, inode, &key, addr, blen);
                if (err)
                        break;
-               if (++i >= UBIFS_BLOCKS_PER_PAGE)
+               len -= blen;
+               if (!len)
                        break;
                block += 1;
                addr += blen;
-               len -= blen;
+               if (folio_test_highmem(folio) && !offset_in_page(addr)) {
+                       kunmap_local(addr - blen);
+                       offset += PAGE_SIZE;
+                       addr = kmap_local_folio(folio, offset);
+               }
        }
+       kunmap_local(addr);
        if (err) {
-               SetPageError(page);
-               ubifs_err(c, "cannot write page %lu of inode %lu, error %d",
-                         page->index, inode->i_ino, err);
+               mapping_set_error(folio->mapping, err);
+               ubifs_err(c, "cannot write folio %lu of inode %lu, error %d",
+                         folio->index, inode->i_ino, err);
                ubifs_ro_mode(c, err);
        }
 
-       ubifs_assert(c, PagePrivate(page));
-       if (PageChecked(page))
+       ubifs_assert(c, folio->private != NULL);
+       if (folio_test_checked(folio))
                release_new_page_budget(c);
        else
                release_existing_page_budget(c);
 
        atomic_long_dec(&c->dirty_pg_cnt);
-       detach_page_private(page);
-       ClearPageChecked(page);
+       folio_detach_private(folio);
+       folio_clear_checked(folio);
 
-       kunmap(page);
-       unlock_page(page);
-       end_page_writeback(page);
+       folio_unlock(folio);
+       folio_end_writeback(folio);
        return err;
 }
 
@@ -1006,22 +1002,21 @@ static int do_writepage(struct page *page, int len)
  * on the page lock and it would not write the truncated inode node to the
  * journal before we have finished.
  */
-static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
+static int ubifs_writepage(struct folio *folio, struct writeback_control *wbc,
+               void *data)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = folio->mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        struct ubifs_inode *ui = ubifs_inode(inode);
        loff_t i_size =  i_size_read(inode), synced_i_size;
-       pgoff_t end_index = i_size >> PAGE_SHIFT;
-       int err, len = i_size & (PAGE_SIZE - 1);
-       void *kaddr;
+       int err, len = folio_size(folio);
 
        dbg_gen("ino %lu, pg %lu, pg flags %#lx",
-               inode->i_ino, page->index, page->flags);
-       ubifs_assert(c, PagePrivate(page));
+               inode->i_ino, folio->index, folio->flags);
+       ubifs_assert(c, folio->private != NULL);
 
-       /* Is the page fully outside @i_size? (truncate in progress) */
-       if (page->index > end_index || (page->index == end_index && !len)) {
+       /* Is the folio fully outside @i_size? (truncate in progress) */
+       if (folio_pos(folio) >= i_size) {
                err = 0;
                goto out_unlock;
        }
@@ -1030,9 +1025,9 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
        synced_i_size = ui->synced_i_size;
        spin_unlock(&ui->ui_lock);
 
-       /* Is the page fully inside @i_size? */
-       if (page->index < end_index) {
-               if (page->index >= synced_i_size >> PAGE_SHIFT) {
+       /* Is the folio fully inside i_size? */
+       if (folio_pos(folio) + len <= i_size) {
+               if (folio_pos(folio) >= synced_i_size) {
                        err = inode->i_sb->s_op->write_inode(inode, NULL);
                        if (err)
                                goto out_redirty;
@@ -1045,20 +1040,18 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
                         * with this.
                         */
                }
-               return do_writepage(page, PAGE_SIZE);
+               return do_writepage(folio, len);
        }
 
        /*
-        * The page straddles @i_size. It must be zeroed out on each and every
+        * The folio straddles @i_size. It must be zeroed out on each and every
         * writepage invocation because it may be mmapped. "A file is mapped
         * in multiples of the page size. For a file that is not a multiple of
         * the page size, the remaining memory is zeroed when mapped, and
         * writes to that region are not written out to the file."
         */
-       kaddr = kmap_atomic(page);
-       memset(kaddr + len, 0, PAGE_SIZE - len);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr);
+       len = i_size - folio_pos(folio);
+       folio_zero_segment(folio, len, folio_size(folio));
 
        if (i_size > synced_i_size) {
                err = inode->i_sb->s_op->write_inode(inode, NULL);
@@ -1066,19 +1059,25 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
                        goto out_redirty;
        }
 
-       return do_writepage(page, len);
+       return do_writepage(folio, len);
 out_redirty:
        /*
-        * redirty_page_for_writepage() won't call ubifs_dirty_inode() because
+        * folio_redirty_for_writepage() won't call ubifs_dirty_inode() because
         * it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so
         * there is no need to do space budget for dirty inode.
         */
-       redirty_page_for_writepage(wbc, page);
+       folio_redirty_for_writepage(wbc, folio);
 out_unlock:
-       unlock_page(page);
+       folio_unlock(folio);
        return err;
 }
 
+static int ubifs_writepages(struct address_space *mapping,
+               struct writeback_control *wbc)
+{
+       return write_cache_pages(mapping, wbc, ubifs_writepage, NULL);
+}
+
 /**
  * do_attr_changes - change inode attributes.
  * @inode: inode to change attributes for
@@ -1155,11 +1154,11 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
 
        if (offset) {
                pgoff_t index = new_size >> PAGE_SHIFT;
-               struct page *page;
+               struct folio *folio;
 
-               page = find_lock_page(inode->i_mapping, index);
-               if (page) {
-                       if (PageDirty(page)) {
+               folio = filemap_lock_folio(inode->i_mapping, index);
+               if (!IS_ERR(folio)) {
+                       if (folio_test_dirty(folio)) {
                                /*
                                 * 'ubifs_jnl_truncate()' will try to truncate
                                 * the last data node, but it contains
@@ -1168,14 +1167,14 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
                                 * 'ubifs_jnl_truncate()' will see an already
                                 * truncated (and up to date) data node.
                                 */
-                               ubifs_assert(c, PagePrivate(page));
+                               ubifs_assert(c, folio->private != NULL);
 
-                               clear_page_dirty_for_io(page);
+                               folio_clear_dirty_for_io(folio);
                                if (UBIFS_BLOCKS_PER_PAGE_SHIFT)
-                                       offset = new_size &
-                                                (PAGE_SIZE - 1);
-                               err = do_writepage(page, offset);
-                               put_page(page);
+                                       offset = offset_in_folio(folio,
+                                                       new_size);
+                               err = do_writepage(folio, offset);
+                               folio_put(folio);
                                if (err)
                                        goto out_budg;
                                /*
@@ -1188,8 +1187,8 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
                                 * to 'ubifs_jnl_truncate()' to save it from
                                 * having to read it.
                                 */
-                               unlock_page(page);
-                               put_page(page);
+                               folio_unlock(folio);
+                               folio_put(folio);
                        }
                }
        }
@@ -1512,14 +1511,14 @@ static bool ubifs_release_folio(struct folio *folio, gfp_t unused_gfp_flags)
  */
 static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf)
 {
-       struct page *page = vmf->page;
+       struct folio *folio = page_folio(vmf->page);
        struct inode *inode = file_inode(vmf->vma->vm_file);
        struct ubifs_info *c = inode->i_sb->s_fs_info;
        struct timespec64 now = current_time(inode);
        struct ubifs_budget_req req = { .new_page = 1 };
        int err, update_time;
 
-       dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index,
+       dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, folio->index,
                i_size_read(inode));
        ubifs_assert(c, !c->ro_media && !c->ro_mount);
 
@@ -1527,17 +1526,17 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf)
                return VM_FAULT_SIGBUS; /* -EROFS */
 
        /*
-        * We have not locked @page so far so we may budget for changing the
-        * page. Note, we cannot do this after we locked the page, because
+        * We have not locked @folio so far so we may budget for changing the
+        * folio. Note, we cannot do this after we locked the folio, because
         * budgeting may cause write-back which would cause deadlock.
         *
-        * At the moment we do not know whether the page is dirty or not, so we
-        * assume that it is not and budget for a new page. We could look at
+        * At the moment we do not know whether the folio is dirty or not, so we
+        * assume that it is not and budget for a new folio. We could look at
         * the @PG_private flag and figure this out, but we may race with write
-        * back and the page state may change by the time we lock it, so this
+        * back and the folio state may change by the time we lock it, so this
         * would need additional care. We do not bother with this at the
         * moment, although it might be good idea to do. Instead, we allocate
-        * budget for a new page and amend it later on if the page was in fact
+        * budget for a new folio and amend it later on if the folio was in fact
         * dirty.
         *
         * The budgeting-related logic of this function is similar to what we
@@ -1560,21 +1559,21 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
        }
 
-       lock_page(page);
-       if (unlikely(page->mapping != inode->i_mapping ||
-                    page_offset(page) > i_size_read(inode))) {
-               /* Page got truncated out from underneath us */
+       folio_lock(folio);
+       if (unlikely(folio->mapping != inode->i_mapping ||
+                    folio_pos(folio) >= i_size_read(inode))) {
+               /* Folio got truncated out from underneath us */
                goto sigbus;
        }
 
-       if (PagePrivate(page))
+       if (folio->private)
                release_new_page_budget(c);
        else {
-               if (!PageChecked(page))
+               if (!folio_test_checked(folio))
                        ubifs_convert_page_budget(c);
-               attach_page_private(page, (void *)1);
+               folio_attach_private(folio, (void *)1);
                atomic_long_inc(&c->dirty_pg_cnt);
-               __set_page_dirty_nobuffers(page);
+               filemap_dirty_folio(folio->mapping, folio);
        }
 
        if (update_time) {
@@ -1590,11 +1589,11 @@ static vm_fault_t ubifs_vm_page_mkwrite(struct vm_fault *vmf)
                        ubifs_release_dirty_inode_budget(c, ui);
        }
 
-       wait_for_stable_page(page);
+       folio_wait_stable(folio);
        return VM_FAULT_LOCKED;
 
 sigbus:
-       unlock_page(page);
+       folio_unlock(folio);
        ubifs_release_budget(c, &req);
        return VM_FAULT_SIGBUS;
 }
@@ -1648,7 +1647,7 @@ static int ubifs_symlink_getattr(struct mnt_idmap *idmap,
 
 const struct address_space_operations ubifs_file_address_operations = {
        .read_folio     = ubifs_read_folio,
-       .writepage      = ubifs_writepage,
+       .writepages     = ubifs_writepages,
        .write_begin    = ubifs_write_begin,
        .write_end      = ubifs_write_end,
        .invalidate_folio = ubifs_invalidate_folio,
index 873e6e1c92b5c788f1e6444439efe3eabb74b578..6ebf3c04ac5feaa75185b2ee6025b8748667140b 100644 (file)
@@ -82,8 +82,9 @@ static int valuable(struct ubifs_info *c, const struct ubifs_lprops *lprops)
  */
 static int scan_for_dirty_cb(struct ubifs_info *c,
                             const struct ubifs_lprops *lprops, int in_tree,
-                            struct scan_data *data)
+                            void *arg)
 {
+       struct scan_data *data = arg;
        int ret = LPT_SCAN_CONTINUE;
 
        /* Exclude LEBs that are currently in use */
@@ -166,8 +167,7 @@ static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c,
        data.pick_free = pick_free;
        data.lnum = -1;
        data.exclude_index = exclude_index;
-       err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
-                                   (ubifs_lpt_scan_callback)scan_for_dirty_cb,
+       err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, scan_for_dirty_cb,
                                    &data);
        if (err)
                return ERR_PTR(err);
@@ -349,8 +349,9 @@ out:
  */
 static int scan_for_free_cb(struct ubifs_info *c,
                            const struct ubifs_lprops *lprops, int in_tree,
-                           struct scan_data *data)
+                           void *arg)
 {
+       struct scan_data *data = arg;
        int ret = LPT_SCAN_CONTINUE;
 
        /* Exclude LEBs that are currently in use */
@@ -446,7 +447,7 @@ const struct ubifs_lprops *do_find_free_space(struct ubifs_info *c,
        data.pick_free = pick_free;
        data.lnum = -1;
        err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
-                                   (ubifs_lpt_scan_callback)scan_for_free_cb,
+                                   scan_for_free_cb,
                                    &data);
        if (err)
                return ERR_PTR(err);
@@ -589,8 +590,9 @@ out:
  */
 static int scan_for_idx_cb(struct ubifs_info *c,
                           const struct ubifs_lprops *lprops, int in_tree,
-                          struct scan_data *data)
+                          void *arg)
 {
+       struct scan_data *data = arg;
        int ret = LPT_SCAN_CONTINUE;
 
        /* Exclude LEBs that are currently in use */
@@ -625,8 +627,7 @@ static const struct ubifs_lprops *scan_for_leb_for_idx(struct ubifs_info *c)
        int err;
 
        data.lnum = -1;
-       err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
-                                   (ubifs_lpt_scan_callback)scan_for_idx_cb,
+       err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, scan_for_idx_cb,
                                    &data);
        if (err)
                return ERR_PTR(err);
@@ -726,11 +727,10 @@ out:
        return err;
 }
 
-static int cmp_dirty_idx(const struct ubifs_lprops **a,
-                        const struct ubifs_lprops **b)
+static int cmp_dirty_idx(const void *a, const void *b)
 {
-       const struct ubifs_lprops *lpa = *a;
-       const struct ubifs_lprops *lpb = *b;
+       const struct ubifs_lprops *lpa = *(const struct ubifs_lprops **)a;
+       const struct ubifs_lprops *lpb = *(const struct ubifs_lprops **)b;
 
        return lpa->dirty + lpa->free - lpb->dirty - lpb->free;
 }
@@ -754,7 +754,7 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
               sizeof(void *) * c->dirty_idx.cnt);
        /* Sort it so that the dirtiest is now at the end */
        sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *),
-            (int (*)(const void *, const void *))cmp_dirty_idx, NULL);
+            cmp_dirty_idx, NULL);
        dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt);
        if (c->dirty_idx.cnt)
                dbg_find("dirtiest index LEB is %d with dirty %d and free %d",
@@ -782,8 +782,9 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c)
  */
 static int scan_dirty_idx_cb(struct ubifs_info *c,
                           const struct ubifs_lprops *lprops, int in_tree,
-                          struct scan_data *data)
+                          void *arg)
 {
+       struct scan_data *data = arg;
        int ret = LPT_SCAN_CONTINUE;
 
        /* Exclude LEBs that are currently in use */
@@ -842,8 +843,7 @@ static int find_dirty_idx_leb(struct ubifs_info *c)
        if (c->pnodes_have >= c->pnode_cnt)
                /* All pnodes are in memory, so skip scan */
                return -ENOSPC;
-       err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum,
-                                   (ubifs_lpt_scan_callback)scan_dirty_idx_cb,
+       err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, scan_dirty_idx_cb,
                                    &data);
        if (err)
                return err;
index f0a5538c84b0f2be4a3b061dc5f1d84f1f024a0c..74aee92433d75c2fe0880e351519e00a85b1729a 100644 (file)
@@ -292,6 +292,96 @@ static int write_head(struct ubifs_info *c, int jhead, void *buf, int len,
        return err;
 }
 
+/**
+ * __queue_and_wait - queue a task and wait until the task is waked up.
+ * @c: UBIFS file-system description object
+ *
+ * This function adds current task in queue and waits until the task is waked
+ * up. This function should be called with @c->reserve_space_wq locked.
+ */
+static void __queue_and_wait(struct ubifs_info *c)
+{
+       DEFINE_WAIT(wait);
+
+       __add_wait_queue_entry_tail_exclusive(&c->reserve_space_wq, &wait);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       spin_unlock(&c->reserve_space_wq.lock);
+
+       schedule();
+       finish_wait(&c->reserve_space_wq, &wait);
+}
+
+/**
+ * wait_for_reservation - try queuing current task to wait until waked up.
+ * @c: UBIFS file-system description object
+ *
+ * This function queues current task to wait until waked up, if queuing is
+ * started(@c->need_wait_space is not %0). Returns %true if current task is
+ * added in queue, otherwise %false is returned.
+ */
+static bool wait_for_reservation(struct ubifs_info *c)
+{
+       if (likely(atomic_read(&c->need_wait_space) == 0))
+               /* Quick path to check whether queuing is started. */
+               return false;
+
+       spin_lock(&c->reserve_space_wq.lock);
+       if (atomic_read(&c->need_wait_space) == 0) {
+               /* Queuing is not started, don't queue current task. */
+               spin_unlock(&c->reserve_space_wq.lock);
+               return false;
+       }
+
+       __queue_and_wait(c);
+       return true;
+}
+
+/**
+ * wake_up_reservation - wake up first task in queue or stop queuing.
+ * @c: UBIFS file-system description object
+ *
+ * This function wakes up the first task in queue if it exists, or stops
+ * queuing if no tasks in queue.
+ */
+static void wake_up_reservation(struct ubifs_info *c)
+{
+       spin_lock(&c->reserve_space_wq.lock);
+       if (waitqueue_active(&c->reserve_space_wq))
+               wake_up_locked(&c->reserve_space_wq);
+       else
+               /*
+                * Compared with wait_for_reservation(), set @c->need_wait_space
+                * under the protection of wait queue lock, which can avoid that
+                * @c->need_wait_space is set to 0 after new task queued.
+                */
+               atomic_set(&c->need_wait_space, 0);
+       spin_unlock(&c->reserve_space_wq.lock);
+}
+
+/**
+ * wake_up_reservation - add current task in queue or start queuing.
+ * @c: UBIFS file-system description object
+ *
+ * This function starts queuing if queuing is not started, otherwise adds
+ * current task in queue.
+ */
+static void add_or_start_queue(struct ubifs_info *c)
+{
+       spin_lock(&c->reserve_space_wq.lock);
+       if (atomic_cmpxchg(&c->need_wait_space, 0, 1) == 0) {
+               /* Starts queuing, task can go on directly. */
+               spin_unlock(&c->reserve_space_wq.lock);
+               return;
+       }
+
+       /*
+        * There are at least two tasks have retried more than 32 times
+        * at certain point, first task has started queuing, just queue
+        * the left tasks.
+        */
+       __queue_and_wait(c);
+}
+
 /**
  * make_reservation - reserve journal space.
  * @c: UBIFS file-system description object
@@ -311,33 +401,27 @@ static int write_head(struct ubifs_info *c, int jhead, void *buf, int len,
 static int make_reservation(struct ubifs_info *c, int jhead, int len)
 {
        int err, cmt_retries = 0, nospc_retries = 0;
+       bool blocked = wait_for_reservation(c);
 
 again:
        down_read(&c->commit_sem);
        err = reserve_space(c, jhead, len);
-       if (!err)
+       if (!err) {
                /* c->commit_sem will get released via finish_reservation(). */
-               return 0;
+               goto out_wake_up;
+       }
        up_read(&c->commit_sem);
 
        if (err == -ENOSPC) {
                /*
                 * GC could not make any progress. We should try to commit
-                * once because it could make some dirty space and GC would
-                * make progress, so make the error -EAGAIN so that the below
+                * because it could make some dirty space and GC would make
+                * progress, so make the error -EAGAIN so that the below
                 * will commit and re-try.
                 */
-               if (nospc_retries++ < 2) {
-                       dbg_jnl("no space, retry");
-                       err = -EAGAIN;
-               }
-
-               /*
-                * This means that the budgeting is incorrect. We always have
-                * to be able to write to the media, because all operations are
-                * budgeted. Deletions are not budgeted, though, but we reserve
-                * an extra LEB for them.
-                */
+               nospc_retries++;
+               dbg_jnl("no space, retry");
+               err = -EAGAIN;
        }
 
        if (err != -EAGAIN)
@@ -349,15 +433,37 @@ again:
         */
        if (cmt_retries > 128) {
                /*
-                * This should not happen unless the journal size limitations
-                * are too tough.
+                * This should not happen unless:
+                * 1. The journal size limitations are too tough.
+                * 2. The budgeting is incorrect. We always have to be able to
+                *    write to the media, because all operations are budgeted.
+                *    Deletions are not budgeted, though, but we reserve an
+                *    extra LEB for them.
                 */
-               ubifs_err(c, "stuck in space allocation");
+               ubifs_err(c, "stuck in space allocation, nospc_retries %d",
+                         nospc_retries);
                err = -ENOSPC;
                goto out;
-       } else if (cmt_retries > 32)
-               ubifs_warn(c, "too many space allocation re-tries (%d)",
-                          cmt_retries);
+       } else if (cmt_retries > 32) {
+               /*
+                * It's almost impossible to happen, unless there are many tasks
+                * making reservation concurrently and someone task has retried
+                * gc + commit for many times, generated available space during
+                * this period are grabbed by other tasks.
+                * But if it happens, start queuing up all tasks that will make
+                * space reservation, then there is only one task making space
+                * reservation at any time, and it can always make success under
+                * the premise of correct budgeting.
+                */
+               ubifs_warn(c, "too many space allocation cmt_retries (%d) "
+                          "nospc_retries (%d), start queuing tasks",
+                          cmt_retries, nospc_retries);
+
+               if (!blocked) {
+                       blocked = true;
+                       add_or_start_queue(c);
+               }
+       }
 
        dbg_jnl("-EAGAIN, commit and retry (retried %d times)",
                cmt_retries);
@@ -365,7 +471,7 @@ again:
 
        err = ubifs_run_commit(c);
        if (err)
-               return err;
+               goto out_wake_up;
        goto again;
 
 out:
@@ -380,6 +486,27 @@ out:
                cmt_retries = dbg_check_lprops(c);
                up_write(&c->commit_sem);
        }
+out_wake_up:
+       if (blocked) {
+               /*
+                * Only tasks that have ever started queuing or ever been queued
+                * can wake up other queued tasks, which can make sure that
+                * there is only one task waked up to make space reservation.
+                * For example:
+                *      task A          task B           task C
+                *                 make_reservation  make_reservation
+                * reserve_space // 0
+                * wake_up_reservation
+                *                  atomic_cmpxchg // 0, start queuing
+                *                  reserve_space
+                *                                    wait_for_reservation
+                *                                     __queue_and_wait
+                *                                      add_wait_queue
+                *  if (blocked) // false
+                *  // So that task C won't be waked up to race with task B
+                */
+               wake_up_reservation(c);
+       }
        return err;
 }
 
index 6d6cd85c2b4cab69e98116c5809352416c4a8577..a11c3dab7e168c9e4dd96a9df93c758ea0fb2006 100644 (file)
@@ -1014,8 +1014,9 @@ out:
  */
 static int scan_check_cb(struct ubifs_info *c,
                         const struct ubifs_lprops *lp, int in_tree,
-                        struct ubifs_lp_stats *lst)
+                        void *arg)
 {
+       struct ubifs_lp_stats *lst = arg;
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
        int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
@@ -1269,8 +1270,7 @@ int dbg_check_lprops(struct ubifs_info *c)
 
        memset(&lst, 0, sizeof(struct ubifs_lp_stats));
        err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
-                                   (ubifs_lpt_scan_callback)scan_check_cb,
-                                   &lst);
+                                   scan_check_cb, &lst);
        if (err && err != -ENOSPC)
                goto out;
 
index c4d079328b929f68429eb7db87bb98cf096d346f..07351fdce72230f81d1caa48998741e09fe11722 100644 (file)
@@ -1646,7 +1646,6 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
                len -= node_len;
        }
 
-       err = 0;
 out:
        vfree(buf);
        return err;
index 7f4031a15f4df8a41ab7cd29d0f7d062d35e62c0..291583005dd123e506d61b39f8f45a6c84166083 100644 (file)
@@ -2151,6 +2151,8 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
                mutex_init(&c->bu_mutex);
                mutex_init(&c->write_reserve_mutex);
                init_waitqueue_head(&c->cmt_wq);
+               init_waitqueue_head(&c->reserve_space_wq);
+               atomic_set(&c->need_wait_space, 0);
                c->buds = RB_ROOT;
                c->old_idx = RB_ROOT;
                c->size_tree = RB_ROOT;
index f4728e65d1bda4d4838b4373de92df76f3c2a4ae..45cacdcd4746bcdc276eda7b4686cf09dbf6481a 100644 (file)
@@ -3116,14 +3116,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
 void ubifs_tnc_close(struct ubifs_info *c)
 {
        tnc_destroy_cnext(c);
-       if (c->zroot.znode) {
-               long n, freed;
-
-               n = atomic_long_read(&c->clean_zn_cnt);
-               freed = ubifs_destroy_tnc_subtree(c, c->zroot.znode);
-               ubifs_assert(c, freed == n);
-               atomic_long_sub(n, &ubifs_clean_zn_cnt);
-       }
+       ubifs_destroy_tnc_tree(c);
        kfree(c->gap_lebs);
        kfree(c->ilebs);
        destroy_old_idx(c);
index 4d686e34e64d99feb54a3ab351fbf31fd6a5a476..d3f8a6aa1f49da522941d9e3e94130715d19c591 100644 (file)
@@ -250,6 +250,28 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
        }
 }
 
+/**
+ * ubifs_destroy_tnc_tree - destroy all znodes connected to the TNC tree.
+ * @c: UBIFS file-system description object
+ *
+ * This function destroys the whole TNC tree and updates clean global znode
+ * count.
+ */
+void ubifs_destroy_tnc_tree(struct ubifs_info *c)
+{
+       long n, freed;
+
+       if (!c->zroot.znode)
+               return;
+
+       n = atomic_long_read(&c->clean_zn_cnt);
+       freed = ubifs_destroy_tnc_subtree(c, c->zroot.znode);
+       ubifs_assert(c, freed == n);
+       atomic_long_sub(n, &ubifs_clean_zn_cnt);
+
+       c->zroot.znode = NULL;
+}
+
 /**
  * read_znode - read an indexing node from flash and fill znode.
  * @c: UBIFS file-system description object
index 3916dc4f30caa65072eb90b3d78762f41d56c82a..1f3ea879d93afb1a9a1f7638f8df3b71ba0b10b2 100644 (file)
@@ -1047,6 +1047,8 @@ struct ubifs_debug_info;
  * @bg_bud_bytes: number of bud bytes when background commit is initiated
  * @old_buds: buds to be released after commit ends
  * @max_bud_cnt: maximum number of buds
+ * @need_wait_space: Non %0 means space reservation tasks need to wait in queue
+ * @reserve_space_wq: wait queue to sleep on if @need_wait_space is not %0
  *
  * @commit_sem: synchronizes committer with other processes
  * @cmt_state: commit state
@@ -1305,6 +1307,8 @@ struct ubifs_info {
        long long bg_bud_bytes;
        struct list_head old_buds;
        int max_bud_cnt;
+       atomic_t need_wait_space;
+       wait_queue_head_t reserve_space_wq;
 
        struct rw_semaphore commit_sem;
        int cmt_state;
@@ -1903,6 +1907,7 @@ struct ubifs_znode *ubifs_tnc_postorder_next(const struct ubifs_info *c,
                                             struct ubifs_znode *znode);
 long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
                               struct ubifs_znode *zr);
+void ubifs_destroy_tnc_tree(struct ubifs_info *c);
 struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
                                     struct ubifs_zbranch *zbr,
                                     struct ubifs_znode *parent, int iip);
index 8ad38c64708ec5c2f1103ebdb5fa683cc7afc28d..9bb2d24de7094114a6f8c303647fe1b857805fb4 100644 (file)
@@ -81,8 +81,6 @@ xmbuf_alloc(
        /* ensure all writes are below EOF to avoid pagecache zeroing */
        i_size_write(inode, inode->i_sb->s_maxbytes);
 
-       trace_xmbuf_create(btp);
-
        error = xfs_buf_cache_init(btp->bt_cache);
        if (error)
                goto out_file;
@@ -99,6 +97,8 @@ xmbuf_alloc(
        if (error)
                goto out_bcache;
 
+       trace_xmbuf_create(btp);
+
        *btpp = btp;
        return 0;
 
index 30d36596a2e46aab1a58ffd058236a0585b699a2..c98cb468c35780e3045da25de62612637b0867a8 100644 (file)
@@ -811,6 +811,12 @@ restart:
  * caller should throw away the dquot and start over.  Otherwise, the dquot
  * is returned locked (and held by the cache) as if there had been a cache
  * hit.
+ *
+ * The insert needs to be done under memalloc_nofs context because the radix
+ * tree can do memory allocation during insert. The qi->qi_tree_lock is taken in
+ * memory reclaim when freeing unused dquots, so we cannot have the radix tree
+ * node allocation recursing into filesystem reclaim whilst we hold the
+ * qi_tree_lock.
  */
 static int
 xfs_qm_dqget_cache_insert(
@@ -820,25 +826,27 @@ xfs_qm_dqget_cache_insert(
        xfs_dqid_t              id,
        struct xfs_dquot        *dqp)
 {
+       unsigned int            nofs_flags;
        int                     error;
 
+       nofs_flags = memalloc_nofs_save();
        mutex_lock(&qi->qi_tree_lock);
        error = radix_tree_insert(tree, id, dqp);
        if (unlikely(error)) {
                /* Duplicate found!  Caller must try again. */
-               mutex_unlock(&qi->qi_tree_lock);
                trace_xfs_dqget_dup(dqp);
-               return error;
+               goto out_unlock;
        }
 
        /* Return a locked dquot to the caller, with a reference taken. */
        xfs_dqlock(dqp);
        dqp->q_nrefs = 1;
-
        qi->qi_dquots++;
-       mutex_unlock(&qi->qi_tree_lock);
 
-       return 0;
+out_unlock:
+       mutex_unlock(&qi->qi_tree_lock);
+       memalloc_nofs_restore(nofs_flags);
+       return error;
 }
 
 /* Check our input parameters. */
index 56b07d8ed431f214325fd810b93d6469294bd6cd..aea97fc074f8de2d786d393e85075f1aad46e155 100644 (file)
@@ -4626,6 +4626,7 @@ TRACE_EVENT(xmbuf_create,
                char            *path;
                struct file     *file = btp->bt_file;
 
+               __entry->dev = btp->bt_mount->m_super->s_dev;
                __entry->ino = file_inode(file)->i_ino;
                memset(pathname, 0, sizeof(pathname));
                path = file_path(file, pathname, sizeof(pathname) - 1);
@@ -4633,7 +4634,8 @@ TRACE_EVENT(xmbuf_create,
                        path = "(unknown)";
                strncpy(__entry->pathname, path, sizeof(__entry->pathname));
        ),
-       TP_printk("xmino 0x%lx path '%s'",
+       TP_printk("dev %d:%d xmino 0x%lx path '%s'",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __entry->pathname)
 );
@@ -4642,6 +4644,7 @@ TRACE_EVENT(xmbuf_free,
        TP_PROTO(struct xfs_buftarg *btp),
        TP_ARGS(btp),
        TP_STRUCT__entry(
+               __field(dev_t, dev)
                __field(unsigned long, ino)
                __field(unsigned long long, bytes)
                __field(loff_t, size)
@@ -4650,11 +4653,13 @@ TRACE_EVENT(xmbuf_free,
                struct file     *file = btp->bt_file;
                struct inode    *inode = file_inode(file);
 
+               __entry->dev = btp->bt_mount->m_super->s_dev;
                __entry->size = i_size_read(inode);
                __entry->bytes = (inode->i_blocks << SECTOR_SHIFT) + inode->i_bytes;
                __entry->ino = inode->i_ino;
        ),
-       TP_printk("xmino 0x%lx mem_bytes 0x%llx isize 0x%llx",
+       TP_printk("dev %d:%d xmino 0x%lx mem_bytes 0x%llx isize 0x%llx",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
                  __entry->ino,
                  __entry->bytes,
                  __entry->size)
index 39e56e1c72032413a082d6f336e01ba5d3d8be92..446fea6dda78b97953d363945a1599712e371b39 100644 (file)
@@ -5,12 +5,12 @@
 #include <asm/types.h>
 
 /**
- * __ffs - find first bit in word.
+ * generic___ffs - find first bit in word.
  * @word: The word to search
  *
  * Undefined if no bit exists, so code should check against 0 first.
  */
-static __always_inline unsigned long __ffs(unsigned long word)
+static __always_inline unsigned long generic___ffs(unsigned long word)
 {
        int num = 0;
 
@@ -41,4 +41,8 @@ static __always_inline unsigned long __ffs(unsigned long word)
        return num;
 }
 
+#ifndef __HAVE_ARCH___FFS
+#define __ffs(word) generic___ffs(word)
+#endif
+
 #endif /* _ASM_GENERIC_BITOPS___FFS_H_ */
index 03f721a8a2b1993734e458399a68848637112c87..54ccccf96e21eaad9cf4a681d304ad8ac689f371 100644 (file)
@@ -5,12 +5,12 @@
 #include <asm/types.h>
 
 /**
- * __fls - find last (most-significant) set bit in a long word
+ * generic___fls - find last (most-significant) set bit in a long word
  * @word: the word to search
  *
  * Undefined if no set bit exists, so code should check against 0 first.
  */
-static __always_inline unsigned long __fls(unsigned long word)
+static __always_inline unsigned long generic___fls(unsigned long word)
 {
        int num = BITS_PER_LONG - 1;
 
@@ -41,4 +41,8 @@ static __always_inline unsigned long __fls(unsigned long word)
        return num;
 }
 
+#ifndef __HAVE_ARCH___FLS
+#define __fls(word) generic___fls(word)
+#endif
+
 #endif /* _ASM_GENERIC_BITOPS___FLS_H_ */
index 323fd5d6ae263ab329ab67f6aa678ec324a3885d..4c43f242daeb172f3bb42dd085d9c36c7f616587 100644 (file)
@@ -3,14 +3,14 @@
 #define _ASM_GENERIC_BITOPS_FFS_H_
 
 /**
- * ffs - find first bit set
+ * generic_ffs - find first bit set
  * @x: the word to search
  *
  * This is defined the same way as
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from ffz (man ffs).
  */
-static inline int ffs(int x)
+static inline int generic_ffs(int x)
 {
        int r = 1;
 
@@ -39,4 +39,8 @@ static inline int ffs(int x)
        return r;
 }
 
+#ifndef __HAVE_ARCH_FFS
+#define ffs(x) generic_ffs(x)
+#endif
+
 #endif /* _ASM_GENERIC_BITOPS_FFS_H_ */
index b168bb10e1be17bb6394e749c238da3940ea3a01..26f3ce1dd6e44872000d7066d4b3e37325e915fa 100644 (file)
@@ -3,14 +3,14 @@
 #define _ASM_GENERIC_BITOPS_FLS_H_
 
 /**
- * fls - find last (most-significant) bit set
+ * generic_fls - find last (most-significant) bit set
  * @x: the word to search
  *
  * This is defined the same way as ffs.
  * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
  */
 
-static __always_inline int fls(unsigned int x)
+static __always_inline int generic_fls(unsigned int x)
 {
        int r = 32;
 
@@ -39,4 +39,8 @@ static __always_inline int fls(unsigned int x)
        return r;
 }
 
+#ifndef __HAVE_ARCH_FLS
+#define fls(x) generic_fls(x)
+#endif
+
 #endif /* _ASM_GENERIC_BITOPS_FLS_H_ */
index fdac4a1714ec092647116c090db0e033a30aa5c8..87e3d49a4e29bf7af1de43d1da45bfd9ca3791ea 100644 (file)
@@ -625,6 +625,37 @@ struct hv_retarget_device_interrupt {
        struct hv_device_interrupt_target int_target;
 } __packed __aligned(8);
 
+/*
+ * These Hyper-V registers provide information equivalent to the CPUID
+ * instruction on x86/x64.
+ */
+#define HV_REGISTER_HYPERVISOR_VERSION         0x00000100 /*CPUID 0x40000002 */
+#define HV_REGISTER_FEATURES                   0x00000200 /*CPUID 0x40000003 */
+#define HV_REGISTER_ENLIGHTENMENTS             0x00000201 /*CPUID 0x40000004 */
+
+/*
+ * Synthetic register definitions equivalent to MSRs on x86/x64
+ */
+#define HV_REGISTER_GUEST_CRASH_P0     0x00000210
+#define HV_REGISTER_GUEST_CRASH_P1     0x00000211
+#define HV_REGISTER_GUEST_CRASH_P2     0x00000212
+#define HV_REGISTER_GUEST_CRASH_P3     0x00000213
+#define HV_REGISTER_GUEST_CRASH_P4     0x00000214
+#define HV_REGISTER_GUEST_CRASH_CTL    0x00000215
+
+#define HV_REGISTER_GUEST_OS_ID                0x00090002
+#define HV_REGISTER_VP_INDEX           0x00090003
+#define HV_REGISTER_TIME_REF_COUNT     0x00090004
+#define HV_REGISTER_REFERENCE_TSC      0x00090017
+
+#define HV_REGISTER_SINT0              0x000A0000
+#define HV_REGISTER_SCONTROL           0x000A0010
+#define HV_REGISTER_SIEFP              0x000A0012
+#define HV_REGISTER_SIMP               0x000A0013
+#define HV_REGISTER_EOM                        0x000A0014
+
+#define HV_REGISTER_STIMER0_CONFIG     0x000B0000
+#define HV_REGISTER_STIMER0_COUNT      0x000B0001
 
 /* HvGetVpRegisters hypercall input with variable size reg name list*/
 struct hv_get_vp_registers_input {
@@ -640,7 +671,6 @@ struct hv_get_vp_registers_input {
        } element[];
 } __packed;
 
-
 /* HvGetVpRegisters returns an array of these output elements */
 struct hv_get_vp_registers_output {
        union {
@@ -787,6 +817,29 @@ struct hv_input_unmap_device_interrupt {
 #define HV_SOURCE_SHADOW_NONE               0x0
 #define HV_SOURCE_SHADOW_BRIDGE_BUS_RANGE   0x1
 
+/*
+ * Version info reported by hypervisor
+ */
+union hv_hypervisor_version_info {
+       struct {
+               u32 build_number;
+
+               u32 minor_version : 16;
+               u32 major_version : 16;
+
+               u32 service_pack;
+
+               u32 service_number : 24;
+               u32 service_branch : 8;
+       };
+       struct {
+               u32 eax;
+               u32 ebx;
+               u32 ecx;
+               u32 edx;
+       };
+};
+
 /*
  * The whole argument should fit in a page to be able to pass to the hypervisor
  * in one hypercall.
index 430f0ae0dde2d0046dd37067ed4403c213a2029a..99935779682dc29180f556469c4487603b082740 100644 (file)
@@ -157,10 +157,12 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
                 * possibly deliver another msg from the
                 * hypervisor
                 */
-               hv_set_register(HV_REGISTER_EOM, 0);
+               hv_set_msr(HV_MSR_EOM, 0);
        }
 }
 
+int hv_get_hypervisor_version(union hv_hypervisor_version_info *info);
+
 void hv_setup_vmbus_handler(void (*handler)(void));
 void hv_remove_vmbus_handler(void);
 void hv_setup_stimer0_handler(void (*handler)(void));
@@ -193,6 +195,7 @@ extern u64 (*hv_read_reference_counter)(void);
 
 int __init hv_common_init(void);
 void __init hv_common_free(void);
+void __init ms_hyperv_late_init(void);
 int hv_common_cpu_init(unsigned int cpu);
 int hv_common_cpu_die(unsigned int cpu);
 
@@ -290,6 +293,7 @@ void hv_setup_dma_ops(struct device *dev, bool coherent);
 static inline bool hv_is_hyperv_initialized(void) { return false; }
 static inline bool hv_is_hibernation_supported(void) { return false; }
 static inline void hyperv_cleanup(void) {}
+static inline void ms_hyperv_late_init(void) {}
 static inline bool hv_is_isolation_supported(void) { return false; }
 static inline enum hv_isolation_type hv_get_isolation_type(void)
 {
index 3606e1a7f965b7ae3d5ac0acc2b5d1a68bbfee38..4baca0d9107b059a79e15949f0e831128cb0a573 100644 (file)
@@ -541,7 +541,7 @@ struct drm_bridge_funcs {
         * The @get_modes callback is mostly intended to support non-probeable
         * displays such as many fixed panels. Bridges that support reading
         * EDID shall leave @get_modes unimplemented and implement the
-        * &drm_bridge_funcs->get_edid callback instead.
+        * &drm_bridge_funcs->edid_read callback instead.
         *
         * This callback is optional. Bridges that implement it shall set the
         * DRM_BRIDGE_OP_MODES flag in their &drm_bridge->ops.
@@ -687,7 +687,7 @@ enum drm_bridge_ops {
        /**
         * @DRM_BRIDGE_OP_EDID: The bridge can retrieve the EDID of the display
         * connected to its output. Bridges that set this flag shall implement
-        * the &drm_bridge_funcs->get_edid callback.
+        * the &drm_bridge_funcs->edid_read callback.
         */
        DRM_BRIDGE_OP_EDID = BIT(1),
        /**
index 0c9f917a4d4be956d50c587a8c7b90011335c9ce..81572d32db0c2bf7c6e2720f4e09d346b0b1a792 100644 (file)
@@ -71,7 +71,6 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
 }
 
 #define DRM_FIXED_POINT                32
-#define DRM_FIXED_POINT_HALF   16
 #define DRM_FIXED_ONE          (1ULL << DRM_FIXED_POINT)
 #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1)
 #define DRM_FIXED_DIGITS_MASK  (~DRM_FIXED_DECIMAL_MASK)
@@ -90,7 +89,7 @@ static inline int drm_fixp2int(s64 a)
 
 static inline int drm_fixp2int_round(s64 a)
 {
-       return drm_fixp2int(a + (1 << (DRM_FIXED_POINT_HALF - 1)));
+       return drm_fixp2int(a + DRM_FIXED_ONE / 2);
 }
 
 static inline int drm_fixp2int_ceil(s64 a)
index 881b03e4dc2882844eb641b23ea34a9e10101d27..9ed42469540eb63e6a45d138ee2a51ff41d91b81 100644 (file)
@@ -898,7 +898,8 @@ struct drm_connector_helper_funcs {
         *
         * RETURNS:
         *
-        * The number of modes added by calling drm_mode_probed_add().
+        * The number of modes added by calling drm_mode_probed_add(). Return 0
+        * on failures (no modes) instead of negative error codes.
         */
        int (*get_modes)(struct drm_connector *connector);
 
diff --git a/include/dt-bindings/interconnect/qcom,msm8909.h b/include/dt-bindings/interconnect/qcom,msm8909.h
new file mode 100644 (file)
index 0000000..76365d8
--- /dev/null
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Qualcomm MSM8909 interconnect IDs
+ */
+
+#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_MSM8909_H
+#define __DT_BINDINGS_INTERCONNECT_QCOM_MSM8909_H
+
+/* BIMC fabric */
+#define MAS_APPS_PROC                  0
+#define MAS_OXILI                      1
+#define MAS_SNOC_BIMC_0                        2
+#define MAS_SNOC_BIMC_1                        3
+#define MAS_TCU_0                      4
+#define MAS_TCU_1                      5
+#define SLV_EBI                                6
+#define SLV_BIMC_SNOC                  7
+
+/* PCNOC fabric */
+#define MAS_AUDIO                      0
+#define MAS_SPDM                       1
+#define MAS_DEHR                       2
+#define MAS_QPIC                       3
+#define MAS_BLSP_1                     4
+#define MAS_USB_HS                     5
+#define MAS_CRYPTO                     6
+#define MAS_SDCC_1                     7
+#define MAS_SDCC_2                     8
+#define MAS_SNOC_PCNOC                 9
+#define PCNOC_M_0                      10
+#define PCNOC_M_1                      11
+#define PCNOC_INT_0                    12
+#define PCNOC_INT_1                    13
+#define PCNOC_S_0                      14
+#define PCNOC_S_1                      15
+#define PCNOC_S_2                      16
+#define PCNOC_S_3                      17
+#define PCNOC_S_4                      18
+#define PCNOC_S_5                      19
+#define PCNOC_S_7                      20
+#define SLV_TCSR                       21
+#define SLV_SDCC_1                     22
+#define SLV_BLSP_1                     23
+#define SLV_CRYPTO_0_CFG               24
+#define SLV_MESSAGE_RAM                        25
+#define SLV_PDM                                26
+#define SLV_PRNG                       27
+#define SLV_USB_HS                     28
+#define SLV_QPIC                       29
+#define SLV_SPDM                       30
+#define SLV_SDCC_2                     31
+#define SLV_AUDIO                      32
+#define SLV_DEHR_CFG                   33
+#define SLV_SNOC_CFG                   34
+#define SLV_QDSS_CFG                   35
+#define SLV_USB_PHY                    36
+#define SLV_CAMERA_SS_CFG              37
+#define SLV_DISP_SS_CFG                        38
+#define SLV_VENUS_CFG                  39
+#define SLV_TLMM                       40
+#define SLV_GPU_CFG                    41
+#define SLV_IMEM_CFG                   42
+#define SLV_BIMC_CFG                   43
+#define SLV_PMIC_ARB                   44
+#define SLV_TCU                                45
+#define SLV_PCNOC_SNOC                 46
+
+/* SNOC fabric */
+#define MAS_QDSS_BAM                   0
+#define MAS_BIMC_SNOC                  1
+#define MAS_MDP                                2
+#define MAS_PCNOC_SNOC                 3
+#define MAS_VENUS                      4
+#define MAS_VFE                                5
+#define MAS_QDSS_ETR                   6
+#define MM_INT_0                       7
+#define MM_INT_1                       8
+#define MM_INT_2                       9
+#define MM_INT_BIMC                    10
+#define QDSS_INT                       11
+#define SNOC_INT_0                     12
+#define SNOC_INT_1                     13
+#define SNOC_INT_BIMC                  14
+#define SLV_KPSS_AHB                   15
+#define SLV_SNOC_BIMC_0                        16
+#define SLV_SNOC_BIMC_1                        17
+#define SLV_IMEM                       18
+#define SLV_SNOC_PCNOC                 19
+#define SLV_QDSS_STM                   20
+#define SLV_CATS_0                     21
+#define SLV_CATS_1                     22
+
+#endif /* __DT_BINDINGS_INTERCONNECT_QCOM_MSM8909_H */
diff --git a/include/dt-bindings/interconnect/qcom,sm7150-rpmh.h b/include/dt-bindings/interconnect/qcom,sm7150-rpmh.h
new file mode 100644 (file)
index 0000000..1f610eb
--- /dev/null
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Qualcomm SM7150 interconnect IDs
+ *
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.com>
+ */
+
+#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SM7150_H
+#define __DT_BINDINGS_INTERCONNECT_QCOM_SM7150_H
+
+#define MASTER_A1NOC_CFG               0
+#define MASTER_QUP_0                   1
+#define MASTER_TSIF                    2
+#define MASTER_EMMC                    3
+#define MASTER_SDCC_2                  4
+#define MASTER_SDCC_4                  5
+#define MASTER_UFS_MEM                 6
+#define A1NOC_SNOC_SLV                 7
+#define SLAVE_SERVICE_A1NOC            8
+
+#define MASTER_A2NOC_CFG               0
+#define MASTER_QDSS_BAM                        1
+#define MASTER_QUP_1                   2
+#define MASTER_CNOC_A2NOC              3
+#define MASTER_CRYPTO_CORE_0           4
+#define MASTER_IPA                     5
+#define MASTER_PCIE                    6
+#define MASTER_QDSS_ETR                        7
+#define MASTER_USB3                    8
+#define A2NOC_SNOC_SLV                 9
+#define SLAVE_ANOC_PCIE_GEM_NOC                10
+#define SLAVE_SERVICE_A2NOC            11
+
+#define MASTER_CAMNOC_HF0_UNCOMP       0
+#define MASTER_CAMNOC_RT_UNCOMP                1
+#define MASTER_CAMNOC_SF_UNCOMP                2
+#define MASTER_CAMNOC_NRT_UNCOMP       3
+#define SLAVE_CAMNOC_UNCOMP            4
+
+#define MASTER_NPU                     0
+#define SLAVE_CDSP_GEM_NOC             1
+
+#define MASTER_SPDM                    0
+#define SNOC_CNOC_MAS                  1
+#define MASTER_QDSS_DAP                        2
+#define SLAVE_A1NOC_CFG                        3
+#define SLAVE_A2NOC_CFG                        4
+#define SLAVE_AHB2PHY_NORTH            5
+#define SLAVE_AHB2PHY_SOUTH            6
+#define SLAVE_AHB2PHY_WEST             7
+#define SLAVE_AOP                      8
+#define SLAVE_AOSS                     9
+#define SLAVE_CAMERA_CFG               10
+#define SLAVE_CAMERA_NRT_THROTTLE_CFG  11
+#define SLAVE_CAMERA_RT_THROTTLE_CFG   12
+#define SLAVE_CLK_CTL                  13
+#define SLAVE_CDSP_CFG                 14
+#define SLAVE_RBCPR_CX_CFG             15
+#define SLAVE_RBCPR_MX_CFG             16
+#define SLAVE_CRYPTO_0_CFG             17
+#define SLAVE_CNOC_DDRSS               18
+#define SLAVE_DISPLAY_CFG              19
+#define SLAVE_DISPLAY_THROTTLE_CFG     20
+#define SLAVE_EMMC_CFG                 21
+#define SLAVE_GLM                      22
+#define SLAVE_GRAPHICS_3D_CFG          23
+#define SLAVE_IMEM_CFG                 24
+#define SLAVE_IPA_CFG                  25
+#define SLAVE_CNOC_MNOC_CFG            26
+#define SLAVE_PCIE_CFG                 27
+#define SLAVE_PDM                      28
+#define SLAVE_PIMEM_CFG                        29
+#define SLAVE_PRNG                     30
+#define SLAVE_QDSS_CFG                 31
+#define SLAVE_QUP_0                    32
+#define SLAVE_QUP_1                    33
+#define SLAVE_SDCC_2                   34
+#define SLAVE_SDCC_4                   35
+#define SLAVE_SNOC_CFG                 36
+#define SLAVE_SPDM_WRAPPER             37
+#define SLAVE_TCSR                     38
+#define SLAVE_TLMM_NORTH               39
+#define SLAVE_TLMM_SOUTH               40
+#define SLAVE_TLMM_WEST                        41
+#define SLAVE_TSIF                     42
+#define SLAVE_UFS_MEM_CFG              43
+#define SLAVE_USB3                     44
+#define SLAVE_VENUS_CFG                        45
+#define SLAVE_VENUS_CVP_THROTTLE_CFG   46
+#define SLAVE_VENUS_THROTTLE_CFG       47
+#define SLAVE_VSENSE_CTRL_CFG          48
+#define SLAVE_CNOC_A2NOC               49
+#define SLAVE_SERVICE_CNOC             50
+
+#define MASTER_CNOC_DC_NOC             0
+#define SLAVE_GEM_NOC_CFG              1
+#define SLAVE_LLCC_CFG                 2
+
+#define MASTER_AMPSS_M0                        0
+#define MASTER_SYS_TCU                 1
+#define MASTER_GEM_NOC_CFG             2
+#define MASTER_COMPUTE_NOC             3
+#define MASTER_MNOC_HF_MEM_NOC         4
+#define MASTER_MNOC_SF_MEM_NOC         5
+#define MASTER_GEM_NOC_PCIE_SNOC       6
+#define MASTER_SNOC_GC_MEM_NOC         7
+#define MASTER_SNOC_SF_MEM_NOC         8
+#define MASTER_GRAPHICS_3D             9
+#define SLAVE_MSS_PROC_MS_MPU_CFG      10
+#define SLAVE_GEM_NOC_SNOC             11
+#define SLAVE_LLCC                     12
+#define SLAVE_SERVICE_GEM_NOC          13
+
+
+#define MASTER_LLCC                    0
+#define SLAVE_EBI_CH0                  1
+
+#define MASTER_CNOC_MNOC_CFG           0
+#define MASTER_CAMNOC_HF0              1
+#define MASTER_CAMNOC_NRT              2
+#define MASTER_CAMNOC_RT               3
+#define MASTER_CAMNOC_SF               4
+#define MASTER_MDP_PORT0               5
+#define MASTER_MDP_PORT1               6
+#define MASTER_ROTATOR                 7
+#define MASTER_VIDEO_P0                        8
+#define MASTER_VIDEO_P1                        9
+#define MASTER_VIDEO_PROC              10
+#define SLAVE_MNOC_SF_MEM_NOC          11
+#define SLAVE_MNOC_HF_MEM_NOC          12
+#define SLAVE_SERVICE_MNOC             13
+
+#define MASTER_SNOC_CFG                        0
+#define A1NOC_SNOC_MAS                 1
+#define A2NOC_SNOC_MAS                 2
+#define MASTER_GEM_NOC_SNOC            3
+#define MASTER_PIMEM                   4
+#define MASTER_GIC                     5
+#define SLAVE_APPSS                    6
+#define SNOC_CNOC_SLV                  7
+#define SLAVE_SNOC_GEM_NOC_GC          8
+#define SLAVE_SNOC_GEM_NOC_SF          9
+#define SLAVE_OCIMEM                   10
+#define SLAVE_PIMEM                    11
+#define SLAVE_SERVICE_SNOC             12
+#define SLAVE_QDSS_STM                 13
+#define SLAVE_TCU                      14
+
+#endif
index a38c3472698aa1e7b5fe4d1ed0b8fad3884924c9..7d9710881149050bdb574a0d4407b994d36fe64c 100644 (file)
 #define SLAVE_GEM_NOC_CNOC                     12
 #define SLAVE_LLCC                             13
 #define SLAVE_MEM_NOC_PCIE_SNOC                        14
-#define MASTER_MNOC_HF_MEM_NOC_DISP            15
-#define MASTER_ANOC_PCIE_GEM_NOC_DISP          16
-#define SLAVE_LLCC_DISP                                17
-#define MASTER_ANOC_PCIE_GEM_NOC_PCIE          18
-#define SLAVE_LLCC_PCIE                                19
 
 #define MASTER_LPIAON_NOC                      0
 #define SLAVE_LPASS_GEM_NOC                    1
 
 #define MASTER_LLCC                            0
 #define SLAVE_EBI1                             1
-#define MASTER_LLCC_DISP                       2
-#define SLAVE_EBI1_DISP                                3
-#define MASTER_LLCC_PCIE                       4
-#define SLAVE_EBI1_PCIE                                5
 
 #define MASTER_AV1_ENC                         0
 #define MASTER_CAMNOC_HF                       1
 #define SLAVE_MNOC_HF_MEM_NOC                  10
 #define SLAVE_MNOC_SF_MEM_NOC                  11
 #define SLAVE_SERVICE_MNOC                     12
-#define MASTER_MDP_DISP                                13
-#define SLAVE_MNOC_HF_MEM_NOC_DISP             14
 
 #define MASTER_CDSP_PROC                       0
 #define SLAVE_CDSP_MEM_NOC                     1
 #define MASTER_PCIE_NORTH                      0
 #define MASTER_PCIE_SOUTH                      1
 #define SLAVE_ANOC_PCIE_GEM_NOC                        2
-#define MASTER_PCIE_NORTH_PCIE                 3
-#define MASTER_PCIE_SOUTH_PCIE                 4
-#define SLAVE_ANOC_PCIE_GEM_NOC_PCIE           5
 
 #define MASTER_PCIE_3                          0
 #define MASTER_PCIE_4                          1
 #define MASTER_PCIE_5                          2
 #define SLAVE_PCIE_NORTH                       3
-#define MASTER_PCIE_3_PCIE                     4
-#define MASTER_PCIE_4_PCIE                     5
-#define MASTER_PCIE_5_PCIE                     6
-#define SLAVE_PCIE_NORTH_PCIE                  7
 
 #define MASTER_PCIE_0                          0
 #define MASTER_PCIE_1                          1
 #define MASTER_PCIE_6A                         3
 #define MASTER_PCIE_6B                         4
 #define SLAVE_PCIE_SOUTH                       5
-#define MASTER_PCIE_0_PCIE                     6
-#define MASTER_PCIE_1_PCIE                     7
-#define MASTER_PCIE_2_PCIE                     8
-#define MASTER_PCIE_6A_PCIE                    9
-#define MASTER_PCIE_6B_PCIE                    10
-#define SLAVE_PCIE_SOUTH_PCIE                  11
 
 #define MASTER_A1NOC_SNOC                      0
 #define MASTER_A2NOC_SNOC                      1
diff --git a/include/dt-bindings/reset/sophgo,sg2042-reset.h b/include/dt-bindings/reset/sophgo,sg2042-reset.h
new file mode 100644 (file)
index 0000000..9ab0980
--- /dev/null
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Copyright (C) 2023 Sophgo Technology Inc. All rights reserved.
+ */
+
+#ifndef __DT_BINDINGS_RESET_SOPHGO_SG2042_H_
+#define __DT_BINDINGS_RESET_SOPHGO_SG2042_H_
+
+#define RST_MAIN_AP                    0
+#define RST_RISCV_CPU                  1
+#define RST_RISCV_LOW_SPEED_LOGIC      2
+#define RST_RISCV_CMN                  3
+#define RST_HSDMA                      4
+#define RST_SYSDMA                     5
+#define RST_EFUSE0                     6
+#define RST_EFUSE1                     7
+#define RST_RTC                                8
+#define RST_TIMER                      9
+#define RST_WDT                                10
+#define RST_AHB_ROM0                   11
+#define RST_AHB_ROM1                   12
+#define RST_I2C0                       13
+#define RST_I2C1                       14
+#define RST_I2C2                       15
+#define RST_I2C3                       16
+#define RST_GPIO0                      17
+#define RST_GPIO1                      18
+#define RST_GPIO2                      19
+#define RST_PWM                                20
+#define RST_AXI_SRAM0                  21
+#define RST_AXI_SRAM1                  22
+#define RST_SF0                                23
+#define RST_SF1                                24
+#define RST_LPC                                25
+#define RST_ETH0                       26
+#define RST_EMMC                       27
+#define RST_SD                         28
+#define RST_UART0                      29
+#define RST_UART1                      30
+#define RST_UART2                      31
+#define RST_UART3                      32
+#define RST_SPI0                       33
+#define RST_SPI1                       34
+#define RST_DBG_I2C                    35
+#define RST_PCIE0                      36
+#define RST_PCIE1                      37
+#define RST_DDR0                       38
+#define RST_DDR1                       39
+#define RST_DDR2                       40
+#define RST_DDR3                       41
+#define RST_FAU0                       42
+#define RST_FAU1                       43
+#define RST_FAU2                       44
+#define RST_RXU0                       45
+#define RST_RXU1                       46
+#define RST_RXU2                       47
+#define RST_RXU3                       48
+#define RST_RXU4                       49
+#define RST_RXU5                       50
+#define RST_RXU6                       51
+#define RST_RXU7                       52
+#define RST_RXU8                       53
+#define RST_RXU9                       54
+#define RST_RXU10                      55
+#define RST_RXU11                      56
+#define RST_RXU12                      57
+#define RST_RXU13                      58
+#define RST_RXU14                      59
+#define RST_RXU15                      60
+#define RST_RXU16                      61
+#define RST_RXU17                      62
+#define RST_RXU18                      63
+#define RST_RXU19                      64
+#define RST_RXU20                      65
+#define RST_RXU21                      66
+#define RST_RXU22                      67
+#define RST_RXU23                      68
+#define RST_RXU24                      69
+#define RST_RXU25                      70
+#define RST_RXU26                      71
+#define RST_RXU27                      72
+#define RST_RXU28                      73
+#define RST_RXU29                      74
+#define RST_RXU30                      75
+#define RST_RXU31                      76
+
+#endif /* __DT_BINDINGS_RESET_SOPHGO_SG2042_H_ */
index fb3a9c93ac86af937e3319fc2e445e0f0d9cb4e6..aa4096126553753de4d2201e596b92a8a804bc1c 100644 (file)
@@ -522,17 +522,18 @@ static inline void bitmap_replace(unsigned long *dst,
  *
  * (Bits 0, 1, 2, 3, 4, 5 are copied to the bits 0, 1, 4, 8, 9, 12)
  *
- * A more 'visual' description of the operation:
- * src:  0000000001011010
- *                 ||||||
- *          +------+|||||
- *          |  +----+||||
- *          |  |+----+|||
- *          |  ||   +-+||
- *          |  ||   |  ||
- * mask: ...v..vv...v..vv
- *       ...0..11...0..10
- * dst:  0000001100000010
+ * A more 'visual' description of the operation::
+ *
+ *     src:  0000000001011010
+ *                     ||||||
+ *              +------+|||||
+ *              |  +----+||||
+ *              |  |+----+|||
+ *              |  ||   +-+||
+ *              |  ||   |  ||
+ *     mask: ...v..vv...v..vv
+ *           ...0..11...0..10
+ *     dst:  0000001100000010
  *
  * A relationship exists between bitmap_scatter() and bitmap_gather().
  * bitmap_gather() can be seen as the 'reverse' bitmap_scatter() operation.
@@ -568,16 +569,17 @@ static inline void bitmap_scatter(unsigned long *dst, const unsigned long *src,
  *
  * (Bits 0, 1, 4, 8, 9, 12 are copied to the bits 0, 1, 2, 3, 4, 5)
  *
- * A more 'visual' description of the operation:
- * mask: ...v..vv...v..vv
- * src:  0000001100000010
- *          ^  ^^   ^   0
- *          |  ||   |  10
- *          |  ||   > 010
- *          |  |+--> 1010
- *          |  +--> 11010
- *          +----> 011010
- * dst:  0000000000011010
+ * A more 'visual' description of the operation::
+ *
+ *     mask: ...v..vv...v..vv
+ *     src:  0000001100000010
+ *              ^  ^^   ^   0
+ *              |  ||   |  10
+ *              |  ||   > 010
+ *              |  |+--> 1010
+ *              |  +--> 11010
+ *              +----> 011010
+ *     dst:  0000000000011010
  *
  * A relationship exists between bitmap_gather() and bitmap_scatter(). See
  * bitmap_scatter() for the bitmap scatter detailed operations.
index f9b87c39cab0478aac030e50174dd5b3fd7c8f16..c3e8f7cf96be9e1c10169d2e7afe31696082eb8f 100644 (file)
@@ -1505,6 +1505,16 @@ struct blk_holder_ops {
         * Thaw the file system mounted on the block device.
         */
        int (*thaw)(struct block_device *bdev);
+
+       /*
+        * If needed, get a reference to the holder.
+        */
+       void (*get_holder)(void *holder);
+
+       /*
+        * Release the holder.
+        */
+       void (*put_holder)(void *holder);
 };
 
 /*
index 6355a36a3f8151f96c17d9d343903bd715dc157e..b57118aaa67978849850349135a3fb5b1b59b5e0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/mod_devicetable.h>
+#include <linux/msi.h>
 
 #define MAX_CDX_DEV_RESOURCES  4
 #define CDX_CONTROLLER_ID_SHIFT 4
 struct cdx_controller;
 
 enum {
+       CDX_DEV_MSI_CONF,
        CDX_DEV_BUS_MASTER_CONF,
        CDX_DEV_RESET_CONF,
+       CDX_DEV_MSI_ENABLE,
+};
+
+struct cdx_msi_config {
+       u64 addr;
+       u32 data;
+       u16 msi_index;
 };
 
 struct cdx_device_config {
        u8 type;
-       bool bus_master_enable;
+       union {
+               struct cdx_msi_config msi;
+               bool bus_master_enable;
+               bool msi_enable;
+       };
 };
 
 typedef int (*cdx_bus_enable_cb)(struct cdx_controller *cdx, u8 bus_num);
@@ -87,6 +100,7 @@ struct cdx_ops {
  * struct cdx_controller: CDX controller object
  * @dev: Linux device associated with the CDX controller.
  * @priv: private data
+ * @msi_domain: MSI domain
  * @id: Controller ID
  * @controller_registered: controller registered with bus
  * @ops: CDX controller ops
@@ -94,6 +108,7 @@ struct cdx_ops {
 struct cdx_controller {
        struct device *dev;
        void *priv;
+       struct irq_domain *msi_domain;
        u32 id;
        bool controller_registered;
        struct cdx_ops *ops;
@@ -120,9 +135,13 @@ struct cdx_controller {
  * @req_id: Requestor ID associated with CDX device
  * @is_bus: Is this bus device
  * @enabled: is this bus enabled
+ * @msi_dev_id: MSI Device ID associated with CDX device
+ * @num_msi: Number of MSI's supported by the device
  * @driver_override: driver name to force a match; do not set directly,
  *                   because core frees it; use driver_set_override() to
  *                   set or clear it.
+ * @irqchip_lock: lock to synchronize irq/msi configuration
+ * @msi_write_pending: MSI write pending for this device
  */
 struct cdx_device {
        struct device dev;
@@ -144,7 +163,11 @@ struct cdx_device {
        u32 req_id;
        bool is_bus;
        bool enabled;
+       u32 msi_dev_id;
+       u32 num_msi;
        const char *driver_override;
+       struct mutex irqchip_lock;
+       bool msi_write_pending;
 };
 
 #define to_cdx_device(_dev) \
@@ -237,4 +260,32 @@ int cdx_set_master(struct cdx_device *cdx_dev);
  */
 int cdx_clear_master(struct cdx_device *cdx_dev);
 
+#ifdef CONFIG_GENERIC_MSI_IRQ
+/**
+ * cdx_enable_msi - Enable MSI for the CDX device.
+ * @cdx_dev: device pointer
+ *
+ * Return: 0 for success, -errno on failure
+ */
+int cdx_enable_msi(struct cdx_device *cdx_dev);
+
+/**
+ * cdx_disable_msi - Disable MSI for the CDX device.
+ * @cdx_dev: device pointer
+ */
+void cdx_disable_msi(struct cdx_device *cdx_dev);
+
+#else /* CONFIG_GENERIC_MSI_IRQ */
+
+static inline int cdx_enable_msi(struct cdx_device *cdx_dev)
+{
+       return -ENODEV;
+}
+
+static inline void cdx_disable_msi(struct cdx_device *cdx_dev)
+{
+}
+
+#endif /* CONFIG_GENERIC_MSI_IRQ */
+
 #endif /* _CDX_BUS_H_ */
index cbfcbf186ce33069a28e1a8afad337f4c5b03a69..e656f63efdcee77ee3e8bc55e763423686cee06f 100644 (file)
 /**
  * struct clk_omap_reg - OMAP register declaration
  * @offset: offset from the master IP module base address
+ * @bit: register bit offset
  * @index: index of the master IP module
+ * @flags: flags
  */
 struct clk_omap_reg {
        void __iomem *ptr;
        u16 offset;
+       u8 bit;
        u8 index;
        u8 flags;
 };
index 52730e4236811b3949d02d1a8c0bf4328a1e6c52..c00cc6c0878a1e173701a6267ac062fa3d41b790 100644 (file)
@@ -116,6 +116,14 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
  */
 #define __stringify_label(n) #n
 
+#define __annotate_reachable(c) ({                                     \
+       asm volatile(__stringify_label(c) ":\n\t"                       \
+                       ".pushsection .discard.reachable\n\t"           \
+                       ".long " __stringify_label(c) "b - .\n\t"       \
+                       ".popsection\n\t");                             \
+})
+#define annotate_reachable() __annotate_reachable(__COUNTER__)
+
 #define __annotate_unreachable(c) ({                                   \
        asm volatile(__stringify_label(c) ":\n\t"                       \
                     ".pushsection .discard.unreachable\n\t"            \
@@ -128,6 +136,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
 #define __annotate_jump_table __section(".rodata..c_jump_table")
 
 #else /* !CONFIG_OBJTOOL */
+#define annotate_reachable()
 #define annotate_unreachable()
 #define __annotate_jump_table
 #endif /* CONFIG_OBJTOOL */
index 3e64ec0f7ac80b03af19a4812bc97cd80396efa9..2abaa3a825a9ec3f86a69e6e9cf169ad9614b20c 100644 (file)
@@ -99,17 +99,17 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html#index-cold-label-attribute
  *
  * When -falign-functions=N is in use, we must avoid the cold attribute as
- * contemporary versions of GCC drop the alignment for cold functions. Worse,
- * GCC can implicitly mark callees of cold functions as cold themselves, so
- * it's not sufficient to add __function_aligned here as that will not ensure
- * that callees are correctly aligned.
+ * GCC drops the alignment for cold functions. Worse, GCC can implicitly mark
+ * callees of cold functions as cold themselves, so it's not sufficient to add
+ * __function_aligned here as that will not ensure that callees are correctly
+ * aligned.
  *
  * See:
  *
  *   https://lore.kernel.org/lkml/Y77%2FqVgvaJidFpYt@FVFF77S0Q05N
  *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88345#c9
  */
-#if !defined(CONFIG_CC_IS_GCC) || (CONFIG_FUNCTION_ALIGNMENT == 0)
+#if defined(CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT) || (CONFIG_FUNCTION_ALIGNMENT == 0)
 #define __cold                         __attribute__((__cold__))
 #else
 #define __cold
index 779d388af8a0a275ecd864baa4089a761ed5c6f6..31a8f5b85f5d7483c402e0cff64a6e4cef1a2893 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/bits.h>
 #include <linux/rculist.h>
 #include <linux/types.h>
+#include <linux/vesa.h>
 
 struct vc_data;
 struct console_font_op;
@@ -36,63 +37,91 @@ enum vc_intensity;
 /**
  * struct consw - callbacks for consoles
  *
+ * @owner:      the module to get references of when this console is used
+ * @con_startup: set up the console and return its name (like VGA, EGA, ...)
+ * @con_init:   initialize the console on @vc. @init is true for the very first
+ *             call on this @vc.
+ * @con_deinit: deinitialize the console from @vc.
+ * @con_clear:  erase @count characters at [@x, @y] on @vc. @count >= 1.
+ * @con_putc:   emit one character with attributes @ca to [@x, @y] on @vc.
+ *             (optional -- @con_putcs would be called instead)
+ * @con_putcs:  emit @count characters with attributes @s to [@x, @y] on @vc.
+ * @con_cursor: enable/disable cursor depending on @enable
  * @con_scroll: move lines from @top to @bottom in direction @dir by @lines.
  *             Return true if no generic handling should be done.
  *             Invoked by csi_M and printing to the console.
- * @con_set_palette: sets the palette of the console to @table (optional)
+ * @con_switch: notifier about the console switch; it is supposed to return
+ *             true if a redraw is needed.
+ * @con_blank:  blank/unblank the console. The target mode is passed in @blank.
+ *             @mode_switch is set if changing from/to text/graphics. The hook
+ *             is supposed to return true if a redraw is needed.
+ * @con_font_set: set console @vc font to @font with height @vpitch. @flags can
+ *             be %KD_FONT_FLAG_DONT_RECALC. (optional)
+ * @con_font_get: fetch the current font on @vc of height @vpitch into @font.
+ *             (optional)
+ * @con_font_default: set default font on @vc. @name can be %NULL or font name
+ *             to search for. @font can be filled back. (optional)
+ * @con_resize:        resize the @vc console to @width x @height. @from_user is true
+ *             when this change comes from the user space.
+ * @con_set_palette: sets the palette of the console @vc to @table (optional)
  * @con_scrolldelta: the contents of the console should be scrolled by @lines.
  *                  Invoked by user. (optional)
+ * @con_set_origin: set origin (see &vc_data::vc_origin) of the @vc. If not
+ *             provided or returns false, the origin is set to
+ *             @vc->vc_screenbuf. (optional)
+ * @con_save_screen: save screen content into @vc->vc_screenbuf. Called e.g.
+ *             upon entering graphics. (optional)
+ * @con_build_attr: build attributes based on @color, @intensity and other
+ *             parameters. The result is used for both normal and erase
+ *             characters. (optional)
+ * @con_invert_region: invert a region of length @count on @vc starting at @p.
+ *             (optional)
+ * @con_debug_enter: prepare the console for the debugger. This includes, but
+ *             is not limited to, unblanking the console, loading an
+ *             appropriate palette, and allowing debugger generated output.
+ *             (optional)
+ * @con_debug_leave: restore the console to its pre-debug state as closely as
+ *             possible. (optional)
  */
 struct consw {
        struct module *owner;
        const char *(*con_startup)(void);
-       void    (*con_init)(struct vc_data *vc, int init);
+       void    (*con_init)(struct vc_data *vc, bool init);
        void    (*con_deinit)(struct vc_data *vc);
-       void    (*con_clear)(struct vc_data *vc, int sy, int sx, int height,
-                       int width);
-       void    (*con_putc)(struct vc_data *vc, int c, int ypos, int xpos);
-       void    (*con_putcs)(struct vc_data *vc, const unsigned short *s,
-                       int count, int ypos, int xpos);
-       void    (*con_cursor)(struct vc_data *vc, int mode);
+       void    (*con_clear)(struct vc_data *vc, unsigned int y,
+                            unsigned int x, unsigned int count);
+       void    (*con_putc)(struct vc_data *vc, u16 ca, unsigned int y,
+                           unsigned int x);
+       void    (*con_putcs)(struct vc_data *vc, const u16 *s,
+                            unsigned int count, unsigned int ypos,
+                            unsigned int xpos);
+       void    (*con_cursor)(struct vc_data *vc, bool enable);
        bool    (*con_scroll)(struct vc_data *vc, unsigned int top,
                        unsigned int bottom, enum con_scroll dir,
                        unsigned int lines);
-       int     (*con_switch)(struct vc_data *vc);
-       int     (*con_blank)(struct vc_data *vc, int blank, int mode_switch);
-       int     (*con_font_set)(struct vc_data *vc, struct console_font *font,
-                       unsigned int vpitch, unsigned int flags);
+       bool    (*con_switch)(struct vc_data *vc);
+       bool    (*con_blank)(struct vc_data *vc, enum vesa_blank_mode blank,
+                            bool mode_switch);
+       int     (*con_font_set)(struct vc_data *vc,
+                               const struct console_font *font,
+                               unsigned int vpitch, unsigned int flags);
        int     (*con_font_get)(struct vc_data *vc, struct console_font *font,
                        unsigned int vpitch);
        int     (*con_font_default)(struct vc_data *vc,
-                       struct console_font *font, char *name);
+                       struct console_font *font, const char *name);
        int     (*con_resize)(struct vc_data *vc, unsigned int width,
-                       unsigned int height, unsigned int user);
+                             unsigned int height, bool from_user);
        void    (*con_set_palette)(struct vc_data *vc,
                        const unsigned char *table);
        void    (*con_scrolldelta)(struct vc_data *vc, int lines);
-       int     (*con_set_origin)(struct vc_data *vc);
+       bool    (*con_set_origin)(struct vc_data *vc);
        void    (*con_save_screen)(struct vc_data *vc);
        u8      (*con_build_attr)(struct vc_data *vc, u8 color,
                        enum vc_intensity intensity,
                        bool blink, bool underline, bool reverse, bool italic);
        void    (*con_invert_region)(struct vc_data *vc, u16 *p, int count);
-       u16    *(*con_screen_pos)(const struct vc_data *vc, int offset);
-       unsigned long (*con_getxy)(struct vc_data *vc, unsigned long position,
-                       int *px, int *py);
-       /*
-        * Flush the video console driver's scrollback buffer
-        */
-       void    (*con_flush_scrollback)(struct vc_data *vc);
-       /*
-        * Prepare the console for the debugger.  This includes, but is not
-        * limited to, unblanking the console, loading an appropriate
-        * palette, and allowing debugger generated output.
-        */
-       int     (*con_debug_enter)(struct vc_data *vc);
-       /*
-        * Restore the console to its pre-debug state as closely as possible.
-        */
-       int     (*con_debug_leave)(struct vc_data *vc);
+       void    (*con_debug_enter)(struct vc_data *vc);
+       void    (*con_debug_leave)(struct vc_data *vc);
 };
 
 extern const struct consw *conswitchp;
@@ -112,32 +141,21 @@ int con_is_bound(const struct consw *csw);
 int do_unregister_con_driver(const struct consw *csw);
 int do_take_over_console(const struct consw *sw, int first, int last, int deflt);
 void give_up_console(const struct consw *sw);
-#ifdef CONFIG_HW_CONSOLE
-int con_debug_enter(struct vc_data *vc);
-int con_debug_leave(void);
+#ifdef CONFIG_VT
+void con_debug_enter(struct vc_data *vc);
+void con_debug_leave(void);
 #else
-static inline int con_debug_enter(struct vc_data *vc)
-{
-       return 0;
-}
-static inline int con_debug_leave(void)
-{
-       return 0;
-}
+static inline void con_debug_enter(struct vc_data *vc) { }
+static inline void con_debug_leave(void) { }
 #endif
 
-/* cursor */
-#define CM_DRAW     (1)
-#define CM_ERASE    (2)
-#define CM_MOVE     (3)
-
 /*
  * The interface for a console, or any other device that wants to capture
  * console messages (printer driver?)
  */
 
 /**
- * cons_flags - General console flags
+ * enum cons_flags - General console flags
  * @CON_PRINTBUFFER:   Used by newly registered consoles to avoid duplicate
  *                     output of messages that were already shown by boot
  *                     consoles or read by userspace via syslog() syscall.
@@ -218,7 +236,7 @@ struct nbcon_state {
 static_assert(sizeof(struct nbcon_state) <= sizeof(int));
 
 /**
- * nbcon_prio - console owner priority for nbcon consoles
+ * enum nbcon_prio - console owner priority for nbcon consoles
  * @NBCON_PRIO_NONE:           Unused
  * @NBCON_PRIO_NORMAL:         Normal (non-emergency) usage
  * @NBCON_PRIO_EMERGENCY:      Emergency output (WARN/OOPS...)
@@ -450,7 +468,7 @@ static inline bool console_is_registered(const struct console *con)
  * for_each_console() - Iterator over registered consoles
  * @con:       struct console pointer used as loop cursor
  *
- * The console list and the console->flags are immutable while iterating.
+ * The console list and the &console.flags are immutable while iterating.
  *
  * Requires console_list_lock to be held.
  */
@@ -520,12 +538,6 @@ void vcs_remove_sysfs(int index);
  */
 extern atomic_t ignore_console_lock_warning;
 
-/* VESA Blanking Levels */
-#define VESA_NO_BLANKING        0
-#define VESA_VSYNC_SUSPEND      1
-#define VESA_HSYNC_SUSPEND      2
-#define VESA_POWERDOWN          3
-
 extern void console_init(void);
 
 /* For deferred console takeover */
index 539f1cd45309472c2be973ce155b8746ef998ed3..20f564e9855234308afc6768d67635435d6c5bed 100644 (file)
@@ -151,7 +151,6 @@ struct vc_data {
        DECLARE_BITMAP(vc_tab_stop, VC_TABSTOPS_COUNT); /* Tab stops. 256 columns. */
        unsigned char   vc_palette[16*3];       /* Colour palette for VGA+ */
        unsigned short * vc_translate;
-       unsigned int    vc_resize_user;         /* resize request from user */
        unsigned int    vc_bell_pitch;          /* Console bell pitch */
        unsigned int    vc_bell_duration;       /* Console bell duration */
        unsigned short  vc_cur_blink_ms;        /* Cursor blink duration */
index a4cb7dd6ca2374c91d9cee002b04024bba0ada7a..5f288d475490c92a2283f9288e7119b8ff1710c7 100644 (file)
@@ -35,7 +35,7 @@
 
 #define CORESIGHT_UNLOCK       0xc5acce55
 
-extern struct bus_type coresight_bustype;
+extern const struct bus_type coresight_bustype;
 
 enum coresight_dev_type {
        CORESIGHT_DEV_TYPE_SINK,
@@ -226,13 +226,26 @@ struct coresight_sysfs_link {
  *             by @coresight_ops.
  * @access:    Device i/o access abstraction for this device.
  * @dev:       The device entity associated to this component.
- * @refcnt:    keep track of what is in use.
+ * @mode:      This tracer's mode, i.e sysFS, Perf or disabled. This is
+ *             actually an 'enum cs_mode', but is stored in an atomic type.
+ *             This is always accessed through local_read() and local_set(),
+ *             but wherever it's done from within the Coresight device's lock,
+ *             a non-atomic read would also work. This is the main point of
+ *             synchronisation between code happening inside the sysfs mode's
+ *             coresight_mutex and outside when running in Perf mode. A compare
+ *             and exchange swap is done to atomically claim one mode or the
+ *             other.
+ * @refcnt:    keep track of what is in use. Only access this outside of the
+ *             device's spinlock when the coresight_mutex held and mode ==
+ *             CS_MODE_SYSFS. Otherwise it must be accessed from inside the
+ *             spinlock.
  * @orphan:    true if the component has connections that haven't been linked.
- * @enable:    'true' if component is currently part of an active path.
- * @activated: 'true' only if a _sink_ has been activated.  A sink can be
- *             activated but not yet enabled.  Enabling for a _sink_
- *             happens when a source has been selected and a path is enabled
- *             from source to that sink.
+ * @sysfs_sink_activated: 'true' when a sink has been selected for use via sysfs
+ *             by writing a 1 to the 'enable_sink' file.  A sink can be
+ *             activated but not yet enabled.  Enabling for a _sink_ happens
+ *             when a source has been selected and a path is enabled from
+ *             source to that sink. A sink can also become enabled but not
+ *             activated if it's used via Perf.
  * @ea:                Device attribute for sink representation under PMU directory.
  * @def_sink:  cached reference to default sink found for this device.
  * @nr_links:   number of sysfs links created to other components from this
@@ -250,11 +263,11 @@ struct coresight_device {
        const struct coresight_ops *ops;
        struct csdev_access access;
        struct device dev;
-       atomic_t refcnt;
+       local_t mode;
+       int refcnt;
        bool orphan;
-       bool enable;    /* true only if configured as part of a path */
        /* sink specific fields */
-       bool activated; /* true only if a sink is part of a path */
+       bool sysfs_sink_activated;
        struct dev_ext_attribute *ea;
        struct coresight_device *def_sink;
        /* sysfs links between components */
@@ -378,8 +391,6 @@ struct coresight_ops {
        const struct coresight_ops_helper *helper_ops;
 };
 
-#if IS_ENABLED(CONFIG_CORESIGHT)
-
 static inline u32 csdev_access_relaxed_read32(struct csdev_access *csa,
                                              u32 offset)
 {
@@ -569,11 +580,43 @@ static inline bool coresight_is_percpu_sink(struct coresight_device *csdev)
               (csdev->subtype.sink_subtype == CORESIGHT_DEV_SUBTYPE_SINK_PERCPU_SYSMEM);
 }
 
+/*
+ * Atomically try to take the device and set a new mode. Returns true on
+ * success, false if the device is already taken by someone else.
+ */
+static inline bool coresight_take_mode(struct coresight_device *csdev,
+                                      enum cs_mode new_mode)
+{
+       return local_cmpxchg(&csdev->mode, CS_MODE_DISABLED, new_mode) ==
+              CS_MODE_DISABLED;
+}
+
+static inline enum cs_mode coresight_get_mode(struct coresight_device *csdev)
+{
+       return local_read(&csdev->mode);
+}
+
+static inline void coresight_set_mode(struct coresight_device *csdev,
+                                     enum cs_mode new_mode)
+{
+       enum cs_mode current_mode = coresight_get_mode(csdev);
+
+       /*
+        * Changing to a new mode must be done from an already disabled state
+        * unless it's synchronized with coresight_take_mode(). Otherwise the
+        * device is already in use and signifies a locking issue.
+        */
+       WARN(new_mode != CS_MODE_DISABLED && current_mode != CS_MODE_DISABLED &&
+            current_mode != new_mode, "Device already in use\n");
+
+       local_set(&csdev->mode, new_mode);
+}
+
 extern struct coresight_device *
 coresight_register(struct coresight_desc *desc);
 extern void coresight_unregister(struct coresight_device *csdev);
-extern int coresight_enable(struct coresight_device *csdev);
-extern void coresight_disable(struct coresight_device *csdev);
+extern int coresight_enable_sysfs(struct coresight_device *csdev);
+extern void coresight_disable_sysfs(struct coresight_device *csdev);
 extern int coresight_timeout(struct csdev_access *csa, u32 offset,
                             int position, int value);
 
@@ -598,83 +641,6 @@ void coresight_relaxed_write64(struct coresight_device *csdev,
                               u64 val, u32 offset);
 void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset);
 
-#else
-static inline struct coresight_device *
-coresight_register(struct coresight_desc *desc) { return NULL; }
-static inline void coresight_unregister(struct coresight_device *csdev) {}
-static inline int
-coresight_enable(struct coresight_device *csdev) { return -ENOSYS; }
-static inline void coresight_disable(struct coresight_device *csdev) {}
-
-static inline int coresight_timeout(struct csdev_access *csa, u32 offset,
-                                   int position, int value)
-{
-       return 1;
-}
-
-static inline int coresight_claim_device_unlocked(struct coresight_device *csdev)
-{
-       return -EINVAL;
-}
-
-static inline int coresight_claim_device(struct coresight_device *csdev)
-{
-       return -EINVAL;
-}
-
-static inline void coresight_disclaim_device(struct coresight_device *csdev) {}
-static inline void coresight_disclaim_device_unlocked(struct coresight_device *csdev) {}
-
-static inline bool coresight_loses_context_with_cpu(struct device *dev)
-{
-       return false;
-}
-
-static inline u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset)
-{
-       WARN_ON_ONCE(1);
-       return 0;
-}
-
-static inline u32 coresight_read32(struct coresight_device *csdev, u32 offset)
-{
-       WARN_ON_ONCE(1);
-       return 0;
-}
-
-static inline void coresight_write32(struct coresight_device *csdev, u32 val, u32 offset)
-{
-}
-
-static inline void coresight_relaxed_write32(struct coresight_device *csdev,
-                                            u32 val, u32 offset)
-{
-}
-
-static inline u64 coresight_relaxed_read64(struct coresight_device *csdev,
-                                          u32 offset)
-{
-       WARN_ON_ONCE(1);
-       return 0;
-}
-
-static inline u64 coresight_read64(struct coresight_device *csdev, u32 offset)
-{
-       WARN_ON_ONCE(1);
-       return 0;
-}
-
-static inline void coresight_relaxed_write64(struct coresight_device *csdev,
-                                            u64 val, u32 offset)
-{
-}
-
-static inline void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
-{
-}
-
-#endif         /* IS_ENABLED(CONFIG_CORESIGHT) */
-
 extern int coresight_get_cpu(struct device *dev);
 
 struct coresight_platform_data *coresight_get_platform_data(struct device *dev);
index ae5a20cf2f9c16c6bb05b3db79d7e76a825f8be3..272e4e79e15c48db487feba3b7e6103e71b21e8d 100644 (file)
@@ -130,7 +130,7 @@ static inline void cpu_maps_update_done(void)
 static inline int add_cpu(unsigned int cpu) { return 0;}
 
 #endif /* CONFIG_SMP */
-extern struct bus_type cpu_subsys;
+extern const struct bus_type cpu_subsys;
 
 extern int lockdep_is_cpus_held(void);
 
index 836d575798281567c5850a1179361ea6f9c4cc31..9956afb9acc2332d0d919a836998b441f8062ad3 100644 (file)
@@ -1141,8 +1141,7 @@ static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_
                if (ret < 0)
                        continue;
 
-               if (pargs->np == args.np && pargs->args_count == args.args_count &&
-                   !memcmp(pargs->args, args.args, sizeof(args.args[0]) * args.args_count))
+               if (of_phandle_args_equal(pargs, &args))
                        cpumask_set_cpu(cpu, cpumask);
 
                of_node_put(args.np);
index 23270b16e1dbf3c41740d06b1afd7755ea03dc7b..d33352c2e3865fdbd82c42ca9645d8898127c0cd 100644 (file)
@@ -8,6 +8,12 @@
 
 struct kimage;
 
+struct crash_mem {
+       unsigned int max_nr_ranges;
+       unsigned int nr_ranges;
+       struct range ranges[] __counted_by(max_nr_ranges);
+};
+
 #ifdef CONFIG_CRASH_DUMP
 
 int crash_shrink_memory(unsigned long new_size);
@@ -51,12 +57,6 @@ static inline unsigned int crash_get_elfcorehdr_size(void) { return 0; }
 /* Alignment required for elf header segment */
 #define ELF_CORE_HEADER_ALIGN   4096
 
-struct crash_mem {
-       unsigned int max_nr_ranges;
-       unsigned int nr_ranges;
-       struct range ranges[] __counted_by(max_nr_ranges);
-};
-
 extern int crash_exclude_mem_range(struct crash_mem *mem,
                                   unsigned long long mstart,
                                   unsigned long long mend);
index 5abd07361eb516b530937004a874bc758967a49a..2b5923909f963372f997020b53ae0f0db6f55679 100644 (file)
@@ -68,7 +68,7 @@ struct dio_bus {
 };
 
 extern struct dio_bus dio_bus;      /* Single DIO bus */
-extern struct bus_type dio_bus_type;
+extern const struct bus_type dio_bus_type;
 
     /*
      *  DIO device IDs
index 053137a0fe45678d0d2319f13953c2bbc77a588a..a357287eac1eab198ca1448ae678a9a2076c3859 100644 (file)
@@ -27,6 +27,7 @@
 
 #define F2FS_BYTES_TO_BLK(bytes)       ((bytes) >> F2FS_BLKSIZE_BITS)
 #define F2FS_BLK_TO_BYTES(blk)         ((blk) << F2FS_BLKSIZE_BITS)
+#define F2FS_BLK_END_BYTES(blk)                (F2FS_BLK_TO_BYTES(blk + 1) - 1)
 
 /* 0, 1(node nid), 2(meta nid) are reserved node id */
 #define F2FS_RESERVED_NODE_NUM         3
 
 #define F2FS_ENC_UTF8_12_1     1
 
-#define F2FS_IO_SIZE(sbi)      BIT(F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */
-#define F2FS_IO_SIZE_KB(sbi)   BIT(F2FS_OPTION(sbi).write_io_size_bits + 2) /* KB */
-#define F2FS_IO_SIZE_BITS(sbi) (F2FS_OPTION(sbi).write_io_size_bits) /* power of 2 */
-#define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1)
-#define F2FS_IO_ALIGNED(sbi)   (F2FS_IO_SIZE(sbi) > 1)
-
 /* This flag is used by node and meta inodes, and by recovery */
 #define GFP_F2FS_ZERO          (GFP_NOFS | __GFP_ZERO)
 
@@ -81,6 +76,7 @@ enum stop_cp_reason {
        STOP_CP_REASON_CORRUPTED_SUMMARY,
        STOP_CP_REASON_UPDATE_INODE,
        STOP_CP_REASON_FLUSH_FAIL,
+       STOP_CP_REASON_NO_SEGMENT,
        STOP_CP_REASON_MAX,
 };
 
index 708e6a177b1be07c3227e7a1ede7b681a0c9beee..0dd27364d56fe04e7a72bc3319ff4c8790cb2282 100644 (file)
@@ -145,9 +145,13 @@ struct fb_event {
        void *data;
 };
 
+/*     Enough for the VT console needs, see its max_font_width/height */
+#define FB_MAX_BLIT_WIDTH      64
+#define FB_MAX_BLIT_HEIGHT     128
+
 struct fb_blit_caps {
-       u32 x;
-       u32 y;
+       DECLARE_BITMAP(x, FB_MAX_BLIT_WIDTH);
+       DECLARE_BITMAP(y, FB_MAX_BLIT_HEIGHT);
        u32 len;
        u32 flags;
 };
@@ -194,10 +198,12 @@ struct fb_pixmap {
        u32 scan_align;         /* alignment per scanline               */
        u32 access_align;       /* alignment per read/write (bits)      */
        u32 flags;              /* see FB_PIXMAP_*                      */
-       u32 blit_x;             /* supported bit block dimensions (1-32)*/
-       u32 blit_y;             /* Format: blit_x = 1 << (width - 1)    */
-                               /*         blit_y = 1 << (height - 1)   */
-                               /* if 0, will be set to 0xffffffff (all)*/
+                               /* supported bit block dimensions       */
+                               /* Format: test_bit(width - 1, blit_x)  */
+                               /*         test_bit(height - 1, blit_y) */
+                               /* if zero, will be set to full (all)   */
+       DECLARE_BITMAP(blit_x, FB_MAX_BLIT_WIDTH);
+       DECLARE_BITMAP(blit_y, FB_MAX_BLIT_HEIGHT);
        /* access methods */
        void (*writeio)(struct fb_info *info, void __iomem *dst, void *src, unsigned int size);
        void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size);
index 5e4f39ef2e72cc00b5924f048d60394e6e579313..c69598e383c1618fbbdd99e252f70c2cacfd72df 100644 (file)
@@ -405,7 +405,7 @@ unsigned long find_next_and_bit_wrap(const unsigned long *addr1,
 {
        unsigned long bit = find_next_and_bit(addr1, addr2, size, offset);
 
-       if (bit < size)
+       if (bit < size || offset == 0)
                return bit;
 
        bit = find_first_and_bit(addr1, addr2, offset);
@@ -413,8 +413,8 @@ unsigned long find_next_and_bit_wrap(const unsigned long *addr1,
 }
 
 /**
- * find_next_bit_wrap - find the next set bit in both memory regions
- * @addr: The first address to base the search on
+ * find_next_bit_wrap - find the next set bit in a memory region
+ * @addr: The address to base the search on
  * @size: The bitmap size in bits
  * @offset: The bitnumber to start searching at
  *
@@ -427,7 +427,7 @@ unsigned long find_next_bit_wrap(const unsigned long *addr,
 {
        unsigned long bit = find_next_bit(addr, size, offset);
 
-       if (bit < size)
+       if (bit < size || offset == 0)
                return bit;
 
        bit = find_first_bit(addr, offset);
index 0311858b46cef2d0b966e7420159f580187f95bc..f026f8926d79255553f4bdabea9b49539c8ed499 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <linux/cleanup.h>
 #include <linux/gfp.h>
 
 #define FW_ACTION_NOUEVENT 0
@@ -198,4 +199,6 @@ static inline void firmware_upload_unregister(struct fw_upload *fw_upload)
 
 int firmware_request_cache(struct device *device, const char *name);
 
+DEFINE_FREE(firmware, struct firmware *, release_firmware(_T))
+
 #endif
index 9a7e527392512c69955ab015ac9f9f5273c4c65f..1a069a56c961b6a96c0bf283507551ca7916a7fc 100644 (file)
@@ -3,6 +3,7 @@
  * Xilinx Zynq MPSoC Firmware layer
  *
  *  Copyright (C) 2014-2021 Xilinx
+ *  Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
  *
  *  Michal Simek <michal.simek@amd.com>
  *  Davorin Mista <davorin.mista@aggios.com>
@@ -171,6 +172,7 @@ enum pm_api_id {
        PM_CLOCK_GETPARENT = 44,
        PM_FPGA_READ = 46,
        PM_SECURE_AES = 47,
+       PM_EFUSE_ACCESS = 53,
        PM_FEATURE_CHECK = 63,
 };
 
@@ -562,6 +564,7 @@ int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
                              const u32 qos,
                              const enum zynqmp_pm_request_ack ack);
 int zynqmp_pm_aes_engine(const u64 address, u32 *out);
+int zynqmp_pm_efuse_access(const u64 address, u32 *out);
 int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags);
 int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags);
 int zynqmp_pm_fpga_get_status(u32 *value);
@@ -749,6 +752,11 @@ static inline int zynqmp_pm_aes_engine(const u64 address, u32 *out)
        return -ENODEV;
 }
 
+static inline int zynqmp_pm_efuse_access(const u64 address, u32 *out)
+{
+       return -ENODEV;
+}
+
 static inline int zynqmp_pm_sha_hash(const u64 address, const u32 size,
                                     const u32 flags)
 {
index abf1442ce71919e0562d0f457e791cd23a1952b1..81caffd51bb49433eb4bd903f5e8b032c2deb63e 100644 (file)
@@ -57,7 +57,8 @@ extern const struct font_desc *find_font(const char *name);
 /* Get the default font for a specific screen size */
 
 extern const struct font_desc *get_default_font(int xres, int yres,
-                                               u32 font_w, u32 font_h);
+                                               unsigned long *font_w,
+                                               unsigned long *font_h);
 
 /* Max. length for the name of a predefined font */
 #define MAX_FONT_NAME  32
index e8921871ef9aaa4ff9a8c74359bf49ebe95d8b3e..54d53f345d14974720f308b9fba1a754b3c6d712 100644 (file)
@@ -1151,7 +1151,9 @@ static inline void unpause_graph_tracing(void) { }
 #ifdef CONFIG_TRACING
 enum ftrace_dump_mode;
 
-extern enum ftrace_dump_mode ftrace_dump_on_oops;
+#define MAX_TRACER_SIZE                100
+extern char ftrace_dump_on_oops[];
+extern int ftrace_dump_on_oops_enabled(void);
 extern int tracepoint_printk;
 
 extern void disable_trace_on_warning(void);
index 2a72f55d26eb89ffde17e0cd9ec345cdf1dcb1c7..0d79070c5a70f21e9d73751941f28cefb244950d 100644 (file)
@@ -9,10 +9,16 @@
 #ifndef _LINUX_FWNODE_H_
 #define _LINUX_FWNODE_H_
 
-#include <linux/types.h>
-#include <linux/list.h>
 #include <linux/bits.h>
 #include <linux/err.h>
+#include <linux/list.h>
+#include <linux/types.h>
+
+enum dev_dma_attr {
+       DEV_DMA_NOT_SUPPORTED,
+       DEV_DMA_NON_COHERENT,
+       DEV_DMA_COHERENT,
+};
 
 struct fwnode_operations;
 struct device;
@@ -53,8 +59,10 @@ struct fwnode_handle {
  * fwnode link flags
  *
  * CYCLE:      The fwnode link is part of a cycle. Don't defer probe.
+ * IGNORE:     Completely ignore this link, even during cycle detection.
  */
 #define FWLINK_FLAG_CYCLE                      BIT(0)
+#define FWLINK_FLAG_IGNORE                     BIT(1)
 
 struct fwnode_link {
        struct fwnode_handle *supplier;
@@ -187,7 +195,6 @@ struct fwnode_operations {
                if (fwnode_has_op(fwnode, op))                          \
                        (fwnode)->ops->op(fwnode, ## __VA_ARGS__);      \
        } while (false)
-#define get_dev_from_fwnode(fwnode)    get_device((fwnode)->dev)
 
 static inline void fwnode_init(struct fwnode_handle *fwnode,
                               const struct fwnode_operations *ops)
@@ -209,9 +216,10 @@ static inline void fwnode_dev_initialized(struct fwnode_handle *fwnode,
                fwnode->flags &= ~FWNODE_FLAG_INITIALIZED;
 }
 
-extern bool fw_devlink_is_strict(void);
-int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup);
+int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,
+                   u8 flags);
 void fwnode_links_purge(struct fwnode_handle *fwnode);
 void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode);
+bool fw_devlink_is_strict(void);
 
 #endif
index 18c0fb958b74022663617698258e5ac29c349836..634c9511cf787bd626671000ce57f810e335fa35 100644 (file)
@@ -104,44 +104,14 @@ void gb_debugfs_init(void);
 void gb_debugfs_cleanup(void);
 struct dentry *gb_debugfs_get(void);
 
-extern struct bus_type greybus_bus_type;
-
-extern struct device_type greybus_hd_type;
-extern struct device_type greybus_module_type;
-extern struct device_type greybus_interface_type;
-extern struct device_type greybus_control_type;
-extern struct device_type greybus_bundle_type;
-extern struct device_type greybus_svc_type;
-
-static inline int is_gb_host_device(const struct device *dev)
-{
-       return dev->type == &greybus_hd_type;
-}
-
-static inline int is_gb_module(const struct device *dev)
-{
-       return dev->type == &greybus_module_type;
-}
-
-static inline int is_gb_interface(const struct device *dev)
-{
-       return dev->type == &greybus_interface_type;
-}
-
-static inline int is_gb_control(const struct device *dev)
-{
-       return dev->type == &greybus_control_type;
-}
-
-static inline int is_gb_bundle(const struct device *dev)
-{
-       return dev->type == &greybus_bundle_type;
-}
-
-static inline int is_gb_svc(const struct device *dev)
-{
-       return dev->type == &greybus_svc_type;
-}
+extern const struct bus_type greybus_bus_type;
+
+extern const struct device_type greybus_hd_type;
+extern const struct device_type greybus_module_type;
+extern const struct device_type greybus_interface_type;
+extern const struct device_type greybus_control_type;
+extern const struct device_type greybus_bundle_type;
+extern const struct device_type greybus_svc_type;
 
 static inline bool cport_id_valid(struct gb_host_device *hd, u16 cport_id)
 {
index aeb8f9243545f10e777fbb05e694de1246b29ab8..820134b0105c2caf8cea3ff0985c92d48d3a2d4c 100644 (file)
@@ -232,9 +232,7 @@ struct gb_fw_download_fetch_firmware_request {
        __le32                  size;
 } __packed;
 
-struct gb_fw_download_fetch_firmware_response {
-       __u8                    data[0];
-} __packed;
+/* gb_fw_download_fetch_firmware_response contains no other data */
 
 /* firmware download release firmware request */
 struct gb_fw_download_release_firmware_request {
@@ -414,9 +412,7 @@ struct gb_bootrom_get_firmware_request {
        __le32                  size;
 } __packed;
 
-struct gb_bootrom_get_firmware_response {
-       __u8                    data[0];
-} __packed;
+/* gb_bootrom_get_firmware_response contains no other data */
 
 /* Bootrom protocol Ready to boot request */
 struct gb_bootrom_ready_to_boot_request {
index 13b1e65fbdccb710ed4fa25ae9f4f8ff2ff298be..6730ee900ee1c9559eabe48bb278ea2ecedb1d5c 100644 (file)
 #define HID_USAGE_SENSOR_ALS                                   0x200041
 #define HID_USAGE_SENSOR_DATA_LIGHT                            0x2004d0
 #define HID_USAGE_SENSOR_LIGHT_ILLUM                           0x2004d1
+#define HID_USAGE_SENSOR_LIGHT_COLOR_TEMPERATURE               0x2004d2
+#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY                    0x2004d3
+#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY_X                  0x2004d4
+#define HID_USAGE_SENSOR_LIGHT_CHROMATICITY_Y                  0x2004d5
 
 /* PROX (200011) */
 #define HID_USAGE_SENSOR_PROX                                   0x200011
diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h
deleted file mode 100644 (file)
index b790499..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Analog Devices Generic AXI ADC IP core driver/library
- * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip
- *
- * Copyright 2012-2020 Analog Devices Inc.
- */
-#ifndef __ADI_AXI_ADC_H__
-#define __ADI_AXI_ADC_H__
-
-struct device;
-struct iio_chan_spec;
-
-/**
- * struct adi_axi_adc_chip_info - Chip specific information
- * @name               Chip name
- * @id                 Chip ID (usually product ID)
- * @channels           Channel specifications of type @struct iio_chan_spec
- * @num_channels       Number of @channels
- * @scale_table                Supported scales by the chip; tuples of 2 ints
- * @num_scales         Number of scales in the table
- * @max_rate           Maximum sampling rate supported by the device
- */
-struct adi_axi_adc_chip_info {
-       const char                      *name;
-       unsigned int                    id;
-
-       const struct iio_chan_spec      *channels;
-       unsigned int                    num_channels;
-
-       const unsigned int              (*scale_table)[2];
-       int                             num_scales;
-
-       unsigned long                   max_rate;
-};
-
-/**
- * struct adi_axi_adc_conv - data of the ADC attached to the AXI ADC
- * @chip_info          chip info details for the client ADC
- * @preenable_setup    op to run in the client before enabling the AXI ADC
- * @reg_access         IIO debugfs_reg_access hook for the client ADC
- * @read_raw           IIO read_raw hook for the client ADC
- * @write_raw          IIO write_raw hook for the client ADC
- * @read_avail         IIO read_avail hook for the client ADC
- */
-struct adi_axi_adc_conv {
-       const struct adi_axi_adc_chip_info              *chip_info;
-
-       int (*preenable_setup)(struct adi_axi_adc_conv *conv);
-       int (*reg_access)(struct adi_axi_adc_conv *conv, unsigned int reg,
-                         unsigned int writeval, unsigned int *readval);
-       int (*read_raw)(struct adi_axi_adc_conv *conv,
-                       struct iio_chan_spec const *chan,
-                       int *val, int *val2, long mask);
-       int (*write_raw)(struct adi_axi_adc_conv *conv,
-                        struct iio_chan_spec const *chan,
-                        int val, int val2, long mask);
-       int (*read_avail)(struct adi_axi_adc_conv *conv,
-                         struct iio_chan_spec const *chan,
-                         const int **val, int *type, int *length, long mask);
-};
-
-struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
-                                                       size_t sizeof_priv);
-
-void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv);
-
-#endif
diff --git a/include/linux/iio/backend.h b/include/linux/iio/backend.h
new file mode 100644 (file)
index 0000000..a6d7938
--- /dev/null
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _IIO_BACKEND_H_
+#define _IIO_BACKEND_H_
+
+#include <linux/types.h>
+
+struct fwnode_handle;
+struct iio_backend;
+struct device;
+struct iio_dev;
+
+enum iio_backend_data_type {
+       IIO_BACKEND_TWOS_COMPLEMENT,
+       IIO_BACKEND_OFFSET_BINARY,
+       IIO_BACKEND_DATA_TYPE_MAX
+};
+
+/**
+ * struct iio_backend_data_fmt - Backend data format
+ * @type:              Data type.
+ * @sign_extend:       Bool to tell if the data is sign extended.
+ * @enable:            Enable/Disable the data format module. If disabled,
+ *                     not formatting will happen.
+ */
+struct iio_backend_data_fmt {
+       enum iio_backend_data_type type;
+       bool sign_extend;
+       bool enable;
+};
+
+/**
+ * struct iio_backend_ops - operations structure for an iio_backend
+ * @enable:            Enable backend.
+ * @disable:           Disable backend.
+ * @chan_enable:       Enable one channel.
+ * @chan_disable:      Disable one channel.
+ * @data_format_set:   Configure the data format for a specific channel.
+ * @request_buffer:    Request an IIO buffer.
+ * @free_buffer:       Free an IIO buffer.
+ **/
+struct iio_backend_ops {
+       int (*enable)(struct iio_backend *back);
+       void (*disable)(struct iio_backend *back);
+       int (*chan_enable)(struct iio_backend *back, unsigned int chan);
+       int (*chan_disable)(struct iio_backend *back, unsigned int chan);
+       int (*data_format_set)(struct iio_backend *back, unsigned int chan,
+                              const struct iio_backend_data_fmt *data);
+       struct iio_buffer *(*request_buffer)(struct iio_backend *back,
+                                            struct iio_dev *indio_dev);
+       void (*free_buffer)(struct iio_backend *back,
+                           struct iio_buffer *buffer);
+};
+
+int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan);
+int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan);
+int devm_iio_backend_enable(struct device *dev, struct iio_backend *back);
+int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan,
+                               const struct iio_backend_data_fmt *data);
+int devm_iio_backend_request_buffer(struct device *dev,
+                                   struct iio_backend *back,
+                                   struct iio_dev *indio_dev);
+
+void *iio_backend_get_priv(const struct iio_backend *conv);
+struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name);
+struct iio_backend *
+__devm_iio_backend_get_from_fwnode_lookup(struct device *dev,
+                                         struct fwnode_handle *fwnode);
+
+int devm_iio_backend_register(struct device *dev,
+                             const struct iio_backend_ops *ops, void *priv);
+
+#endif
index 5c355be8981493bce03fdaa5a16b0cae080dc0e9..cbb8ba957fade348855f1deebf8527eaabf447af 100644 (file)
@@ -10,6 +10,9 @@
 struct iio_dev;
 struct device;
 
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+                                             const char *channel);
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer);
 int devm_iio_dmaengine_buffer_setup(struct device *dev,
                                    struct iio_dev *indio_dev,
                                    const char *channel);
index c5b36d2c1e7359891a90d89b9b1680c736b263e1..e370a7bb3300b770f614696c55e2225f8b3e8464 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/device.h>
 #include <linux/cdev.h>
+#include <linux/cleanup.h>
 #include <linux/slab.h>
 #include <linux/iio/types.h>
 /* IIO TODO LIST */
@@ -638,10 +639,37 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev,
 int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
 int iio_device_claim_direct_mode(struct iio_dev *indio_dev);
 void iio_device_release_direct_mode(struct iio_dev *indio_dev);
+
+/*
+ * This autocleanup logic is normally used via
+ * iio_device_claim_direct_scoped().
+ */
+DEFINE_GUARD(iio_claim_direct, struct iio_dev *, iio_device_claim_direct_mode(_T),
+            iio_device_release_direct_mode(_T))
+
+DEFINE_GUARD_COND(iio_claim_direct, _try, ({
+                       struct iio_dev *dev;
+                       int d = iio_device_claim_direct_mode(_T);
+
+                       if (d < 0)
+                               dev = NULL;
+                       else
+                               dev = _T;
+                       dev;
+               }))
+
+/**
+ * iio_device_claim_direct_scoped() - Scoped call to iio_device_claim_direct.
+ * @fail: What to do on failure to claim device.
+ * @iio_dev: Pointer to the IIO devices structure
+ */
+#define iio_device_claim_direct_scoped(fail, iio_dev) \
+       scoped_cond_guard(iio_claim_direct_try, fail, iio_dev)
+
 int iio_device_claim_buffer_mode(struct iio_dev *indio_dev);
 void iio_device_release_buffer_mode(struct iio_dev *indio_dev);
 
-extern struct bus_type iio_bus_type;
+extern const struct bus_type iio_bus_type;
 
 /**
  * iio_device_put() - reference counted deallocation of struct device
index 7ba183f221f1828f35cd90a6c09310f6bfb62409..f5aef8784692102d41f84132ba3f7bf9353c14c8 100644 (file)
@@ -36,7 +36,7 @@ struct icc_onecell_data {
        struct icc_node *nodes[] __counted_by(num_nodes);
 };
 
-struct icc_node *of_icc_xlate_onecell(struct of_phandle_args *spec,
+struct icc_node *of_icc_xlate_onecell(const struct of_phandle_args *spec,
                                      void *data);
 
 /**
@@ -65,8 +65,9 @@ struct icc_provider {
                         u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
        void (*pre_aggregate)(struct icc_node *node);
        int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak);
-       struct icc_node* (*xlate)(struct of_phandle_args *spec, void *data);
-       struct icc_node_data* (*xlate_extended)(struct of_phandle_args *spec, void *data);
+       struct icc_node* (*xlate)(const struct of_phandle_args *spec, void *data);
+       struct icc_node_data* (*xlate_extended)(const struct of_phandle_args *spec,
+                                               void *data);
        struct device           *dev;
        int                     users;
        bool                    inter_set;
@@ -124,7 +125,7 @@ int icc_nodes_remove(struct icc_provider *provider);
 void icc_provider_init(struct icc_provider *provider);
 int icc_provider_register(struct icc_provider *provider);
 void icc_provider_deregister(struct icc_provider *provider);
-struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec);
+struct icc_node_data *of_icc_get_from_provider(const struct of_phandle_args *spec);
 void icc_sync_state(struct device *dev);
 
 #else
@@ -171,7 +172,7 @@ static inline int icc_provider_register(struct icc_provider *provider)
 
 static inline void icc_provider_deregister(struct icc_provider *provider) { }
 
-static inline struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec)
+static inline struct icc_node_data *of_icc_get_from_provider(const struct of_phandle_args *spec)
 {
        return ERR_PTR(-ENOTSUPP);
 }
index d718fbec72dd661f920171b4beed68f7c319ae60..be2e8c0a187e4b26a704ee5e628b7afe404d9211 100644 (file)
@@ -215,6 +215,7 @@ enum ftrace_dump_mode {
        DUMP_NONE,
        DUMP_ALL,
        DUMP_ORIG,
+       DUMP_PARAM,
 };
 
 #ifdef CONFIG_TRACING
index 99aaa050ccb767954ebcbb0fc47dd522987582e5..87c79d076d6d7396c6da4efc5873a49a5feac873 100644 (file)
@@ -206,23 +206,25 @@ struct kernfs_node {
 
        const void              *ns;    /* namespace tag */
        unsigned int            hash;   /* ns + name hash */
+       unsigned short          flags;
+       umode_t                 mode;
+
        union {
                struct kernfs_elem_dir          dir;
                struct kernfs_elem_symlink      symlink;
                struct kernfs_elem_attr         attr;
        };
 
-       void                    *priv;
-
        /*
         * 64bit unique ID.  On 64bit ino setups, id is the ino.  On 32bit,
         * the low 32bits are ino and upper generation.
         */
        u64                     id;
 
-       unsigned short          flags;
-       umode_t                 mode;
+       void                    *priv;
        struct kernfs_iattrs    *iattr;
+
+       struct rcu_head         rcu;
 };
 
 /*
index c30affcc43b444cc17cb894b83b17b52e41f8ebc..c8219505a79f98bc370e52997efc8af51833cfda 100644 (file)
@@ -38,7 +38,7 @@ extern char uevent_helper[];
 #endif
 
 /* counter to tag the uevent, read only except for the kobject core */
-extern u64 uevent_seqnum;
+extern atomic64_t uevent_seqnum;
 
 /*
  * The actions here must match the index to the string array
index d0f9b522f328bf5a4a846fd46be84a4705ab5657..77b8c0a26674fd05b3796a08ff20562d3a307323 100644 (file)
@@ -320,12 +320,7 @@ struct mhi_controller_config {
  * @hw_ev_rings: Number of hardware event rings
  * @sw_ev_rings: Number of software event rings
  * @nr_irqs: Number of IRQ allocated by bus master (required)
- * @family_number: MHI controller family number
- * @device_number: MHI controller device number
- * @major_version: MHI controller major revision number
- * @minor_version: MHI controller minor revision number
  * @serial_number: MHI controller serial number obtained from BHI
- * @oem_pk_hash: MHI controller OEM PK Hash obtained from BHI
  * @mhi_event: MHI event ring configurations table
  * @mhi_cmd: MHI command ring configurations table
  * @mhi_ctxt: MHI device context, shared memory between host and device
@@ -369,15 +364,6 @@ struct mhi_controller_config {
  * Fields marked as (required) need to be populated by the controller driver
  * before calling mhi_register_controller(). For the fields marked as (optional)
  * they can be populated depending on the usecase.
- *
- * The following fields are present for the purpose of implementing any device
- * specific quirks or customizations for specific MHI revisions used in device
- * by the controller drivers. The MHI stack will just populate these fields
- * during mhi_register_controller():
- *  family_number
- *  device_number
- *  major_version
- *  minor_version
  */
 struct mhi_controller {
        struct device *cntrl_dev;
@@ -408,12 +394,7 @@ struct mhi_controller {
        u32 hw_ev_rings;
        u32 sw_ev_rings;
        u32 nr_irqs;
-       u32 family_number;
-       u32 device_number;
-       u32 major_version;
-       u32 minor_version;
        u32 serial_number;
-       u32 oem_pk_hash[MHI_MAX_OEM_PK_HASH_SEGMENTS];
 
        struct mhi_event *mhi_event;
        struct mhi_cmd *mhi_cmd;
index 2c0910bc3e4a2cacca59a9af5b74cf8a114dab03..0436b919f1c7fc535b30400bf95affc7e4534186 100644 (file)
@@ -87,7 +87,7 @@ extern int sysctl_legacy_va_layout;
 
 #ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS
 extern const int mmap_rnd_bits_min;
-extern const int mmap_rnd_bits_max;
+extern int mmap_rnd_bits_max __ro_after_init;
 extern int mmap_rnd_bits __read_mostly;
 #endif
 #ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
index a529347fd75b2a065f618d45771b27a7bd163f80..562f92504f2b7c9aa271eada506c7d91baf4a243 100644 (file)
@@ -192,6 +192,7 @@ struct ubi_device_info {
  *                     or a volume was removed)
  * @UBI_VOLUME_RESIZED: a volume has been re-sized
  * @UBI_VOLUME_RENAMED: a volume has been re-named
+ * @UBI_VOLUME_SHUTDOWN: a volume is going to removed, shutdown users
  * @UBI_VOLUME_UPDATED: data has been written to a volume
  *
  * These constants define which type of event has happened when a volume
@@ -202,6 +203,7 @@ enum {
        UBI_VOLUME_REMOVED,
        UBI_VOLUME_RESIZED,
        UBI_VOLUME_RENAMED,
+       UBI_VOLUME_SHUTDOWN,
        UBI_VOLUME_UPDATED,
 };
 
index c6f6ac779b34ef1a8f98853c84a7a2e0192e0e8f..cb37817d6382c29117afd8ce54db6dba94f8c930 100644 (file)
@@ -2072,6 +2072,7 @@ struct net_device {
                struct pcpu_sw_netstats __percpu        *tstats;
                struct pcpu_dstats __percpu             *dstats;
        };
+       unsigned long           state;
        unsigned int            flags;
        unsigned short          hard_header_len;
        netdev_features_t       features;
@@ -2117,7 +2118,6 @@ struct net_device {
         *      part of the usual set specified in Space.c.
         */
 
-       unsigned long           state;
 
        struct list_head        dev_list;
        struct list_head        napi_list;
index df702b2c2ae3a61f465331c073118d3779b89250..a0bedd038a059b1d8a32644b09b6a73f04eea2d2 100644 (file)
@@ -1083,6 +1083,22 @@ static inline int of_parse_phandle_with_optional_args(const struct device_node *
                                            0, index, out_args);
 }
 
+/**
+ * of_phandle_args_equal() - Compare two of_phandle_args
+ * @a1:                First of_phandle_args to compare
+ * @a2:                Second of_phandle_args to compare
+ *
+ * Return: True if a1 and a2 are the same (same node pointer, same phandle
+ * args), false otherwise.
+ */
+static inline bool of_phandle_args_equal(const struct of_phandle_args *a1,
+                                        const struct of_phandle_args *a2)
+{
+       return a1->np == a2->np &&
+              a1->args_count == a2->args_count &&
+              !memcmp(a1->args, a2->args, sizeof(a1->args[0]) * a1->args_count);
+}
+
 /**
  * of_property_count_u8_elems - Count the number of u8 elements in a property
  *
index aa691f2119b0bbc8c3be7739c857f2f89775d784..0c7e3dcfe8670cb95f371a6f7d41bb8b63b1786c 100644 (file)
@@ -398,7 +398,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
  * @count: Number of elements in the array; must be compile-time const.
  * @initializer: initializer expression (could be empty for no init).
  */
-#define _DEFINE_FLEX(type, name, member, count, initializer)                   \
+#define _DEFINE_FLEX(type, name, member, count, initializer...)                        \
        _Static_assert(__builtin_constant_p(count),                             \
                       "onstack flex array members require compile-time const count"); \
        union {                                                                 \
@@ -408,8 +408,8 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
        type *name = (type *)&name##_u
 
 /**
- * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing
- * flexible array member.
+ * DEFINE_RAW_FLEX() - Define an on-stack instance of structure with a trailing
+ * flexible array member, when it does not have a __counted_by annotation.
  *
  * @type: structure type name, including "struct" keyword.
  * @name: Name for a variable to define.
@@ -420,7 +420,24 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
  * flexible array member.
  * Use __struct_size(@name) to get compile-time size of it afterwards.
  */
-#define DEFINE_FLEX(type, name, member, count)                 \
+#define DEFINE_RAW_FLEX(type, name, member, count)     \
        _DEFINE_FLEX(type, name, member, count, = {})
 
+/**
+ * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing
+ * flexible array member.
+ *
+ * @TYPE: structure type name, including "struct" keyword.
+ * @NAME: Name for a variable to define.
+ * @MEMBER: Name of the array member.
+ * @COUNTER: Name of the __counted_by member.
+ * @COUNT: Number of elements in the array; must be compile-time const.
+ *
+ * Define a zeroed, on-stack, instance of @TYPE structure with a trailing
+ * flexible array member.
+ * Use __struct_size(@NAME) to get compile-time size of it afterwards.
+ */
+#define DEFINE_FLEX(TYPE, NAME, MEMBER, COUNTER, COUNT)        \
+       _DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .obj.COUNTER = COUNT, })
+
 #endif /* __LINUX_OVERFLOW_H */
index 58be86e6fe83ba2a0357d62e00af502b88432b9e..03cd5bae92d3f189d739c453fe4c160dd2a5063e 100644 (file)
@@ -122,6 +122,11 @@ struct phy_ops {
                            union phy_configure_opts *opts);
        int     (*reset)(struct phy *phy);
        int     (*calibrate)(struct phy *phy);
+
+       /* notify phy connect status change */
+       int     (*connect)(struct phy *phy, int port);
+       int     (*disconnect)(struct phy *phy, int port);
+
        void    (*release)(struct phy *phy);
        struct module *owner;
 };
@@ -243,6 +248,8 @@ static inline enum phy_mode phy_get_mode(struct phy *phy)
 }
 int phy_reset(struct phy *phy);
 int phy_calibrate(struct phy *phy);
+int phy_notify_connect(struct phy *phy, int port);
+int phy_notify_disconnect(struct phy *phy, int port);
 static inline int phy_get_bus_width(struct phy *phy)
 {
        return phy->attrs.bus_width;
@@ -396,6 +403,20 @@ static inline int phy_calibrate(struct phy *phy)
        return -ENOSYS;
 }
 
+static inline int phy_notify_connect(struct phy *phy, int index)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
+static inline int phy_notify_disconnect(struct phy *phy, int index)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
 static inline int phy_configure(struct phy *phy,
                                union phy_configure_opts *opts)
 {
index 70998e6dd6fdc9ea5665d8e01615709b042d6b69..6ca51e0080ec092eeadfda3d55f1ef551f1f7262 100644 (file)
@@ -26,6 +26,7 @@ void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy);
 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);
+int tegra_xusb_padctl_get_port_number(struct phy *phy);
 int tegra_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy,
                                           enum usb_device_speed speed);
 int tegra_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl, struct phy *phy);
index e6516d0b7d52ad0570eb345955701be5856455c0..3a1045eb786c4cf30d8d0bda8845a2ef2993a14b 100644 (file)
@@ -11,6 +11,7 @@
 #define _LINUX_PROPERTY_H_
 
 #include <linux/args.h>
+#include <linux/array_size.h>
 #include <linux/bits.h>
 #include <linux/fwnode.h>
 #include <linux/stddef.h>
@@ -27,12 +28,6 @@ enum dev_prop_type {
        DEV_PROP_REF,
 };
 
-enum dev_dma_attr {
-       DEV_DMA_NOT_SUPPORTED,
-       DEV_DMA_NON_COHERENT,
-       DEV_DMA_COHERENT,
-};
-
 const struct fwnode_handle *__dev_fwnode_const(const struct device *dev);
 struct fwnode_handle *__dev_fwnode(struct device *dev);
 #define dev_fwnode(dev)                                                        \
@@ -156,11 +151,9 @@ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);
        for (parent = fwnode_get_parent(fwnode); parent;        \
             parent = fwnode_get_next_parent(parent))
 
-struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode);
 unsigned int fwnode_count_parents(const struct fwnode_handle *fwn);
 struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn,
                                            unsigned int depth);
-bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor, const struct fwnode_handle *child);
 struct fwnode_handle *fwnode_get_next_child_node(
        const struct fwnode_handle *fwnode, struct fwnode_handle *child);
 struct fwnode_handle *fwnode_get_next_available_child_node(
index 16f519914415ebf5592e75be67e8660339d6b0e7..17d7ed5f3ae6e5c612acd4261be763855069946d 100644 (file)
@@ -247,6 +247,37 @@ do { \
        cond_resched(); \
 } while (0)
 
+/**
+ * rcu_softirq_qs_periodic - Report RCU and RCU-Tasks quiescent states
+ * @old_ts: jiffies at start of processing.
+ *
+ * This helper is for long-running softirq handlers, such as NAPI threads in
+ * networking. The caller should initialize the variable passed in as @old_ts
+ * at the beginning of the softirq handler. When invoked frequently, this macro
+ * will invoke rcu_softirq_qs() every 100 milliseconds thereafter, which will
+ * provide both RCU and RCU-Tasks quiescent states. Note that this macro
+ * modifies its old_ts argument.
+ *
+ * Because regions of code that have disabled softirq act as RCU read-side
+ * critical sections, this macro should be invoked with softirq (and
+ * preemption) enabled.
+ *
+ * The macro is not needed when CONFIG_PREEMPT_RT is defined. RT kernels would
+ * have more chance to invoke schedule() calls and provide necessary quiescent
+ * states. As a contrast, calling cond_resched() only won't achieve the same
+ * effect because cond_resched() does not provide RCU-Tasks quiescent states.
+ */
+#define rcu_softirq_qs_periodic(old_ts) \
+do { \
+       if (!IS_ENABLED(CONFIG_PREEMPT_RT) && \
+           time_after(jiffies, (old_ts) + HZ / 10)) { \
+               preempt_disable(); \
+               rcu_softirq_qs(); \
+               preempt_enable(); \
+               (old_ts) = jiffies; \
+       } \
+} while (0)
+
 /*
  * Infrastructure to implement the synchronize_() primitives in
  * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
index 0fa4f60e11862d088d35eed5f6e0e79f3be1c9c1..357df16ede328657478eceb1ba6065f42a210ea2 100644 (file)
@@ -60,6 +60,9 @@ struct reset_control_lookup {
  * @reset_control_head: head of internal list of requested reset controls
  * @dev: corresponding driver model device struct
  * @of_node: corresponding device tree node as phandle target
+ * @of_args: for reset-gpios controllers: corresponding phandle args with
+ *           of_node and GPIO number complementing of_node; either this or
+ *           of_node should be present
  * @of_reset_n_cells: number of cells in reset line specifiers
  * @of_xlate: translation function to translate from specifier as found in the
  *            device tree to id as given to the reset control ops, defaults
@@ -73,6 +76,7 @@ struct reset_controller_dev {
        struct list_head reset_control_head;
        struct device *dev;
        struct device_node *of_node;
+       const struct of_phandle_args *of_args;
        int of_reset_n_cells;
        int (*of_xlate)(struct reset_controller_dev *rcdev,
                        const struct of_phandle_args *reset_spec);
index 5f8e438a0312bd579d6d78b159c796c5394649bc..3f4d315aaec9e641e35c1c86a522f2879bec19ba 100644 (file)
@@ -42,7 +42,7 @@ static inline time64_t rtc_tm_sub(struct rtc_time *lhs, struct rtc_time *rhs)
 #include <linux/timerqueue.h>
 #include <linux/workqueue.h>
 
-extern struct class *rtc_class;
+extern const struct class rtc_class;
 
 /*
  * For these RTC methods the device parameter is the physical device
index 170ef28ff26b99e742e5b8209dc4d025ddcbb947..bab7d30d34462ac7305720380f46a7391756fc1d 100644 (file)
 struct tty_struct;
 struct vc_data;
 
-extern void clear_selection(void);
-extern int set_selection_user(const struct tiocl_selection __user *sel,
-                             struct tty_struct *tty);
-extern int set_selection_kernel(struct tiocl_selection *v,
-                               struct tty_struct *tty);
-extern int paste_selection(struct tty_struct *tty);
-extern int sel_loadlut(char __user *p);
-extern int mouse_reporting(void);
-extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
-
-bool vc_is_sel(struct vc_data *vc);
+void clear_selection(void);
+int set_selection_user(const struct tiocl_selection __user *sel,
+                      struct tty_struct *tty);
+int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty);
+int paste_selection(struct tty_struct *tty);
+int sel_loadlut(u32 __user *lut);
+int mouse_reporting(void);
+void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry);
+
+bool vc_is_sel(const struct vc_data *vc);
 
 extern int console_blanked;
 
@@ -33,24 +32,21 @@ extern unsigned char default_red[];
 extern unsigned char default_grn[];
 extern unsigned char default_blu[];
 
-extern unsigned short *screen_pos(const struct vc_data *vc, int w_offset,
-               bool viewed);
-extern u16 screen_glyph(const struct vc_data *vc, int offset);
-extern u32 screen_glyph_unicode(const struct vc_data *vc, int offset);
-extern void complement_pos(struct vc_data *vc, int offset);
-extern void invert_screen(struct vc_data *vc, int offset, int count, bool viewed);
-
-extern void getconsxy(const struct vc_data *vc, unsigned char xy[static 2]);
-extern void putconsxy(struct vc_data *vc, unsigned char xy[static const 2]);
-
-extern u16 vcs_scr_readw(const struct vc_data *vc, const u16 *org);
-extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org);
-extern void vcs_scr_updated(struct vc_data *vc);
-
-extern int vc_uniscr_check(struct vc_data *vc);
-extern void vc_uniscr_copy_line(const struct vc_data *vc, void *dest,
-                               bool viewed,
-                               unsigned int row, unsigned int col,
-                               unsigned int nr);
+unsigned short *screen_pos(const struct vc_data *vc, int w_offset, bool viewed);
+u16 screen_glyph(const struct vc_data *vc, int offset);
+u32 screen_glyph_unicode(const struct vc_data *vc, int offset);
+void complement_pos(struct vc_data *vc, int offset);
+void invert_screen(struct vc_data *vc, int offset, int count, bool viewed);
+
+void getconsxy(const struct vc_data *vc, unsigned char xy[static 2]);
+void putconsxy(struct vc_data *vc, unsigned char xy[static const 2]);
+
+u16 vcs_scr_readw(const struct vc_data *vc, const u16 *org);
+void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org);
+void vcs_scr_updated(struct vc_data *vc);
+
+int vc_uniscr_check(struct vc_data *vc);
+void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
+                        unsigned int row, unsigned int col, unsigned int nr);
 
 #endif
index 3fab88ba265ee1d44ce48d9efe0ddc31d5c8e934..ff78efc1f60df4341fc8f9d82ac5e8bd6f6910c1 100644 (file)
@@ -27,7 +27,7 @@ struct serdev_device;
  *                     not sleep.
  */
 struct serdev_device_ops {
-       ssize_t (*receive_buf)(struct serdev_device *, const u8 *, size_t);
+       size_t (*receive_buf)(struct serdev_device *, const u8 *, size_t);
        void (*write_wakeup)(struct serdev_device *);
 };
 
@@ -185,9 +185,9 @@ static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl
        serdev->ops->write_wakeup(serdev);
 }
 
-static inline ssize_t serdev_controller_receive_buf(struct serdev_controller *ctrl,
-                                                   const u8 *data,
-                                                   size_t count)
+static inline size_t serdev_controller_receive_buf(struct serdev_controller *ctrl,
+                                                  const u8 *data,
+                                                  size_t count)
 {
        struct serdev_device *serdev = ctrl->serdev;
 
index be65de65fe612007932c76b71c4b48d2dbd006d8..fd59ed2cca53e967af17fa23c13740d67b6733e7 100644 (file)
@@ -210,6 +210,12 @@ int serial8250_console_exit(struct uart_port *port);
 void serial8250_set_isa_configurator(void (*v)(int port, struct uart_port *up,
                                               u32 *capabilities));
 
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+extern int hp300_setup_serial_console(void) __init;
+#else
+static inline int hp300_setup_serial_console(void) { return 0; }
+#endif
+
 #ifdef CONFIG_SERIAL_8250_RT288X
 int rt288x_setup(struct uart_port *p);
 int au_platform_setup(struct plat_serial8250_port *p);
index 55b1f3ba48ac1725f110747b8d05ce6bbfc1de0b..0a0f6e21d40ec130e458523947c2caaaf28528cd 100644 (file)
@@ -467,9 +467,10 @@ struct uart_port {
        unsigned int            fifosize;               /* tx fifo size */
        unsigned char           x_char;                 /* xon/xoff char */
        unsigned char           regshift;               /* reg offset shift */
+
        unsigned char           iotype;                 /* io access style */
-       unsigned char           quirks;                 /* internal quirks */
 
+#define UPIO_UNKNOWN           ((unsigned char)~0U)    /* UCHAR_MAX */
 #define UPIO_PORT              (SERIAL_IO_PORT)        /* 8b I/O port access */
 #define UPIO_HUB6              (SERIAL_IO_HUB6)        /* Hub6 ISA card */
 #define UPIO_MEM               (SERIAL_IO_MEM)         /* driver-specific */
@@ -479,7 +480,9 @@ struct uart_port {
 #define UPIO_MEM32BE           (SERIAL_IO_MEM32BE)     /* 32b big endian */
 #define UPIO_MEM16             (SERIAL_IO_MEM16)       /* 16b little endian */
 
-       /* quirks must be updated while holding port mutex */
+       unsigned char           quirks;                 /* internal quirks */
+
+       /* internal quirks must be updated while holding port mutex */
 #define UPQ_NO_TXEN_TEST       BIT(0)
 
        unsigned int            read_status_mask;       /* driver specific */
@@ -786,7 +789,8 @@ enum UART_TX_FLAGS {
        if (pending < WAKEUP_CHARS) {                                         \
                uart_write_wakeup(__port);                                    \
                                                                              \
-               if (!((flags) & UART_TX_NOSTOP) && pending == 0)              \
+               if (!((flags) & UART_TX_NOSTOP) && pending == 0 &&            \
+                   __port->ops->tx_empty(__port))                            \
                        __port->ops->stop_tx(__port);                         \
        }                                                                     \
                                                                              \
@@ -959,6 +963,8 @@ int uart_register_driver(struct uart_driver *uart);
 void uart_unregister_driver(struct uart_driver *uart);
 int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
 void uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
+int uart_read_port_properties(struct uart_port *port);
+int uart_read_and_validate_port_properties(struct uart_port *port);
 bool uart_match_port(const struct uart_port *port1,
                const struct uart_port *port2);
 
index 3023bc2be6a1c126bdbba2a0bc9b1f11d4131735..0c7c67b3a87b2351a3a65408c6d00b6eadf583bb 100644 (file)
@@ -822,9 +822,9 @@ typedef unsigned char *sk_buff_data_t;
  *     @decrypted: Decrypted SKB
  *     @slow_gro: state present at GRO time, slower prepare step required
  *     @mono_delivery_time: When set, skb->tstamp has the
- *             delivery_time in mono clock base (i.e., EDT) or a clock base chosen
- *             by SO_TXTIME. If zero, skb->tstamp has the (rcv) timestamp at
- *             ingress.
+ *             delivery_time in mono clock base (i.e. EDT).  Otherwise, the
+ *             skb->tstamp has the (rcv) timestamp at ingress and
+ *             delivery_time at egress.
  *     @napi_id: id of the NAPI struct this skb came from
  *     @sender_cpu: (aka @napi_id) source CPU in XPS
  *     @alloc_cpu: CPU which did the skb allocation.
@@ -3523,6 +3523,16 @@ int skb_cow_data_for_xdp(struct page_pool *pool, struct sk_buff **pskb,
                         struct bpf_prog *prog);
 bool napi_pp_put_page(struct page *page, bool napi_safe);
 
+static inline void
+skb_page_unref(const struct sk_buff *skb, struct page *page, bool napi_safe)
+{
+#ifdef CONFIG_PAGE_POOL
+       if (skb->pp_recycle && napi_pp_put_page(page, napi_safe))
+               return;
+#endif
+       put_page(page);
+}
+
 static inline void
 napi_frag_unref(skb_frag_t *frag, bool recycle, bool napi_safe)
 {
index 12c9719b2a554e67a5abe11105e4e7867b3501f1..3042385b7b40333fd0df12dbbfc55933b0d910f2 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/completion.h>
 #include <linux/mod_devicetable.h>
 
-extern struct bus_type slimbus_bus;
+extern const struct bus_type slimbus_bus;
 
 /**
  * struct slim_eaddr - Enumeration address for a SLIMbus device
index 29e06905bc1f0e4509315656d878ecbb48629aca..0f038a1a033099bfeaf094fd3742f59a63a3f076 100644 (file)
@@ -178,6 +178,7 @@ struct geni_se {
 #define M_GP_IRQ_3_EN                  BIT(12)
 #define M_GP_IRQ_4_EN                  BIT(13)
 #define M_GP_IRQ_5_EN                  BIT(14)
+#define M_TX_FIFO_NOT_EMPTY_EN         BIT(21)
 #define M_IO_DATA_DEASSERT_EN          BIT(22)
 #define M_IO_DATA_ASSERT_EN            BIT(23)
 #define M_RX_FIFO_RD_ERR_EN            BIT(24)
index cfcb7e2c3813f2dbd3fd5ca9d123a6883713d672..139c330ccf2c3bf995a0c05db14db4f286f7eab6 100644 (file)
@@ -422,13 +422,6 @@ extern long __sys_recvmsg_sock(struct socket *sock, struct msghdr *msg,
                               struct user_msghdr __user *umsg,
                               struct sockaddr __user *uaddr,
                               unsigned int flags);
-extern int sendmsg_copy_msghdr(struct msghdr *msg,
-                              struct user_msghdr __user *umsg, unsigned flags,
-                              struct iovec **iov);
-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(struct msghdr *kmsg,
                         struct user_msghdr *umsg,
                         struct sockaddr __user **save_addr);
index 013da4b8b3272c6aff56a84cc40ce8d8a5d17041..67bb9794b87585c5d4584205879fbcb469fa0469 100644 (file)
@@ -17,5 +17,19 @@ static inline void sync_core_before_usermode(void)
 }
 #endif
 
-#endif /* _LINUX_SYNC_CORE_H */
+#ifdef CONFIG_ARCH_HAS_PREPARE_SYNC_CORE_CMD
+#include <asm/sync_core.h>
+#else
+/*
+ * This is a dummy prepare_sync_core_cmd() implementation that can be used on
+ * all architectures which provide unconditional core serializing instructions
+ * in switch_mm().
+ * If your architecture doesn't provide such core serializing instructions in
+ * switch_mm(), you may need to write your own functions.
+ */
+static inline void prepare_sync_core_cmd(struct mm_struct *mm)
+{
+}
+#endif
 
+#endif /* _LINUX_SYNC_CORE_H */
index b717a70219f65186907c036f2e8b7e38e8e3083e..326341c623857e2afbb9b0c20a5f9b9ae4a54293 100644 (file)
@@ -61,22 +61,32 @@ do {                                                        \
 /**
  * struct attribute_group - data structure used to declare an attribute group.
  * @name:      Optional: Attribute group name
- *             If specified, the attribute group will be created in
- *             a new subdirectory with this name.
+ *             If specified, the attribute group will be created in a
+ *             new subdirectory with this name. Additionally when a
+ *             group is named, @is_visible and @is_bin_visible may
+ *             return SYSFS_GROUP_INVISIBLE to control visibility of
+ *             the directory itself.
  * @is_visible:        Optional: Function to return permissions associated with an
- *             attribute of the group. Will be called repeatedly for each
- *             non-binary attribute in the group. Only read/write
+ *             attribute of the group. Will be called repeatedly for
+ *             each non-binary attribute in the group. Only read/write
  *             permissions as well as SYSFS_PREALLOC are accepted. Must
- *             return 0 if an attribute is not visible. The returned value
- *             will replace static permissions defined in struct attribute.
+ *             return 0 if an attribute is not visible. The returned
+ *             value will replace static permissions defined in struct
+ *             attribute. Use SYSFS_GROUP_VISIBLE() when assigning this
+ *             callback to specify separate _group_visible() and
+ *             _attr_visible() handlers.
  * @is_bin_visible:
  *             Optional: Function to return permissions associated with a
  *             binary attribute of the group. Will be called repeatedly
  *             for each binary attribute in the group. Only read/write
- *             permissions as well as SYSFS_PREALLOC are accepted. Must
- *             return 0 if a binary attribute is not visible. The returned
- *             value will replace static permissions defined in
- *             struct bin_attribute.
+ *             permissions as well as SYSFS_PREALLOC (and the
+ *             visibility flags for named groups) are accepted. Must
+ *             return 0 if a binary attribute is not visible. The
+ *             returned value will replace static permissions defined
+ *             in struct bin_attribute. If @is_visible is not set, Use
+ *             SYSFS_GROUP_VISIBLE() when assigning this callback to
+ *             specify separate _group_visible() and _attr_visible()
+ *             handlers.
  * @attrs:     Pointer to NULL terminated list of attributes.
  * @bin_attrs: Pointer to NULL terminated list of binary attributes.
  *             Either attrs or bin_attrs or both must be provided.
@@ -91,13 +101,121 @@ struct attribute_group {
        struct bin_attribute    **bin_attrs;
 };
 
+#define SYSFS_PREALLOC         010000
+#define SYSFS_GROUP_INVISIBLE  020000
+
+/*
+ * DEFINE_SYSFS_GROUP_VISIBLE(name):
+ *     A helper macro to pair with the assignment of ".is_visible =
+ *     SYSFS_GROUP_VISIBLE(name)", that arranges for the directory
+ *     associated with a named attribute_group to optionally be hidden.
+ *     This allows for static declaration of attribute_groups, and the
+ *     simplification of attribute visibility lifetime that implies,
+ *     without polluting sysfs with empty attribute directories.
+ * Ex.
+ *
+ * static umode_t example_attr_visible(struct kobject *kobj,
+ *                                   struct attribute *attr, int n)
+ * {
+ *       if (example_attr_condition)
+ *               return 0;
+ *       else if (ro_attr_condition)
+ *               return 0444;
+ *       return a->mode;
+ * }
+ *
+ * static bool example_group_visible(struct kobject *kobj)
+ * {
+ *       if (example_group_condition)
+ *               return false;
+ *       return true;
+ * }
+ *
+ * DEFINE_SYSFS_GROUP_VISIBLE(example);
+ *
+ * static struct attribute_group example_group = {
+ *       .name = "example",
+ *       .is_visible = SYSFS_GROUP_VISIBLE(example),
+ *       .attrs = &example_attrs,
+ * };
+ *
+ * Note that it expects <name>_attr_visible and <name>_group_visible to
+ * be defined. For cases where individual attributes do not need
+ * separate visibility consideration, only entire group visibility at
+ * once, see DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE().
+ */
+#define DEFINE_SYSFS_GROUP_VISIBLE(name)                             \
+       static inline umode_t sysfs_group_visible_##name(            \
+               struct kobject *kobj, struct attribute *attr, int n) \
+       {                                                            \
+               if (n == 0 && !name##_group_visible(kobj))           \
+                       return SYSFS_GROUP_INVISIBLE;                \
+               return name##_attr_visible(kobj, attr, n);           \
+       }
+
+/*
+ * DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(name):
+ *     A helper macro to pair with SYSFS_GROUP_VISIBLE() that like
+ *     DEFINE_SYSFS_GROUP_VISIBLE() controls group visibility, but does
+ *     not require the implementation of a per-attribute visibility
+ *     callback.
+ * Ex.
+ *
+ * static bool example_group_visible(struct kobject *kobj)
+ * {
+ *       if (example_group_condition)
+ *               return false;
+ *       return true;
+ * }
+ *
+ * DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(example);
+ *
+ * static struct attribute_group example_group = {
+ *       .name = "example",
+ *       .is_visible = SYSFS_GROUP_VISIBLE(example),
+ *       .attrs = &example_attrs,
+ * };
+ */
+#define DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(name)                   \
+       static inline umode_t sysfs_group_visible_##name(         \
+               struct kobject *kobj, struct attribute *a, int n) \
+       {                                                         \
+               if (n == 0 && !name##_group_visible(kobj))        \
+                       return SYSFS_GROUP_INVISIBLE;             \
+               return a->mode;                                   \
+       }
+
+/*
+ * Same as DEFINE_SYSFS_GROUP_VISIBLE, but for groups with only binary
+ * attributes. If an attribute_group defines both text and binary
+ * attributes, the group visibility is determined by the function
+ * specified to is_visible() not is_bin_visible()
+ */
+#define DEFINE_SYSFS_BIN_GROUP_VISIBLE(name)                             \
+       static inline umode_t sysfs_group_visible_##name(                \
+               struct kobject *kobj, struct bin_attribute *attr, int n) \
+       {                                                                \
+               if (n == 0 && !name##_group_visible(kobj))               \
+                       return SYSFS_GROUP_INVISIBLE;                    \
+               return name##_attr_visible(kobj, attr, n);               \
+       }
+
+#define DEFINE_SIMPLE_SYSFS_BIN_GROUP_VISIBLE(name)                   \
+       static inline umode_t sysfs_group_visible_##name(             \
+               struct kobject *kobj, struct bin_attribute *a, int n) \
+       {                                                             \
+               if (n == 0 && !name##_group_visible(kobj))            \
+                       return SYSFS_GROUP_INVISIBLE;                 \
+               return a->mode;                                       \
+       }
+
+#define SYSFS_GROUP_VISIBLE(fn) sysfs_group_visible_##fn
+
 /*
  * Use these macros to make defining attributes easier.
  * See include/linux/device.h for examples..
  */
 
-#define SYSFS_PREALLOC 010000
-
 #define __ATTR(_name, _mode, _show, _store) {                          \
        .attr = {.name = __stringify(_name),                            \
                 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },             \
index 2c835e5c41f6303da0d86e25619a5dbedc4743d3..4338ea9ac4fd9a62bd25b71ccd448386f682487d 100644 (file)
@@ -87,8 +87,8 @@ struct tb {
 };
 
 extern const struct bus_type tb_bus_type;
-extern struct device_type tb_service_type;
-extern struct device_type tb_xdomain_type;
+extern const struct device_type tb_service_type;
+extern const struct device_type tb_xdomain_type;
 
 #define TB_LINKS_PER_PHY_PORT  2
 
index fc6d0af56bb172c4c5356404b19160568c751d4b..6f9bdfb09d1da5cd0f6dc84635380f4f49156352 100644 (file)
@@ -17,6 +17,9 @@ struct dentry;
 struct bpf_prog;
 union bpf_attr;
 
+/* Used for event string fields when they are NULL */
+#define EVENT_NULL_STR         "(null)"
+
 const char *trace_print_flags_seq(struct trace_seq *p, const char *delim,
                                  unsigned long flags,
                                  const struct trace_print_flags *flag_array);
index 88c0ba623ee6bf5b59cdf0521961ab46c67e2829..689b6d71590e99db90f6bd4da8615b092c1c6cbc 100644 (file)
@@ -199,7 +199,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
                if (!(cond))                                            \
                        return;                                         \
                                                                        \
-               if (WARN_ON_ONCE(RCUIDLE_COND(rcuidle)))                \
+               if (WARN_ONCE(RCUIDLE_COND(rcuidle),                    \
+                             "Bad RCU usage for tracepoint"))          \
                        return;                                         \
                                                                        \
                /* keep srcu and sched-rcu usage consistent */          \
@@ -259,7 +260,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
                                TP_ARGS(args),                          \
                                TP_CONDITION(cond), 0);                 \
                if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) {             \
-                       WARN_ON_ONCE(!rcu_is_watching());               \
+                       WARN_ONCE(!rcu_is_watching(),                   \
+                                 "RCU not watching for tracepoint");   \
                }                                                       \
        }                                                               \
        __DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args),          \
index 8c76fd97d4adcd5cb9189dd0eceb5d33dac47b56..2b2e6f0a54d6e6fc0038ca699b76a8d612eb5a38 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/major.h>
 #include <linux/termios.h>
 #include <linux/workqueue.h>
-#include <linux/tty_buffer.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_ldisc.h>
 #include <linux/tty_port.h>
index 47c5962b876b027e2ea935c4003b37f7a1bfdca3..18238dc8bfd356a20996ba6cd84f1ff508bbb81c 100644 (file)
@@ -28,19 +28,26 @@ struct uio_map;
  *                     logical, virtual, or physical & phys_addr_t
  *                     should always be large enough to handle any of
  *                     the address types)
+ * @dma_addr:          DMA handle set by dma_alloc_coherent, used with
+ *                     UIO_MEM_DMA_COHERENT only (@addr should be the
+ *                     void * returned from the same dma_alloc_coherent call)
  * @offs:               offset of device memory within the page
  * @size:              size of IO (multiple of page size)
  * @memtype:           type of memory addr points to
  * @internal_addr:     ioremap-ped version of addr, for driver internal use
+ * @dma_device:                device struct that was passed to dma_alloc_coherent,
+ *                     used with UIO_MEM_DMA_COHERENT only
  * @map:               for use by the UIO core only.
  */
 struct uio_mem {
        const char              *name;
        phys_addr_t             addr;
+       dma_addr_t              dma_addr;
        unsigned long           offs;
        resource_size_t         size;
        int                     memtype;
        void __iomem            *internal_addr;
+       struct device           *dma_device;
        struct uio_map          *map;
 };
 
@@ -158,6 +165,12 @@ extern int __must_check
 #define UIO_MEM_LOGICAL        2
 #define UIO_MEM_VIRTUAL 3
 #define UIO_MEM_IOVA   4
+/*
+ * UIO_MEM_DMA_COHERENT exists for legacy drivers that had been getting by with
+ * improperly mapping DMA coherent allocations through the other modes.
+ * Do not use in new drivers.
+ */
+#define UIO_MEM_DMA_COHERENT   5
 
 /* defines for uio_port->porttype */
 #define UIO_PORT_NONE  0
index ca796dc1a984f26ee0d71cae724f222f6e49da5b..6e555561001008bc0f1c23124e48dc51b152e8d0 100644 (file)
@@ -82,7 +82,7 @@ struct uac_clock_source_descriptor {
 #define UAC_CLOCK_SOURCE_TYPE_INT_PROG 0x3
 #define UAC_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 2)
 
-/* 4.7.2.2 Clock Source Descriptor */
+/* 4.7.2.2 Clock Selector Descriptor */
 
 struct uac_clock_selector_descriptor {
        __u8 bLength;
@@ -91,7 +91,7 @@ struct uac_clock_selector_descriptor {
        __u8 bClockID;
        __u8 bNrInPins;
        __u8 baCSourceID[];
-       /* bmControls and iClockSource omitted */
+       /* bmControls and iClockSelector omitted */
 } __attribute__((packed));
 
 /* 4.7.2.3 Clock Multiplier Descriptor */
index 6532beb587b1978e09bc5b17dc088daf91f9f88c..56dda8e1562d1f471ee4d91f6ad8b98e660fa79b 100644 (file)
@@ -52,6 +52,7 @@ struct usb_ep;
  * @short_not_ok: When reading data, makes short packets be
  *     treated as errors (queue stops advancing till cleanup).
  * @dma_mapped: Indicates if request has been mapped to DMA (internal)
+ * @sg_was_mapped: Set if the scatterlist has been mapped before the request
  * @complete: Function called when request completes, so this request and
  *     its buffer may be re-used.  The function will always be called with
  *     interrupts disabled, and it must not sleep.
@@ -111,6 +112,7 @@ struct usb_request {
        unsigned                zero:1;
        unsigned                short_not_ok:1;
        unsigned                dma_mapped:1;
+       unsigned                sg_was_mapped:1;
 
        void                    (*complete)(struct usb_ep *ep,
                                        struct usb_request *req);
index 98487fd7ab1164135ab088fd54036f3cc39dba59..de42f14bd28003d8f2b9f918bf64e19a556123d4 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __LINUX_USB_OF_H
 #define __LINUX_USB_OF_H
 
+#include <linux/usb.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/phy.h>
@@ -17,6 +18,7 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0);
 bool of_usb_host_tpl_support(struct device_node *np);
 int of_usb_update_otg_caps(struct device_node *np,
                        struct usb_otg_caps *otg_caps);
+enum usb_port_connect_type usb_of_get_connect_type(struct usb_device *hub, int port1);
 struct device_node *usb_of_get_device_node(struct usb_device *hub, int port1);
 bool usb_of_has_combined_node(struct usb_device *udev);
 struct device_node *usb_of_get_interface_node(struct usb_device *udev,
@@ -37,6 +39,11 @@ static inline int of_usb_update_otg_caps(struct device_node *np,
 {
        return 0;
 }
+static inline enum usb_port_connect_type
+usb_of_get_connect_type(const struct usb_device *hub, int port1)
+{
+       return USB_PORT_CONNECT_TYPE_UNKNOWN;
+}
 static inline struct device_node *
 usb_of_get_device_node(struct usb_device *hub, int port1)
 {
index eb626af0e4e7cfc739842a34736317688ac88187..d50098fb16b5d2e2d9e39c55db4329224115e8b1 100644 (file)
@@ -483,6 +483,7 @@ static inline unsigned int rdo_max_power(u32 rdo)
 #define PD_T_BIST_CONT_MODE    50      /* 30 - 60 ms */
 #define PD_T_SINK_TX           16      /* 16 - 20 ms */
 #define PD_T_CHUNK_NOT_SUPP    42      /* 40 - 50 ms */
+#define PD_T_VCONN_STABLE      50
 
 #define PD_T_DRP_TRY           100     /* 75 - 150 ms */
 #define PD_T_DRP_TRYWAIT       600     /* 400 - 800 ms */
index 3a747938cdab499ad77607aebfbddb38a0c09026..5c48e8a81403d62ed520d15da9a866d49c3c443d 100644 (file)
@@ -7,6 +7,7 @@
 #define __LINUX_USB_PD_VDO_H
 
 #include "pd.h"
+#include <linux/bitfield.h>
 
 /*
  * VDO : Vendor Defined Message Object
  *
  * Request is simply properly formatted SVDM header
  *
- * Response is 4 data objects:
+ * Response is 4 data objects for Power Delivery 2.0 and Passive Cables for
+ * Power Delivery 3.0. Active Cables in Power Delivery 3.0 have 5 data objects.
  * [0] :: SVDM header
  * [1] :: Identitiy header
  * [2] :: Cert Stat VDO
  * [3] :: (Product | Cable) VDO
+ * [4] :: Cable VDO 1
  * [4] :: AMA VDO
+ * [5] :: Cable VDO 2
  *
  */
 #define VDO_INDEX_HDR          0
 #define VDO_INDEX_CABLE                3
 #define VDO_INDEX_PRODUCT      3
 #define VDO_INDEX_AMA          4
+#define VDO_INDEX_CABLE_1      4
+#define VDO_INDEX_CABLE_2      5
 
 /*
  * SVDM Identity Header
 #define PD_IDH_MODAL_SUPP(vdo) ((vdo) & (1 << 26))
 #define PD_IDH_DFP_PTYPE(vdo)  (((vdo) >> 23) & 0x7)
 #define PD_IDH_CONN_TYPE(vdo)  (((vdo) >> 21) & 0x3)
+#define PD_IDH_HOST_SUPP(vdo)  ((vdo) & (1 << 31))
 
 /*
  * Cert Stat VDO
  * <5:3>   :: Alternate modes
  * <2:0>   :: USB highest speed
  */
-#define PD_VDO_UFP_DEVCAP(vdo) (((vdo) & GENMASK(27, 24)) >> 24)
+#define PD_VDO_UFP_DEVCAP(vdo) FIELD_GET(GENMASK(27, 24), vdo)
 
 /* UFP VDO Version */
 #define UFP_VDO_VER1_2         2
  * <21:5>  :: Reserved
  * <4:0>   :: Port number
  */
-#define PD_VDO_DFP_HOSTCAP(vdo)        (((vdo) & GENMASK(26, 24)) >> 24)
+#define PD_VDO_DFP_HOSTCAP(vdo)        FIELD_GET(GENMASK(26, 24), vdo)
 
 #define DFP_VDO_VER1_1         1
 #define HOST_USB2_CAPABLE      BIT(0)
index 467e8045e9f8690e461df4094b6afd47346b0c17..47a86b8a4a507b3c1e5719f27bed37fe3d3b42c2 100644 (file)
 #define TCPC_RX_BYTE_CNT               0x30
 #define TCPC_RX_BUF_FRAME_TYPE         0x31
 #define TCPC_RX_BUF_FRAME_TYPE_SOP     0
+#define TCPC_RX_BUF_FRAME_TYPE_SOP1    1
 #define TCPC_RX_HDR                    0x32
 #define TCPC_RX_DATA                   0x34 /* through 0x4f */
 
@@ -198,12 +199,23 @@ struct tcpci;
  *             Chip level drivers are expected to check for contaminant and call
  *             tcpm_clean_port when the port is clean to put the port back into
  *             toggling state.
+ * @cable_comm_capable
+ *             optional; Set when TCPC can communicate with cable plugs over SOP'
+ * @attempt_vconn_swap_discovery:
+ *             Optional; The callback is called by the TCPM when the result of
+ *             a Discover Identity request indicates that the port partner is
+ *             a receptacle capable of modal operation. Chip level TCPCI drivers
+ *             can implement their own policy to determine if and when a Vconn
+ *             swap following Discover Identity on SOP' occurs.
+ *             Return true when the TCPM is allowed to request a Vconn swap
+ *             after Discovery Identity on SOP.
  */
 struct tcpci_data {
        struct regmap *regmap;
        unsigned char TX_BUF_BYTE_x_hidden:1;
        unsigned char auto_discharge_disconnect:1;
        unsigned char vbus_vsafe0v:1;
+       unsigned char cable_comm_capable:1;
 
        int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
        int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
@@ -215,6 +227,7 @@ struct tcpci_data {
        void (*set_partner_usb_comm_capable)(struct tcpci *tcpci, struct tcpci_data *data,
                                             bool capable);
        void (*check_contaminant)(struct tcpci *tcpci, struct tcpci_data *data);
+       bool (*attempt_vconn_swap_discovery)(struct tcpci *tcpci, struct tcpci_data *data);
 };
 
 struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
index 65fac5e1f3178c4b11650771ded16d35b792b6a2..061da9546a813137645bfef5e6c024017d35a989 100644 (file)
@@ -119,6 +119,17 @@ enum tcpm_transmit_type {
  *             at the end of the deboumce period or when the port is still
  *             toggling. Chip level drivers are expected to check for contaminant
  *             and call tcpm_clean_port when the port is clean.
+ * @cable_comm_capable
+ *             Optional; Returns whether cable communication over SOP' is supported
+ *             by the tcpc
+ * @attempt_vconn_swap_discovery:
+ *             Optional; The callback is called by the TCPM when the result of
+ *             a Discover Identity request indicates that the port partner is
+ *             a receptacle capable of modal operation. Chip level TCPCI drivers
+ *             can implement their own policy to determine if and when a Vconn
+ *             swap following Discover Identity on SOP' occurs.
+ *             Return true when the TCPM is allowed to request a Vconn swap
+ *             after Discovery Identity on SOP.
  */
 struct tcpc_dev {
        struct fwnode_handle *fwnode;
@@ -133,6 +144,8 @@ struct tcpc_dev {
                      enum typec_cc_status *cc2);
        int (*set_polarity)(struct tcpc_dev *dev,
                            enum typec_cc_polarity polarity);
+       int (*set_orientation)(struct tcpc_dev *dev,
+                              enum typec_orientation orientation);
        int (*set_vconn)(struct tcpc_dev *dev, bool on);
        int (*set_vbus)(struct tcpc_dev *dev, bool on, bool charge);
        int (*set_current_limit)(struct tcpc_dev *dev, u32 max_ma, u32 mv);
@@ -154,6 +167,8 @@ struct tcpc_dev {
        bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev);
        void (*set_partner_usb_comm_capable)(struct tcpc_dev *dev, bool enable);
        void (*check_contaminant)(struct tcpc_dev *dev);
+       bool (*cable_comm_capable)(struct tcpc_dev *dev);
+       bool (*attempt_vconn_swap_discovery)(struct tcpc_dev *dev);
 };
 
 struct tcpm_port;
@@ -166,7 +181,8 @@ void tcpm_cc_change(struct tcpm_port *port);
 void tcpm_sink_frs(struct tcpm_port *port);
 void tcpm_sourcing_vbus(struct tcpm_port *port);
 void tcpm_pd_receive(struct tcpm_port *port,
-                    const struct pd_message *msg);
+                    const struct pd_message *msg,
+                    enum tcpm_transmit_type rx_sop_type);
 void tcpm_pd_transmit_complete(struct tcpm_port *port,
                               enum tcpm_transmit_status status);
 void tcpm_pd_hard_reset(struct tcpm_port *port);
index a05d6f6f2536921306c6a9c8177956c943f488cc..b35b427561ab53057de15d07110a8e306d6d77ef 100644 (file)
@@ -18,6 +18,7 @@ struct typec_cable;
 struct typec_plug;
 struct typec_port;
 struct typec_altmode_ops;
+struct typec_cable_ops;
 
 struct fwnode_handle;
 struct device;
@@ -157,6 +158,9 @@ void typec_port_register_altmodes(struct typec_port *port,
        const struct typec_altmode_ops *ops, void *drvdata,
        struct typec_altmode **altmodes, size_t n);
 
+void typec_port_register_cable_ops(struct typec_altmode **altmodes, int max_altmodes,
+                                  const struct typec_cable_ops *ops);
+
 void typec_unregister_altmode(struct typec_altmode *altmode);
 
 struct typec_port *typec_altmode2port(struct typec_altmode *alt);
@@ -333,6 +337,9 @@ void typec_partner_set_svdm_version(struct typec_partner *partner,
                                    enum usb_pd_svdm_ver svdm_version);
 int typec_get_negotiated_svdm_version(struct typec_port *port);
 
+int typec_get_cable_svdm_version(struct typec_port *port);
+void typec_cable_set_svdm_version(struct typec_cable *cable, enum usb_pd_svdm_ver svdm_version);
+
 struct usb_power_delivery *typec_partner_usb_power_delivery_register(struct typec_partner *partner,
                                                        struct usb_power_delivery_desc *desc);
 
index 28aeef8f9e7b5d9b6b55f0930dce116d02a4a3ce..b3c0866ea70f9faa78ba6f061ee6285966ea6947 100644 (file)
@@ -20,6 +20,7 @@ struct typec_altmode_ops;
  * @active: Tells has the mode been entered or not
  * @desc: Optional human readable description of the mode
  * @ops: Operations vector from the driver
+ * @cable_ops: Cable operations vector from the driver.
  */
 struct typec_altmode {
        struct device                   dev;
@@ -30,6 +31,7 @@ struct typec_altmode {
 
        char                            *desc;
        const struct typec_altmode_ops  *ops;
+       const struct typec_cable_ops    *cable_ops;
 };
 
 #define to_typec_altmode(d) container_of(d, struct typec_altmode, dev)
@@ -75,6 +77,34 @@ int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf,
 const struct typec_altmode *
 typec_altmode_get_partner(struct typec_altmode *altmode);
 
+/**
+ * struct typec_cable_ops - Cable alternate mode operations vector
+ * @enter: Operations to be executed with Enter Mode Command
+ * @exit: Operations to be executed with Exit Mode Command
+ * @vdm: Callback for SVID specific commands
+ */
+struct typec_cable_ops {
+       int (*enter)(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo);
+       int (*exit)(struct typec_altmode *altmode, enum typec_plug_index sop);
+       int (*vdm)(struct typec_altmode *altmode, enum typec_plug_index sop,
+                  const u32 hdr, const u32 *vdo, int cnt);
+};
+
+int typec_cable_altmode_enter(struct typec_altmode *altmode, enum typec_plug_index sop, u32 *vdo);
+int typec_cable_altmode_exit(struct typec_altmode *altmode, enum typec_plug_index sop);
+int typec_cable_altmode_vdm(struct typec_altmode *altmode, enum typec_plug_index sop,
+                           const u32 header, const u32 *vdo, int count);
+
+/**
+ * typec_altmode_get_cable_svdm_version - Get negotiated SVDM version for cable plug
+ * @altmode: Handle to the alternate mode
+ */
+static inline int
+typec_altmode_get_cable_svdm_version(struct typec_altmode *altmode)
+{
+       return typec_get_cable_svdm_version(typec_altmode2port(altmode));
+}
+
 /*
  * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C
  * Specification. SVID specific connector states are expected to follow and
index 1f358098522df71b2a8435b2e69c5f5b8530ee6e..f2da264d9c140c4b9b33de2a6e21a24e5ab25a1a 100644 (file)
@@ -3,6 +3,7 @@
 #define __USB_TYPEC_DP_H
 
 #include <linux/usb/typec_altmode.h>
+#include <linux/bitfield.h>
 
 #define USB_TYPEC_DP_SID       0xff01
 /* USB IF has not assigned a Standard ID (SID) for VirtualLink,
@@ -67,21 +68,21 @@ enum {
 #define   DP_CAP_UFP_D                 1
 #define   DP_CAP_DFP_D                 2
 #define   DP_CAP_DFP_D_AND_UFP_D       3
-#define DP_CAP_DP_SIGNALLING(_cap_)    (((_cap_) & GENMASK(5, 2)) >> 2)
+#define DP_CAP_DP_SIGNALLING(_cap_)    FIELD_GET(GENMASK(5, 2), _cap_)
 #define   DP_CAP_SIGNALLING_HBR3       1
 #define   DP_CAP_SIGNALLING_UHBR10     2
 #define   DP_CAP_SIGNALLING_UHBR20     3
 #define DP_CAP_RECEPTACLE              BIT(6)
 #define DP_CAP_USB                     BIT(7)
-#define DP_CAP_DFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(15, 8)) >> 8)
-#define DP_CAP_UFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(23, 16)) >> 16)
+#define DP_CAP_DFP_D_PIN_ASSIGN(_cap_) FIELD_GET(GENMASK(15, 8), _cap_)
+#define DP_CAP_UFP_D_PIN_ASSIGN(_cap_) FIELD_GET(GENMASK(23, 16), _cap_)
 /* Get pin assignment taking plug & receptacle into consideration */
 #define DP_CAP_PIN_ASSIGN_UFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \
                        DP_CAP_UFP_D_PIN_ASSIGN(_cap_) : DP_CAP_DFP_D_PIN_ASSIGN(_cap_))
 #define DP_CAP_PIN_ASSIGN_DFP_D(_cap_) ((_cap_ & DP_CAP_RECEPTACLE) ? \
                        DP_CAP_DFP_D_PIN_ASSIGN(_cap_) : DP_CAP_UFP_D_PIN_ASSIGN(_cap_))
 #define DP_CAP_UHBR_13_5_SUPPORT       BIT(26)
-#define DP_CAP_CABLE_TYPE(_cap_)       (((_cap_) & GENMASK(29, 28)) >> 28)
+#define DP_CAP_CABLE_TYPE(_cap_)       FIELD_GET(GENMASK(29, 28), _cap_)
 #define   DP_CAP_CABLE_TYPE_PASSIVE    0
 #define   DP_CAP_CABLE_TYPE_RE_TIMER   1
 #define   DP_CAP_CABLE_TYPE_RE_DRIVER  2
@@ -116,7 +117,7 @@ enum {
 
 /* Helper for setting/getting the pin assignment value to the configuration */
 #define DP_CONF_SET_PIN_ASSIGN(_a_)    ((_a_) << 8)
-#define DP_CONF_GET_PIN_ASSIGN(_conf_) (((_conf_) & GENMASK(15, 8)) >> 8)
+#define DP_CONF_GET_PIN_ASSIGN(_conf_) FIELD_GET(GENMASK(15, 8), _conf_)
 #define DP_CONF_UHBR13_5_SUPPORT       BIT(26)
 #define DP_CONF_CABLE_TYPE_MASK                GENMASK(29, 28)
 #define DP_CONF_CABLE_TYPE_SHIFT       28
index c7a2153bd6f50fa2954f0a292176c3ad31a96811..fa97d7e00f5c7896ab23cd9b25a9e6acef309711 100644 (file)
@@ -3,6 +3,7 @@
 #define __USB_TYPEC_TBT_H
 
 #include <linux/usb/typec_altmode.h>
+#include <linux/bitfield.h>
 
 #define USB_TYPEC_VENDOR_INTEL         0x8087
 /* Alias for convenience */
@@ -25,7 +26,7 @@ struct typec_thunderbolt_data {
 
 /* TBT3 Device Discover Mode VDO bits */
 #define TBT_MODE                       BIT(0)
-#define TBT_ADAPTER(_vdo_)             (((_vdo_) & BIT(16)) >> 16)
+#define TBT_ADAPTER(_vdo_)             FIELD_GET(BIT(16), _vdo_)
 #define   TBT_ADAPTER_LEGACY           0
 #define   TBT_ADAPTER_TBT3             1
 #define TBT_INTEL_SPECIFIC_B0          BIT(26)
@@ -35,12 +36,12 @@ struct typec_thunderbolt_data {
 #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_SPEED(_vdo_)         FIELD_GET(GENMASK(18, 16), _vdo_)
 #define   TBT_CABLE_USB3_GEN1          1
 #define   TBT_CABLE_USB3_PASSIVE       2
 #define   TBT_CABLE_10_AND_20GBPS      3
-#define TBT_CABLE_ROUNDED_SUPPORT(_vdo_) \
-                                       (((_vdo_) & GENMASK(20, 19)) >> 19)
+#define TBT_CABLE_ROUNDED_SUPPORT(_vdo_) FIELD_GET(GENMASK(20, 19), _vdo_)
+
 #define   TBT_GEN3_NON_ROUNDED                 0
 #define   TBT_GEN3_GEN4_ROUNDED_NON_ROUNDED    1
 #define TBT_CABLE_OPTICAL              BIT(21)
index db15ac07f8a6a453bfbe35df555eea6efc83e0d8..7977ca03ac7ade72c028a40ef994260b0719c2f8 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/interrupt.h>
 #include <linux/vhost_iotlb.h>
 #include <linux/virtio_net.h>
+#include <linux/virtio_blk.h>
 #include <linux/if_ether.h>
 
 /**
@@ -195,6 +196,10 @@ struct vdpa_map_file {
  *                             @idx: virtqueue index
  *                             Returns int: irq number of a virtqueue,
  *                             negative number if no irq assigned.
+ * @get_vq_size:               Get the size of a specific virtqueue (optional)
+ *                             @vdev: vdpa device
+ *                             @idx: virtqueue index
+ *                             Return u16: the size of the virtqueue
  * @get_vq_align:              Get the virtqueue align requirement
  *                             for the device
  *                             @vdev: vdpa device
@@ -386,6 +391,7 @@ struct vdpa_config_ops {
        (*get_vq_notification)(struct vdpa_device *vdev, u16 idx);
        /* vq irq is not expected to be changed once DRIVER_OK is set */
        int (*get_vq_irq)(struct vdpa_device *vdev, u16 idx);
+       u16 (*get_vq_size)(struct vdpa_device *vdev, u16 idx);
 
        /* Device ops */
        u32 (*get_vq_align)(struct vdpa_device *vdev);
index c1f5aebef1705c15ba03120653d5cfbea104b39c..d008c3d0a9bbfe0858caee2b89a8f44e5e89fc17 100644 (file)
@@ -25,7 +25,8 @@ extern int fg_console, last_console, want_console;
 
 int vc_allocate(unsigned int console);
 int vc_cons_allocated(unsigned int console);
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
+int __vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines,
+               bool from_user);
 struct vc_data *vc_deallocate(unsigned int console);
 void reset_palette(struct vc_data *vc);
 void do_blank_screen(int entering_gfx);
@@ -42,6 +43,12 @@ void redraw_screen(struct vc_data *vc, int is_switch);
 #define update_screen(x) redraw_screen(x, 0)
 #define switch_screen(x) redraw_screen(x, 1)
 
+static inline int vc_resize(struct vc_data *vc, unsigned int cols,
+                           unsigned int lines)
+{
+       return __vc_resize(vc, cols, lines, false);
+}
+
 struct tty_struct;
 int tioclinux(struct tty_struct *tty, unsigned long arg);
 
@@ -168,7 +175,4 @@ void vt_set_led_state(unsigned int console, int leds);
 void vt_kbd_con_start(unsigned int console);
 void vt_kbd_con_stop(unsigned int console);
 
-void vc_scrolldelta_helper(struct vc_data *c, int lines,
-               unsigned int rolled_over, void *_base, unsigned int size);
-
 #endif /* _VT_KERN_H */
index 8b2055d64a6bb993c3f40fdb7ef78d01e1baf699..5cd7871127c943120483258a56d4990757a86741 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <asm/dma-types.h>
 #include <asm/debug.h>
 
 /*
@@ -76,7 +77,7 @@
  * and iucv_message_reply if IUCV_IPBUFLST or IUCV_IPANSLST are used.
  */
 struct iucv_array {
-       u32 address;
+       dma32_t address;
        u32 length;
 } __attribute__ ((aligned (8)));
 
index 8839133d6f6b78f8d6c1c9d61330043c8874b02d..004e651e6067e723ee2e3fc6d80474e4f9c1c1ba 100644 (file)
@@ -61,7 +61,11 @@ struct request_sock {
        struct request_sock             *dl_next;
        u16                             mss;
        u8                              num_retrans; /* number of retransmits */
-       u8                              syncookie:1; /* syncookie: encode tcpopts in timestamp */
+       u8                              syncookie:1; /* True if
+                                                     * 1) tcpopts needs to be encoded in
+                                                     *    TS of SYN+ACK
+                                                     * 2) ACK is validated by BPF kfunc.
+                                                     */
        u8                              num_timeout:7; /* number of timeouts */
        u32                             ts_recent;
        struct timer_list               rsk_timer;
@@ -144,6 +148,7 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
        sk_node_init(&req_to_sk(req)->sk_node);
        sk_tx_queue_clear(req_to_sk(req));
        req->saved_syn = NULL;
+       req->syncookie = 0;
        req->timeout = 0;
        req->num_timeout = 0;
        req->num_retrans = 0;
index b7b6b58dd3486d98e5d641149b69dcf13e694292..477bf9dd5e714473bb8d896e384e2806cb8baf80 100644 (file)
@@ -1910,8 +1910,6 @@ struct ib_flow_eth_filter {
        u8      src_mac[6];
        __be16  ether_type;
        __be16  vlan_tag;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_eth {
@@ -1924,8 +1922,6 @@ struct ib_flow_spec_eth {
 struct ib_flow_ib_filter {
        __be16 dlid;
        __u8   sl;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_ib {
@@ -1949,8 +1945,6 @@ struct ib_flow_ipv4_filter {
        u8      tos;
        u8      ttl;
        u8      flags;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_ipv4 {
@@ -1967,9 +1961,7 @@ struct ib_flow_ipv6_filter {
        u8      next_hdr;
        u8      traffic_class;
        u8      hop_limit;
-       /* Must be last */
-       u8      real_sz[];
-};
+} __packed;
 
 struct ib_flow_spec_ipv6 {
        u32                        type;
@@ -1981,8 +1973,6 @@ struct ib_flow_spec_ipv6 {
 struct ib_flow_tcp_udp_filter {
        __be16  dst_port;
        __be16  src_port;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_tcp_udp {
@@ -1994,7 +1984,6 @@ struct ib_flow_spec_tcp_udp {
 
 struct ib_flow_tunnel_filter {
        __be32  tunnel_id;
-       u8      real_sz[];
 };
 
 /* ib_flow_spec_tunnel describes the Vxlan tunnel
@@ -2010,8 +1999,6 @@ struct ib_flow_spec_tunnel {
 struct ib_flow_esp_filter {
        __be32  spi;
        __be32  seq;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_esp {
@@ -2025,8 +2012,6 @@ struct ib_flow_gre_filter {
        __be16 c_ks_res0_ver;
        __be16 protocol;
        __be32 key;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_gre {
@@ -2038,8 +2023,6 @@ struct ib_flow_spec_gre {
 
 struct ib_flow_mpls_filter {
        __be32 tag;
-       /* Must be last */
-       u8      real_sz[];
 };
 
 struct ib_flow_spec_mpls {
index 06287de69cd29855b109a441cb0927e3ed24f102..e6c0de227fad3d0587b486076713bd5f9b2f1d3f 100644 (file)
@@ -629,12 +629,14 @@ struct uverbs_attr {
 };
 
 struct uverbs_attr_bundle {
-       struct ib_udata driver_udata;
-       struct ib_udata ucore;
-       struct ib_uverbs_file *ufile;
-       struct ib_ucontext *context;
-       struct ib_uobject *uobject;
-       DECLARE_BITMAP(attr_present, UVERBS_API_ATTR_BKEY_LEN);
+       struct_group_tagged(uverbs_attr_bundle_hdr, hdr,
+               struct ib_udata driver_udata;
+               struct ib_udata ucore;
+               struct ib_uverbs_file *ufile;
+               struct ib_ucontext *context;
+               struct ib_uobject *uobject;
+               DECLARE_BITMAP(attr_present, UVERBS_API_ATTR_BKEY_LEN);
+       );
        struct uverbs_attr attrs[];
 };
 
index fddc767c47871f9191cf7927c5ee037ed09aee58..9c540f5468ebff9885359214863d21ea33ac8d20 100644 (file)
@@ -149,6 +149,7 @@ struct scsi_device {
        struct scsi_vpd __rcu *vpd_pgb0;
        struct scsi_vpd __rcu *vpd_pgb1;
        struct scsi_vpd __rcu *vpd_pgb2;
+       struct scsi_vpd __rcu *vpd_pgb7;
 
        struct scsi_target      *sdev_target;
 
index 07d65c1f59db33e98591071cee9d8a9c3513ffbe..843106e1109f43f74a4aa09f8a6e30a740ec0007 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef _SCSI_PROTO_H_
 #define _SCSI_PROTO_H_
 
+#include <linux/build_bug.h>
 #include <linux/types.h>
 
 /*
 #define        SAI_READ_CAPACITY_16  0x10
 #define SAI_GET_LBA_STATUS    0x12
 #define SAI_REPORT_REFERRALS  0x13
+#define SAI_GET_STREAM_STATUS 0x16
 /* values for maintenance in */
 #define MI_REPORT_IDENTIFYING_INFORMATION 0x05
 #define MI_REPORT_TARGET_PGS  0x0a
@@ -275,6 +277,82 @@ struct scsi_lun {
        __u8 scsi_lun[8];
 };
 
+/* SBC-5 IO advice hints group descriptor */
+struct scsi_io_group_descriptor {
+#if defined(__BIG_ENDIAN)
+       u8 io_advice_hints_mode: 2;
+       u8 reserved1: 3;
+       u8 st_enble: 1;
+       u8 cs_enble: 1;
+       u8 ic_enable: 1;
+#elif defined(__LITTLE_ENDIAN)
+       u8 ic_enable: 1;
+       u8 cs_enble: 1;
+       u8 st_enble: 1;
+       u8 reserved1: 3;
+       u8 io_advice_hints_mode: 2;
+#else
+#error
+#endif
+       u8 reserved2[3];
+       /* Logical block markup descriptor */
+#if defined(__BIG_ENDIAN)
+       u8 acdlu: 1;
+       u8 reserved3: 1;
+       u8 rlbsr: 2;
+       u8 lbm_descriptor_type: 4;
+#elif defined(__LITTLE_ENDIAN)
+       u8 lbm_descriptor_type: 4;
+       u8 rlbsr: 2;
+       u8 reserved3: 1;
+       u8 acdlu: 1;
+#else
+#error
+#endif
+       u8 params[2];
+       u8 reserved4;
+       u8 reserved5[8];
+};
+
+static_assert(sizeof(struct scsi_io_group_descriptor) == 16);
+
+/* SCSI stream status descriptor */
+struct scsi_stream_status {
+#if defined(__BIG_ENDIAN)
+       u8 perm: 1;
+       u8 reserved1: 7;
+#elif defined(__LITTLE_ENDIAN)
+       u8 reserved1: 7;
+       u8 perm: 1;
+#else
+#error
+#endif
+       u8 reserved2;
+       __be16 stream_identifier;
+#if defined(__BIG_ENDIAN)
+       u8 reserved3: 2;
+       u8 rel_lifetime: 6;
+#elif defined(__LITTLE_ENDIAN)
+       u8 rel_lifetime: 6;
+       u8 reserved3: 2;
+#else
+#error
+#endif
+       u8 reserved4[3];
+};
+
+static_assert(sizeof(struct scsi_stream_status) == 8);
+
+/* GET STREAM STATUS parameter data */
+struct scsi_stream_status_header {
+       __be32 len;     /* length in bytes of stream_status[] array. */
+       u16 reserved;
+       __be16 number_of_open_streams;
+       DECLARE_FLEX_ARRAY(struct scsi_stream_status, stream_status);
+};
+
+static_assert(sizeof(struct scsi_stream_status_header) == 8);
+
 /* SPC asymmetric access states */
 #define SCSI_ACCESS_STATE_OPTIMAL     0x00
 #define SCSI_ACCESS_STATE_ACTIVE      0x01
index af1d73a7f0cd10736e2e403be2f3e3942f1687a7..6ee4c59db6201f9e2d415349f4385ce8d07226a3 100644 (file)
@@ -146,13 +146,14 @@ struct tegra_mc_icc_ops {
        int (*set)(struct icc_node *src, struct icc_node *dst);
        int (*aggregate)(struct icc_node *node, u32 tag, u32 avg_bw,
                         u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
-       struct icc_node* (*xlate)(struct of_phandle_args *spec, void *data);
-       struct icc_node_data *(*xlate_extended)(struct of_phandle_args *spec,
+       struct icc_node* (*xlate)(const struct of_phandle_args *spec, void *data);
+       struct icc_node_data *(*xlate_extended)(const struct of_phandle_args *spec,
                                                void *data);
        int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak);
 };
 
-struct icc_node *tegra_mc_icc_xlate(struct of_phandle_args *spec, void *data);
+struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec,
+                                   void *data);
 extern const struct tegra_mc_icc_ops tegra_mc_icc_ops;
 
 struct tegra_mc_ops {
index 4a2abf9daa465b6dd563c5e793df1ed42cd30740..ac05ed06a0714eff56e5d01e612917286369f020 100644 (file)
@@ -1331,18 +1331,18 @@ TRACE_EVENT(xs_stream_read_data,
                __field(ssize_t, err)
                __field(size_t, total)
                __string(addr, xprt ? xprt->address_strings[RPC_DISPLAY_ADDR] :
-                               "(null)")
+                               EVENT_NULL_STR)
                __string(port, xprt ? xprt->address_strings[RPC_DISPLAY_PORT] :
-                               "(null)")
+                               EVENT_NULL_STR)
        ),
 
        TP_fast_assign(
                __entry->err = err;
                __entry->total = total;
                __assign_str(addr, xprt ?
-                       xprt->address_strings[RPC_DISPLAY_ADDR] : "(null)");
+                       xprt->address_strings[RPC_DISPLAY_ADDR] : EVENT_NULL_STR);
                __assign_str(port, xprt ?
-                       xprt->address_strings[RPC_DISPLAY_PORT] : "(null)");
+                       xprt->address_strings[RPC_DISPLAY_PORT] : EVENT_NULL_STR);
        ),
 
        TP_printk("peer=[%s]:%s err=%zd total=%zu", __get_str(addr),
@@ -1787,7 +1787,7 @@ TRACE_EVENT(svc_process,
                __string(service, name)
                __string(procedure, svc_proc_name(rqst))
                __string(addr, rqst->rq_xprt ?
-                        rqst->rq_xprt->xpt_remotebuf : "(null)")
+                        rqst->rq_xprt->xpt_remotebuf : EVENT_NULL_STR)
        ),
 
        TP_fast_assign(
@@ -1797,7 +1797,7 @@ TRACE_EVENT(svc_process,
                __assign_str(service, name);
                __assign_str(procedure, svc_proc_name(rqst));
                __assign_str(addr, rqst->rq_xprt ?
-                            rqst->rq_xprt->xpt_remotebuf : "(null)");
+                            rqst->rq_xprt->xpt_remotebuf : EVENT_NULL_STR);
        ),
 
        TP_printk("addr=%s xid=0x%08x service=%s vers=%u proc=%s",
index 469b6a64293de14d00d141eb4daa7f07fee1a650..8b0cff06d34633d8fc0169922342640254fd9a00 100644 (file)
@@ -24,7 +24,7 @@
 #define __array(type, item, len)
 
 #undef __dynamic_array
-#define __dynamic_array(type, item, len)       u32 item;
+#define __dynamic_array(type, item, len)       u32 item; const void *item##_ptr_;
 
 #undef __string
 #define __string(item, src) __dynamic_array(char, item, -1)
@@ -45,7 +45,7 @@
 #define __sockaddr(field, len) __dynamic_array(u8, field, len)
 
 #undef __rel_dynamic_array
-#define __rel_dynamic_array(type, item, len)   u32 item;
+#define __rel_dynamic_array(type, item, len)   u32 item; const void *item##_ptr_;
 
 #undef __rel_string
 #define __rel_string(item, src) __rel_dynamic_array(char, item, -1)
index e30a13be46ba560eaac1d11eb8e4843faf176891..c6a62dfb18ef583e0c906c17927c61e7fe1aaad5 100644 (file)
@@ -9,6 +9,16 @@
 #undef __entry
 #define __entry entry
 
+#ifndef __STAGE5_STRING_SRC_H
+#define __STAGE5_STRING_SRC_H
+static inline const char *__string_src(const char *str)
+{
+       if (!str)
+              return EVENT_NULL_STR;
+       return str;
+}
+#endif /* __STAGE5_STRING_SRC_H */
+
 /*
  * Fields should never declare an array: i.e. __field(int, arr[5])
  * If they do, it will cause issues in parsing and possibly corrupt the
 
 #undef __string
 #define __string(item, src) __dynamic_array(char, item,                        \
-                   strlen((src) ? (const char *)(src) : "(null)") + 1)
+                   strlen(__string_src(src)) + 1)                      \
+       __data_offsets->item##_ptr_ = src;
 
 #undef __string_len
-#define __string_len(item, src, len) __dynamic_array(char, item, (len) + 1)
+#define __string_len(item, src, len) __dynamic_array(char, item, (len) + 1)\
+       __data_offsets->item##_ptr_ = src;
 
 #undef __vstring
 #define __vstring(item, fmt, ap) __dynamic_array(char, item,           \
        __data_size += __item_length;
 
 #undef __rel_string
-#define __rel_string(item, src) __rel_dynamic_array(char, item,                        \
-                   strlen((src) ? (const char *)(src) : "(null)") + 1)
+#define __rel_string(item, src) __rel_dynamic_array(char, item,                \
+                   strlen(__string_src(src)) + 1)                      \
+       __data_offsets->item##_ptr_ = src;
 
 #undef __rel_string_len
-#define __rel_string_len(item, src, len) __rel_dynamic_array(char, item, (len) + 1)
+#define __rel_string_len(item, src, len) __rel_dynamic_array(char, item, (len) + 1)\
+       __data_offsets->item##_ptr_ = src;
+
 /*
  * __bitmask_size_in_bytes_raw is the number of bytes needed to hold
  * num_possible_cpus().
index 919b1a4da9807b71b0f7ef5e23a81b131ae5c379..3690e677263f53f105e961bdbc9a52ac44579d67 100644 (file)
 
 #undef __assign_str
 #define __assign_str(dst, src)                                         \
-       strcpy(__get_str(dst), (src) ? (const char *)(src) : "(null)");
-
-#undef __assign_str_len
-#define __assign_str_len(dst, src, len)                                        \
        do {                                                            \
-               memcpy(__get_str(dst), (src), (len));                   \
-               __get_str(dst)[len] = '\0';                             \
-       } while(0)
+               char *__str__ = __get_str(dst);                         \
+               int __len__ = __get_dynamic_array_len(dst) - 1;         \
+               WARN_ON_ONCE(!(void *)(src) != !(void *)__data_offsets.dst##_ptr_); \
+               WARN_ON_ONCE((src) && strcmp((src), __data_offsets.dst##_ptr_)); \
+               memcpy(__str__, __data_offsets.dst##_ptr_ ? :           \
+                      EVENT_NULL_STR, __len__);                        \
+               __str__[__len__] = '\0';                                \
+       } while (0)
 
 #undef __assign_vstr
 #define __assign_vstr(dst, fmt, va)                                    \
 #define __rel_string_len(item, src, len) __rel_dynamic_array(char, item, -1)
 
 #undef __assign_rel_str
-#define __assign_rel_str(dst, src)                                     \
-       strcpy(__get_rel_str(dst), (src) ? (const char *)(src) : "(null)");
-
-#undef __assign_rel_str_len
-#define __assign_rel_str_len(dst, src, len)                            \
+#define __assign_rel_str(dst)                                          \
        do {                                                            \
-               memcpy(__get_rel_str(dst), (src), (len));               \
-               __get_rel_str(dst)[len] = '\0';                         \
+               char *__str__ = __get_rel_str(dst);                     \
+               int __len__ = __get_rel_dynamic_array_len(dst) - 1;     \
+               memcpy(__str__, __data_offsets.dst##_ptr_ ? :           \
+                      EVENT_NULL_STR, __len__);                        \
+               __str__[__len__] = '\0';                                \
        } while (0)
 
 #undef __rel_bitmask
index 3a49913d006c9bf6e502ea209336d24d2924effd..cde8f173f566b81a5e602b789ee72278400420d3 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/types.h>
 #include <linux/i2c.h>
+#include <linux/vesa.h>
 
 /* Definitions of frame buffers                                                */
 
@@ -293,13 +294,6 @@ struct fb_con2fbmap {
        __u32 framebuffer;
 };
 
-/* VESA Blanking Levels */
-#define VESA_NO_BLANKING        0
-#define VESA_VSYNC_SUSPEND      1
-#define VESA_HSYNC_SUSPEND      2
-#define VESA_POWERDOWN          3
-
-
 enum {
        /* screen: unblanked, hsync: on,  vsync: on */
        FB_BLANK_UNBLANK       = VESA_NO_BLANKING,
index 8a147abfc6806590c3bfd91d37364478fc15f486..44d73ba8788dc46b09441415575cd4ad6b759ebb 100644 (file)
@@ -763,6 +763,8 @@ struct usb_otg20_descriptor {
 #define USB_OTG_SRP            (1 << 0)
 #define USB_OTG_HNP            (1 << 1)        /* swap host/device roles */
 #define USB_OTG_ADP            (1 << 2)        /* support ADP */
+/* OTG 3.0 */
+#define USB_OTG_RSP            (1 << 3)        /* support RSP */
 
 #define OTG_STS_SELECTOR       0xF000          /* OTG status selector */
 /*-------------------------------------------------------------------------*/
index 078098e73fd3e20776c8ba39a2d8c4594f10ea5f..9f88de9c3d6601a08e4c67e80a6cac953f3a45ff 100644 (file)
@@ -86,6 +86,22 @@ struct usb_ext_prop_desc {
        __le16  wPropertyNameLength;
 } __attribute__((packed));
 
+/* Flags for usb_ffs_dmabuf_transfer_req->flags (none for now) */
+#define USB_FFS_DMABUF_TRANSFER_MASK   0x0
+
+/**
+ * struct usb_ffs_dmabuf_transfer_req - Transfer request for a DMABUF object
+ * @fd:                file descriptor of the DMABUF object
+ * @flags:     one or more USB_FFS_DMABUF_TRANSFER_* flags
+ * @length:    number of bytes used in this DMABUF for the data transfer.
+ *             Should generally be set to the DMABUF's size.
+ */
+struct usb_ffs_dmabuf_transfer_req {
+       int fd;
+       __u32 flags;
+       __u64 length;
+} __attribute__((packed));
+
 #ifndef __KERNEL__
 
 /*
@@ -290,6 +306,31 @@ struct usb_functionfs_event {
 #define        FUNCTIONFS_ENDPOINT_DESC        _IOR('g', 130, \
                                             struct usb_endpoint_descriptor)
 
+/*
+ * Attach the DMABUF object, identified by its file descriptor, to the
+ * data endpoint. Returns zero on success, and a negative errno value
+ * on error.
+ */
+#define FUNCTIONFS_DMABUF_ATTACH       _IOW('g', 131, int)
+
 
+/*
+ * Detach the given DMABUF object, identified by its file descriptor,
+ * from the data endpoint. Returns zero on success, and a negative
+ * errno value on error. Note that closing the endpoint's file
+ * descriptor will automatically detach all attached DMABUFs.
+ */
+#define FUNCTIONFS_DMABUF_DETACH       _IOW('g', 132, int)
+
+/*
+ * Enqueue the previously attached DMABUF to the transfer queue.
+ * The argument is a structure that packs the DMABUF's file descriptor,
+ * the size in bytes to transfer (which should generally correspond to
+ * the size of the DMABUF), and a 'flags' field which is unused
+ * for now. Returns zero on success, and a negative errno value on
+ * error.
+ */
+#define FUNCTIONFS_DMABUF_TRANSFER     _IOW('g', 133, \
+                                            struct usb_ffs_dmabuf_transfer_req)
 
 #endif /* _UAPI__LINUX_FUNCTIONFS_H__ */
index f74f3aedd49ce922f8a233e0bf24ea06b533f0ab..a03de03dccbcf4edac6e4efd0adffaf368af4966 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/ioctl.h>
 
 #define USER_EVENTS_SYSTEM "user_events"
+#define USER_EVENTS_MULTI_SYSTEM "user_events_multi"
 #define USER_EVENTS_PREFIX "u:"
 
 /* Create dynamic location entry within a 32-bit value */
@@ -22,8 +23,11 @@ enum user_reg_flag {
        /* Event will not delete upon last reference closing */
        USER_EVENT_REG_PERSIST          = 1U << 0,
 
+       /* Event will be allowed to have multiple formats */
+       USER_EVENT_REG_MULTI_FORMAT     = 1U << 1,
+
        /* This value or above is currently non-ABI */
-       USER_EVENT_REG_MAX              = 1U << 1,
+       USER_EVENT_REG_MAX              = 1U << 2,
 };
 
 /*
index 54b649ab0f22b6c6d4aad09cca3141db505be496..43c51698195ceb0619e5b2787428be675b007a7f 100644 (file)
@@ -56,6 +56,23 @@ enum vdpa_attr {
        /* virtio features that are provisioned to the vDPA device */
        VDPA_ATTR_DEV_FEATURES,                 /* u64 */
 
+       VDPA_ATTR_DEV_BLK_CFG_CAPACITY,         /* u64 */
+       VDPA_ATTR_DEV_BLK_CFG_SEG_SIZE,         /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_BLK_SIZE,         /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_SEG_MAX,          /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_NUM_QUEUES,       /* u16 */
+       VDPA_ATTR_DEV_BLK_CFG_PHY_BLK_EXP,      /* u8 */
+       VDPA_ATTR_DEV_BLK_CFG_ALIGN_OFFSET,     /* u8 */
+       VDPA_ATTR_DEV_BLK_CFG_MIN_IO_SIZE,      /* u16 */
+       VDPA_ATTR_DEV_BLK_CFG_OPT_IO_SIZE,      /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_MAX_DISCARD_SEC,  /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_MAX_DISCARD_SEG,  /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_DISCARD_SEC_ALIGN,/* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_MAX_WRITE_ZEROES_SEC,     /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_MAX_WRITE_ZEROES_SEG,     /* u32 */
+       VDPA_ATTR_DEV_BLK_CFG_READ_ONLY,                /* u8 */
+       VDPA_ATTR_DEV_BLK_CFG_FLUSH,            /* u8 */
+
        /* new attributes must be added above here */
        VDPA_ATTR_MAX,
 };
diff --git a/include/uapi/linux/vesa.h b/include/uapi/linux/vesa.h
new file mode 100644 (file)
index 0000000..81947f5
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_VESA_H
+#define _UAPI_LINUX_VESA_H
+
+/* VESA Blanking Levels */
+enum vesa_blank_mode {
+       VESA_NO_BLANKING        = 0,
+#define VESA_NO_BLANKING       VESA_NO_BLANKING
+       VESA_VSYNC_SUSPEND      = 1,
+#define VESA_VSYNC_SUSPEND     VESA_VSYNC_SUSPEND
+       VESA_HSYNC_SUSPEND      = 2,
+#define VESA_HSYNC_SUSPEND     VESA_HSYNC_SUSPEND
+       VESA_POWERDOWN          = VESA_VSYNC_SUSPEND | VESA_HSYNC_SUSPEND,
+#define VESA_POWERDOWN         VESA_POWERDOWN
+       VESA_BLANK_MAX          = VESA_POWERDOWN,
+};
+
+#endif
index 649560c685f13b73feaafb96b64c351b6eec2c25..bea6973906134656d84299958258205932c23e04 100644 (file)
  */
 #define VHOST_VDPA_GET_VRING_DESC_GROUP        _IOWR(VHOST_VIRTIO, 0x7F,       \
                                              struct vhost_vring_state)
+
+/* Get the queue size of a specific virtqueue.
+ * userspace set the vring index in vhost_vring_state.index
+ * kernel set the queue size in vhost_vring_state.num
+ */
+#define VHOST_VDPA_GET_VRING_SIZE      _IOWR(VHOST_VIRTIO, 0x80,       \
+                                             struct vhost_vring_state)
 #endif
index ef3810dee7efac5d337d55db03131cb4796f4358..a8208492e82279525385924995a5b93943f1f6d0 100644 (file)
@@ -240,7 +240,7 @@ struct virtio_pci_cfg_cap {
 #define VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ           0x5
 #define VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO            0x6
 
-struct __packed virtio_admin_cmd_hdr {
+struct virtio_admin_cmd_hdr {
        __le16 opcode;
        /*
         * 1 - SR-IOV
@@ -252,20 +252,20 @@ struct __packed virtio_admin_cmd_hdr {
        __le64 group_member_id;
 };
 
-struct __packed virtio_admin_cmd_status {
+struct virtio_admin_cmd_status {
        __le16 status;
        __le16 status_qualifier;
        /* Unused, reserved for future extensions. */
        __u8 reserved2[4];
 };
 
-struct __packed virtio_admin_cmd_legacy_wr_data {
+struct virtio_admin_cmd_legacy_wr_data {
        __u8 offset; /* Starting offset of the register(s) to write. */
        __u8 reserved[7];
        __u8 registers[];
 };
 
-struct __packed virtio_admin_cmd_legacy_rd_data {
+struct virtio_admin_cmd_legacy_rd_data {
        __u8 offset; /* Starting offset of the register(s) to read. */
 };
 
@@ -275,7 +275,7 @@ struct __packed virtio_admin_cmd_legacy_rd_data {
 
 #define VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO 4
 
-struct __packed virtio_admin_cmd_notify_info_data {
+struct virtio_admin_cmd_notify_info_data {
        __u8 flags; /* 0 = end of list, 1 = owner device, 2 = member device */
        __u8 bar; /* BAR of the member or the owner device */
        __u8 padding[6];
index c996e151081eb845b42734df878d1216d4418db8..158670da2b2a56d6217cb8f3022fecd3a1acaf38 100644 (file)
@@ -73,6 +73,17 @@ struct hns_roce_ib_create_srq_resp {
        __u32   cap_flags; /* Use enum hns_roce_srq_cap_flags */
 };
 
+enum hns_roce_congest_type_flags {
+       HNS_ROCE_CREATE_QP_FLAGS_DCQCN,
+       HNS_ROCE_CREATE_QP_FLAGS_LDCP,
+       HNS_ROCE_CREATE_QP_FLAGS_HC3,
+       HNS_ROCE_CREATE_QP_FLAGS_DIP,
+};
+
+enum hns_roce_create_qp_comp_mask {
+       HNS_ROCE_CREATE_QP_MASK_CONGEST_TYPE = 1 << 0,
+};
+
 struct hns_roce_ib_create_qp {
        __aligned_u64 buf_addr;
        __aligned_u64 db_addr;
@@ -81,6 +92,9 @@ struct hns_roce_ib_create_qp {
        __u8    sq_no_prefetch;
        __u8    reserved[5];
        __aligned_u64 sdb_addr;
+       __aligned_u64 comp_mask; /* Use enum hns_roce_create_qp_comp_mask */
+       __aligned_u64 create_flags;
+       __aligned_u64 cong_type_flags;
 };
 
 enum hns_roce_qp_cap_flags {
@@ -114,6 +128,8 @@ struct hns_roce_ib_alloc_ucontext_resp {
        __u32   reserved;
        __u32   config;
        __u32   max_inline_data;
+       __u8    congest_type;
+       __u8    reserved0[7];
 };
 
 struct hns_roce_ib_alloc_ucontext {
index f3ea5dea9c8510db8148d0fb5f51fc6b441dbf06..aa02aec6aa7d29432f1974003900fce14bf14452 100644 (file)
@@ -1499,7 +1499,7 @@ config MULTIUSER
 
 config SGETMASK_SYSCALL
        bool "sgetmask/ssetmask syscalls support" if EXPERT
-       def_bool PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH
+       default PARISC || M68K || PPC || MIPS || X86 || SPARC || MICROBLAZE || SUPERH
        help
          sys_sgetmask and sys_ssetmask are obsolete system calls
          no longer supported in libc but still enabled by default in some
@@ -1986,6 +1986,9 @@ source "kernel/Kconfig.locks"
 config ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
        bool
 
+config ARCH_HAS_PREPARE_SYNC_CORE_CMD
+       bool
+
 config ARCH_HAS_SYNC_CORE_BEFORE_USERMODE
        bool
 
index 3c3575303c3d0033e3d5d537aa094f5150fa244d..792a03df58deac775d9c0ce05d9a77f63df0545f 100644 (file)
@@ -159,6 +159,7 @@ bool io_futex_remove_all(struct io_ring_ctx *ctx, struct task_struct *task,
        hlist_for_each_entry_safe(req, tmp, &ctx->futex_list, hash_node) {
                if (!io_match_task_safe(req, task, cancel_all))
                        continue;
+               hlist_del_init(&req->hash_node);
                __io_futex_cancel(ctx, req);
                found = true;
        }
index cf348c33f4855e519d1d28ef29cff8f106db5ff3..5d4b448fdc503822cb97ca5ca93d545ade642db5 100644 (file)
@@ -2181,6 +2181,13 @@ static void io_init_req_drain(struct io_kiocb *req)
        }
 }
 
+static __cold int io_init_fail_req(struct io_kiocb *req, int err)
+{
+       /* ensure per-opcode data is cleared if we fail before prep */
+       memset(&req->cmd.data, 0, sizeof(req->cmd.data));
+       return err;
+}
+
 static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
                       const struct io_uring_sqe *sqe)
        __must_hold(&ctx->uring_lock)
@@ -2202,29 +2209,29 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 
        if (unlikely(opcode >= IORING_OP_LAST)) {
                req->opcode = 0;
-               return -EINVAL;
+               return io_init_fail_req(req, -EINVAL);
        }
        def = &io_issue_defs[opcode];
        if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
                /* enforce forwards compatibility on users */
                if (sqe_flags & ~SQE_VALID_FLAGS)
-                       return -EINVAL;
+                       return io_init_fail_req(req, -EINVAL);
                if (sqe_flags & IOSQE_BUFFER_SELECT) {
                        if (!def->buffer_select)
-                               return -EOPNOTSUPP;
+                               return io_init_fail_req(req, -EOPNOTSUPP);
                        req->buf_index = READ_ONCE(sqe->buf_group);
                }
                if (sqe_flags & IOSQE_CQE_SKIP_SUCCESS)
                        ctx->drain_disabled = true;
                if (sqe_flags & IOSQE_IO_DRAIN) {
                        if (ctx->drain_disabled)
-                               return -EOPNOTSUPP;
+                               return io_init_fail_req(req, -EOPNOTSUPP);
                        io_init_req_drain(req);
                }
        }
        if (unlikely(ctx->restricted || ctx->drain_active || ctx->drain_next)) {
                if (ctx->restricted && !io_check_restriction(ctx, req, sqe_flags))
-                       return -EACCES;
+                       return io_init_fail_req(req, -EACCES);
                /* knock it to the slow queue path, will be drained there */
                if (ctx->drain_active)
                        req->flags |= REQ_F_FORCE_ASYNC;
@@ -2237,9 +2244,9 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
        }
 
        if (!def->ioprio && sqe->ioprio)
-               return -EINVAL;
+               return io_init_fail_req(req, -EINVAL);
        if (!def->iopoll && (ctx->flags & IORING_SETUP_IOPOLL))
-               return -EINVAL;
+               return io_init_fail_req(req, -EINVAL);
 
        if (def->needs_file) {
                struct io_submit_state *state = &ctx->submit_state;
@@ -2263,12 +2270,12 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
 
                req->creds = xa_load(&ctx->personalities, personality);
                if (!req->creds)
-                       return -EINVAL;
+                       return io_init_fail_req(req, -EINVAL);
                get_cred(req->creds);
                ret = security_uring_override_creds(req->creds);
                if (ret) {
                        put_cred(req->creds);
-                       return ret;
+                       return io_init_fail_req(req, ret);
                }
                req->flags |= REQ_F_CREDS;
        }
@@ -2539,7 +2546,7 @@ static bool current_pending_io(void)
 static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
                                          struct io_wait_queue *iowq)
 {
-       int io_wait, ret;
+       int ret;
 
        if (unlikely(READ_ONCE(ctx->check_cq)))
                return 1;
@@ -2557,7 +2564,6 @@ static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
         * can take into account that the task is waiting for IO - turns out
         * to be important for low QD IO.
         */
-       io_wait = current->in_iowait;
        if (current_pending_io())
                current->in_iowait = 1;
        ret = 0;
@@ -2565,7 +2571,7 @@ static inline int io_cqring_wait_schedule(struct io_ring_ctx *ctx,
                schedule();
        else if (!schedule_hrtimeout(&iowq->timeout, HRTIMER_MODE_ABS))
                ret = -ETIME;
-       current->in_iowait = io_wait;
+       current->in_iowait = 0;
        return ret;
 }
 
@@ -2697,13 +2703,9 @@ void io_mem_free(void *ptr)
 
 static void io_pages_free(struct page ***pages, int npages)
 {
-       struct page **page_array;
+       struct page **page_array = *pages;
        int i;
 
-       if (!pages)
-               return;
-
-       page_array = *pages;
        if (!page_array)
                return;
 
@@ -2719,7 +2721,7 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
        struct page **page_array;
        unsigned int nr_pages;
        void *page_addr;
-       int ret, i;
+       int ret, i, pinned;
 
        *npages = 0;
 
@@ -2733,12 +2735,12 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
        if (!page_array)
                return ERR_PTR(-ENOMEM);
 
-       ret = pin_user_pages_fast(uaddr, nr_pages, FOLL_WRITE | FOLL_LONGTERM,
-                                       page_array);
-       if (ret != nr_pages) {
-err:
-               io_pages_free(&page_array, ret > 0 ? ret : 0);
-               return ret < 0 ? ERR_PTR(ret) : ERR_PTR(-EFAULT);
+
+       pinned = pin_user_pages_fast(uaddr, nr_pages, FOLL_WRITE | FOLL_LONGTERM,
+                                    page_array);
+       if (pinned != nr_pages) {
+               ret = (pinned < 0) ? pinned : -EFAULT;
+               goto free_pages;
        }
 
        page_addr = page_address(page_array[0]);
@@ -2752,7 +2754,7 @@ err:
                 * didn't support this feature.
                 */
                if (PageHighMem(page_array[i]))
-                       goto err;
+                       goto free_pages;
 
                /*
                 * No support for discontig pages for now, should either be a
@@ -2761,13 +2763,17 @@ err:
                 * just fail them with EINVAL.
                 */
                if (page_address(page_array[i]) != page_addr)
-                       goto err;
+                       goto free_pages;
                page_addr += PAGE_SIZE;
        }
 
        *pages = page_array;
        *npages = nr_pages;
        return page_to_virt(page_array[0]);
+
+free_pages:
+       io_pages_free(&page_array, pinned > 0 ? pinned : 0);
+       return ERR_PTR(ret);
 }
 
 static void *io_rings_map(struct io_ring_ctx *ctx, unsigned long uaddr,
@@ -2789,14 +2795,15 @@ static void io_rings_free(struct io_ring_ctx *ctx)
        if (!(ctx->flags & IORING_SETUP_NO_MMAP)) {
                io_mem_free(ctx->rings);
                io_mem_free(ctx->sq_sqes);
-               ctx->rings = NULL;
-               ctx->sq_sqes = NULL;
        } else {
                io_pages_free(&ctx->ring_pages, ctx->n_ring_pages);
                ctx->n_ring_pages = 0;
                io_pages_free(&ctx->sqe_pages, ctx->n_sqe_pages);
                ctx->n_sqe_pages = 0;
        }
+
+       ctx->rings = NULL;
+       ctx->sq_sqes = NULL;
 }
 
 void *io_mem_alloc(size_t size)
index 9be42bff936b95750beee16661893d7686a1fcb9..693c26da4ee1a36b4b0acee0b0cc7a7d0cfde3e6 100644 (file)
@@ -199,7 +199,7 @@ void __user *io_buffer_select(struct io_kiocb *req, size_t *len,
 
        bl = io_buffer_get_list(ctx, req->buf_index);
        if (likely(bl)) {
-               if (bl->is_mapped)
+               if (bl->is_buf_ring)
                        ret = io_ring_buffer_select(req, len, bl, issue_flags);
                else
                        ret = io_provided_buffer_select(req, len, bl);
@@ -253,7 +253,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx,
        if (!nbufs)
                return 0;
 
-       if (bl->is_mapped) {
+       if (bl->is_buf_ring) {
                i = bl->buf_ring->tail - bl->head;
                if (bl->is_mmap) {
                        /*
@@ -274,7 +274,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx,
                }
                /* make sure it's seen as empty */
                INIT_LIST_HEAD(&bl->buf_list);
-               bl->is_mapped = 0;
+               bl->is_buf_ring = 0;
                return i;
        }
 
@@ -361,7 +361,7 @@ int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
        if (bl) {
                ret = -EINVAL;
                /* can't use provide/remove buffers command on mapped buffers */
-               if (!bl->is_mapped)
+               if (!bl->is_buf_ring)
                        ret = __io_remove_buffers(ctx, bl, p->nbufs);
        }
        io_ring_submit_unlock(ctx, issue_flags);
@@ -519,7 +519,7 @@ int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
                }
        }
        /* can't add buffers via this command for a mapped buffer ring */
-       if (bl->is_mapped) {
+       if (bl->is_buf_ring) {
                ret = -EINVAL;
                goto err;
        }
@@ -575,7 +575,7 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
        bl->buf_pages = pages;
        bl->buf_nr_pages = nr_pages;
        bl->buf_ring = br;
-       bl->is_mapped = 1;
+       bl->is_buf_ring = 1;
        bl->is_mmap = 0;
        return 0;
 error_unpin:
@@ -642,7 +642,7 @@ static int io_alloc_pbuf_ring(struct io_ring_ctx *ctx,
        }
        ibf->inuse = 1;
        bl->buf_ring = ibf->mem;
-       bl->is_mapped = 1;
+       bl->is_buf_ring = 1;
        bl->is_mmap = 1;
        return 0;
 }
@@ -688,7 +688,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
        bl = io_buffer_get_list(ctx, reg.bgid);
        if (bl) {
                /* if mapped buffer ring OR classic exists, don't allow */
-               if (bl->is_mapped || !list_empty(&bl->buf_list))
+               if (bl->is_buf_ring || !list_empty(&bl->buf_list))
                        return -EEXIST;
        } else {
                free_bl = bl = kzalloc(sizeof(*bl), GFP_KERNEL);
@@ -730,7 +730,7 @@ int io_unregister_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
        bl = io_buffer_get_list(ctx, reg.bgid);
        if (!bl)
                return -ENOENT;
-       if (!bl->is_mapped)
+       if (!bl->is_buf_ring)
                return -EINVAL;
 
        __io_remove_buffers(ctx, bl, -1U);
@@ -757,7 +757,7 @@ int io_register_pbuf_status(struct io_ring_ctx *ctx, void __user *arg)
        bl = io_buffer_get_list(ctx, buf_status.buf_group);
        if (!bl)
                return -ENOENT;
-       if (!bl->is_mapped)
+       if (!bl->is_buf_ring)
                return -EINVAL;
 
        buf_status.head = bl->head;
index 5218bfd79e871eef88d0a34445ee72731320be22..1c7b654ee7263af16e1491934dcbc21744a4a337 100644 (file)
@@ -26,7 +26,7 @@ struct io_buffer_list {
        __u16 mask;
 
        /* ring mapped provided buffers */
-       __u8 is_mapped;
+       __u8 is_buf_ring;
        /* ring mapped provided buffers, but mmap'ed by application */
        __u8 is_mmap;
        /* bl is visible from an RCU point of view for lookup */
index 19451f0dbf813664f9b26e0a27c12b52be080944..1e7665ff6ef70264b26206f99c34aa5516190129 100644 (file)
@@ -326,7 +326,10 @@ int io_send_prep_async(struct io_kiocb *req)
        struct io_async_msghdr *io;
        int ret;
 
-       if (!zc->addr || req_has_async_data(req))
+       if (req_has_async_data(req))
+               return 0;
+       zc->done_io = 0;
+       if (!zc->addr)
                return 0;
        io = io_msg_alloc_async_prep(req);
        if (!io)
@@ -353,8 +356,10 @@ static int io_setup_async_addr(struct io_kiocb *req,
 
 int io_sendmsg_prep_async(struct io_kiocb *req)
 {
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
        int ret;
 
+       sr->done_io = 0;
        if (!io_msg_alloc_async_prep(req))
                return -ENOMEM;
        ret = io_sendmsg_copy_hdr(req, req->async_data);
@@ -608,9 +613,11 @@ static int io_recvmsg_copy_hdr(struct io_kiocb *req,
 
 int io_recvmsg_prep_async(struct io_kiocb *req)
 {
+       struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
        struct io_async_msghdr *iomsg;
        int ret;
 
+       sr->done_io = 0;
        if (!io_msg_alloc_async_prep(req))
                return -ENOMEM;
        iomsg = req->async_data;
index 5f779139cae1849e30f6caaae484c060f938febc..6db1dcb2c7977662dc62127803d6bd1ef5d0b517 100644 (file)
@@ -996,7 +996,6 @@ int io_poll_remove(struct io_kiocb *req, unsigned int issue_flags)
        struct io_hash_bucket *bucket;
        struct io_kiocb *preq;
        int ret2, ret = 0;
-       struct io_tw_state ts = { .locked = true };
 
        io_ring_submit_lock(ctx, issue_flags);
        preq = io_poll_find(ctx, true, &cd, &ctx->cancel_table, &bucket);
@@ -1045,7 +1044,8 @@ found:
 
        req_set_fail(preq);
        io_req_set_res(preq, -ECANCELED, 0);
-       io_req_task_complete(preq, &ts);
+       preq->io_task_work.func = io_req_task_complete;
+       io_req_task_work_add(preq);
 out:
        io_ring_submit_unlock(ctx, issue_flags);
        if (ret < 0) {
index 47e097ab5d7e4f2e0617146cb5c139dc3b92a667..0585ebcc9773d3349b007e6ff436c0320e26356d 100644 (file)
@@ -947,6 +947,8 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
                 */
                if (io_kbuf_recycle(req, issue_flags))
                        rw->len = 0;
+               if (issue_flags & IO_URING_F_MULTISHOT)
+                       return IOU_ISSUE_SKIP_COMPLETE;
                return -EAGAIN;
        }
 
index 363052b4ea76a218f2266f543203631a08d0502b..3983708cef5b431789e0dee10592b73952f7a4e5 100644 (file)
@@ -274,6 +274,10 @@ static int io_sq_thread(void *data)
        char buf[TASK_COMM_LEN];
        DEFINE_WAIT(wait);
 
+       /* offload context creation failed, just exit */
+       if (!current->io_uring)
+               goto err_out;
+
        snprintf(buf, sizeof(buf), "iou-sqp-%d", sqd->task_pid);
        set_task_comm(current, buf);
 
@@ -371,7 +375,7 @@ static int io_sq_thread(void *data)
                atomic_or(IORING_SQ_NEED_WAKEUP, &ctx->rings->sq_flags);
        io_run_task_work();
        mutex_unlock(&sqd->lock);
-
+err_out:
        complete(&sqd->exited);
        do_exit(0);
 }
index 6f851978606d988cfe2486d725d905b558b4a066..77d340666cb95b61a98ccd4717e033f35ec2f9f8 100644 (file)
@@ -125,12 +125,6 @@ static void io_waitid_complete(struct io_kiocb *req, int ret)
 
        lockdep_assert_held(&req->ctx->uring_lock);
 
-       /*
-        * Did cancel find it meanwhile?
-        */
-       if (hlist_unhashed(&req->hash_node))
-               return;
-
        hlist_del_init(&req->hash_node);
 
        ret = io_waitid_finish(req, ret);
@@ -202,6 +196,7 @@ bool io_waitid_remove_all(struct io_ring_ctx *ctx, struct task_struct *task,
        hlist_for_each_entry_safe(req, tmp, &ctx->waitid_list, hash_node) {
                if (!io_match_task_safe(req, task, cancel_all))
                        continue;
+               hlist_del_init(&req->hash_node);
                __io_waitid_cancel(ctx, req);
                found = true;
        }
index 01c4a50d22b2d253d4661a0b7a59a2ec169963fa..45cb1dabce29ae0ab553c6d8f04808fe8e7f3232 100644 (file)
@@ -292,8 +292,7 @@ bool setup_ipc_sysctls(struct ipc_namespace *ns)
                                tbl[i].data = NULL;
                }
 
-               ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set,
-                                                         "kernel", tbl,
+               ns->ipc_sysctls = __register_sysctl_table(&ns->ipc_set, "kernel", tbl,
                                                          ARRAY_SIZE(ipc_sysctls));
        }
        if (!ns->ipc_sysctls) {
index 9ee8da4774656716718909d2c7d93362d9313ecd..a8e34416e960f5c89d90e0e2981154aa206bac42 100644 (file)
@@ -263,6 +263,7 @@ static int cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames,
 static int cpu_map_kthread_run(void *data)
 {
        struct bpf_cpu_map_entry *rcpu = data;
+       unsigned long last_qs = jiffies;
 
        complete(&rcpu->kthread_running);
        set_current_state(TASK_INTERRUPTIBLE);
@@ -288,10 +289,12 @@ static int cpu_map_kthread_run(void *data)
                        if (__ptr_ring_empty(rcpu->queue)) {
                                schedule();
                                sched = 1;
+                               last_qs = jiffies;
                        } else {
                                __set_current_state(TASK_RUNNING);
                        }
                } else {
+                       rcu_softirq_qs_periodic(last_qs);
                        sched = cond_resched();
                }
 
index 77974cea3e69132dee11eb547e386f170442b146..86fe172b5958232ee29d481bf2f9fe60a51c5881 100644 (file)
@@ -1003,8 +1003,7 @@ static int swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool
        dma_addr_t tbl_dma_addr =
                phys_to_dma_unencrypted(dev, pool->start) & boundary_mask;
        unsigned long max_slots = get_max_slots(boundary_mask);
-       unsigned int iotlb_align_mask =
-               dma_get_min_align_mask(dev) | alloc_align_mask;
+       unsigned int iotlb_align_mask = dma_get_min_align_mask(dev);
        unsigned int nslots = nr_slots(alloc_size), stride;
        unsigned int offset = swiotlb_align_offset(dev, orig_addr);
        unsigned int index, slots_checked, count = 0, i;
@@ -1016,18 +1015,29 @@ static int swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool
        BUG_ON(area_index >= pool->nareas);
 
        /*
-        * For allocations of PAGE_SIZE or larger only look for page aligned
-        * allocations.
+        * Historically, swiotlb allocations >= PAGE_SIZE were guaranteed to be
+        * page-aligned in the absence of any other alignment requirements.
+        * 'alloc_align_mask' was later introduced to specify the alignment
+        * explicitly, however this is passed as zero for streaming mappings
+        * and so we preserve the old behaviour there in case any drivers are
+        * relying on it.
         */
-       if (alloc_size >= PAGE_SIZE)
-               iotlb_align_mask |= ~PAGE_MASK;
-       iotlb_align_mask &= ~(IO_TLB_SIZE - 1);
+       if (!alloc_align_mask && !iotlb_align_mask && alloc_size >= PAGE_SIZE)
+               alloc_align_mask = PAGE_SIZE - 1;
+
+       /*
+        * Ensure that the allocation is at least slot-aligned and update
+        * 'iotlb_align_mask' to ignore bits that will be preserved when
+        * offsetting into the allocation.
+        */
+       alloc_align_mask |= (IO_TLB_SIZE - 1);
+       iotlb_align_mask &= ~alloc_align_mask;
 
        /*
         * For mappings with an alignment requirement don't bother looping to
         * unaligned slots once we found an aligned one.
         */
-       stride = (iotlb_align_mask >> IO_TLB_SHIFT) + 1;
+       stride = get_max_slots(max(alloc_align_mask, iotlb_align_mask));
 
        spin_lock_irqsave(&area->lock, flags);
        if (unlikely(nslots > pool->area_nslabs - area->used))
@@ -1037,11 +1047,14 @@ static int swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool
        index = area->index;
 
        for (slots_checked = 0; slots_checked < pool->area_nslabs; ) {
+               phys_addr_t tlb_addr;
+
                slot_index = slot_base + index;
+               tlb_addr = slot_addr(tbl_dma_addr, slot_index);
 
-               if (orig_addr &&
-                   (slot_addr(tbl_dma_addr, slot_index) &
-                    iotlb_align_mask) != (orig_addr & iotlb_align_mask)) {
+               if ((tlb_addr & alloc_align_mask) ||
+                   (orig_addr && (tlb_addr & iotlb_align_mask) !=
+                                 (orig_addr & iotlb_align_mask))) {
                        index = wrap_area_index(pool, index + 1);
                        slots_checked++;
                        continue;
@@ -1677,16 +1690,24 @@ struct page *swiotlb_alloc(struct device *dev, size_t size)
        struct io_tlb_mem *mem = dev->dma_io_tlb_mem;
        struct io_tlb_pool *pool;
        phys_addr_t tlb_addr;
+       unsigned int align;
        int index;
 
        if (!mem)
                return NULL;
 
-       index = swiotlb_find_slots(dev, 0, size, 0, &pool);
+       align = (1 << (get_order(size) + PAGE_SHIFT)) - 1;
+       index = swiotlb_find_slots(dev, 0, size, align, &pool);
        if (index == -1)
                return NULL;
 
        tlb_addr = slot_addr(pool->start, index);
+       if (unlikely(!PAGE_ALIGNED(tlb_addr))) {
+               dev_WARN_ONCE(dev, 1, "Cannot allocate pages from non page-aligned swiotlb addr 0x%pa.\n",
+                             &tlb_addr);
+               swiotlb_release_slots(dev, tlb_addr);
+               return NULL;
+       }
 
        return pfn_to_page(PFN_DOWN(tlb_addr));
 }
index 88cb3c88aaa5c6c1ca271c1cc95dcd60cdd8ca9c..90843cc38588065ee5c52f8549d6a32c69bdf102 100644 (file)
@@ -57,8 +57,14 @@ long syscall_trace_enter(struct pt_regs *regs, long syscall,
        /* Either of the above might have changed the syscall number */
        syscall = syscall_get_nr(current, regs);
 
-       if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT))
+       if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
                trace_sys_enter(regs, syscall);
+               /*
+                * Probes or BPF hooks in the tracepoint may have changed the
+                * system call number as well.
+                */
+               syscall = syscall_get_nr(current, regs);
+       }
 
        syscall_enter_audit(regs, syscall);
 
index fe7a517fc4abbfd62570692bafb6bb88e5a19da1..495b69a71a5d7d21b44cbf4b9a08ec4bd8388625 100644 (file)
@@ -39,7 +39,7 @@ static struct kobj_attribute _name##_attr = __ATTR_RW(_name)
 static ssize_t uevent_seqnum_show(struct kobject *kobj,
                                  struct kobj_attribute *attr, char *buf)
 {
-       return sysfs_emit(buf, "%llu\n", (unsigned long long)uevent_seqnum);
+       return sysfs_emit(buf, "%llu\n", (u64)atomic64_read(&uevent_seqnum));
 }
 KERNEL_ATTR_RO(uevent_seqnum);
 
index 0ea1b2970a23b544cd6a91c0182fa63c9c98a02d..c3ced519e14ba44b15df3d9a42ecb0102b8e3cf6 100644 (file)
@@ -362,8 +362,7 @@ config MODPROBE_PATH
          userspace can still load modules explicitly).
 
 config TRIM_UNUSED_KSYMS
-       bool "Trim unused exported kernel symbols" if EXPERT
-       depends on !COMPILE_TEST
+       bool "Trim unused exported kernel symbols"
        help
          The kernel and some modules make many symbols available for
          other modules to use via EXPORT_SYMBOL() and variants. Depending
index b686ac0345bd92d6b248814f5a82f49a7ad734b3..9e1c9aa399ea9ce38bd46391909022a3f25a7208 100644 (file)
@@ -612,6 +612,17 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
        else if (cb->get_cost)
                flags |= EM_PERF_DOMAIN_ARTIFICIAL;
 
+       /*
+        * EM only supports uW (exception is artificial EM).
+        * Therefore, check and force the drivers to provide
+        * power in uW.
+        */
+       if (!microwatts && !(flags & EM_PERF_DOMAIN_ARTIFICIAL)) {
+               dev_err(dev, "EM: only supports uW power values\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
+
        ret = em_create_pd(dev, nr_states, cb, cpus, flags);
        if (ret)
                goto unlock;
index b663a97f5867a17e558c028f351b5aad28fa256a..d4856ec61570617648c0d07ebabb9f385d24ba77 100644 (file)
@@ -201,7 +201,7 @@ static int __init test_suspend(void)
        }
 
        /* RTCs have initialized by now too ... can we use one? */
-       dev = class_find_device(rtc_class, NULL, NULL, has_wakealarm);
+       dev = class_find_device(&rtc_class, NULL, NULL, has_wakealarm);
        if (dev) {
                rtc = rtc_class_open(dev_name(dev));
                put_device(dev);
index a000bef511772b4a10613d16c5ea135686f90033..ca5146006b94c6742ac770323aaf123688d65572 100644 (file)
@@ -3269,6 +3269,21 @@ static int __init keep_bootcon_setup(char *str)
 
 early_param("keep_bootcon", keep_bootcon_setup);
 
+static int console_call_setup(struct console *newcon, char *options)
+{
+       int err;
+
+       if (!newcon->setup)
+               return 0;
+
+       /* Synchronize with possible boot console. */
+       console_lock();
+       err = newcon->setup(newcon, options);
+       console_unlock();
+
+       return err;
+}
+
 /*
  * This is called by register_console() to try to match
  * the newly registered console with any of the ones selected
@@ -3304,8 +3319,8 @@ static int try_enable_preferred_console(struct console *newcon,
                        if (_braille_register_console(newcon, c))
                                return 0;
 
-                       if (newcon->setup &&
-                           (err = newcon->setup(newcon, c->options)) != 0)
+                       err = console_call_setup(newcon, c->options);
+                       if (err)
                                return err;
                }
                newcon->flags |= CON_ENABLED;
@@ -3331,7 +3346,7 @@ static void try_enable_default_console(struct console *newcon)
        if (newcon->index < 0)
                newcon->index = 0;
 
-       if (newcon->setup && newcon->setup(newcon, NULL) != 0)
+       if (console_call_setup(newcon, NULL) != 0)
                return;
 
        newcon->flags |= CON_ENABLED;
index d44efa0d06112a8b4f022fe450aa7725987dca9b..7019a40457a6dafd14803896d3cb68a1e26bb2d4 100644 (file)
@@ -6647,7 +6647,9 @@ static void __sched notrace __schedule(unsigned int sched_mode)
         *     if (signal_pending_state())          if (p->state & @state)
         *
         * Also, the membarrier system call requires a full memory barrier
-        * after coming from user-space, before storing to rq->curr.
+        * after coming from user-space, before storing to rq->curr; this
+        * barrier matches a full barrier in the proximity of the membarrier
+        * system call exit.
         */
        rq_lock(rq, &rf);
        smp_mb__after_spinlock();
@@ -6718,12 +6720,20 @@ static void __sched notrace __schedule(unsigned int sched_mode)
                 *
                 * Here are the schemes providing that barrier on the
                 * various architectures:
-                * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC.
-                *   switch_mm() rely on membarrier_arch_switch_mm() on PowerPC.
+                * - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC,
+                *   RISC-V.  switch_mm() relies on membarrier_arch_switch_mm()
+                *   on PowerPC and on RISC-V.
                 * - finish_lock_switch() for weakly-ordered
                 *   architectures where spin_unlock is a full barrier,
                 * - switch_to() for arm64 (weakly-ordered, spin_unlock
                 *   is a RELEASE barrier),
+                *
+                * The barrier matches a full barrier in the proximity of
+                * the membarrier system call entry.
+                *
+                * On RISC-V, this barrier pairing is also needed for the
+                * SYNC_CORE command when switching between processes, cf.
+                * the inline comments in membarrier_arch_switch_mm().
                 */
                ++*switch_count;
 
index 4e715b9b278e7fd7fbea70110f5a829635a4bc01..809194cd779f42fa57759b731c52685a14744f83 100644 (file)
@@ -254,7 +254,7 @@ static int membarrier_global_expedited(void)
                return 0;
 
        /*
-        * Matches memory barriers around rq->curr modification in
+        * Matches memory barriers after rq->curr modification in
         * scheduler.
         */
        smp_mb();       /* system call entry is not a mb. */
@@ -304,7 +304,7 @@ static int membarrier_global_expedited(void)
 
        /*
         * Memory barrier on the caller thread _after_ we finished
-        * waiting for the last IPI. Matches memory barriers around
+        * waiting for the last IPI. Matches memory barriers before
         * rq->curr modification in scheduler.
         */
        smp_mb();       /* exit from system call is not a mb */
@@ -324,6 +324,7 @@ static int membarrier_private_expedited(int flags, int cpu_id)
                      MEMBARRIER_STATE_PRIVATE_EXPEDITED_SYNC_CORE_READY))
                        return -EPERM;
                ipi_func = ipi_sync_core;
+               prepare_sync_core_cmd(mm);
        } else if (flags == MEMBARRIER_FLAG_RSEQ) {
                if (!IS_ENABLED(CONFIG_RSEQ))
                        return -EINVAL;
@@ -343,8 +344,12 @@ static int membarrier_private_expedited(int flags, int cpu_id)
                return 0;
 
        /*
-        * Matches memory barriers around rq->curr modification in
+        * Matches memory barriers after rq->curr modification in
         * scheduler.
+        *
+        * On RISC-V, this barrier pairing is also needed for the
+        * SYNC_CORE command when switching between processes, cf.
+        * the inline comments in membarrier_arch_switch_mm().
         */
        smp_mb();       /* system call entry is not a mb. */
 
@@ -420,7 +425,7 @@ out:
 
        /*
         * Memory barrier on the caller thread _after_ we finished
-        * waiting for the last IPI. Matches memory barriers around
+        * waiting for the last IPI. Matches memory barriers before
         * rq->curr modification in scheduler.
         */
        smp_mb();       /* exit from system call is not a mb */
index 157f7ce2942d26a6401bc3c8f0dd2077ad69ff5d..81cc974913bb901ec9319d836d09fbb24bf60c56 100644 (file)
@@ -1710,9 +1710,9 @@ static struct ctl_table kern_table[] = {
        {
                .procname       = "ftrace_dump_on_oops",
                .data           = &ftrace_dump_on_oops,
-               .maxlen         = sizeof(int),
+               .maxlen         = MAX_TRACER_SIZE,
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dostring,
        },
        {
                .procname       = "traceoff_on_warning",
index 4657cb8e8b1f9482b9e20109335b168720eabe77..5abfa43906732b7868585b3c48ccadde47bc8c03 100644 (file)
@@ -134,7 +134,7 @@ static struct class_interface alarmtimer_rtc_interface = {
 
 static int alarmtimer_rtc_interface_setup(void)
 {
-       alarmtimer_rtc_interface.class = rtc_class;
+       alarmtimer_rtc_interface.class = &rtc_class;
        return class_interface_register(&alarmtimer_rtc_interface);
 }
 static void alarmtimer_rtc_interface_remove(void)
index e69e75d3858c21d9ce8bf8f60afbe7750bda3f0d..dee29f1f5b75f3c059f831a2cd1c86cd8907fef9 100644 (file)
@@ -642,7 +642,8 @@ trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer)
         * the base lock:
         */
        if (base->is_idle) {
-               WARN_ON_ONCE(!(timer->flags & TIMER_PINNED));
+               WARN_ON_ONCE(!(timer->flags & TIMER_PINNED ||
+                              tick_nohz_full_cpu(base->cpu)));
                wake_up_nohz_cpu(base->cpu);
        }
 }
@@ -2292,6 +2293,13 @@ static inline u64 __get_next_timer_interrupt(unsigned long basej, u64 basem,
                 */
                if (!base_local->is_idle && time_after(nextevt, basej + 1)) {
                        base_local->is_idle = true;
+                       /*
+                        * Global timers queued locally while running in a task
+                        * in nohz_full mode need a self-IPI to kick reprogramming
+                        * in IRQ tail.
+                        */
+                       if (tick_nohz_full_cpu(base_local->cpu))
+                               base_global->is_idle = true;
                        trace_timer_base_idle(true, base_local->cpu);
                }
                *idle = base_local->is_idle;
@@ -2364,6 +2372,8 @@ void timer_clear_idle(void)
         * path. Required for BASE_LOCAL only.
         */
        __this_cpu_write(timer_bases[BASE_LOCAL].is_idle, false);
+       if (tick_nohz_full_cpu(smp_processor_id()))
+               __this_cpu_write(timer_bases[BASE_GLOBAL].is_idle, false);
        trace_timer_base_idle(false, smp_processor_id());
 
        /* Activate without holding the timer_base->lock */
index 611cd904f0357e08fffca607ba1de0b51a109479..c63a0afdcebed5c1e8b7bff161647d194f810ef2 100644 (file)
@@ -1038,8 +1038,15 @@ void tmigr_handle_remote(void)
         * in tmigr_handle_remote_up() anyway. Keep this check to speed up the
         * return when nothing has to be done.
         */
-       if (!tmigr_check_migrator(tmc->tmgroup, tmc->childmask))
-               return;
+       if (!tmigr_check_migrator(tmc->tmgroup, tmc->childmask)) {
+               /*
+                * If this CPU was an idle migrator, make sure to clear its wakeup
+                * value so it won't chase timers that have already expired elsewhere.
+                * This avoids endless requeue from tmigr_new_timer().
+                */
+               if (READ_ONCE(tmc->wakeup) == KTIME_MAX)
+                       return;
+       }
 
        data.now = get_jiffies_update(&data.basej);
 
index 83ba342aef31f7d919f4c24a73d2c4cea76be137..da1710499698b0ed56ea89183d18befda56c0243 100644 (file)
@@ -1160,7 +1160,7 @@ __ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)
  * Search a given @hash to see if a given instruction pointer (@ip)
  * exists in it.
  *
- * Returns the entry that holds the @ip if found. NULL otherwise.
+ * Returns: the entry that holds the @ip if found. NULL otherwise.
  */
 struct ftrace_func_entry *
 ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)
@@ -1282,7 +1282,7 @@ static void free_ftrace_hash_rcu(struct ftrace_hash *hash)
 
 /**
  * ftrace_free_filter - remove all filters for an ftrace_ops
- * @ops - the ops to remove the filters from
+ * @ops: the ops to remove the filters from
  */
 void ftrace_free_filter(struct ftrace_ops *ops)
 {
@@ -1587,7 +1587,7 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end)
  * @end: end of range to search (inclusive). @end points to the last byte
  *     to check.
  *
- * Returns rec->ip if the related ftrace location is a least partly within
+ * Returns: rec->ip if the related ftrace location is a least partly within
  * the given address range. That is, the first address of the instruction
  * that is either a NOP or call to the function tracer. It checks the ftrace
  * internal tables to determine if the address belongs or not.
@@ -1607,9 +1607,10 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)
  * ftrace_location - return the ftrace location
  * @ip: the instruction pointer to check
  *
- * If @ip matches the ftrace location, return @ip.
- * If @ip matches sym+0, return sym's ftrace location.
- * Otherwise, return 0.
+ * Returns:
+ * * If @ip matches the ftrace location, return @ip.
+ * * If @ip matches sym+0, return sym's ftrace location.
+ * * Otherwise, return 0.
  */
 unsigned long ftrace_location(unsigned long ip)
 {
@@ -1639,7 +1640,7 @@ out:
  * @start: start of range to search
  * @end: end of range to search (inclusive). @end points to the last byte to check.
  *
- * Returns 1 if @start and @end contains a ftrace location.
+ * Returns: 1 if @start and @end contains a ftrace location.
  * That is, the instruction that is either a NOP or call to
  * the function tracer. It checks the ftrace internal tables to
  * determine if the address belongs or not.
@@ -2574,7 +2575,7 @@ static void call_direct_funcs(unsigned long ip, unsigned long pip,
  * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS
  * is not set, then it wants to convert to the normal callback.
  *
- * Returns the address of the trampoline to set to
+ * Returns: the address of the trampoline to set to
  */
 unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec)
 {
@@ -2615,7 +2616,7 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec)
  * a function that saves all the regs. Basically the '_EN' version
  * represents the current state of the function.
  *
- * Returns the address of the trampoline that is currently being called
+ * Returns: the address of the trampoline that is currently being called
  */
 unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec)
 {
@@ -2719,7 +2720,7 @@ struct ftrace_rec_iter {
 /**
  * ftrace_rec_iter_start - start up iterating over traced functions
  *
- * Returns an iterator handle that is used to iterate over all
+ * Returns: an iterator handle that is used to iterate over all
  * the records that represent address locations where functions
  * are traced.
  *
@@ -2751,7 +2752,7 @@ struct ftrace_rec_iter *ftrace_rec_iter_start(void)
  * ftrace_rec_iter_next - get the next record to process.
  * @iter: The handle to the iterator.
  *
- * Returns the next iterator after the given iterator @iter.
+ * Returns: the next iterator after the given iterator @iter.
  */
 struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter)
 {
@@ -2776,7 +2777,7 @@ struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter)
  * ftrace_rec_iter_record - get the record at the iterator location
  * @iter: The current iterator location
  *
- * Returns the record that the current @iter is at.
+ * Returns: the record that the current @iter is at.
  */
 struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter)
 {
@@ -4010,6 +4011,8 @@ ftrace_avail_addrs_open(struct inode *inode, struct file *file)
  * ftrace_notrace_write() if @flag has FTRACE_ITER_NOTRACE set.
  * tracing_lseek() should be used as the lseek routine, and
  * release must call ftrace_regex_release().
+ *
+ * Returns: 0 on success or a negative errno value on failure
  */
 int
 ftrace_regex_open(struct ftrace_ops *ops, int flag,
@@ -4626,7 +4629,7 @@ struct ftrace_func_mapper {
 /**
  * allocate_ftrace_func_mapper - allocate a new ftrace_func_mapper
  *
- * Returns a ftrace_func_mapper descriptor that can be used to map ips to data.
+ * Returns: a ftrace_func_mapper descriptor that can be used to map ips to data.
  */
 struct ftrace_func_mapper *allocate_ftrace_func_mapper(void)
 {
@@ -4646,7 +4649,7 @@ struct ftrace_func_mapper *allocate_ftrace_func_mapper(void)
  * @mapper: The mapper that has the ip maps
  * @ip: the instruction pointer to find the data for
  *
- * Returns the data mapped to @ip if found otherwise NULL. The return
+ * Returns: the data mapped to @ip if found otherwise NULL. The return
  * is actually the address of the mapper data pointer. The address is
  * returned for use cases where the data is no bigger than a long, and
  * the user can use the data pointer as its data instead of having to
@@ -4672,7 +4675,7 @@ void **ftrace_func_mapper_find_ip(struct ftrace_func_mapper *mapper,
  * @ip: The instruction pointer address to map @data to
  * @data: The data to map to @ip
  *
- * Returns 0 on success otherwise an error.
+ * Returns: 0 on success otherwise an error.
  */
 int ftrace_func_mapper_add_ip(struct ftrace_func_mapper *mapper,
                              unsigned long ip, void *data)
@@ -4701,7 +4704,7 @@ int ftrace_func_mapper_add_ip(struct ftrace_func_mapper *mapper,
  * @mapper: The mapper that has the ip maps
  * @ip: The instruction pointer address to remove the data from
  *
- * Returns the data if it is found, otherwise NULL.
+ * Returns: the data if it is found, otherwise NULL.
  * Note, if the data pointer is used as the data itself, (see
  * ftrace_func_mapper_find_ip(), then the return value may be meaningless,
  * if the data pointer was set to zero.
@@ -5625,10 +5628,10 @@ EXPORT_SYMBOL_GPL(modify_ftrace_direct);
 
 /**
  * ftrace_set_filter_ip - set a function to filter on in ftrace by address
- * @ops - the ops to set the filter with
- * @ip - the address to add to or remove from the filter.
- * @remove - non zero to remove the ip from the filter
- * @reset - non zero to reset all filters before applying this filter.
+ * @ops: the ops to set the filter with
+ * @ip: the address to add to or remove from the filter.
+ * @remove: non zero to remove the ip from the filter
+ * @reset: non zero to reset all filters before applying this filter.
  *
  * Filters denote which functions should be enabled when tracing is enabled
  * If @ip is NULL, it fails to update filter.
@@ -5647,11 +5650,11 @@ EXPORT_SYMBOL_GPL(ftrace_set_filter_ip);
 
 /**
  * ftrace_set_filter_ips - set functions to filter on in ftrace by addresses
- * @ops - the ops to set the filter with
- * @ips - the array of addresses to add to or remove from the filter.
- * @cnt - the number of addresses in @ips
- * @remove - non zero to remove ips from the filter
- * @reset - non zero to reset all filters before applying this filter.
+ * @ops: the ops to set the filter with
+ * @ips: the array of addresses to add to or remove from the filter.
+ * @cnt: the number of addresses in @ips
+ * @remove: non zero to remove ips from the filter
+ * @reset: non zero to reset all filters before applying this filter.
  *
  * Filters denote which functions should be enabled when tracing is enabled
  * If @ips array or any ip specified within is NULL , it fails to update filter.
@@ -5670,7 +5673,7 @@ EXPORT_SYMBOL_GPL(ftrace_set_filter_ips);
 
 /**
  * ftrace_ops_set_global_filter - setup ops to use global filters
- * @ops - the ops which will use the global filters
+ * @ops: the ops which will use the global filters
  *
  * ftrace users who need global function trace filtering should call this.
  * It can set the global filter only if ops were not initialized before.
@@ -5694,10 +5697,10 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
 
 /**
  * ftrace_set_filter - set a function to filter on in ftrace
- * @ops - the ops to set the filter with
- * @buf - the string that holds the function filter text.
- * @len - the length of the string.
- * @reset - non zero to reset all filters before applying this filter.
+ * @ops: the ops to set the filter with
+ * @buf: the string that holds the function filter text.
+ * @len: the length of the string.
+ * @reset: non-zero to reset all filters before applying this filter.
  *
  * Filters denote which functions should be enabled when tracing is enabled.
  * If @buf is NULL and reset is set, all functions will be enabled for tracing.
@@ -5716,10 +5719,10 @@ EXPORT_SYMBOL_GPL(ftrace_set_filter);
 
 /**
  * ftrace_set_notrace - set a function to not trace in ftrace
- * @ops - the ops to set the notrace filter with
- * @buf - the string that holds the function notrace text.
- * @len - the length of the string.
- * @reset - non zero to reset all filters before applying this filter.
+ * @ops: the ops to set the notrace filter with
+ * @buf: the string that holds the function notrace text.
+ * @len: the length of the string.
+ * @reset: non-zero to reset all filters before applying this filter.
  *
  * Notrace Filters denote which functions should not be enabled when tracing
  * is enabled. If @buf is NULL and reset is set, all functions will be enabled
@@ -5738,9 +5741,9 @@ int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
 EXPORT_SYMBOL_GPL(ftrace_set_notrace);
 /**
  * ftrace_set_global_filter - set a function to filter on with global tracers
- * @buf - the string that holds the function filter text.
- * @len - the length of the string.
- * @reset - non zero to reset all filters before applying this filter.
+ * @buf: the string that holds the function filter text.
+ * @len: the length of the string.
+ * @reset: non-zero to reset all filters before applying this filter.
  *
  * Filters denote which functions should be enabled when tracing is enabled.
  * If @buf is NULL and reset is set, all functions will be enabled for tracing.
@@ -5753,9 +5756,9 @@ EXPORT_SYMBOL_GPL(ftrace_set_global_filter);
 
 /**
  * ftrace_set_global_notrace - set a function to not trace with global tracers
- * @buf - the string that holds the function notrace text.
- * @len - the length of the string.
- * @reset - non zero to reset all filters before applying this filter.
+ * @buf: the string that holds the function notrace text.
+ * @len: the length of the string.
+ * @reset: non-zero to reset all filters before applying this filter.
  *
  * Notrace Filters denote which functions should not be enabled when tracing
  * is enabled. If @buf is NULL and reset is set, all functions will be enabled
@@ -7443,7 +7446,7 @@ NOKPROBE_SYMBOL(ftrace_ops_assist_func);
  * have its own recursion protection, then it should call the
  * ftrace_ops_assist_func() instead.
  *
- * Returns the function that the trampoline should call for @ops.
+ * Returns: the function that the trampoline should call for @ops.
  */
 ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops)
 {
@@ -7897,7 +7900,7 @@ void ftrace_kill(void)
 /**
  * ftrace_is_dead - Test if ftrace is dead or not.
  *
- * Returns 1 if ftrace is "dead", zero otherwise.
+ * Returns: 1 if ftrace is "dead", zero otherwise.
  */
 int ftrace_is_dead(void)
 {
@@ -8142,8 +8145,7 @@ static int kallsyms_callback(void *data, const char *name, unsigned long addr)
  * @addrs array, which needs to be big enough to store at least @cnt
  * addresses.
  *
- * This function returns 0 if all provided symbols are found,
- * -ESRCH otherwise.
+ * Returns: 0 if all provided symbols are found, -ESRCH otherwise.
  */
 int ftrace_lookup_symbols(const char **sorted_syms, size_t cnt, unsigned long *addrs)
 {
index 09df645ab9c75fc98dda1f92435df438da4c0347..25476ead681b8411f41d713a77603cdf0653b4ad 100644 (file)
@@ -384,6 +384,7 @@ struct rb_irq_work {
        struct irq_work                 work;
        wait_queue_head_t               waiters;
        wait_queue_head_t               full_waiters;
+       atomic_t                        seq;
        bool                            waiters_pending;
        bool                            full_waiters_pending;
        bool                            wakeup_full;
@@ -753,6 +754,9 @@ static void rb_wake_up_waiters(struct irq_work *work)
 {
        struct rb_irq_work *rbwork = container_of(work, struct rb_irq_work, work);
 
+       /* For waiters waiting for the first wake up */
+       (void)atomic_fetch_inc_release(&rbwork->seq);
+
        wake_up_all(&rbwork->waiters);
        if (rbwork->full_waiters_pending || rbwork->wakeup_full) {
                /* Only cpu_buffer sets the above flags */
@@ -881,20 +885,21 @@ rb_wait_cond(struct rb_irq_work *rbwork, struct trace_buffer *buffer,
        return false;
 }
 
+struct rb_wait_data {
+       struct rb_irq_work              *irq_work;
+       int                             seq;
+};
+
 /*
  * The default wait condition for ring_buffer_wait() is to just to exit the
  * wait loop the first time it is woken up.
  */
 static bool rb_wait_once(void *data)
 {
-       long *once = data;
-
-       /* wait_event() actually calls this twice before scheduling*/
-       if (*once > 1)
-               return true;
+       struct rb_wait_data *rdata = data;
+       struct rb_irq_work *rbwork = rdata->irq_work;
 
-       (*once)++;
-       return false;
+       return atomic_read_acquire(&rbwork->seq) != rdata->seq;
 }
 
 /**
@@ -915,14 +920,9 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full,
        struct ring_buffer_per_cpu *cpu_buffer;
        struct wait_queue_head *waitq;
        struct rb_irq_work *rbwork;
-       long once = 0;
+       struct rb_wait_data rdata;
        int ret = 0;
 
-       if (!cond) {
-               cond = rb_wait_once;
-               data = &once;
-       }
-
        /*
         * Depending on what the caller is waiting for, either any
         * data in any cpu buffer, or a specific buffer, put the
@@ -944,6 +944,14 @@ int ring_buffer_wait(struct trace_buffer *buffer, int cpu, int full,
        else
                waitq = &rbwork->waiters;
 
+       /* Set up to exit loop as soon as it is woken */
+       if (!cond) {
+               cond = rb_wait_once;
+               rdata.irq_work = rbwork;
+               rdata.seq = atomic_read_acquire(&rbwork->seq);
+               data = &rdata;
+       }
+
        ret = wait_event_interruptible((*waitq),
                                rb_wait_cond(rbwork, buffer, cpu, full, cond, data));
 
@@ -1515,7 +1523,8 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
 
                list_add(&bpage->list, pages);
 
-               page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu), mflags,
+               page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu),
+                                       mflags | __GFP_ZERO,
                                        cpu_buffer->buffer->subbuf_order);
                if (!page)
                        goto free_pages;
@@ -1600,7 +1609,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
 
        cpu_buffer->reader_page = bpage;
 
-       page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL, cpu_buffer->buffer->subbuf_order);
+       page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL | __GFP_ZERO,
+                               cpu_buffer->buffer->subbuf_order);
        if (!page)
                goto fail_free_reader;
        bpage->page = page_address(page);
@@ -4380,7 +4390,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
        cpu_buffer = iter->cpu_buffer;
        reader = cpu_buffer->reader_page;
        head_page = cpu_buffer->head_page;
-       commit_page = cpu_buffer->commit_page;
+       commit_page = READ_ONCE(cpu_buffer->commit_page);
        commit_ts = commit_page->page->time_stamp;
 
        /*
@@ -5568,7 +5578,8 @@ ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
        if (bpage->data)
                goto out;
 
-       page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL | __GFP_NORETRY,
+       page = alloc_pages_node(cpu_to_node(cpu),
+                               GFP_KERNEL | __GFP_NORETRY | __GFP_ZERO,
                                cpu_buffer->buffer->subbuf_order);
        if (!page) {
                kfree(bpage);
index ab4c1a1fbda8604bb75f3d34d09504d6ca3fff62..233d1af39fffe29b459c09e9a5e0a82fa07e992a 100644 (file)
@@ -13,7 +13,7 @@
  *  Copyright (C) 2004 Nadia Yvette Chambers
  */
 #include <linux/ring_buffer.h>
-#include <generated/utsrelease.h>
+#include <linux/utsname.h>
 #include <linux/stacktrace.h>
 #include <linux/writeback.h>
 #include <linux/kallsyms.h>
@@ -39,7 +39,6 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/panic_notifier.h>
-#include <linux/kmemleak.h>
 #include <linux/poll.h>
 #include <linux/nmi.h>
 #include <linux/fs.h>
@@ -105,7 +104,7 @@ dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
  * tracing is active, only save the comm when a trace event
  * occurred.
  */
-static DEFINE_PER_CPU(bool, trace_taskinfo_save);
+DEFINE_PER_CPU(bool, trace_taskinfo_save);
 
 /*
  * Kill all tracing for good (never come back).
@@ -131,9 +130,12 @@ cpumask_var_t __read_mostly        tracing_buffer_mask;
  * /proc/sys/kernel/ftrace_dump_on_oops
  * Set 1 if you want to dump buffers of all CPUs
  * Set 2 if you want to dump the buffer of the CPU that triggered oops
+ * Set instance name if you want to dump the specific trace instance
+ * Multiple instance dump is also supported, and instances are seperated
+ * by commas.
  */
-
-enum ftrace_dump_mode ftrace_dump_on_oops;
+/* Set to string format zero to disable by default */
+char ftrace_dump_on_oops[MAX_TRACER_SIZE] = "0";
 
 /* When set, tracing will stop when a WARN*() is hit */
 int __disable_trace_on_warning;
@@ -179,7 +181,6 @@ static void ftrace_trace_userstack(struct trace_array *tr,
                                   struct trace_buffer *buffer,
                                   unsigned int trace_ctx);
 
-#define MAX_TRACER_SIZE                100
 static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
 static char *default_bootup_tracer;
 
@@ -202,19 +203,33 @@ static int __init set_cmdline_ftrace(char *str)
 }
 __setup("ftrace=", set_cmdline_ftrace);
 
+int ftrace_dump_on_oops_enabled(void)
+{
+       if (!strcmp("0", ftrace_dump_on_oops))
+               return 0;
+       else
+               return 1;
+}
+
 static int __init set_ftrace_dump_on_oops(char *str)
 {
-       if (*str++ != '=' || !*str || !strcmp("1", str)) {
-               ftrace_dump_on_oops = DUMP_ALL;
+       if (!*str) {
+               strscpy(ftrace_dump_on_oops, "1", MAX_TRACER_SIZE);
                return 1;
        }
 
-       if (!strcmp("orig_cpu", str) || !strcmp("2", str)) {
-               ftrace_dump_on_oops = DUMP_ORIG;
-                return 1;
-        }
+       if (*str == ',') {
+               strscpy(ftrace_dump_on_oops, "1", MAX_TRACER_SIZE);
+               strscpy(ftrace_dump_on_oops + 1, str, MAX_TRACER_SIZE - 1);
+               return 1;
+       }
+
+       if (*str++ == '=') {
+               strscpy(ftrace_dump_on_oops, str, MAX_TRACER_SIZE);
+               return 1;
+       }
 
-        return 0;
+       return 0;
 }
 __setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
 
@@ -1301,6 +1316,50 @@ static void free_snapshot(struct trace_array *tr)
        tr->allocated_snapshot = false;
 }
 
+static int tracing_arm_snapshot_locked(struct trace_array *tr)
+{
+       int ret;
+
+       lockdep_assert_held(&trace_types_lock);
+
+       spin_lock(&tr->snapshot_trigger_lock);
+       if (tr->snapshot == UINT_MAX) {
+               spin_unlock(&tr->snapshot_trigger_lock);
+               return -EBUSY;
+       }
+
+       tr->snapshot++;
+       spin_unlock(&tr->snapshot_trigger_lock);
+
+       ret = tracing_alloc_snapshot_instance(tr);
+       if (ret) {
+               spin_lock(&tr->snapshot_trigger_lock);
+               tr->snapshot--;
+               spin_unlock(&tr->snapshot_trigger_lock);
+       }
+
+       return ret;
+}
+
+int tracing_arm_snapshot(struct trace_array *tr)
+{
+       int ret;
+
+       mutex_lock(&trace_types_lock);
+       ret = tracing_arm_snapshot_locked(tr);
+       mutex_unlock(&trace_types_lock);
+
+       return ret;
+}
+
+void tracing_disarm_snapshot(struct trace_array *tr)
+{
+       spin_lock(&tr->snapshot_trigger_lock);
+       if (!WARN_ON(!tr->snapshot))
+               tr->snapshot--;
+       spin_unlock(&tr->snapshot_trigger_lock);
+}
+
 /**
  * tracing_alloc_snapshot - allocate snapshot buffer.
  *
@@ -1374,10 +1433,6 @@ int tracing_snapshot_cond_enable(struct trace_array *tr, void *cond_data,
 
        mutex_lock(&trace_types_lock);
 
-       ret = tracing_alloc_snapshot_instance(tr);
-       if (ret)
-               goto fail_unlock;
-
        if (tr->current_trace->use_max_tr) {
                ret = -EBUSY;
                goto fail_unlock;
@@ -1396,6 +1451,10 @@ int tracing_snapshot_cond_enable(struct trace_array *tr, void *cond_data,
                goto fail_unlock;
        }
 
+       ret = tracing_arm_snapshot_locked(tr);
+       if (ret)
+               goto fail_unlock;
+
        local_irq_disable();
        arch_spin_lock(&tr->max_lock);
        tr->cond_snapshot = cond_snapshot;
@@ -1440,6 +1499,8 @@ int tracing_snapshot_cond_disable(struct trace_array *tr)
        arch_spin_unlock(&tr->max_lock);
        local_irq_enable();
 
+       tracing_disarm_snapshot(tr);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(tracing_snapshot_cond_disable);
@@ -1482,6 +1543,7 @@ int tracing_snapshot_cond_disable(struct trace_array *tr)
 }
 EXPORT_SYMBOL_GPL(tracing_snapshot_cond_disable);
 #define free_snapshot(tr)      do { } while (0)
+#define tracing_arm_snapshot_locked(tr) ({ -EBUSY; })
 #endif /* CONFIG_TRACER_SNAPSHOT */
 
 void tracer_tracing_off(struct trace_array *tr)
@@ -2320,98 +2382,6 @@ void tracing_reset_all_online_cpus(void)
        mutex_unlock(&trace_types_lock);
 }
 
-/*
- * The tgid_map array maps from pid to tgid; i.e. the value stored at index i
- * is the tgid last observed corresponding to pid=i.
- */
-static int *tgid_map;
-
-/* The maximum valid index into tgid_map. */
-static size_t tgid_map_max;
-
-#define SAVED_CMDLINES_DEFAULT 128
-#define NO_CMDLINE_MAP UINT_MAX
-/*
- * Preemption must be disabled before acquiring trace_cmdline_lock.
- * The various trace_arrays' max_lock must be acquired in a context
- * where interrupt is disabled.
- */
-static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
-struct saved_cmdlines_buffer {
-       unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
-       unsigned *map_cmdline_to_pid;
-       unsigned cmdline_num;
-       int cmdline_idx;
-       char saved_cmdlines[];
-};
-static struct saved_cmdlines_buffer *savedcmd;
-
-static inline char *get_saved_cmdlines(int idx)
-{
-       return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN];
-}
-
-static inline void set_cmdline(int idx, const char *cmdline)
-{
-       strncpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN);
-}
-
-static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s)
-{
-       int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN);
-
-       kfree(s->map_cmdline_to_pid);
-       kmemleak_free(s);
-       free_pages((unsigned long)s, order);
-}
-
-static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val)
-{
-       struct saved_cmdlines_buffer *s;
-       struct page *page;
-       int orig_size, size;
-       int order;
-
-       /* Figure out how much is needed to hold the given number of cmdlines */
-       orig_size = sizeof(*s) + val * TASK_COMM_LEN;
-       order = get_order(orig_size);
-       size = 1 << (order + PAGE_SHIFT);
-       page = alloc_pages(GFP_KERNEL, order);
-       if (!page)
-               return NULL;
-
-       s = page_address(page);
-       kmemleak_alloc(s, size, 1, GFP_KERNEL);
-       memset(s, 0, sizeof(*s));
-
-       /* Round up to actual allocation */
-       val = (size - sizeof(*s)) / TASK_COMM_LEN;
-       s->cmdline_num = val;
-
-       s->map_cmdline_to_pid = kmalloc_array(val,
-                                             sizeof(*s->map_cmdline_to_pid),
-                                             GFP_KERNEL);
-       if (!s->map_cmdline_to_pid) {
-               free_saved_cmdlines_buffer(s);
-               return NULL;
-       }
-
-       s->cmdline_idx = 0;
-       memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP,
-              sizeof(s->map_pid_to_cmdline));
-       memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP,
-              val * sizeof(*s->map_cmdline_to_pid));
-
-       return s;
-}
-
-static int trace_create_savedcmd(void)
-{
-       savedcmd = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT);
-
-       return savedcmd ? 0 : -ENOMEM;
-}
-
 int is_tracing_stopped(void)
 {
        return global_trace.stop_count;
@@ -2504,201 +2474,6 @@ void tracing_stop(void)
        return tracing_stop_tr(&global_trace);
 }
 
-static int trace_save_cmdline(struct task_struct *tsk)
-{
-       unsigned tpid, idx;
-
-       /* treat recording of idle task as a success */
-       if (!tsk->pid)
-               return 1;
-
-       tpid = tsk->pid & (PID_MAX_DEFAULT - 1);
-
-       /*
-        * It's not the end of the world if we don't get
-        * the lock, but we also don't want to spin
-        * nor do we want to disable interrupts,
-        * so if we miss here, then better luck next time.
-        *
-        * This is called within the scheduler and wake up, so interrupts
-        * had better been disabled and run queue lock been held.
-        */
-       lockdep_assert_preemption_disabled();
-       if (!arch_spin_trylock(&trace_cmdline_lock))
-               return 0;
-
-       idx = savedcmd->map_pid_to_cmdline[tpid];
-       if (idx == NO_CMDLINE_MAP) {
-               idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num;
-
-               savedcmd->map_pid_to_cmdline[tpid] = idx;
-               savedcmd->cmdline_idx = idx;
-       }
-
-       savedcmd->map_cmdline_to_pid[idx] = tsk->pid;
-       set_cmdline(idx, tsk->comm);
-
-       arch_spin_unlock(&trace_cmdline_lock);
-
-       return 1;
-}
-
-static void __trace_find_cmdline(int pid, char comm[])
-{
-       unsigned map;
-       int tpid;
-
-       if (!pid) {
-               strcpy(comm, "<idle>");
-               return;
-       }
-
-       if (WARN_ON_ONCE(pid < 0)) {
-               strcpy(comm, "<XXX>");
-               return;
-       }
-
-       tpid = pid & (PID_MAX_DEFAULT - 1);
-       map = savedcmd->map_pid_to_cmdline[tpid];
-       if (map != NO_CMDLINE_MAP) {
-               tpid = savedcmd->map_cmdline_to_pid[map];
-               if (tpid == pid) {
-                       strscpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN);
-                       return;
-               }
-       }
-       strcpy(comm, "<...>");
-}
-
-void trace_find_cmdline(int pid, char comm[])
-{
-       preempt_disable();
-       arch_spin_lock(&trace_cmdline_lock);
-
-       __trace_find_cmdline(pid, comm);
-
-       arch_spin_unlock(&trace_cmdline_lock);
-       preempt_enable();
-}
-
-static int *trace_find_tgid_ptr(int pid)
-{
-       /*
-        * Pairs with the smp_store_release in set_tracer_flag() to ensure that
-        * if we observe a non-NULL tgid_map then we also observe the correct
-        * tgid_map_max.
-        */
-       int *map = smp_load_acquire(&tgid_map);
-
-       if (unlikely(!map || pid > tgid_map_max))
-               return NULL;
-
-       return &map[pid];
-}
-
-int trace_find_tgid(int pid)
-{
-       int *ptr = trace_find_tgid_ptr(pid);
-
-       return ptr ? *ptr : 0;
-}
-
-static int trace_save_tgid(struct task_struct *tsk)
-{
-       int *ptr;
-
-       /* treat recording of idle task as a success */
-       if (!tsk->pid)
-               return 1;
-
-       ptr = trace_find_tgid_ptr(tsk->pid);
-       if (!ptr)
-               return 0;
-
-       *ptr = tsk->tgid;
-       return 1;
-}
-
-static bool tracing_record_taskinfo_skip(int flags)
-{
-       if (unlikely(!(flags & (TRACE_RECORD_CMDLINE | TRACE_RECORD_TGID))))
-               return true;
-       if (!__this_cpu_read(trace_taskinfo_save))
-               return true;
-       return false;
-}
-
-/**
- * tracing_record_taskinfo - record the task info of a task
- *
- * @task:  task to record
- * @flags: TRACE_RECORD_CMDLINE for recording comm
- *         TRACE_RECORD_TGID for recording tgid
- */
-void tracing_record_taskinfo(struct task_struct *task, int flags)
-{
-       bool done;
-
-       if (tracing_record_taskinfo_skip(flags))
-               return;
-
-       /*
-        * Record as much task information as possible. If some fail, continue
-        * to try to record the others.
-        */
-       done = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(task);
-       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(task);
-
-       /* If recording any information failed, retry again soon. */
-       if (!done)
-               return;
-
-       __this_cpu_write(trace_taskinfo_save, false);
-}
-
-/**
- * tracing_record_taskinfo_sched_switch - record task info for sched_switch
- *
- * @prev: previous task during sched_switch
- * @next: next task during sched_switch
- * @flags: TRACE_RECORD_CMDLINE for recording comm
- *         TRACE_RECORD_TGID for recording tgid
- */
-void tracing_record_taskinfo_sched_switch(struct task_struct *prev,
-                                         struct task_struct *next, int flags)
-{
-       bool done;
-
-       if (tracing_record_taskinfo_skip(flags))
-               return;
-
-       /*
-        * Record as much task information as possible. If some fail, continue
-        * to try to record the others.
-        */
-       done  = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(prev);
-       done &= !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(next);
-       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(prev);
-       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(next);
-
-       /* If recording any information failed, retry again soon. */
-       if (!done)
-               return;
-
-       __this_cpu_write(trace_taskinfo_save, false);
-}
-
-/* Helpers to record a specific task information */
-void tracing_record_cmdline(struct task_struct *task)
-{
-       tracing_record_taskinfo(task, TRACE_RECORD_CMDLINE);
-}
-
-void tracing_record_tgid(struct task_struct *task)
-{
-       tracing_record_taskinfo(task, TRACE_RECORD_TGID);
-}
-
 /*
  * Several functions return TRACE_TYPE_PARTIAL_LINE if the trace_seq
  * overflowed, and TRACE_TYPE_HANDLED otherwise. This helper function
@@ -4389,7 +4164,7 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
        get_total_entries(buf, &total, &entries);
 
        seq_printf(m, "# %s latency trace v1.1.5 on %s\n",
-                  name, UTS_RELEASE);
+                  name, init_utsname()->release);
        seq_puts(m, "# -----------------------------------"
                 "---------------------------------\n");
        seq_printf(m, "# latency: %lu us, #%lu/%lu, CPU#%d |"
@@ -5457,8 +5232,6 @@ int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
 
 int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
 {
-       int *map;
-
        if ((mask == TRACE_ITER_RECORD_TGID) ||
            (mask == TRACE_ITER_RECORD_CMD))
                lockdep_assert_held(&event_mutex);
@@ -5481,20 +5254,8 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
                trace_event_enable_cmd_record(enabled);
 
        if (mask == TRACE_ITER_RECORD_TGID) {
-               if (!tgid_map) {
-                       tgid_map_max = pid_max;
-                       map = kvcalloc(tgid_map_max + 1, sizeof(*tgid_map),
-                                      GFP_KERNEL);
 
-                       /*
-                        * Pairs with smp_load_acquire() in
-                        * trace_find_tgid_ptr() to ensure that if it observes
-                        * the tgid_map we just allocated then it also observes
-                        * the corresponding tgid_map_max value.
-                        */
-                       smp_store_release(&tgid_map, map);
-               }
-               if (!tgid_map) {
+               if (trace_alloc_tgid_map() < 0) {
                        tr->trace_flags &= ~TRACE_ITER_RECORD_TGID;
                        return -ENOMEM;
                }
@@ -5938,207 +5699,6 @@ static const struct file_operations tracing_readme_fops = {
        .llseek         = generic_file_llseek,
 };
 
-static void *saved_tgids_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       int pid = ++(*pos);
-
-       return trace_find_tgid_ptr(pid);
-}
-
-static void *saved_tgids_start(struct seq_file *m, loff_t *pos)
-{
-       int pid = *pos;
-
-       return trace_find_tgid_ptr(pid);
-}
-
-static void saved_tgids_stop(struct seq_file *m, void *v)
-{
-}
-
-static int saved_tgids_show(struct seq_file *m, void *v)
-{
-       int *entry = (int *)v;
-       int pid = entry - tgid_map;
-       int tgid = *entry;
-
-       if (tgid == 0)
-               return SEQ_SKIP;
-
-       seq_printf(m, "%d %d\n", pid, tgid);
-       return 0;
-}
-
-static const struct seq_operations tracing_saved_tgids_seq_ops = {
-       .start          = saved_tgids_start,
-       .stop           = saved_tgids_stop,
-       .next           = saved_tgids_next,
-       .show           = saved_tgids_show,
-};
-
-static int tracing_saved_tgids_open(struct inode *inode, struct file *filp)
-{
-       int ret;
-
-       ret = tracing_check_open_get_tr(NULL);
-       if (ret)
-               return ret;
-
-       return seq_open(filp, &tracing_saved_tgids_seq_ops);
-}
-
-
-static const struct file_operations tracing_saved_tgids_fops = {
-       .open           = tracing_saved_tgids_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       unsigned int *ptr = v;
-
-       if (*pos || m->count)
-               ptr++;
-
-       (*pos)++;
-
-       for (; ptr < &savedcmd->map_cmdline_to_pid[savedcmd->cmdline_num];
-            ptr++) {
-               if (*ptr == -1 || *ptr == NO_CMDLINE_MAP)
-                       continue;
-
-               return ptr;
-       }
-
-       return NULL;
-}
-
-static void *saved_cmdlines_start(struct seq_file *m, loff_t *pos)
-{
-       void *v;
-       loff_t l = 0;
-
-       preempt_disable();
-       arch_spin_lock(&trace_cmdline_lock);
-
-       v = &savedcmd->map_cmdline_to_pid[0];
-       while (l <= *pos) {
-               v = saved_cmdlines_next(m, v, &l);
-               if (!v)
-                       return NULL;
-       }
-
-       return v;
-}
-
-static void saved_cmdlines_stop(struct seq_file *m, void *v)
-{
-       arch_spin_unlock(&trace_cmdline_lock);
-       preempt_enable();
-}
-
-static int saved_cmdlines_show(struct seq_file *m, void *v)
-{
-       char buf[TASK_COMM_LEN];
-       unsigned int *pid = v;
-
-       __trace_find_cmdline(*pid, buf);
-       seq_printf(m, "%d %s\n", *pid, buf);
-       return 0;
-}
-
-static const struct seq_operations tracing_saved_cmdlines_seq_ops = {
-       .start          = saved_cmdlines_start,
-       .next           = saved_cmdlines_next,
-       .stop           = saved_cmdlines_stop,
-       .show           = saved_cmdlines_show,
-};
-
-static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp)
-{
-       int ret;
-
-       ret = tracing_check_open_get_tr(NULL);
-       if (ret)
-               return ret;
-
-       return seq_open(filp, &tracing_saved_cmdlines_seq_ops);
-}
-
-static const struct file_operations tracing_saved_cmdlines_fops = {
-       .open           = tracing_saved_cmdlines_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static ssize_t
-tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf,
-                                size_t cnt, loff_t *ppos)
-{
-       char buf[64];
-       int r;
-
-       preempt_disable();
-       arch_spin_lock(&trace_cmdline_lock);
-       r = scnprintf(buf, sizeof(buf), "%u\n", savedcmd->cmdline_num);
-       arch_spin_unlock(&trace_cmdline_lock);
-       preempt_enable();
-
-       return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-}
-
-static int tracing_resize_saved_cmdlines(unsigned int val)
-{
-       struct saved_cmdlines_buffer *s, *savedcmd_temp;
-
-       s = allocate_cmdlines_buffer(val);
-       if (!s)
-               return -ENOMEM;
-
-       preempt_disable();
-       arch_spin_lock(&trace_cmdline_lock);
-       savedcmd_temp = savedcmd;
-       savedcmd = s;
-       arch_spin_unlock(&trace_cmdline_lock);
-       preempt_enable();
-       free_saved_cmdlines_buffer(savedcmd_temp);
-
-       return 0;
-}
-
-static ssize_t
-tracing_saved_cmdlines_size_write(struct file *filp, const char __user *ubuf,
-                                 size_t cnt, loff_t *ppos)
-{
-       unsigned long val;
-       int ret;
-
-       ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
-       if (ret)
-               return ret;
-
-       /* must have at least 1 entry or less than PID_MAX_DEFAULT */
-       if (!val || val > PID_MAX_DEFAULT)
-               return -EINVAL;
-
-       ret = tracing_resize_saved_cmdlines((unsigned int)val);
-       if (ret < 0)
-               return ret;
-
-       *ppos += cnt;
-
-       return cnt;
-}
-
-static const struct file_operations tracing_saved_cmdlines_size_fops = {
-       .open           = tracing_open_generic,
-       .read           = tracing_saved_cmdlines_size_read,
-       .write          = tracing_saved_cmdlines_size_write,
-};
-
 #ifdef CONFIG_TRACE_EVAL_MAP_FILE
 static union trace_eval_map_item *
 update_eval_map(union trace_eval_map_item *ptr)
@@ -6615,11 +6175,12 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)
                 */
                synchronize_rcu();
                free_snapshot(tr);
+               tracing_disarm_snapshot(tr);
        }
 
-       if (t->use_max_tr && !tr->allocated_snapshot) {
-               ret = tracing_alloc_snapshot_instance(tr);
-               if (ret < 0)
+       if (!had_max_tr && t->use_max_tr) {
+               ret = tracing_arm_snapshot_locked(tr);
+               if (ret)
                        goto out;
        }
 #else
@@ -6628,8 +6189,13 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)
 
        if (t->init) {
                ret = tracer_init(t, tr);
-               if (ret)
+               if (ret) {
+#ifdef CONFIG_TRACER_MAX_TRACE
+                       if (t->use_max_tr)
+                               tracing_disarm_snapshot(tr);
+#endif
                        goto out;
+               }
        }
 
        tr->current_trace = t;
@@ -7731,10 +7297,11 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
                if (tr->allocated_snapshot)
                        ret = resize_buffer_duplicate_size(&tr->max_buffer,
                                        &tr->array_buffer, iter->cpu_file);
-               else
-                       ret = tracing_alloc_snapshot_instance(tr);
-               if (ret < 0)
+
+               ret = tracing_arm_snapshot_locked(tr);
+               if (ret)
                        break;
+
                /* Now, we're going to swap */
                if (iter->cpu_file == RING_BUFFER_ALL_CPUS) {
                        local_irq_disable();
@@ -7744,6 +7311,7 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
                        smp_call_function_single(iter->cpu_file, tracing_swap_cpu_buffer,
                                                 (void *)tr, 1);
                }
+               tracing_disarm_snapshot(tr);
                break;
        default:
                if (tr->allocated_snapshot) {
@@ -8875,8 +8443,13 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
 
        ops = param ? &snapshot_count_probe_ops :  &snapshot_probe_ops;
 
-       if (glob[0] == '!')
-               return unregister_ftrace_function_probe_func(glob+1, tr, ops);
+       if (glob[0] == '!') {
+               ret = unregister_ftrace_function_probe_func(glob+1, tr, ops);
+               if (!ret)
+                       tracing_disarm_snapshot(tr);
+
+               return ret;
+       }
 
        if (!param)
                goto out_reg;
@@ -8895,12 +8468,13 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
                return ret;
 
  out_reg:
-       ret = tracing_alloc_snapshot_instance(tr);
+       ret = tracing_arm_snapshot(tr);
        if (ret < 0)
                goto out;
 
        ret = register_ftrace_function_probe(glob, tr, ops, count);
-
+       if (ret < 0)
+               tracing_disarm_snapshot(tr);
  out:
        return ret < 0 ? ret : 0;
 }
@@ -9707,7 +9281,9 @@ trace_array_create_systems(const char *name, const char *systems)
        raw_spin_lock_init(&tr->start_lock);
 
        tr->max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
-
+#ifdef CONFIG_TRACER_MAX_TRACE
+       spin_lock_init(&tr->snapshot_trigger_lock);
+#endif
        tr->current_trace = &nop_trace;
 
        INIT_LIST_HEAD(&tr->systems);
@@ -10272,14 +9848,14 @@ static struct notifier_block trace_die_notifier = {
 static int trace_die_panic_handler(struct notifier_block *self,
                                unsigned long ev, void *unused)
 {
-       if (!ftrace_dump_on_oops)
+       if (!ftrace_dump_on_oops_enabled())
                return NOTIFY_DONE;
 
        /* The die notifier requires DIE_OOPS to trigger */
        if (self == &trace_die_notifier && ev != DIE_OOPS)
                return NOTIFY_DONE;
 
-       ftrace_dump(ftrace_dump_on_oops);
+       ftrace_dump(DUMP_PARAM);
 
        return NOTIFY_DONE;
 }
@@ -10320,12 +9896,12 @@ trace_printk_seq(struct trace_seq *s)
        trace_seq_init(s);
 }
 
-void trace_init_global_iter(struct trace_iterator *iter)
+static void trace_init_iter(struct trace_iterator *iter, struct trace_array *tr)
 {
-       iter->tr = &global_trace;
+       iter->tr = tr;
        iter->trace = iter->tr->current_trace;
        iter->cpu_file = RING_BUFFER_ALL_CPUS;
-       iter->array_buffer = &global_trace.array_buffer;
+       iter->array_buffer = &tr->array_buffer;
 
        if (iter->trace && iter->trace->open)
                iter->trace->open(iter);
@@ -10345,22 +9921,19 @@ void trace_init_global_iter(struct trace_iterator *iter)
        iter->fmt_size = STATIC_FMT_BUF_SIZE;
 }
 
-void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
+void trace_init_global_iter(struct trace_iterator *iter)
+{
+       trace_init_iter(iter, &global_trace);
+}
+
+static void ftrace_dump_one(struct trace_array *tr, enum ftrace_dump_mode dump_mode)
 {
        /* use static because iter can be a bit big for the stack */
        static struct trace_iterator iter;
-       static atomic_t dump_running;
-       struct trace_array *tr = &global_trace;
        unsigned int old_userobj;
        unsigned long flags;
        int cnt = 0, cpu;
 
-       /* Only allow one dump user at a time. */
-       if (atomic_inc_return(&dump_running) != 1) {
-               atomic_dec(&dump_running);
-               return;
-       }
-
        /*
         * Always turn off tracing when we dump.
         * We don't need to show trace output of what happens
@@ -10369,12 +9942,12 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
         * If the user does a sysrq-z, then they can re-enable
         * tracing with echo 1 > tracing_on.
         */
-       tracing_off();
+       tracer_tracing_off(tr);
 
        local_irq_save(flags);
 
        /* Simulate the iterator */
-       trace_init_global_iter(&iter);
+       trace_init_iter(&iter, tr);
 
        for_each_tracing_cpu(cpu) {
                atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
@@ -10385,21 +9958,15 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
        /* don't look at user memory in panic mode */
        tr->trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
 
-       switch (oops_dump_mode) {
-       case DUMP_ALL:
-               iter.cpu_file = RING_BUFFER_ALL_CPUS;
-               break;
-       case DUMP_ORIG:
+       if (dump_mode == DUMP_ORIG)
                iter.cpu_file = raw_smp_processor_id();
-               break;
-       case DUMP_NONE:
-               goto out_enable;
-       default:
-               printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
+       else
                iter.cpu_file = RING_BUFFER_ALL_CPUS;
-       }
 
-       printk(KERN_TRACE "Dumping ftrace buffer:\n");
+       if (tr == &global_trace)
+               printk(KERN_TRACE "Dumping ftrace buffer:\n");
+       else
+               printk(KERN_TRACE "Dumping ftrace instance %s buffer:\n", tr->name);
 
        /* Did function tracer already get disabled? */
        if (ftrace_is_dead()) {
@@ -10441,15 +10008,84 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
        else
                printk(KERN_TRACE "---------------------------------\n");
 
- out_enable:
        tr->trace_flags |= old_userobj;
 
        for_each_tracing_cpu(cpu) {
                atomic_dec(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
        }
-       atomic_dec(&dump_running);
        local_irq_restore(flags);
 }
+
+static void ftrace_dump_by_param(void)
+{
+       bool first_param = true;
+       char dump_param[MAX_TRACER_SIZE];
+       char *buf, *token, *inst_name;
+       struct trace_array *tr;
+
+       strscpy(dump_param, ftrace_dump_on_oops, MAX_TRACER_SIZE);
+       buf = dump_param;
+
+       while ((token = strsep(&buf, ",")) != NULL) {
+               if (first_param) {
+                       first_param = false;
+                       if (!strcmp("0", token))
+                               continue;
+                       else if (!strcmp("1", token)) {
+                               ftrace_dump_one(&global_trace, DUMP_ALL);
+                               continue;
+                       }
+                       else if (!strcmp("2", token) ||
+                         !strcmp("orig_cpu", token)) {
+                               ftrace_dump_one(&global_trace, DUMP_ORIG);
+                               continue;
+                       }
+               }
+
+               inst_name = strsep(&token, "=");
+               tr = trace_array_find(inst_name);
+               if (!tr) {
+                       printk(KERN_TRACE "Instance %s not found\n", inst_name);
+                       continue;
+               }
+
+               if (token && (!strcmp("2", token) ||
+                         !strcmp("orig_cpu", token)))
+                       ftrace_dump_one(tr, DUMP_ORIG);
+               else
+                       ftrace_dump_one(tr, DUMP_ALL);
+       }
+}
+
+void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
+{
+       static atomic_t dump_running;
+
+       /* Only allow one dump user at a time. */
+       if (atomic_inc_return(&dump_running) != 1) {
+               atomic_dec(&dump_running);
+               return;
+       }
+
+       switch (oops_dump_mode) {
+       case DUMP_ALL:
+               ftrace_dump_one(&global_trace, DUMP_ALL);
+               break;
+       case DUMP_ORIG:
+               ftrace_dump_one(&global_trace, DUMP_ORIG);
+               break;
+       case DUMP_PARAM:
+               ftrace_dump_by_param();
+               break;
+       case DUMP_NONE:
+               break;
+       default:
+               printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
+               ftrace_dump_one(&global_trace, DUMP_ALL);
+       }
+
+       atomic_dec(&dump_running);
+}
 EXPORT_SYMBOL_GPL(ftrace_dump);
 
 #define WRITE_BUFSIZE  4096
@@ -10677,7 +10313,9 @@ __init static int tracer_alloc_buffers(void)
        global_trace.current_trace = &nop_trace;
 
        global_trace.max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
-
+#ifdef CONFIG_TRACER_MAX_TRACE
+       spin_lock_init(&global_trace.snapshot_trigger_lock);
+#endif
        ftrace_init_global_array_ops(&global_trace);
 
        init_trace_flags_index(&global_trace);
@@ -10714,7 +10352,7 @@ __init static int tracer_alloc_buffers(void)
 out_free_pipe_cpumask:
        free_cpumask_var(global_trace.pipe_cpumask);
 out_free_savedcmd:
-       free_saved_cmdlines_buffer(savedcmd);
+       trace_free_saved_cmdlines_buffer();
 out_free_temp_buffer:
        ring_buffer_free(temp_buffer);
 out_rm_hp_state:
index 00f873910c5d9c835b335ba2731c1062c7427057..64450615ca0cbfa71ffe0e9fb077b556dab2aa2d 100644 (file)
@@ -334,8 +334,8 @@ struct trace_array {
         */
        struct array_buffer     max_buffer;
        bool                    allocated_snapshot;
-#endif
-#ifdef CONFIG_TRACER_MAX_TRACE
+       spinlock_t              snapshot_trigger_lock;
+       unsigned int            snapshot;
        unsigned long           max_latency;
 #ifdef CONFIG_FSNOTIFY
        struct dentry           *d_max_latency;
@@ -1375,6 +1375,16 @@ static inline void trace_buffer_unlock_commit(struct trace_array *tr,
        trace_buffer_unlock_commit_regs(tr, buffer, event, trace_ctx, NULL);
 }
 
+DECLARE_PER_CPU(bool, trace_taskinfo_save);
+int trace_save_cmdline(struct task_struct *tsk);
+int trace_create_savedcmd(void);
+int trace_alloc_tgid_map(void);
+void trace_free_saved_cmdlines_buffer(void);
+
+extern const struct file_operations tracing_saved_cmdlines_fops;
+extern const struct file_operations tracing_saved_tgids_fops;
+extern const struct file_operations tracing_saved_cmdlines_size_fops;
+
 DECLARE_PER_CPU(struct ring_buffer_event *, trace_buffered_event);
 DECLARE_PER_CPU(int, trace_buffered_event_cnt);
 void trace_buffered_event_disable(void);
@@ -1973,12 +1983,16 @@ static inline void trace_event_eval_update(struct trace_eval_map **map, int len)
 #ifdef CONFIG_TRACER_SNAPSHOT
 void tracing_snapshot_instance(struct trace_array *tr);
 int tracing_alloc_snapshot_instance(struct trace_array *tr);
+int tracing_arm_snapshot(struct trace_array *tr);
+void tracing_disarm_snapshot(struct trace_array *tr);
 #else
 static inline void tracing_snapshot_instance(struct trace_array *tr) { }
 static inline int tracing_alloc_snapshot_instance(struct trace_array *tr)
 {
        return 0;
 }
+static inline int tracing_arm_snapshot(struct trace_array *tr) { return 0; }
+static inline void tracing_disarm_snapshot(struct trace_array *tr) { }
 #endif
 
 #ifdef CONFIG_PREEMPT_TRACER
index 54d5fa35c90abf77d2dc268bfaa37c54a8fd90dd..811b08439406a04cb96fe2f5b51a01d0233ee1a4 100644 (file)
@@ -92,7 +92,6 @@ static void trace_do_benchmark(void)
        bm_total += delta;
        bm_totalsq += delta * delta;
 
-
        if (bm_cnt > 1) {
                /*
                 * Apply Welford's method to calculate standard deviation:
@@ -105,7 +104,7 @@ static void trace_do_benchmark(void)
                stddev = 0;
 
        delta = bm_total;
-       do_div(delta, bm_cnt);
+       delta = div64_u64(delta, bm_cnt);
        avg = delta;
 
        if (stddev > 0) {
@@ -127,7 +126,7 @@ static void trace_do_benchmark(void)
                        seed = stddev;
                        if (!last_seed)
                                break;
-                       do_div(seed, last_seed);
+                       seed = div64_u64(seed, last_seed);
                        seed += last_seed;
                        do_div(seed, 2);
                } while (i++ < 10 && last_seed != seed);
index b33c3861fbbbf303e78f740a0fcc41caa2a77d77..4bec043c8690d382f8c493721e0f6e7a1ce1a91a 100644 (file)
@@ -597,20 +597,12 @@ out:
        return ret;
 }
 
-/**
- * unregister_trigger - Generic event_command @unreg implementation
- * @glob: The raw string used to register the trigger
- * @test: Trigger-specific data used to find the trigger to remove
- * @file: The trace_event_file associated with the event
- *
- * Common implementation for event trigger unregistration.
- *
- * Usually used directly as the @unreg method in event command
- * implementations.
+/*
+ * True if the trigger was found and unregistered, else false.
  */
-static void unregister_trigger(char *glob,
-                              struct event_trigger_data *test,
-                              struct trace_event_file *file)
+static bool try_unregister_trigger(char *glob,
+                                  struct event_trigger_data *test,
+                                  struct trace_event_file *file)
 {
        struct event_trigger_data *data = NULL, *iter;
 
@@ -626,8 +618,32 @@ static void unregister_trigger(char *glob,
                }
        }
 
-       if (data && data->ops->free)
-               data->ops->free(data);
+       if (data) {
+               if (data->ops->free)
+                       data->ops->free(data);
+
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * unregister_trigger - Generic event_command @unreg implementation
+ * @glob: The raw string used to register the trigger
+ * @test: Trigger-specific data used to find the trigger to remove
+ * @file: The trace_event_file associated with the event
+ *
+ * Common implementation for event trigger unregistration.
+ *
+ * Usually used directly as the @unreg method in event command
+ * implementations.
+ */
+static void unregister_trigger(char *glob,
+                              struct event_trigger_data *test,
+                              struct trace_event_file *file)
+{
+       try_unregister_trigger(glob, test, file);
 }
 
 /*
@@ -1470,12 +1486,23 @@ register_snapshot_trigger(char *glob,
                          struct event_trigger_data *data,
                          struct trace_event_file *file)
 {
-       int ret = tracing_alloc_snapshot_instance(file->tr);
+       int ret = tracing_arm_snapshot(file->tr);
 
        if (ret < 0)
                return ret;
 
-       return register_trigger(glob, data, file);
+       ret = register_trigger(glob, data, file);
+       if (ret < 0)
+               tracing_disarm_snapshot(file->tr);
+       return ret;
+}
+
+static void unregister_snapshot_trigger(char *glob,
+                                       struct event_trigger_data *data,
+                                       struct trace_event_file *file)
+{
+       if (try_unregister_trigger(glob, data, file))
+               tracing_disarm_snapshot(file->tr);
 }
 
 static int
@@ -1510,7 +1537,7 @@ static struct event_command trigger_snapshot_cmd = {
        .trigger_type           = ETT_SNAPSHOT,
        .parse                  = event_trigger_parse,
        .reg                    = register_snapshot_trigger,
-       .unreg                  = unregister_trigger,
+       .unreg                  = unregister_snapshot_trigger,
        .get_trigger_ops        = snapshot_get_trigger_ops,
        .set_filter             = set_trigger_filter,
 };
index e76f5e1efdf2dacdcf4415e308a8ba050c3be062..70d428c394b68dee53cc26a08c101945ef8587cd 100644 (file)
@@ -34,7 +34,8 @@
 
 /* Limit how long of an event name plus args within the subsystem. */
 #define MAX_EVENT_DESC 512
-#define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
+#define EVENT_NAME(user_event) ((user_event)->reg_name)
+#define EVENT_TP_NAME(user_event) ((user_event)->tracepoint.name)
 #define MAX_FIELD_ARRAY_SIZE 1024
 
 /*
  * allows isolation for events by various means.
  */
 struct user_event_group {
-       char            *system_name;
-       struct          hlist_node node;
-       struct          mutex reg_mutex;
+       char                    *system_name;
+       char                    *system_multi_name;
+       struct hlist_node       node;
+       struct mutex            reg_mutex;
        DECLARE_HASHTABLE(register_table, 8);
+       /* ID that moves forward within the group for multi-event names */
+       u64                     multi_id;
 };
 
 /* Group for init_user_ns mapping, top-most group */
@@ -78,6 +82,7 @@ static unsigned int current_user_events;
  */
 struct user_event {
        struct user_event_group         *group;
+       char                            *reg_name;
        struct tracepoint               tracepoint;
        struct trace_event_call         call;
        struct trace_event_class        class;
@@ -127,6 +132,8 @@ struct user_event_enabler {
 
 #define ENABLE_BIT(e) ((int)((e)->values & ENABLE_VAL_BIT_MASK))
 
+#define EVENT_MULTI_FORMAT(f) ((f) & USER_EVENT_REG_MULTI_FORMAT)
+
 /* Used for asynchronous faulting in of pages */
 struct user_event_enabler_fault {
        struct work_struct              work;
@@ -202,6 +209,8 @@ static struct user_event_mm *user_event_mm_get(struct user_event_mm *mm);
 static struct user_event_mm *user_event_mm_get_all(struct user_event *user);
 static void user_event_mm_put(struct user_event_mm *mm);
 static int destroy_user_event(struct user_event *user);
+static bool user_fields_match(struct user_event *user, int argc,
+                             const char **argv);
 
 static u32 user_event_key(char *name)
 {
@@ -328,6 +337,7 @@ out:
 static void user_event_group_destroy(struct user_event_group *group)
 {
        kfree(group->system_name);
+       kfree(group->system_multi_name);
        kfree(group);
 }
 
@@ -346,6 +356,11 @@ static char *user_event_group_system_name(void)
        return system_name;
 }
 
+static char *user_event_group_system_multi_name(void)
+{
+       return kstrdup(USER_EVENTS_MULTI_SYSTEM, GFP_KERNEL);
+}
+
 static struct user_event_group *current_user_event_group(void)
 {
        return init_group;
@@ -365,6 +380,11 @@ static struct user_event_group *user_event_group_create(void)
        if (!group->system_name)
                goto error;
 
+       group->system_multi_name = user_event_group_system_multi_name();
+
+       if (!group->system_multi_name)
+               goto error;
+
        mutex_init(&group->reg_mutex);
        hash_init(group->register_table);
 
@@ -1480,6 +1500,11 @@ static int destroy_user_event(struct user_event *user)
        hash_del(&user->node);
 
        user_event_destroy_validators(user);
+
+       /* If we have different names, both must be freed */
+       if (EVENT_NAME(user) != EVENT_TP_NAME(user))
+               kfree(EVENT_TP_NAME(user));
+
        kfree(user->call.print_fmt);
        kfree(EVENT_NAME(user));
        kfree(user);
@@ -1493,17 +1518,36 @@ static int destroy_user_event(struct user_event *user)
 }
 
 static struct user_event *find_user_event(struct user_event_group *group,
-                                         char *name, u32 *outkey)
+                                         char *name, int argc, const char **argv,
+                                         u32 flags, u32 *outkey)
 {
        struct user_event *user;
        u32 key = user_event_key(name);
 
        *outkey = key;
 
-       hash_for_each_possible(group->register_table, user, node, key)
-               if (!strcmp(EVENT_NAME(user), name))
+       hash_for_each_possible(group->register_table, user, node, key) {
+               /*
+                * Single-format events shouldn't return multi-format
+                * events. Callers expect the underlying tracepoint to match
+                * the name exactly in these cases. Only check like-formats.
+                */
+               if (EVENT_MULTI_FORMAT(flags) != EVENT_MULTI_FORMAT(user->reg_flags))
+                       continue;
+
+               if (strcmp(EVENT_NAME(user), name))
+                       continue;
+
+               if (user_fields_match(user, argc, argv))
                        return user_event_get(user);
 
+               /* Scan others if this is a multi-format event */
+               if (EVENT_MULTI_FORMAT(flags))
+                       continue;
+
+               return ERR_PTR(-EADDRINUSE);
+       }
+
        return NULL;
 }
 
@@ -1860,6 +1904,9 @@ static bool user_fields_match(struct user_event *user, int argc,
        struct list_head *head = &user->fields;
        int i = 0;
 
+       if (argc == 0)
+               return list_empty(head);
+
        list_for_each_entry_reverse(field, head, link) {
                if (!user_field_match(field, argc, argv, &i))
                        return false;
@@ -1877,13 +1924,15 @@ static bool user_event_match(const char *system, const char *event,
        struct user_event *user = container_of(ev, struct user_event, devent);
        bool match;
 
-       match = strcmp(EVENT_NAME(user), event) == 0 &&
-               (!system || strcmp(system, USER_EVENTS_SYSTEM) == 0);
+       match = strcmp(EVENT_NAME(user), event) == 0;
+
+       if (match && system) {
+               match = strcmp(system, user->group->system_name) == 0 ||
+                       strcmp(system, user->group->system_multi_name) == 0;
+       }
 
-       if (match && argc > 0)
+       if (match)
                match = user_fields_match(user, argc, argv);
-       else if (match && argc == 0)
-               match = list_empty(&user->fields);
 
        return match;
 }
@@ -1913,6 +1962,33 @@ static int user_event_trace_register(struct user_event *user)
        return ret;
 }
 
+static int user_event_set_tp_name(struct user_event *user)
+{
+       lockdep_assert_held(&user->group->reg_mutex);
+
+       if (EVENT_MULTI_FORMAT(user->reg_flags)) {
+               char *multi_name;
+
+               multi_name = kasprintf(GFP_KERNEL_ACCOUNT, "%s.%llx",
+                                      user->reg_name, user->group->multi_id);
+
+               if (!multi_name)
+                       return -ENOMEM;
+
+               user->call.name = multi_name;
+               user->tracepoint.name = multi_name;
+
+               /* Inc to ensure unique multi-event name next time */
+               user->group->multi_id++;
+       } else {
+               /* Non Multi-format uses register name */
+               user->call.name = user->reg_name;
+               user->tracepoint.name = user->reg_name;
+       }
+
+       return 0;
+}
+
 /*
  * Parses the event name, arguments and flags then registers if successful.
  * The name buffer lifetime is owned by this method for success cases only.
@@ -1922,11 +1998,11 @@ static int user_event_parse(struct user_event_group *group, char *name,
                            char *args, char *flags,
                            struct user_event **newuser, int reg_flags)
 {
-       int ret;
-       u32 key;
        struct user_event *user;
+       char **argv = NULL;
        int argc = 0;
-       char **argv;
+       int ret;
+       u32 key;
 
        /* Currently don't support any text based flags */
        if (flags != NULL)
@@ -1935,41 +2011,34 @@ static int user_event_parse(struct user_event_group *group, char *name,
        if (!user_event_capable(reg_flags))
                return -EPERM;
 
+       if (args) {
+               argv = argv_split(GFP_KERNEL, args, &argc);
+
+               if (!argv)
+                       return -ENOMEM;
+       }
+
        /* Prevent dyn_event from racing */
        mutex_lock(&event_mutex);
-       user = find_user_event(group, name, &key);
+       user = find_user_event(group, name, argc, (const char **)argv,
+                              reg_flags, &key);
        mutex_unlock(&event_mutex);
 
-       if (user) {
-               if (args) {
-                       argv = argv_split(GFP_KERNEL, args, &argc);
-                       if (!argv) {
-                               ret = -ENOMEM;
-                               goto error;
-                       }
+       if (argv)
+               argv_free(argv);
 
-                       ret = user_fields_match(user, argc, (const char **)argv);
-                       argv_free(argv);
-
-               } else
-                       ret = list_empty(&user->fields);
-
-               if (ret) {
-                       *newuser = user;
-                       /*
-                        * Name is allocated by caller, free it since it already exists.
-                        * Caller only worries about failure cases for freeing.
-                        */
-                       kfree(name);
-               } else {
-                       ret = -EADDRINUSE;
-                       goto error;
-               }
+       if (IS_ERR(user))
+               return PTR_ERR(user);
+
+       if (user) {
+               *newuser = user;
+               /*
+                * Name is allocated by caller, free it since it already exists.
+                * Caller only worries about failure cases for freeing.
+                */
+               kfree(name);
 
                return 0;
-error:
-               user_event_put(user, false);
-               return ret;
        }
 
        user = kzalloc(sizeof(*user), GFP_KERNEL_ACCOUNT);
@@ -1982,7 +2051,13 @@ error:
        INIT_LIST_HEAD(&user->validators);
 
        user->group = group;
-       user->tracepoint.name = name;
+       user->reg_name = name;
+       user->reg_flags = reg_flags;
+
+       ret = user_event_set_tp_name(user);
+
+       if (ret)
+               goto put_user;
 
        ret = user_event_parse_fields(user, args);
 
@@ -1996,11 +2071,14 @@ error:
 
        user->call.data = user;
        user->call.class = &user->class;
-       user->call.name = name;
        user->call.flags = TRACE_EVENT_FL_TRACEPOINT;
        user->call.tp = &user->tracepoint;
        user->call.event.funcs = &user_event_funcs;
-       user->class.system = group->system_name;
+
+       if (EVENT_MULTI_FORMAT(user->reg_flags))
+               user->class.system = group->system_multi_name;
+       else
+               user->class.system = group->system_name;
 
        user->class.fields_array = user_event_fields_array;
        user->class.get_fields = user_event_get_fields;
@@ -2022,8 +2100,6 @@ error:
        if (ret)
                goto put_user_lock;
 
-       user->reg_flags = reg_flags;
-
        if (user->reg_flags & USER_EVENT_REG_PERSIST) {
                /* Ensure we track self ref and caller ref (2) */
                refcount_set(&user->refcnt, 2);
@@ -2047,30 +2123,43 @@ put_user:
        user_event_destroy_fields(user);
        user_event_destroy_validators(user);
        kfree(user->call.print_fmt);
+
+       /* Caller frees reg_name on error, but not multi-name */
+       if (EVENT_NAME(user) != EVENT_TP_NAME(user))
+               kfree(EVENT_TP_NAME(user));
+
        kfree(user);
        return ret;
 }
 
 /*
- * Deletes a previously created event if it is no longer being used.
+ * Deletes previously created events if they are no longer being used.
  */
 static int delete_user_event(struct user_event_group *group, char *name)
 {
-       u32 key;
-       struct user_event *user = find_user_event(group, name, &key);
+       struct user_event *user;
+       struct hlist_node *tmp;
+       u32 key = user_event_key(name);
+       int ret = -ENOENT;
 
-       if (!user)
-               return -ENOENT;
+       /* Attempt to delete all event(s) with the name passed in */
+       hash_for_each_possible_safe(group->register_table, user, tmp, node, key) {
+               if (strcmp(EVENT_NAME(user), name))
+                       continue;
 
-       user_event_put(user, true);
+               if (!user_event_last_ref(user))
+                       return -EBUSY;
 
-       if (!user_event_last_ref(user))
-               return -EBUSY;
+               if (!user_event_capable(user->reg_flags))
+                       return -EPERM;
 
-       if (!user_event_capable(user->reg_flags))
-               return -EPERM;
+               ret = destroy_user_event(user);
 
-       return destroy_user_event(user);
+               if (ret)
+                       goto out;
+       }
+out:
+       return ret;
 }
 
 /*
@@ -2628,7 +2717,7 @@ static int user_seq_show(struct seq_file *m, void *p)
        hash_for_each(group->register_table, i, user, node) {
                status = user->status;
 
-               seq_printf(m, "%s", EVENT_NAME(user));
+               seq_printf(m, "%s", EVENT_TP_NAME(user));
 
                if (status != 0)
                        seq_puts(m, " #");
index c9ffdcfe622e14ae9e09168f8442333dddda8f85..8a407adb0e1c4befc37215b8d191778ef1cd63e2 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/uaccess.h>
+#include <linux/kmemleak.h>
 #include <linux/ftrace.h>
 #include <trace/events/sched.h>
 
@@ -148,3 +149,517 @@ void tracing_stop_tgid_record(void)
 {
        tracing_stop_sched_switch(RECORD_TGID);
 }
+
+/*
+ * The tgid_map array maps from pid to tgid; i.e. the value stored at index i
+ * is the tgid last observed corresponding to pid=i.
+ */
+static int *tgid_map;
+
+/* The maximum valid index into tgid_map. */
+static size_t tgid_map_max;
+
+#define SAVED_CMDLINES_DEFAULT 128
+#define NO_CMDLINE_MAP UINT_MAX
+/*
+ * Preemption must be disabled before acquiring trace_cmdline_lock.
+ * The various trace_arrays' max_lock must be acquired in a context
+ * where interrupt is disabled.
+ */
+static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+struct saved_cmdlines_buffer {
+       unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
+       unsigned *map_cmdline_to_pid;
+       unsigned cmdline_num;
+       int cmdline_idx;
+       char saved_cmdlines[];
+};
+static struct saved_cmdlines_buffer *savedcmd;
+
+/* Holds the size of a cmdline and pid element */
+#define SAVED_CMDLINE_MAP_ELEMENT_SIZE(s)                      \
+       (TASK_COMM_LEN + sizeof((s)->map_cmdline_to_pid[0]))
+
+static inline char *get_saved_cmdlines(int idx)
+{
+       return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN];
+}
+
+static inline void set_cmdline(int idx, const char *cmdline)
+{
+       strncpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN);
+}
+
+static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s)
+{
+       int order = get_order(sizeof(*s) + s->cmdline_num * TASK_COMM_LEN);
+
+       kmemleak_free(s);
+       free_pages((unsigned long)s, order);
+}
+
+static struct saved_cmdlines_buffer *allocate_cmdlines_buffer(unsigned int val)
+{
+       struct saved_cmdlines_buffer *s;
+       struct page *page;
+       int orig_size, size;
+       int order;
+
+       /* Figure out how much is needed to hold the given number of cmdlines */
+       orig_size = sizeof(*s) + val * SAVED_CMDLINE_MAP_ELEMENT_SIZE(s);
+       order = get_order(orig_size);
+       size = 1 << (order + PAGE_SHIFT);
+       page = alloc_pages(GFP_KERNEL, order);
+       if (!page)
+               return NULL;
+
+       s = page_address(page);
+       kmemleak_alloc(s, size, 1, GFP_KERNEL);
+       memset(s, 0, sizeof(*s));
+
+       /* Round up to actual allocation */
+       val = (size - sizeof(*s)) / SAVED_CMDLINE_MAP_ELEMENT_SIZE(s);
+       s->cmdline_num = val;
+
+       /* Place map_cmdline_to_pid array right after saved_cmdlines */
+       s->map_cmdline_to_pid = (unsigned *)&s->saved_cmdlines[val * TASK_COMM_LEN];
+
+       s->cmdline_idx = 0;
+       memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP,
+              sizeof(s->map_pid_to_cmdline));
+       memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP,
+              val * sizeof(*s->map_cmdline_to_pid));
+
+       return s;
+}
+
+int trace_create_savedcmd(void)
+{
+       savedcmd = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT);
+
+       return savedcmd ? 0 : -ENOMEM;
+}
+
+int trace_save_cmdline(struct task_struct *tsk)
+{
+       unsigned tpid, idx;
+
+       /* treat recording of idle task as a success */
+       if (!tsk->pid)
+               return 1;
+
+       tpid = tsk->pid & (PID_MAX_DEFAULT - 1);
+
+       /*
+        * It's not the end of the world if we don't get
+        * the lock, but we also don't want to spin
+        * nor do we want to disable interrupts,
+        * so if we miss here, then better luck next time.
+        *
+        * This is called within the scheduler and wake up, so interrupts
+        * had better been disabled and run queue lock been held.
+        */
+       lockdep_assert_preemption_disabled();
+       if (!arch_spin_trylock(&trace_cmdline_lock))
+               return 0;
+
+       idx = savedcmd->map_pid_to_cmdline[tpid];
+       if (idx == NO_CMDLINE_MAP) {
+               idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num;
+
+               savedcmd->map_pid_to_cmdline[tpid] = idx;
+               savedcmd->cmdline_idx = idx;
+       }
+
+       savedcmd->map_cmdline_to_pid[idx] = tsk->pid;
+       set_cmdline(idx, tsk->comm);
+
+       arch_spin_unlock(&trace_cmdline_lock);
+
+       return 1;
+}
+
+static void __trace_find_cmdline(int pid, char comm[])
+{
+       unsigned map;
+       int tpid;
+
+       if (!pid) {
+               strcpy(comm, "<idle>");
+               return;
+       }
+
+       if (WARN_ON_ONCE(pid < 0)) {
+               strcpy(comm, "<XXX>");
+               return;
+       }
+
+       tpid = pid & (PID_MAX_DEFAULT - 1);
+       map = savedcmd->map_pid_to_cmdline[tpid];
+       if (map != NO_CMDLINE_MAP) {
+               tpid = savedcmd->map_cmdline_to_pid[map];
+               if (tpid == pid) {
+                       strscpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN);
+                       return;
+               }
+       }
+       strcpy(comm, "<...>");
+}
+
+void trace_find_cmdline(int pid, char comm[])
+{
+       preempt_disable();
+       arch_spin_lock(&trace_cmdline_lock);
+
+       __trace_find_cmdline(pid, comm);
+
+       arch_spin_unlock(&trace_cmdline_lock);
+       preempt_enable();
+}
+
+static int *trace_find_tgid_ptr(int pid)
+{
+       /*
+        * Pairs with the smp_store_release in set_tracer_flag() to ensure that
+        * if we observe a non-NULL tgid_map then we also observe the correct
+        * tgid_map_max.
+        */
+       int *map = smp_load_acquire(&tgid_map);
+
+       if (unlikely(!map || pid > tgid_map_max))
+               return NULL;
+
+       return &map[pid];
+}
+
+int trace_find_tgid(int pid)
+{
+       int *ptr = trace_find_tgid_ptr(pid);
+
+       return ptr ? *ptr : 0;
+}
+
+static int trace_save_tgid(struct task_struct *tsk)
+{
+       int *ptr;
+
+       /* treat recording of idle task as a success */
+       if (!tsk->pid)
+               return 1;
+
+       ptr = trace_find_tgid_ptr(tsk->pid);
+       if (!ptr)
+               return 0;
+
+       *ptr = tsk->tgid;
+       return 1;
+}
+
+static bool tracing_record_taskinfo_skip(int flags)
+{
+       if (unlikely(!(flags & (TRACE_RECORD_CMDLINE | TRACE_RECORD_TGID))))
+               return true;
+       if (!__this_cpu_read(trace_taskinfo_save))
+               return true;
+       return false;
+}
+
+/**
+ * tracing_record_taskinfo - record the task info of a task
+ *
+ * @task:  task to record
+ * @flags: TRACE_RECORD_CMDLINE for recording comm
+ *         TRACE_RECORD_TGID for recording tgid
+ */
+void tracing_record_taskinfo(struct task_struct *task, int flags)
+{
+       bool done;
+
+       if (tracing_record_taskinfo_skip(flags))
+               return;
+
+       /*
+        * Record as much task information as possible. If some fail, continue
+        * to try to record the others.
+        */
+       done = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(task);
+       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(task);
+
+       /* If recording any information failed, retry again soon. */
+       if (!done)
+               return;
+
+       __this_cpu_write(trace_taskinfo_save, false);
+}
+
+/**
+ * tracing_record_taskinfo_sched_switch - record task info for sched_switch
+ *
+ * @prev: previous task during sched_switch
+ * @next: next task during sched_switch
+ * @flags: TRACE_RECORD_CMDLINE for recording comm
+ *         TRACE_RECORD_TGID for recording tgid
+ */
+void tracing_record_taskinfo_sched_switch(struct task_struct *prev,
+                                         struct task_struct *next, int flags)
+{
+       bool done;
+
+       if (tracing_record_taskinfo_skip(flags))
+               return;
+
+       /*
+        * Record as much task information as possible. If some fail, continue
+        * to try to record the others.
+        */
+       done  = !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(prev);
+       done &= !(flags & TRACE_RECORD_CMDLINE) || trace_save_cmdline(next);
+       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(prev);
+       done &= !(flags & TRACE_RECORD_TGID) || trace_save_tgid(next);
+
+       /* If recording any information failed, retry again soon. */
+       if (!done)
+               return;
+
+       __this_cpu_write(trace_taskinfo_save, false);
+}
+
+/* Helpers to record a specific task information */
+void tracing_record_cmdline(struct task_struct *task)
+{
+       tracing_record_taskinfo(task, TRACE_RECORD_CMDLINE);
+}
+
+void tracing_record_tgid(struct task_struct *task)
+{
+       tracing_record_taskinfo(task, TRACE_RECORD_TGID);
+}
+
+int trace_alloc_tgid_map(void)
+{
+       int *map;
+
+       if (tgid_map)
+               return 0;
+
+       tgid_map_max = pid_max;
+       map = kvcalloc(tgid_map_max + 1, sizeof(*tgid_map),
+                      GFP_KERNEL);
+       if (!map)
+               return -ENOMEM;
+
+       /*
+        * Pairs with smp_load_acquire() in
+        * trace_find_tgid_ptr() to ensure that if it observes
+        * the tgid_map we just allocated then it also observes
+        * the corresponding tgid_map_max value.
+        */
+       smp_store_release(&tgid_map, map);
+       return 0;
+}
+
+static void *saved_tgids_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       int pid = ++(*pos);
+
+       return trace_find_tgid_ptr(pid);
+}
+
+static void *saved_tgids_start(struct seq_file *m, loff_t *pos)
+{
+       int pid = *pos;
+
+       return trace_find_tgid_ptr(pid);
+}
+
+static void saved_tgids_stop(struct seq_file *m, void *v)
+{
+}
+
+static int saved_tgids_show(struct seq_file *m, void *v)
+{
+       int *entry = (int *)v;
+       int pid = entry - tgid_map;
+       int tgid = *entry;
+
+       if (tgid == 0)
+               return SEQ_SKIP;
+
+       seq_printf(m, "%d %d\n", pid, tgid);
+       return 0;
+}
+
+static const struct seq_operations tracing_saved_tgids_seq_ops = {
+       .start          = saved_tgids_start,
+       .stop           = saved_tgids_stop,
+       .next           = saved_tgids_next,
+       .show           = saved_tgids_show,
+};
+
+static int tracing_saved_tgids_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       ret = tracing_check_open_get_tr(NULL);
+       if (ret)
+               return ret;
+
+       return seq_open(filp, &tracing_saved_tgids_seq_ops);
+}
+
+
+const struct file_operations tracing_saved_tgids_fops = {
+       .open           = tracing_saved_tgids_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       unsigned int *ptr = v;
+
+       if (*pos || m->count)
+               ptr++;
+
+       (*pos)++;
+
+       for (; ptr < &savedcmd->map_cmdline_to_pid[savedcmd->cmdline_num];
+            ptr++) {
+               if (*ptr == -1 || *ptr == NO_CMDLINE_MAP)
+                       continue;
+
+               return ptr;
+       }
+
+       return NULL;
+}
+
+static void *saved_cmdlines_start(struct seq_file *m, loff_t *pos)
+{
+       void *v;
+       loff_t l = 0;
+
+       preempt_disable();
+       arch_spin_lock(&trace_cmdline_lock);
+
+       v = &savedcmd->map_cmdline_to_pid[0];
+       while (l <= *pos) {
+               v = saved_cmdlines_next(m, v, &l);
+               if (!v)
+                       return NULL;
+       }
+
+       return v;
+}
+
+static void saved_cmdlines_stop(struct seq_file *m, void *v)
+{
+       arch_spin_unlock(&trace_cmdline_lock);
+       preempt_enable();
+}
+
+static int saved_cmdlines_show(struct seq_file *m, void *v)
+{
+       char buf[TASK_COMM_LEN];
+       unsigned int *pid = v;
+
+       __trace_find_cmdline(*pid, buf);
+       seq_printf(m, "%d %s\n", *pid, buf);
+       return 0;
+}
+
+static const struct seq_operations tracing_saved_cmdlines_seq_ops = {
+       .start          = saved_cmdlines_start,
+       .next           = saved_cmdlines_next,
+       .stop           = saved_cmdlines_stop,
+       .show           = saved_cmdlines_show,
+};
+
+static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp)
+{
+       int ret;
+
+       ret = tracing_check_open_get_tr(NULL);
+       if (ret)
+               return ret;
+
+       return seq_open(filp, &tracing_saved_cmdlines_seq_ops);
+}
+
+const struct file_operations tracing_saved_cmdlines_fops = {
+       .open           = tracing_saved_cmdlines_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static ssize_t
+tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf,
+                                size_t cnt, loff_t *ppos)
+{
+       char buf[64];
+       int r;
+
+       preempt_disable();
+       arch_spin_lock(&trace_cmdline_lock);
+       r = scnprintf(buf, sizeof(buf), "%u\n", savedcmd->cmdline_num);
+       arch_spin_unlock(&trace_cmdline_lock);
+       preempt_enable();
+
+       return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+void trace_free_saved_cmdlines_buffer(void)
+{
+       free_saved_cmdlines_buffer(savedcmd);
+}
+
+static int tracing_resize_saved_cmdlines(unsigned int val)
+{
+       struct saved_cmdlines_buffer *s, *savedcmd_temp;
+
+       s = allocate_cmdlines_buffer(val);
+       if (!s)
+               return -ENOMEM;
+
+       preempt_disable();
+       arch_spin_lock(&trace_cmdline_lock);
+       savedcmd_temp = savedcmd;
+       savedcmd = s;
+       arch_spin_unlock(&trace_cmdline_lock);
+       preempt_enable();
+       free_saved_cmdlines_buffer(savedcmd_temp);
+
+       return 0;
+}
+
+static ssize_t
+tracing_saved_cmdlines_size_write(struct file *filp, const char __user *ubuf,
+                                 size_t cnt, loff_t *ppos)
+{
+       unsigned long val;
+       int ret;
+
+       ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+       if (ret)
+               return ret;
+
+       /* must have at least 1 entry or less than PID_MAX_DEFAULT */
+       if (!val || val > PID_MAX_DEFAULT)
+               return -EINVAL;
+
+       ret = tracing_resize_saved_cmdlines((unsigned int)val);
+       if (ret < 0)
+               return ret;
+
+       *ppos += cnt;
+
+       return cnt;
+}
+
+const struct file_operations tracing_saved_cmdlines_size_fops = {
+       .open           = tracing_open_generic,
+       .read           = tracing_saved_cmdlines_size_read,
+       .write          = tracing_saved_cmdlines_size_write,
+};
index 529590499b1fa6b5877232aa82bead760813d2ac..e9c5058a8efd8c7e96114df839192f2fd7046e28 100644 (file)
@@ -768,7 +768,7 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
        if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
                ftrace_graph_stop();
                printk(KERN_WARNING "BUG: Function graph tracer hang!\n");
-               if (ftrace_dump_on_oops) {
+               if (ftrace_dump_on_oops_enabled()) {
                        ftrace_dump(DUMP_ALL);
                        /* ftrace_dump() disables tracing */
                        tracing_on();
index bf2bdac46843dc945a7daa37a124e42eeaea489e..0066c8f6c15442641889c87995410ac82d078423 100644 (file)
@@ -7080,7 +7080,7 @@ static struct device_attribute wq_sysfs_unbound_attrs[] = {
        __ATTR_NULL,
 };
 
-static struct bus_type wq_subsys = {
+static const struct bus_type wq_subsys = {
        .name                           = "workqueue",
        .dev_groups                     = wq_sysfs_groups,
 };
index 733ee2ac0138e34b8da1f97956758cc9e1cba030..c63a5fbf1f1c2b45b67603886ef9e6f07510f61d 100644 (file)
@@ -2127,7 +2127,7 @@ config KCOV_IRQ_AREA_SIZE
 
 menuconfig RUNTIME_TESTING_MENU
        bool "Runtime Testing"
-       def_bool y
+       default y
 
 if RUNTIME_TESTING_MENU
 
@@ -2703,18 +2703,6 @@ config MEMCPY_KUNIT_TEST
 
          If unsure, say N.
 
-config MEMCPY_SLOW_KUNIT_TEST
-       bool "Include exhaustive memcpy tests"
-       depends on MEMCPY_KUNIT_TEST
-       default y
-       help
-         Some memcpy tests are quite exhaustive in checking for overlaps
-         and bit ranges. These can be very slow, so they are split out
-         as a separate config, in case they need to be disabled.
-
-         Note this config option will be replaced by the use of KUnit test
-         attributes.
-
 config IS_SIGNED_TYPE_KUNIT_TEST
        tristate "Test is_signed_type() macro" if !KUNIT_ALL_TESTS
        depends on KUNIT
index 3b9a44008433201ec86443fe0626967c37a488a3..b5c0e6576749dc31633b4fe0b5135f24c5652da2 100644 (file)
@@ -43,7 +43,7 @@ config KGDB_SERIAL_CONSOLE
        tristate "KGDB: use kgdb over the serial console"
        select CONSOLE_POLL
        select MAGIC_SYSRQ
-       depends on TTY && HW_CONSOLE
+       depends on TTY && VT
        default y
        help
          Share a serial console with kgdb. Sysrq-g must be used
index 48a67058f84eba8eb19a6f12494198bb075db6b0..e81e1ac4a919b5b5548bc6de96276bb5d9d2b69e 100644 (file)
@@ -119,6 +119,8 @@ config UBSAN_SIGNED_WRAP
        bool "Perform checking for signed arithmetic wrap-around"
        default UBSAN
        depends on !COMPILE_TEST
+       # The no_sanitize attribute was introduced in GCC with version 8.
+       depends on !CC_IS_GCC || GCC_VERSION >= 80000
        depends on $(cc-option,-fsanitize=signed-integer-overflow)
        help
          This option enables -fsanitize=signed-integer-overflow which checks
index 973866438608870c06af198de3cfe28756ec7831..47e34950b665c3d4de0472ff0558601351701ca9 100644 (file)
@@ -96,18 +96,21 @@ EXPORT_SYMBOL(find_font);
  *     get_default_font - get default font
  *     @xres: screen size of X
  *     @yres: screen size of Y
- *      @font_w: bit array of supported widths (1 - 32)
- *      @font_h: bit array of supported heights (1 - 32)
+ *     @font_w: bit array of supported widths (1 - FB_MAX_BLIT_WIDTH)
+ *     @font_h: bit array of supported heights (1 - FB_MAX_BLIT_HEIGHT)
  *
  *     Get the default font for a specified screen size.
  *     Dimensions are in pixels.
  *
+ *     font_w or font_h being NULL means all values are supported.
+ *
  *     Returns %NULL if no font is found, or a pointer to the
  *     chosen font.
  *
  */
-const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
-                                        u32 font_h)
+const struct font_desc *get_default_font(int xres, int yres,
+                                        unsigned long *font_w,
+                                        unsigned long *font_h)
 {
        int i, c, cc, res;
        const struct font_desc *f, *g;
@@ -135,8 +138,8 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
                if (res > 20)
                        c += 20 - res;
 
-               if ((font_w & (1U << (f->width - 1))) &&
-                   (font_h & (1U << (f->height - 1))))
+               if ((!font_w || test_bit(f->width - 1, font_w)) &&
+                   (!font_h || test_bit(f->height - 1, font_h)))
                        c += 1000;
 
                if (c > cc) {
index fb9a2f06dd1e79db0e5db17362c88152790e2b36..03b427e2707e357ab12abeb9da234432c4bc0fb3 100644 (file)
@@ -30,7 +30,7 @@
 #include <net/net_namespace.h>
 
 
-u64 uevent_seqnum;
+atomic64_t uevent_seqnum;
 #ifdef CONFIG_UEVENT_HELPER
 char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
 #endif
@@ -42,10 +42,9 @@ struct uevent_sock {
 
 #ifdef CONFIG_NET
 static LIST_HEAD(uevent_sock_list);
-#endif
-
-/* This lock protects uevent_seqnum and uevent_sock_list */
+/* This lock protects uevent_sock_list */
 static DEFINE_MUTEX(uevent_sock_mutex);
+#endif
 
 /* the strings here must match the enum in include/linux/kobject.h */
 static const char *kobject_actions[] = {
@@ -315,6 +314,7 @@ static int uevent_net_broadcast_untagged(struct kobj_uevent_env *env,
        int retval = 0;
 
        /* send netlink message */
+       mutex_lock(&uevent_sock_mutex);
        list_for_each_entry(ue_sk, &uevent_sock_list, list) {
                struct sock *uevent_sock = ue_sk->sk;
 
@@ -334,6 +334,7 @@ static int uevent_net_broadcast_untagged(struct kobj_uevent_env *env,
                if (retval == -ENOBUFS || retval == -ESRCH)
                        retval = 0;
        }
+       mutex_unlock(&uevent_sock_mutex);
        consume_skb(skb);
 
        return retval;
@@ -583,16 +584,14 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
                break;
        }
 
-       mutex_lock(&uevent_sock_mutex);
        /* we will send an event, so request a new sequence number */
-       retval = add_uevent_var(env, "SEQNUM=%llu", ++uevent_seqnum);
-       if (retval) {
-               mutex_unlock(&uevent_sock_mutex);
+       retval = add_uevent_var(env, "SEQNUM=%llu",
+                               atomic64_inc_return(&uevent_seqnum));
+       if (retval)
                goto exit;
-       }
+
        retval = kobject_uevent_net_broadcast(kobj, env, action_string,
                                              devpath);
-       mutex_unlock(&uevent_sock_mutex);
 
 #ifdef CONFIG_UEVENT_HELPER
        /* call uevent_helper, usually only enabled during early boot */
@@ -688,7 +687,8 @@ static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb,
        int ret;
 
        /* bump and prepare sequence number */
-       ret = snprintf(buf, sizeof(buf), "SEQNUM=%llu", ++uevent_seqnum);
+       ret = snprintf(buf, sizeof(buf), "SEQNUM=%llu",
+                      atomic64_inc_return(&uevent_seqnum));
        if (ret < 0 || (size_t)ret >= sizeof(buf))
                return -ENOMEM;
        ret++;
@@ -742,9 +742,7 @@ static int uevent_net_rcv_skb(struct sk_buff *skb, struct nlmsghdr *nlh,
                return -EPERM;
        }
 
-       mutex_lock(&uevent_sock_mutex);
        ret = uevent_net_broadcast(net->uevent_sock->sk, skb, extack);
-       mutex_unlock(&uevent_sock_mutex);
 
        return ret;
 }
index 30e00ef0bf2e0f8e407a97ef555f8aa4f648dac3..fd16e6ce53d1dbc788ed7fd955cba58ef04ee517 100644 (file)
@@ -309,9 +309,6 @@ static void set_random_nonzero(struct kunit *test, u8 *byte)
 
 static void init_large(struct kunit *test)
 {
-       if (!IS_ENABLED(CONFIG_MEMCPY_SLOW_KUNIT_TEST))
-               kunit_skip(test, "Slow test skipped. Enable with CONFIG_MEMCPY_SLOW_KUNIT_TEST=y");
-
        /* Get many bit patterns. */
        get_random_bytes(large_src, ARRAY_SIZE(large_src));
 
index 65e8a72a83bfaa9ccfd2c47b0290eedfa46520d3..4ef31b0bb74d682dbe83997609b2b259ddd600ae 100644 (file)
@@ -1172,6 +1172,24 @@ static void castable_to_type_test(struct kunit *test)
 #undef TEST_CASTABLE_TO_TYPE
 }
 
+struct foo {
+       int a;
+       u32 counter;
+       s16 array[] __counted_by(counter);
+};
+
+static void DEFINE_FLEX_test(struct kunit *test)
+{
+       DEFINE_RAW_FLEX(struct foo, two, array, 2);
+       DEFINE_FLEX(struct foo, eight, array, counter, 8);
+       DEFINE_FLEX(struct foo, empty, array, counter, 0);
+
+       KUNIT_EXPECT_EQ(test, __struct_size(two),
+                       sizeof(struct foo) + sizeof(s16) + sizeof(s16));
+       KUNIT_EXPECT_EQ(test, __struct_size(eight), 24);
+       KUNIT_EXPECT_EQ(test, __struct_size(empty), sizeof(struct foo));
+}
+
 static struct kunit_case overflow_test_cases[] = {
        KUNIT_CASE(u8_u8__u8_overflow_test),
        KUNIT_CASE(s8_s8__s8_overflow_test),
@@ -1194,6 +1212,7 @@ static struct kunit_case overflow_test_cases[] = {
        KUNIT_CASE(overflows_type_test),
        KUNIT_CASE(same_type_test),
        KUNIT_CASE(castable_to_type_test),
+       KUNIT_CASE(DEFINE_FLEX_test),
        {}
 };
 
index b924f4a5a3ef8a7bf71498abe4392a350191e618..b1448aa81e15f48d7a2c14d18b666485635f2df1 100644 (file)
@@ -583,7 +583,7 @@ config MEMORY_BALLOON
 # support for memory balloon compaction
 config BALLOON_COMPACTION
        bool "Allow for balloon memory compaction/migration"
-       def_bool y
+       default y
        depends on COMPACTION && MEMORY_BALLOON
        help
          Memory fragmentation introduced by ballooning might reduce
@@ -598,7 +598,7 @@ config BALLOON_COMPACTION
 # support for memory compaction
 config COMPACTION
        bool "Allow for memory compaction"
-       def_bool y
+       default y
        select MIGRATION
        depends on MMU
        help
@@ -621,7 +621,6 @@ config COMPACT_UNEVICTABLE_DEFAULT
 # support for free page reporting
 config PAGE_REPORTING
        bool "Free page reporting"
-       def_bool n
        help
          Free page reporting allows for the incremental acquisition of
          free pages from the buddy allocator for the purpose of reporting
@@ -633,7 +632,7 @@ config PAGE_REPORTING
 #
 config MIGRATION
        bool "Page migration"
-       def_bool y
+       default y
        depends on (NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION || CMA) && MMU
        help
          Allows the migration of the physical location of pages of processes
index 04da02114c6f992e251f6b52fa10482286947798..6dbda99a47da1c332682c95c03bf3ce6c74f562f 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -64,7 +64,7 @@
 
 #ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS
 const int mmap_rnd_bits_min = CONFIG_ARCH_MMAP_RND_BITS_MIN;
-const int mmap_rnd_bits_max = CONFIG_ARCH_MMAP_RND_BITS_MAX;
+int mmap_rnd_bits_max __ro_after_init = CONFIG_ARCH_MMAP_RND_BITS_MAX;
 int mmap_rnd_bits __read_mostly = CONFIG_ARCH_MMAP_RND_BITS;
 #endif
 #ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
index 0766a245816bdf70f6609dc7b6d694ae81e7a9e5..9a67003e49db87f3f92b6c6296b3e7a5ca9d9171 100644 (file)
@@ -2245,7 +2245,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
        rcu_read_lock();
 again:
        list_for_each_entry_rcu(ptype, ptype_list, list) {
-               if (ptype->ignore_outgoing)
+               if (READ_ONCE(ptype->ignore_outgoing))
                        continue;
 
                /* Never send packets back to the socket
@@ -6743,6 +6743,8 @@ static int napi_threaded_poll(void *data)
        void *have;
 
        while (!napi_thread_wait(napi)) {
+               unsigned long last_qs = jiffies;
+
                for (;;) {
                        bool repoll = false;
 
@@ -6767,6 +6769,7 @@ static int napi_threaded_poll(void *data)
                        if (!repoll)
                                break;
 
+                       rcu_softirq_qs_periodic(last_qs);
                        cond_resched();
                }
        }
@@ -11665,11 +11668,12 @@ static void __init net_dev_struct_check(void)
 
        /* TXRX read-mostly hotpath */
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, lstats);
+       CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, state);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, flags);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, hard_header_len);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, features);
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_txrx, ip6_ptr);
-       CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 38);
+       CACHELINE_ASSERT_GROUP_SIZE(struct net_device, net_device_read_txrx, 46);
 
        /* RX read-mostly hotpath */
        CACHELINE_ASSERT_GROUP_MEMBER(struct net_device, net_device_read_rx, ptype_specific);
index a3eeb84d16f9c6d5f110cb8a811f66b3e626ae06..e3d388c33d256c3733e2f432b451961afee39661 100644 (file)
@@ -13,7 +13,7 @@ config IP_DCCP_CCID2_DEBUG
 
 config IP_DCCP_CCID3
        bool "CCID-3 (TCP-Friendly)"
-       def_bool y if (IP_DCCP = y || IP_DCCP = m)
+       default IP_DCCP = y || IP_DCCP = m
        help
          CCID-3 denotes TCP-Friendly Rate Control (TFRC), an equation-based
          rate-controlled congestion control mechanism.  TFRC is designed to
index 499885c8b9cae21e846ca3e310dc6ec767b184eb..593605c1b1ef4d32eab50c7701b329936b447351 100644 (file)
@@ -193,12 +193,13 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs,
        devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
 
        devlinks_xa_for_each_registered_get(net, index, devlink) {
-               devl_dev_lock(devlink, dev_lock);
-               if (devl_is_registered(devlink) &&
-                   strcmp(devlink->dev->bus->name, busname) == 0 &&
-                   strcmp(dev_name(devlink->dev), devname) == 0)
-                       return devlink;
-               devl_dev_unlock(devlink, dev_lock);
+               if (strcmp(devlink->dev->bus->name, busname) == 0 &&
+                   strcmp(dev_name(devlink->dev), devname) == 0) {
+                       devl_dev_lock(devlink, dev_lock);
+                       if (devl_is_registered(devlink))
+                               return devlink;
+                       devl_dev_unlock(devlink, dev_lock);
+               }
                devlink_put(devlink);
        }
 
index 4b2d46ccfe484f1ae2c21b5b2921a113d59e13f5..118d130d2afd56301c89ea2552bc3f6c625adcfe 100644 (file)
@@ -889,7 +889,7 @@ int devlink_nl_port_new_doit(struct sk_buff *skb, struct genl_info *info)
                err = -ENOMEM;
                goto err_out_port_del;
        }
-       err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW,
+       err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_PORT_NEW,
                                   info->snd_portid, info->snd_seq, 0, NULL);
        if (WARN_ON_ONCE(err))
                goto err_out_msg_free;
index 6d14d935ee828d025d40ea237884d244cb56eb8e..26329db09210bb38cf3fcf81334ce212c2af0d2e 100644 (file)
@@ -228,6 +228,10 @@ struct hsr_node *hsr_get_node(struct hsr_port *port, struct list_head *node_db,
         */
        if (ethhdr->h_proto == htons(ETH_P_PRP) ||
            ethhdr->h_proto == htons(ETH_P_HSR)) {
+               /* Check if skb contains hsr_ethhdr */
+               if (skb->mac_len < sizeof(struct hsr_ethhdr))
+                       return NULL;
+
                /* Use the existing sequence_nr from the tag as starting point
                 * for filtering duplicate frames.
                 */
index cb83c8feb746535fe4126f4172ffbafaac58b0d5..9756e657bab97e95407b8907157b138159d68253 100644 (file)
@@ -148,14 +148,21 @@ static struct notifier_block hsr_nb = {
 
 static int __init hsr_init(void)
 {
-       int res;
+       int err;
 
        BUILD_BUG_ON(sizeof(struct hsr_tag) != HSR_HLEN);
 
-       register_netdevice_notifier(&hsr_nb);
-       res = hsr_netlink_init();
+       err = register_netdevice_notifier(&hsr_nb);
+       if (err)
+               return err;
+
+       err = hsr_netlink_init();
+       if (err) {
+               unregister_netdevice_notifier(&hsr_nb);
+               return err;
+       }
 
-       return res;
+       return 0;
 }
 
 static void __exit hsr_exit(void)
index 4dd9e50406720cfc90d280f61e4616d6a2e58d3c..d33d124218140cfdbf910ce7054c05559c5ecfba 100644 (file)
@@ -95,7 +95,7 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
                             __alignof__(struct scatterlist));
 }
 
-static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
+static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
 {
        struct crypto_aead *aead = x->data;
        int extralen = 0;
@@ -114,7 +114,7 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
         */
        if (req->src != req->dst)
                for (sg = sg_next(req->src); sg; sg = sg_next(sg))
-                       put_page(sg_page(sg));
+                       skb_page_unref(skb, sg_page(sg), false);
 }
 
 #ifdef CONFIG_INET_ESPINTCP
@@ -260,7 +260,7 @@ static void esp_output_done(void *data, int err)
        }
 
        tmp = ESP_SKB_CB(skb)->tmp;
-       esp_ssg_unref(x, tmp);
+       esp_ssg_unref(x, tmp, skb);
        kfree(tmp);
 
        if (xo && (xo->flags & XFRM_DEV_RESUME)) {
@@ -639,7 +639,7 @@ int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
        }
 
        if (sg != dsg)
-               esp_ssg_unref(x, tmp);
+               esp_ssg_unref(x, tmp, skb);
 
        if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
                err = esp_output_tail_tcp(x, skb);
index 7498af3201647fd937bf8177f04c200bea178a79..cf88eca5f1b40563e177c6d84dd59416c62c30e5 100644 (file)
@@ -1135,7 +1135,7 @@ error:
                sock_prot_inuse_add(net, sk->sk_prot, -1);
 
                spin_lock(lock);
-               sk_nulls_del_node_init_rcu(sk);
+               __sk_nulls_del_node_init_rcu(sk);
                spin_unlock(lock);
 
                sk->sk_hash = 0;
index 5befa4de5b2416281ad2795713a70d0fd847b0b2..e8de45d34d56a507a4bdcceaccbd5707692b6c0a 100644 (file)
@@ -263,12 +263,12 @@ void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm)
 }
 EXPORT_SYMBOL_GPL(__inet_twsk_schedule);
 
+/* Remove all non full sockets (TIME_WAIT and NEW_SYN_RECV) for dead netns */
 void inet_twsk_purge(struct inet_hashinfo *hashinfo, int family)
 {
-       struct inet_timewait_sock *tw;
-       struct sock *sk;
        struct hlist_nulls_node *node;
        unsigned int slot;
+       struct sock *sk;
 
        for (slot = 0; slot <= hashinfo->ehash_mask; slot++) {
                struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
@@ -277,38 +277,35 @@ restart_rcu:
                rcu_read_lock();
 restart:
                sk_nulls_for_each_rcu(sk, node, &head->chain) {
-                       if (sk->sk_state != TCP_TIME_WAIT) {
-                               /* A kernel listener socket might not hold refcnt for net,
-                                * so reqsk_timer_handler() could be fired after net is
-                                * freed.  Userspace listener and reqsk never exist here.
-                                */
-                               if (unlikely(sk->sk_state == TCP_NEW_SYN_RECV &&
-                                            hashinfo->pernet)) {
-                                       struct request_sock *req = inet_reqsk(sk);
-
-                                       inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, req);
-                               }
+                       int state = inet_sk_state_load(sk);
 
+                       if ((1 << state) & ~(TCPF_TIME_WAIT |
+                                            TCPF_NEW_SYN_RECV))
                                continue;
-                       }
 
-                       tw = inet_twsk(sk);
-                       if ((tw->tw_family != family) ||
-                               refcount_read(&twsk_net(tw)->ns.count))
+                       if (sk->sk_family != family ||
+                           refcount_read(&sock_net(sk)->ns.count))
                                continue;
 
-                       if (unlikely(!refcount_inc_not_zero(&tw->tw_refcnt)))
+                       if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
                                continue;
 
-                       if (unlikely((tw->tw_family != family) ||
-                                    refcount_read(&twsk_net(tw)->ns.count))) {
-                               inet_twsk_put(tw);
+                       if (unlikely(sk->sk_family != family ||
+                                    refcount_read(&sock_net(sk)->ns.count))) {
+                               sock_gen_put(sk);
                                goto restart;
                        }
 
                        rcu_read_unlock();
                        local_bh_disable();
-                       inet_twsk_deschedule_put(tw);
+                       if (state == TCP_TIME_WAIT) {
+                               inet_twsk_deschedule_put(inet_twsk(sk));
+                       } else {
+                               struct request_sock *req = inet_reqsk(sk);
+
+                               inet_csk_reqsk_queue_drop_and_put(req->rsk_listener,
+                                                                 req);
+                       }
                        local_bh_enable();
                        goto restart_rcu;
                }
index 33f93dc730a3359b2a43e3cab447b94bc63597e0..1fe794967211e249016df00dc3c2ae230d71dcff 100644 (file)
@@ -1458,7 +1458,6 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
        skb->priority = (cork->tos != -1) ? cork->priority: READ_ONCE(sk->sk_priority);
        skb->mark = cork->mark;
        skb->tstamp = cork->transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
        /*
         * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec
         * on dst refcount
index 42ac434cfcfa677ee58408297f4d3ac05d98b546..dcb11f22cbf2b437405d1b373dd0ebc37d02c9ec 100644 (file)
@@ -357,10 +357,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
                goto error;
        skb_reserve(skb, hlen);
 
+       skb->protocol = htons(ETH_P_IP);
        skb->priority = READ_ONCE(sk->sk_priority);
        skb->mark = sockc->mark;
        skb->tstamp = sockc->transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
        skb_dst_set(skb, &rt->dst);
        *rtp = NULL;
 
index 7972ad3d7c73af68d6149ca76f6d12ddf881f3a2..500f665f98cbce4a3d681f8e39ecd368fe4013b1 100644 (file)
@@ -474,6 +474,9 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
                                  ireq->wscale_ok, &rcv_wscale,
                                  dst_metric(&rt->dst, RTAX_INITRWND));
 
+       /* req->syncookie is set true only if ACK is validated
+        * by BPF kfunc, then, rcv_wscale is already configured.
+        */
        if (!req->syncookie)
                ireq->rcv_wscale = rcv_wscale;
        ireq->ecn_ok &= cookie_ecn_ok(net, &rt->dst);
index 52040b0e2616b479cf3f619a594364951c219eae..f0761f060a8376236983a660eea48a6e0ba94de4 100644 (file)
@@ -398,10 +398,6 @@ void tcp_twsk_purge(struct list_head *net_exit_list, int family)
                        /* Even if tw_refcount == 1, we must clean up kernel reqsk */
                        inet_twsk_purge(net->ipv4.tcp_death_row.hashinfo, family);
                } else if (!purged_once) {
-                       /* The last refcount is decremented in tcp_sk_exit_batch() */
-                       if (refcount_read(&net->ipv4.tcp_death_row.tw_refcount) == 1)
-                               continue;
-
                        inet_twsk_purge(&tcp_hashinfo, family);
                        purged_once = true;
                }
index 6e6efe026cdcc2feab9a1f18fb784042b586f045..7371886d4f9f49c39111cfe95ea5dff7e5198740 100644 (file)
@@ -112,7 +112,7 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
                             __alignof__(struct scatterlist));
 }
 
-static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
+static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
 {
        struct crypto_aead *aead = x->data;
        int extralen = 0;
@@ -131,7 +131,7 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
         */
        if (req->src != req->dst)
                for (sg = sg_next(req->src); sg; sg = sg_next(sg))
-                       put_page(sg_page(sg));
+                       skb_page_unref(skb, sg_page(sg), false);
 }
 
 #ifdef CONFIG_INET6_ESPINTCP
@@ -294,7 +294,7 @@ static void esp_output_done(void *data, int err)
        }
 
        tmp = ESP_SKB_CB(skb)->tmp;
-       esp_ssg_unref(x, tmp);
+       esp_ssg_unref(x, tmp, skb);
        kfree(tmp);
 
        esp_output_encap_csum(skb);
@@ -677,7 +677,7 @@ int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
        }
 
        if (sg != dsg)
-               esp_ssg_unref(x, tmp);
+               esp_ssg_unref(x, tmp, skb);
 
        if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
                err = esp_output_tail_tcp(x, skb);
index 02eeca5492cd4d894b4acc8ec89bf004e81c0ccb..b9dd3a66e4236fbf67af75c5f98c921b38c18bf6 100644 (file)
@@ -1925,7 +1925,7 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
        skb->priority = READ_ONCE(sk->sk_priority);
        skb->mark = cork->base.mark;
        skb->tstamp = cork->base.transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
+
        ip6_cork_steal_dst(skb, cork);
        IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
        if (proto == IPPROTO_ICMPV6) {
index ca49e6617afaff3fe6c5f3a174bbe6d96f94ac62..0d896ca7b589122270b9e85815a64ce37d0d932d 100644 (file)
@@ -622,7 +622,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
        skb->priority = READ_ONCE(sk->sk_priority);
        skb->mark = sockc->mark;
        skb->tstamp = sockc->transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
+
        skb_put(skb, length);
        skb_reset_network_header(skb);
        iph = ipv6_hdr(skb);
index 8bad0a44a0a6c593b5fcc327e8ae6a5f106c8794..6d8286c299c9d139938ef6751d9958c80d3031e9 100644 (file)
@@ -258,6 +258,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
                                  ireq->wscale_ok, &rcv_wscale,
                                  dst_metric(dst, RTAX_INITRWND));
 
+       /* req->syncookie is set true only if ACK is validated
+        * by BPF kfunc, then, rcv_wscale is already configured.
+        */
        if (!req->syncookie)
                ireq->rcv_wscale = rcv_wscale;
        ireq->ecn_ok &= cookie_ecn_ok(net, dst);
index 4aa1c72e6c49e2135df8ae5e8760a2d4f6123bbe..7c8c3adcac6e94379360ef6e609c48e3b396ceaa 100644 (file)
@@ -1060,12 +1060,12 @@ static int iucv_sock_sendmsg(struct socket *sock, struct msghdr *msg,
                        int i;
 
                        /* skip iucv_array lying in the headroom */
-                       iba[0].address = (u32)virt_to_phys(skb->data);
+                       iba[0].address = virt_to_dma32(skb->data);
                        iba[0].length = (u32)skb_headlen(skb);
                        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
-                               iba[i + 1].address = (u32)virt_to_phys(skb_frag_address(frag));
+                               iba[i + 1].address = virt_to_dma32(skb_frag_address(frag));
                                iba[i + 1].length = (u32)skb_frag_size(frag);
                        }
                        err = pr_iucv->message_send(iucv->path, &txmsg,
@@ -1161,12 +1161,12 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
                        struct iucv_array *iba = (struct iucv_array *)skb->head;
                        int i;
 
-                       iba[0].address = (u32)virt_to_phys(skb->data);
+                       iba[0].address = virt_to_dma32(skb->data);
                        iba[0].length = (u32)skb_headlen(skb);
                        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
-                               iba[i + 1].address = (u32)virt_to_phys(skb_frag_address(frag));
+                               iba[i + 1].address = virt_to_dma32(skb_frag_address(frag));
                                iba[i + 1].length = (u32)skb_frag_size(frag);
                        }
                        rc = pr_iucv->message_receive(path, msg,
index 4d8ee3607b53df3efd1bf69452682a466b7798c4..a4ab615ca3e3e1d48bfb4298f69507f5f648b112 100644 (file)
@@ -210,7 +210,7 @@ struct iucv_cmd_dpl {
        u8  iprmmsg[8];
        u32 ipsrccls;
        u32 ipmsgtag;
-       u32 ipbfadr2;
+       dma32_t ipbfadr2;
        u32 ipbfln2f;
        u32 res;
 } __attribute__ ((packed,aligned(8)));
@@ -226,11 +226,11 @@ struct iucv_cmd_db {
        u8  iprcode;
        u32 ipmsgid;
        u32 iptrgcls;
-       u32 ipbfadr1;
+       dma32_t ipbfadr1;
        u32 ipbfln1f;
        u32 ipsrccls;
        u32 ipmsgtag;
-       u32 ipbfadr2;
+       dma32_t ipbfadr2;
        u32 ipbfln2f;
        u32 res;
 } __attribute__ ((packed,aligned(8)));
@@ -432,7 +432,7 @@ static void iucv_declare_cpu(void *data)
        /* Declare interrupt buffer. */
        parm = iucv_param_irq[cpu];
        memset(parm, 0, sizeof(union iucv_param));
-       parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]);
+       parm->db.ipbfadr1 = virt_to_dma32(iucv_irq_data[cpu]);
        rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
        if (rc) {
                char *err = "Unknown";
@@ -1081,8 +1081,7 @@ static int iucv_message_receive_iprmdata(struct iucv_path *path,
                size = (size < 8) ? size : 8;
                for (array = buffer; size > 0; array++) {
                        copy = min_t(size_t, size, array->length);
-                       memcpy((u8 *)(addr_t) array->address,
-                               rmmsg, copy);
+                       memcpy(dma32_to_virt(array->address), rmmsg, copy);
                        rmmsg += copy;
                        size -= copy;
                }
@@ -1124,7 +1123,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
 
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
-       parm->db.ipbfadr1 = (u32)virt_to_phys(buffer);
+       parm->db.ipbfadr1 = virt_to_dma32(buffer);
        parm->db.ipbfln1f = (u32) size;
        parm->db.ipmsgid = msg->id;
        parm->db.ippathid = path->pathid;
@@ -1242,7 +1241,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
                parm->dpl.iptrgcls = msg->class;
                memcpy(parm->dpl.iprmmsg, reply, min_t(size_t, size, 8));
        } else {
-               parm->db.ipbfadr1 = (u32)virt_to_phys(reply);
+               parm->db.ipbfadr1 = virt_to_dma32(reply);
                parm->db.ipbfln1f = (u32) size;
                parm->db.ippathid = path->pathid;
                parm->db.ipflags1 = flags;
@@ -1294,7 +1293,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
                parm->dpl.ipmsgtag = msg->tag;
                memcpy(parm->dpl.iprmmsg, buffer, 8);
        } else {
-               parm->db.ipbfadr1 = (u32)virt_to_phys(buffer);
+               parm->db.ipbfadr1 = virt_to_dma32(buffer);
                parm->db.ipbfln1f = (u32) size;
                parm->db.ippathid = path->pathid;
                parm->db.ipflags1 = flags | IUCV_IPNORPY;
@@ -1379,7 +1378,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
                parm->dpl.iptrgcls = msg->class;
                parm->dpl.ipsrccls = srccls;
                parm->dpl.ipmsgtag = msg->tag;
-               parm->dpl.ipbfadr2 = (u32)virt_to_phys(answer);
+               parm->dpl.ipbfadr2 = virt_to_dma32(answer);
                parm->dpl.ipbfln2f = (u32) asize;
                memcpy(parm->dpl.iprmmsg, buffer, 8);
        } else {
@@ -1388,9 +1387,9 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
                parm->db.iptrgcls = msg->class;
                parm->db.ipsrccls = srccls;
                parm->db.ipmsgtag = msg->tag;
-               parm->db.ipbfadr1 = (u32)virt_to_phys(buffer);
+               parm->db.ipbfadr1 = virt_to_dma32(buffer);
                parm->db.ipbfln1f = (u32) size;
-               parm->db.ipbfadr2 = (u32)virt_to_phys(answer);
+               parm->db.ipbfadr2 = virt_to_dma32(answer);
                parm->db.ipbfln2f = (u32) asize;
        }
        rc = iucv_call_b2f0(IUCV_SEND, parm);
index e93f905e60b62e7b54b500be697237616b15f629..5fa3d3540c93c003737fb16ef1e6e7514580e97a 100644 (file)
@@ -1213,7 +1213,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
        if (flags & ~NFT_TABLE_F_MASK)
                return -EOPNOTSUPP;
 
-       if (flags == ctx->table->flags)
+       if (flags == (ctx->table->flags & NFT_TABLE_F_MASK))
                return 0;
 
        if ((nft_table_has_owner(ctx->table) &&
@@ -2631,19 +2631,6 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
                }
        }
 
-       if (nla[NFTA_CHAIN_COUNTERS]) {
-               if (!nft_is_base_chain(chain)) {
-                       err = -EOPNOTSUPP;
-                       goto err_hooks;
-               }
-
-               stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
-               if (IS_ERR(stats)) {
-                       err = PTR_ERR(stats);
-                       goto err_hooks;
-               }
-       }
-
        if (!(table->flags & NFT_TABLE_F_DORMANT) &&
            nft_is_base_chain(chain) &&
            !list_empty(&hook.list)) {
@@ -2658,6 +2645,20 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
        }
 
        unregister = true;
+
+       if (nla[NFTA_CHAIN_COUNTERS]) {
+               if (!nft_is_base_chain(chain)) {
+                       err = -EOPNOTSUPP;
+                       goto err_hooks;
+               }
+
+               stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
+               if (IS_ERR(stats)) {
+                       err = PTR_ERR(stats);
+                       goto err_hooks;
+               }
+       }
+
        err = -ENOMEM;
        trans = nft_trans_alloc(ctx, NFT_MSG_NEWCHAIN,
                                sizeof(struct nft_trans_chain));
index c0ceea068936a64a60f208ddbacb5049847dc71b..df8de50902463738642d4d24b59f12b17b5ff726 100644 (file)
@@ -2329,8 +2329,6 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx,
        if (m) {
                rcu_barrier();
 
-               nft_set_pipapo_match_destroy(ctx, set, m);
-
                for_each_possible_cpu(cpu)
                        pipapo_free_scratch(m, cpu);
                free_percpu(m->scratch);
@@ -2342,8 +2340,7 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx,
        if (priv->clone) {
                m = priv->clone;
 
-               if (priv->dirty)
-                       nft_set_pipapo_match_destroy(ctx, set, m);
+               nft_set_pipapo_match_destroy(ctx, set, m);
 
                for_each_possible_cpu(cpu)
                        pipapo_free_scratch(priv->clone, cpu);
index 61270826b9ac73e66f9011c3230d4668f0bf7c77..18f616f487eaad0f7b31fb074e194c0479f30d77 100644 (file)
@@ -2057,7 +2057,7 @@ retry:
        skb->priority = READ_ONCE(sk->sk_priority);
        skb->mark = READ_ONCE(sk->sk_mark);
        skb->tstamp = sockc.transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
+
        skb_setup_tx_timestamp(skb, sockc.tsflags);
 
        if (unlikely(extra_len == 4))
@@ -2586,7 +2586,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
        skb->priority = READ_ONCE(po->sk.sk_priority);
        skb->mark = READ_ONCE(po->sk.sk_mark);
        skb->tstamp = sockc->transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
        skb_setup_tx_timestamp(skb, sockc->tsflags);
        skb_zcopy_set_nouarg(skb, ph.raw);
 
@@ -3065,7 +3064,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        skb->priority = READ_ONCE(sk->sk_priority);
        skb->mark = sockc.mark;
        skb->tstamp = sockc.transmit_time;
-       skb->mono_delivery_time = !!skb->tstamp;
 
        if (unlikely(extra_len == 4))
                skb->no_fcs = 1;
@@ -4000,7 +3998,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval,
                if (val < 0 || val > 1)
                        return -EINVAL;
 
-               po->prot_hook.ignore_outgoing = !!val;
+               WRITE_ONCE(po->prot_hook.ignore_outgoing, !!val);
                return 0;
        }
        case PACKET_TX_HAS_OFF:
@@ -4134,7 +4132,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
                       0);
                break;
        case PACKET_IGNORE_OUTGOING:
-               val = po->prot_hook.ignore_outgoing;
+               val = READ_ONCE(po->prot_hook.ignore_outgoing);
                break;
        case PACKET_ROLLOVER_STATS:
                if (!po->rollover)
index 2899def23865fa47ce55faa7c7eb72fb52bc432b..09a28011065493abc083a84f8f681cd8a8acef4c 100644 (file)
@@ -103,13 +103,12 @@ EXPORT_SYMBOL_GPL(rds_send_path_reset);
 
 static int acquire_in_xmit(struct rds_conn_path *cp)
 {
-       return test_and_set_bit(RDS_IN_XMIT, &cp->cp_flags) == 0;
+       return test_and_set_bit_lock(RDS_IN_XMIT, &cp->cp_flags) == 0;
 }
 
 static void release_in_xmit(struct rds_conn_path *cp)
 {
-       clear_bit(RDS_IN_XMIT, &cp->cp_flags);
-       smp_mb__after_atomic();
+       clear_bit_unlock(RDS_IN_XMIT, &cp->cp_flags);
        /*
         * We don't use wait_on_bit()/wake_up_bit() because our waking is in a
         * hot path and finding waiters is very rare.  We don't want to walk
index 6f765768c49c5374946a652b60e3c961dc389f9e..894b8fa68e5e9546ad2dd17372420976d7eb76c0 100644 (file)
@@ -349,8 +349,8 @@ reload:
                         */
                        remain = more ? INT_MAX : msg_data_left(msg);
                        txb = call->conn->security->alloc_txbuf(call, remain, sk->sk_allocation);
-                       if (IS_ERR(txb)) {
-                               ret = PTR_ERR(txb);
+                       if (!txb) {
+                               ret = -ENOMEM;
                                goto maybe_error;
                        }
                }
index b2a82ab756c248a35b2bd5e9d2e843b6639c558e..e0679658d9de0e62edd777cad0b7e4281cfe2384 100644 (file)
@@ -33,8 +33,8 @@ struct rxrpc_txbuf *rxrpc_alloc_data_txbuf(struct rxrpc_call *call, size_t data_
        total = hoff + sizeof(*whdr) + data_size;
 
        mutex_lock(&call->conn->tx_data_alloc_lock);
-       buf = page_frag_alloc_align(&call->conn->tx_data_alloc, total, gfp,
-                                   ~(data_align - 1) & ~(L1_CACHE_BYTES - 1));
+       buf = __page_frag_alloc_align(&call->conn->tx_data_alloc, total, gfp,
+                                     ~(data_align - 1) & ~(L1_CACHE_BYTES - 1));
        mutex_unlock(&call->conn->tx_data_alloc_lock);
        if (!buf) {
                kfree(txb);
index 5b595773e59b70acbfe8c743e977a98468469b77..358cf304f4c91203749bac10f6e9154eda0a3778 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/jhash.h>
+#include <linux/module.h>
 #include <linux/sizes.h>
 #include <linux/vmalloc.h>
 #include <net/pkt_cls.h>
@@ -563,6 +564,7 @@ static struct Qdisc_ops fq_pie_qdisc_ops __read_mostly = {
        .dump_stats     = fq_pie_dump_stats,
        .owner          = THIS_MODULE,
 };
+MODULE_ALIAS_NET_SCH("fq_pie");
 
 static int __init fq_pie_module_init(void)
 {
index c5de70efdc866fb1b8ef50a3019962a8e11beeca..a0d54b422186fb5983019791ce688b3685cd18ec 100644 (file)
@@ -997,7 +997,8 @@ static const struct nla_policy entry_policy[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = {
 };
 
 static const struct nla_policy taprio_tc_policy[TCA_TAPRIO_TC_ENTRY_MAX + 1] = {
-       [TCA_TAPRIO_TC_ENTRY_INDEX]        = { .type = NLA_U32 },
+       [TCA_TAPRIO_TC_ENTRY_INDEX]        = NLA_POLICY_MAX(NLA_U32,
+                                                           TC_QOPT_MAX_QUEUE),
        [TCA_TAPRIO_TC_ENTRY_MAX_SDU]      = { .type = NLA_U32 },
        [TCA_TAPRIO_TC_ENTRY_FP]           = NLA_POLICY_RANGE(NLA_U32,
                                                              TC_FP_EXPRESS,
index 7e9c8fc9a5b4545dcb2c2e423ef609bbd77e29f7..e5f3af49a8b6215189066cbc1481406661b594e5 100644 (file)
@@ -2600,9 +2600,9 @@ out:
        return err;
 }
 
-int sendmsg_copy_msghdr(struct msghdr *msg,
-                       struct user_msghdr __user *umsg, unsigned flags,
-                       struct iovec **iov)
+static int sendmsg_copy_msghdr(struct msghdr *msg,
+                              struct user_msghdr __user *umsg, unsigned flags,
+                              struct iovec **iov)
 {
        int err;
 
@@ -2753,10 +2753,10 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
        return __sys_sendmmsg(fd, mmsg, vlen, flags, true);
 }
 
-int recvmsg_copy_msghdr(struct msghdr *msg,
-                       struct user_msghdr __user *umsg, unsigned flags,
-                       struct sockaddr __user **uaddr,
-                       struct iovec **iov)
+static int recvmsg_copy_msghdr(struct msghdr *msg,
+                              struct user_msghdr __user *umsg, unsigned flags,
+                              struct sockaddr __user **uaddr,
+                              struct iovec **iov)
 {
        ssize_t err;
 
index 653e51ae39648da177b84c82881932e9987eaa99..6346690d5c699d4d9f9b46aeeacaa923c0c32256 100644 (file)
@@ -407,7 +407,8 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
        struct net_device *dev = x->xso.dev;
 
-       if (!x->type_offload)
+       if (!x->type_offload ||
+           (x->xso.type == XFRM_DEV_OFFLOAD_UNSPECIFIED && x->encap))
                return false;
 
        if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET ||
index 1eaefc34f4b73c7bb26d0de5180f01b77906cf56..846e6ab9d5a9b660fd871a13c8f984260a1b105a 100644 (file)
@@ -100,7 +100,7 @@ rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
                -e 's:rust-logo-[0-9a-f]+\.svg:logo.svg:g' \
                -e 's:favicon-[0-9a-f]+\.svg:logo.svg:g' \
                -e 's:<link rel="alternate icon" type="image/png" href="[/.]+/static\.files/favicon-(16x16|32x32)-[0-9a-f]+\.png">::g' \
-               -e 's:<a href="srctree/([^"]+)">:<a href="$(abs_srctree)/\1">:g'
+               -e 's:<a href="srctree/([^"]+)">:<a href="$(realpath $(srctree))/\1">:g'
        $(Q)for f in $(rustdoc_output)/static.files/rustdoc-*.css; do \
                echo ".logo-container > img { object-fit: contain; }" >> $$f; done
 
@@ -414,7 +414,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
 rust-analyzer:
        $(Q)$(srctree)/scripts/generate_rust_analyzer.py \
                --cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \
-               $(abs_srctree) $(abs_objtree) \
+               $(realpath $(srctree)) $(realpath $(objtree)) \
                $(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
                $(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
 
index 23f923ccd529863b3c2b342c06709f35c71a52e7..500981eca74d424a25f1e60ba6062f281070c26d 100644 (file)
  *         __string().
  *
  *   __string_len: This is a helper to a __dynamic_array, but it understands
- *        that the array has characters in it, and with the combined
- *         use of __assign_str_len(), it will allocate 'len' + 1 bytes
+ *        that the array has characters in it, it will allocate 'len' + 1 bytes
  *         in the ring buffer and add a '\0' to the string. This is
  *         useful if the string being saved has no terminating '\0' byte.
  *         It requires that the length of the string is known as it acts
  *
  *         __string_len(foo, bar, len)
  *
- *         To assign this string, use the helper macro __assign_str_len().
+ *         To assign this string, use the helper macro __assign_str().
+ *         The length is saved via the __string_len() and is retrieved in
+ *         __assign_str().
  *
- *         __assign_str_len(foo, bar, len);
+ *         __assign_str(foo, bar);
  *
  *         Then len + 1 is allocated to the ring buffer, and a nul terminating
  *         byte is added. This is similar to:
@@ -302,6 +303,7 @@ TRACE_EVENT(foo_bar,
                __bitmask(      cpus,   num_possible_cpus()     )
                __cpumask(      cpum                            )
                __vstring(      vstr,   fmt,    va              )
+               __string_len(   lstr,   foo,    bar / 2 < strlen(foo) ? bar / 2 : strlen(foo) )
        ),
 
        TP_fast_assign(
@@ -310,12 +312,13 @@ TRACE_EVENT(foo_bar,
                memcpy(__get_dynamic_array(list), lst,
                       __length_of(lst) * sizeof(int));
                __assign_str(str, string);
+               __assign_str(lstr, foo);
                __assign_vstr(vstr, fmt, va);
                __assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus());
                __assign_cpumask(cpum, cpumask_bits(mask));
        ),
 
-       TP_printk("foo %s %d %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar,
+       TP_printk("foo %s %d %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar,
 
 /*
  * Notice here the use of some helper functions. This includes:
@@ -359,7 +362,8 @@ TRACE_EVENT(foo_bar,
                  __print_array(__get_dynamic_array(list),
                                __get_dynamic_array_len(list) / sizeof(int),
                                sizeof(int)),
-                 __get_str(str), __get_bitmask(cpus), __get_cpumask(cpum),
+                 __get_str(str), __get_str(lstr),
+                 __get_bitmask(cpus), __get_cpumask(cpum),
                  __get_str(vstr))
 );
 
@@ -570,7 +574,7 @@ TRACE_EVENT(foo_rel_loc,
        ),
 
        TP_fast_assign(
-               __assign_rel_str(foo, foo);
+               __assign_rel_str(foo);
                __entry->bar = bar;
                __assign_rel_bitmask(bitmask, mask,
                        BITS_PER_BYTE * sizeof(unsigned long));
index 7778cc97a4e042cd763fb2f743e542a0c91d71ee..2f331879816b8e2bf6c07f98572cb7c4ac1fec36 100644 (file)
@@ -113,12 +113,6 @@ endef
 # $(Q)$(MAKE) $(build)=dir
 build := -f $(srctree)/scripts/Makefile.build obj
 
-###
-# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
-# Usage:
-# $(Q)$(MAKE) $(dtbinst)=dir
-dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj
-
 ###
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=
 # Usage:
index 6673cbb6194fe0b317014b7a96485d78d87fe19b..bc90520a54266cc1d9cd2584ccde4e874f3827a7 100644 (file)
@@ -33,9 +33,12 @@ HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null |
 
 ifdef CONFIG_UNWINDER_ORC
 ifeq ($(ARCH),x86_64)
-ARCH := x86
+SRCARCH := x86
 endif
-HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include
+ifeq ($(ARCH),loongarch)
+SRCARCH := loongarch
+endif
+HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/$(SRCARCH)/include
 HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED
 endif
 
index 0fb7a785594c961ee2157be94e28172bdbb71666..baf86c0880b6d7d548f4a6a21cd6305acc717078 100644 (file)
@@ -71,6 +71,7 @@ endif
 # subdir-builtin and subdir-modorder may contain duplications. Use $(sort ...)
 subdir-builtin := $(sort $(filter %/built-in.a, $(real-obj-y)))
 subdir-modorder := $(sort $(filter %/modules.order, $(obj-m)))
+subdir-dtbslist := $(sort $(filter %/dtbs-list, $(dtb-y)))
 
 targets-for-builtin := $(extra-y)
 
@@ -213,7 +214,7 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
 # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
 # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
 
-is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y)
+is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(target-stem).o)$(OBJECT_FILES_NON_STANDARD)n),y)
 
 $(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y))
 
@@ -388,6 +389,7 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
 # To build objects in subdirs, we need to descend into the directories
 $(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ;
 $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ;
+$(subdir-dtbslist): $(obj)/%/dtbs-list: $(obj)/% ;
 
 #
 # Rule to compile a set of .o files into one .a file (without symbol table)
@@ -404,19 +406,21 @@ $(obj)/built-in.a: $(real-obj-y) FORCE
        $(call if_changed,ar_builtin)
 
 #
-# Rule to create modules.order file
+# Rule to create modules.order and dtbs-list
 #
-# Create commands to either record .ko file or cat modules.order from
-# a subdirectory
-# Add $(obj-m) as the prerequisite to avoid updating the timestamp of
-# modules.order unless contained modules are updated.
+# This is a list of build artifacts (module or dtb) from the current Makefile
+# and its sub-directories. The timestamp should be updated when any of the
+# member files.
 
-cmd_modules_order = { $(foreach m, $(real-prereqs), \
-       $(if $(filter %/modules.order, $m), cat $m, echo $m);) :; } \
+cmd_gen_order = { $(foreach m, $(real-prereqs), \
+       $(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \
        > $@
 
 $(obj)/modules.order: $(obj-m) FORCE
-       $(call if_changed,modules_order)
+       $(call if_changed,gen_order)
+
+$(obj)/dtbs-list: $(dtb-y) FORCE
+       $(call if_changed,gen_order)
 
 #
 # Rule to compile a set of .o files into one .a file (with symbol table)
index 4405d5b67578d6fdd30f2ec2b5b6e0de985cb231..67956f6496a5c062c65375dcd8c712d0be91d771 100644 (file)
@@ -8,32 +8,36 @@
 #   $INSTALL_PATH/dtbs/$KERNELRELEASE
 # ==========================================================================
 
-src := $(obj)
-
 PHONY := __dtbs_install
 __dtbs_install:
 
 include include/config/auto.conf
 include $(srctree)/scripts/Kbuild.include
-include $(kbuild-file)
-
-dtbs    := $(addprefix $(dst)/, $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-)))
-subdirs := $(addprefix $(obj)/, $(subdir-y) $(subdir-m))
 
-__dtbs_install: $(dtbs) $(subdirs)
-       @:
+dst := $(INSTALL_DTBS_PATH)
 
 quiet_cmd_dtb_install = INSTALL $@
       cmd_dtb_install = install -D $< $@
 
-$(dst)/%.dtb: $(obj)/%.dtb
+$(dst)/%: $(obj)/%
        $(call cmd,dtb_install)
 
-$(dst)/%.dtbo: $(obj)/%.dtbo
-       $(call cmd,dtb_install)
+dtbs := $(patsubst $(obj)/%,%,$(call read-file, $(obj)/dtbs-list))
+
+ifdef CONFIG_ARCH_WANT_FLAT_DTB_INSTALL
 
-PHONY += $(subdirs)
-$(subdirs):
-       $(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@))
+define gen_install_rules
+$(dst)/%: $(obj)/$(1)%
+       $$(call cmd,dtb_install)
+endef
+
+$(foreach d, $(sort $(dir $(dtbs))), $(eval $(call gen_install_rules,$(d))))
+
+dtbs := $(notdir $(dtbs))
+
+endif # CONFIG_ARCH_WANT_FLAT_DTB_INSTALL
+
+__dtbs_install: $(addprefix $(dst)/, $(dtbs))
+       @:
 
 .PHONY: $(PHONY)
index a9e552a1e9105b5efb559a23e4a2943c102b12a2..3ce5d503a6da98efe3b7ec8b62138c5e12eb258c 100644 (file)
@@ -132,6 +132,8 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
 KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
 KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access)
 KBUILD_CFLAGS += $(call cc-disable-warning, cast-function-type-strict)
+KBUILD_CFLAGS += -Wno-enum-compare-conditional
+KBUILD_CFLAGS += -Wno-enum-enum-conversion
 endif
 
 endif
@@ -185,7 +187,6 @@ KBUILD_CFLAGS += -Wpointer-arith
 KBUILD_CFLAGS += -Wredundant-decls
 KBUILD_CFLAGS += -Wsign-compare
 KBUILD_CFLAGS += -Wswitch-default
-KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat)
 
 KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3
 
index 1bd59b8db05f0b8e89a140ee724ec799c3922b86..3179747cbd2cc014d0a8ba98cff008f28fbbc050 100644 (file)
@@ -45,6 +45,11 @@ else
 obj-y          := $(filter-out %/, $(obj-y))
 endif
 
+ifdef need-dtbslist
+dtb-y          += $(addsuffix /dtbs-list, $(subdir-ym))
+always-y       += dtbs-list
+endif
+
 # Expand $(foo-objs) $(foo-y) etc. by replacing their individuals
 suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s))))
 # List composite targets that are constructed by combining other targets
@@ -99,6 +104,7 @@ lib-y                := $(addprefix $(obj)/,$(lib-y))
 real-obj-y     := $(addprefix $(obj)/,$(real-obj-y))
 real-obj-m     := $(addprefix $(obj)/,$(real-obj-m))
 multi-obj-m    := $(addprefix $(obj)/, $(multi-obj-m))
+dtb-y          := $(addprefix $(obj)/, $(dtb-y))
 multi-dtb-y    := $(addprefix $(obj)/, $(multi-dtb-y))
 real-dtb-y     := $(addprefix $(obj)/, $(real-dtb-y))
 subdir-ym      := $(addprefix $(obj)/,$(subdir-ym))
@@ -148,7 +154,7 @@ _cpp_flags     = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds)
 #
 ifeq ($(CONFIG_GCOV_KERNEL),y)
 _c_flags += $(if $(patsubst n%,, \
-               $(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
+               $(GCOV_PROFILE_$(target-stem).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
                $(CFLAGS_GCOV))
 endif
 
@@ -159,32 +165,32 @@ endif
 ifeq ($(CONFIG_KASAN),y)
 ifneq ($(CONFIG_KASAN_HW_TAGS),y)
 _c_flags += $(if $(patsubst n%,, \
-               $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
+               $(KASAN_SANITIZE_$(target-stem).o)$(KASAN_SANITIZE)y), \
                $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE))
 endif
 endif
 
 ifeq ($(CONFIG_KMSAN),y)
 _c_flags += $(if $(patsubst n%,, \
-               $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \
+               $(KMSAN_SANITIZE_$(target-stem).o)$(KMSAN_SANITIZE)y), \
                $(CFLAGS_KMSAN))
 _c_flags += $(if $(patsubst n%,, \
-               $(KMSAN_ENABLE_CHECKS_$(basetarget).o)$(KMSAN_ENABLE_CHECKS)y), \
+               $(KMSAN_ENABLE_CHECKS_$(target-stem).o)$(KMSAN_ENABLE_CHECKS)y), \
                , -mllvm -msan-disable-checks=1)
 endif
 
 ifeq ($(CONFIG_UBSAN),y)
 _c_flags += $(if $(patsubst n%,, \
-               $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)y), \
+               $(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SANITIZE)y), \
                $(CFLAGS_UBSAN))
 _c_flags += $(if $(patsubst n%,, \
-               $(UBSAN_SIGNED_WRAP_$(basetarget).o)$(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)y), \
+               $(UBSAN_SIGNED_WRAP_$(target-stem).o)$(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)y), \
                $(CFLAGS_UBSAN_SIGNED_WRAP))
 endif
 
 ifeq ($(CONFIG_KCOV),y)
 _c_flags += $(if $(patsubst n%,, \
-       $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \
+       $(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \
        $(CFLAGS_KCOV))
 endif
 
@@ -194,12 +200,12 @@ endif
 #
 ifeq ($(CONFIG_KCSAN),y)
 _c_flags += $(if $(patsubst n%,, \
-       $(KCSAN_SANITIZE_$(basetarget).o)$(KCSAN_SANITIZE)y), \
+       $(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)y), \
        $(CFLAGS_KCSAN))
 # Some uninstrumented files provide implied barriers required to avoid false
 # positives: set KCSAN_INSTRUMENT_BARRIERS for barrier instrumentation only.
 _c_flags += $(if $(patsubst n%,, \
-       $(KCSAN_INSTRUMENT_BARRIERS_$(basetarget).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \
+       $(KCSAN_INSTRUMENT_BARRIERS_$(target-stem).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \
        -D__KCSAN_INSTRUMENT_BARRIERS__)
 endif
 
@@ -364,7 +370,7 @@ DTC_FLAGS += -Wnode_name_chars_strict \
        -Wunique_unit_address
 endif
 
-DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
+DTC_FLAGS += $(DTC_FLAGS_$(target-stem))
 
 # Set -@ if the target is a base DTB that overlay is applied onto
 DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@)
index a81dfb1f518106e50d8ebdb2014be1fcb028bba5..38653f3e81088906177b72f22994e57a6cd98068 100644 (file)
@@ -135,7 +135,7 @@ snap-pkg:
        mkdir $(objtree)/snap
        $(MAKE) clean
        sed "s@KERNELRELEASE@$(KERNELRELEASE)@; \
-               s@SRCTREE@$(abs_srctree)@" \
+               s@SRCTREE@$(realpath $(srctree))@" \
                $(srctree)/scripts/package/snapcraft.template > \
                $(objtree)/snap/snapcraft.yaml
        cd $(objtree)/snap && \
index 4f163e0bf6a48719c522ee9d6cd63a5b96c5d1c6..20274c63e7451a8722137e7077f4456f293f4e54 100755 (executable)
@@ -8,7 +8,7 @@
 # Example invocation:
 #      scripts/check-sysctl-docs -vtable="kernel" \
 #              Documentation/admin-guide/sysctl/kernel.rst \
-#              $(git grep -l register_sysctl_)
+#              $(git grep -l register_sysctl)
 #
 # Specify -vdebug=1 to see debugging information
 
@@ -20,14 +20,10 @@ BEGIN {
 }
 
 # 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)
@@ -94,42 +90,23 @@ FNR == NR {
 
 # Stage 2: process each file and find all sysctl tables
 BEGINFILE {
-    delete children
     delete entries
-    delete paths
-    curpath = ""
     curtable = ""
     curentry = ""
+    delete vars
     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]
+/^static( const)? struct ctl_table/ {
+    match($0, /static( const)? struct ctl_table ([^][]+)/, tables)
+    curtable = tables[2]
     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
+    delete vars
 }
 
 curtable && /\.procname[\t ]*=[\t ]*".+"/ {
@@ -140,10 +117,32 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ {
     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.*/ {
+    match($0, /register_sysctl(|_init|_sz)\("([^"]+)" *, *([^,)]+)/, tables)
+    if (debug) print "Registering table " tables[3] " at " tables[2]
+    if (tables[2] == table) {
+        for (entry in entries[tables[3]]) {
+            printentry(entry)
+        }
+    }
+}
+
+/kmemdup.*/ {
+    match($0, /([^ \t]+) *= *kmemdup\(([^,]+) *,/, names)
+    if (debug) print "Found variable " names[1] " for table " names[2]
+    if (names[2] in entries) {
+        vars[names[1]] = names[2]
+    }
+}
+
+/__register_sysctl_table.*/ {
+    match($0, /__register_sysctl_table\([^,]+, *"([^"]+)" *, *([^,]+)/, tables)
+    if (debug) print "Registering variable table " tables[2] " at " tables[1]
+    if (tables[1] == table && tables[2] in vars) {
+        for (entry in entries[vars[tables[2]]]) {
+            printentry(entry)
+        }
+    }
 }
 
 END {
index 550d1d2fc02a9b95f453594268f4bf44045808e9..dfcf9304195f3976189b5f4bc4806319597ffc49 100644 (file)
@@ -28,7 +28,7 @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
 
 @rp depends on patch@
 identifier show, dev, attr, buf;
-expression BUF, SZ, FORMAT, STR;
+expression BUF, SZ, FORMAT;
 @@
 
 ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
diff --git a/scripts/kconfig/array_size.h b/scripts/kconfig/array_size.h
new file mode 100644 (file)
index 0000000..26ba78d
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARRAY_SIZE_H
+#define ARRAY_SIZE_H
+
+/**
+ * ARRAY_SIZE - get the number of elements in array @arr
+ * @arr: array to be sized
+ */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#endif /* ARRAY_SIZE_H */
index 662a5e7c37c28539ce7104085478c718848c4fc3..b5730061872baea05947ca95ec94391a0a468e36 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/time.h>
 #include <errno.h>
 
+#include "internal.h"
 #include "lkc.h"
 
 static void conf(struct menu *menu);
@@ -171,7 +172,7 @@ enum conf_def_mode {
 static bool conf_set_all_new_symbols(enum conf_def_mode mode)
 {
        struct symbol *sym, *csym;
-       int i, cnt;
+       int cnt;
        /*
         * can't go as the default in switch-case below, otherwise gcc whines
         * about -Wmaybe-uninitialized
@@ -226,7 +227,7 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
                }
        }
 
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
                        continue;
                switch (sym_get_type(sym)) {
@@ -278,14 +279,14 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
         * and the rest to no.
         */
        if (mode != def_random) {
-               for_all_symbols(i, csym) {
+               for_all_symbols(csym) {
                        if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
                            sym_is_choice_value(csym))
                                csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
                }
        }
 
-       for_all_symbols(i, csym) {
+       for_all_symbols(csym) {
                if (sym_has_value(csym) || !sym_is_choice(csym))
                        continue;
 
@@ -304,9 +305,8 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
 static void conf_rewrite_tristates(tristate old_val, tristate new_val)
 {
        struct symbol *sym;
-       int i;
 
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                if (sym_get_type(sym) == S_TRISTATE &&
                    sym->def[S_DEF_USER].tri == old_val)
                        sym->def[S_DEF_USER].tri = new_val;
index f53dcdd445976aa8759e13e6e3103ef02f76ead1..0e35c4819cf1d2f71e998b11cac56cdfea9fbbc4 100644 (file)
 #include <time.h>
 #include <unistd.h>
 
+#include "internal.h"
 #include "lkc.h"
 
+struct gstr autoconf_cmd;
+
 /* return true if 'path' exists, false otherwise */
 static bool is_present(const char *path)
 {
@@ -293,63 +296,12 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
        return 0;
 }
 
-#define LINE_GROWTH 16
-static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
-{
-       size_t new_size = slen + 1;
-
-       if (new_size > *n) {
-               new_size += LINE_GROWTH - 1;
-               new_size *= 2;
-               *lineptr = xrealloc(*lineptr, new_size);
-               *n = new_size;
-       }
-
-       (*lineptr)[slen] = c;
-
-       return 0;
-}
-
-static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
-{
-       char *line = *lineptr;
-       size_t slen = 0;
-
-       for (;;) {
-               int c = getc(stream);
-
-               switch (c) {
-               case '\n':
-                       if (add_byte(c, &line, slen, n) < 0)
-                               goto e_out;
-                       slen++;
-                       /* fall through */
-               case EOF:
-                       if (add_byte('\0', &line, slen, n) < 0)
-                               goto e_out;
-                       *lineptr = line;
-                       if (slen == 0)
-                               return -1;
-                       return slen;
-               default:
-                       if (add_byte(c, &line, slen, n) < 0)
-                               goto e_out;
-                       slen++;
-               }
-       }
-
-e_out:
-       line[slen-1] = '\0';
-       *lineptr = line;
-       return -1;
-}
-
 /* like getline(), but the newline character is stripped away */
 static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream)
 {
        ssize_t len;
 
-       len = compat_getline(lineptr, n, stream);
+       len = getline(lineptr, n, stream);
 
        if (len > 0 && (*lineptr)[len - 1] == '\n') {
                len--;
@@ -371,7 +323,7 @@ int conf_read_simple(const char *name, int def)
        size_t  line_asize = 0;
        char *p, *val;
        struct symbol *sym;
-       int i, def_flags;
+       int def_flags;
        const char *warn_unknown, *sym_name;
 
        warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS");
@@ -429,7 +381,7 @@ load:
        conf_warnings = 0;
 
        def_flags = SYMBOL_DEF << def;
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                sym->flags |= SYMBOL_CHANGED;
                sym->flags &= ~(def_flags|SYMBOL_VALID);
                if (sym_is_choice(sym))
@@ -538,7 +490,6 @@ int conf_read(const char *name)
 {
        struct symbol *sym;
        int conf_unsaved = 0;
-       int i;
 
        conf_set_changed(false);
 
@@ -549,7 +500,7 @@ int conf_read(const char *name)
 
        sym_calc_value(modules_sym);
 
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                sym_calc_value(sym);
                if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
                        continue;
@@ -573,7 +524,7 @@ int conf_read(const char *name)
                /* maybe print value in verbose mode... */
        }
 
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
                        /* Reset values of generates values, so they'll appear
                         * as new, if they should become visible, but that
@@ -848,10 +799,7 @@ int conf_write_defconfig(const char *filename)
        while (menu != NULL)
        {
                sym = menu->sym;
-               if (sym == NULL) {
-                       if (!menu_is_visible(menu))
-                               goto next_menu;
-               } else if (!sym_is_choice(sym)) {
+               if (sym && !sym_is_choice(sym)) {
                        sym_calc_value(sym);
                        if (!(sym->flags & SYMBOL_WRITE))
                                goto next_menu;
@@ -911,7 +859,6 @@ int conf_write(const char *name)
        const char *str;
        char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
        char *env;
-       int i;
        bool need_newline = false;
 
        if (!name)
@@ -995,7 +942,7 @@ end_check:
        }
        fclose(out);
 
-       for_all_symbols(i, sym)
+       for_all_symbols(sym)
                sym->flags &= ~SYMBOL_WRITTEN;
 
        if (*tmpname) {
@@ -1023,7 +970,6 @@ end_check:
 static int conf_write_autoconf_cmd(const char *autoconf_name)
 {
        char name[PATH_MAX], tmp[PATH_MAX];
-       struct file *file;
        FILE *out;
        int ret;
 
@@ -1044,15 +990,9 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
                return -1;
        }
 
-       fprintf(out, "deps_config := \\\n");
-       for (file = file_list; file; file = file->next)
-               fprintf(out, "\t%s \\\n", file->name);
-
-       fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
+       fprintf(out, "autoconfig := %s\n", autoconf_name);
 
-       env_write_dep(out, autoconf_name);
-
-       fprintf(out, "\n$(deps_config): ;\n");
+       fputs(str_get(&autoconf_cmd), out);
 
        fflush(out);
        ret = ferror(out); /* error check for all fprintf() calls */
@@ -1072,7 +1012,7 @@ static int conf_touch_deps(void)
 {
        const char *name, *tmp;
        struct symbol *sym;
-       int res, i;
+       int res;
 
        name = conf_get_autoconfig_name();
        tmp = strrchr(name, '/');
@@ -1086,7 +1026,7 @@ static int conf_touch_deps(void)
        conf_read_simple(name, S_DEF_AUTO);
        sym_calc_value(modules_sym);
 
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                sym_calc_value(sym);
                if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
                        continue;
@@ -1152,7 +1092,7 @@ static int __conf_write_autoconf(const char *filename,
        char tmp[PATH_MAX];
        FILE *file;
        struct symbol *sym;
-       int ret, i;
+       int ret;
 
        if (make_parent_dir(filename))
                return -1;
@@ -1169,7 +1109,7 @@ static int __conf_write_autoconf(const char *filename,
 
        conf_write_heading(file, comment_style);
 
-       for_all_symbols(i, sym)
+       for_all_symbols(sym)
                if ((sym->flags & SYMBOL_WRITE) && sym->name)
                        print_symbol(file, sym);
 
@@ -1192,7 +1132,7 @@ int conf_write_autoconf(int overwrite)
 {
        struct symbol *sym;
        const char *autoconf_name = conf_get_autoconfig_name();
-       int ret, i;
+       int ret;
 
        if (!overwrite && is_present(autoconf_name))
                return 0;
@@ -1204,7 +1144,7 @@ int conf_write_autoconf(int overwrite)
        if (conf_touch_deps())
                return 1;
 
-       for_all_symbols(i, sym)
+       for_all_symbols(sym)
                sym_calc_value(sym);
 
        ret = __conf_write_autoconf(conf_get_autoheader_name(),
index 4a9a23b1b7e1f91315f17675685d11dd97c4aa4d..0158f5eac45428eb01ec5525abac7016ba7814de 100644 (file)
@@ -12,17 +12,12 @@ extern "C" {
 
 #include <assert.h>
 #include <stdio.h>
-#include "list.h"
+#include "list_types.h"
 #ifndef __cplusplus
 #include <stdbool.h>
 #endif
 
-struct file {
-       struct file *next;
-       struct file *parent;
-       const char *name;
-       int lineno;
-};
+#include "list_types.h"
 
 typedef enum tristate {
        no, mod, yes
@@ -81,8 +76,8 @@ enum {
  * SYMBOL_CHOICE bit set in 'flags'.
  */
 struct symbol {
-       /* The next symbol in the same bucket in the symbol hash table */
-       struct symbol *next;
+       /* link node for the hash table */
+       struct hlist_node node;
 
        /* The name of the symbol, e.g. "FOO" for 'config FOO' */
        char *name;
@@ -113,6 +108,9 @@ struct symbol {
         */
        tristate visible;
 
+       /* config entries associated with this symbol */
+       struct list_head menus;
+
        /* SYMBOL_* flags */
        int flags;
 
@@ -131,8 +129,6 @@ struct symbol {
        struct expr_value implied;
 };
 
-#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next)
-
 #define SYMBOL_CONST      0x0001  /* symbol is const */
 #define SYMBOL_CHECK      0x0008  /* used during dependency checking */
 #define SYMBOL_CHOICE     0x0010  /* start of a choice block (null name) */
@@ -157,7 +153,6 @@ struct symbol {
 #define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000
 
 #define SYMBOL_MAXLENGTH       256
-#define SYMBOL_HASHSIZE                9973
 
 /* A property represent the config options that can be associated
  * with a config "symbol".
@@ -195,7 +190,7 @@ struct property {
        struct menu *menu;         /* the menu the property are associated with
                                    * valid for: P_SELECT, P_RANGE, P_CHOICE,
                                    * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
-       struct file *file;         /* what file was this property defined */
+       const char *filename;      /* what file was this property defined */
        int lineno;                /* what lineno was this property defined */
 };
 
@@ -230,6 +225,8 @@ struct menu {
         */
        struct symbol *sym;
 
+       struct list_head link;  /* link to symbol::menus */
+
        /*
         * The prompt associated with the node. This holds the prompt for a
         * symbol as well as the text for a menu or comment, along with the
@@ -256,7 +253,7 @@ struct menu {
        char *help;
 
        /* The location where the menu node appears in the Kconfig files */
-       struct file *file;
+       const char *filename;
        int lineno;
 
        /* For use by front ends that need to store auxiliary data */
@@ -277,10 +274,6 @@ struct jump_key {
        struct menu *target;
 };
 
-extern struct file *file_list;
-extern struct file *current_file;
-struct file *lookup_file(const char *name);
-
 extern struct symbol symbol_yes, symbol_no, symbol_mod;
 extern struct symbol *modules_sym;
 extern int cdebug;
diff --git a/scripts/kconfig/hashtable.h b/scripts/kconfig/hashtable.h
new file mode 100644 (file)
index 0000000..a0a2c8f
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef HASHTABLE_H
+#define HASHTABLE_H
+
+#include "array_size.h"
+#include "list.h"
+
+#define HASH_SIZE(name) (ARRAY_SIZE(name))
+
+#define HASHTABLE_DECLARE(name, size)          struct hlist_head name[size]
+
+#define HASHTABLE_DEFINE(name, size)                                           \
+       HASHTABLE_DECLARE(name, size) =                                         \
+                       { [0 ... ((size) - 1)] = HLIST_HEAD_INIT }
+
+#define hash_head(table, key)          (&(table)[(key) % HASH_SIZE(table)])
+
+/**
+ * hash_add - add an object to a hashtable
+ * @table: hashtable to add to
+ * @node: the &struct hlist_node of the object to be added
+ * @key: the key of the object to be added
+ */
+#define hash_add(table, node, key)                                             \
+       hlist_add_head(node, hash_head(table, key))
+
+/**
+ * hash_for_each - iterate over a hashtable
+ * @table: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ */
+#define hash_for_each(table, obj, member)                              \
+       for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++)             \
+               hlist_for_each_entry(obj, &table[_bkt], member)
+
+/**
+ * hash_for_each_possible - iterate over all possible objects hashing to the
+ * same bucket
+ * @table: hashtable to iterate
+ * @obj: the type * to use as a loop cursor for each entry
+ * @member: the name of the hlist_node within the struct
+ * @key: the key of the objects to iterate over
+ */
+#define hash_for_each_possible(table, obj, member, key)                        \
+       hlist_for_each_entry(obj, hash_head(table, key), member)
+
+#endif /* HASHTABLE_H */
index 2f7298c21b64d3cdc48197bc35057994c9a0ff35..6c721c4cfd72bd94370cc7e8c7f61332169bf3bd 100644 (file)
@@ -2,8 +2,20 @@
 #ifndef INTERNAL_H
 #define INTERNAL_H
 
+#include "hashtable.h"
+
+#define SYMBOL_HASHSIZE                (1U << 14)
+
+extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE);
+
+#define for_all_symbols(sym) \
+       hash_for_each(sym_hashtable, sym, node)
+
 struct menu;
 
 extern struct menu *current_menu, *current_entry;
 
+extern const char *cur_filename;
+extern int cur_lineno;
+
 #endif /* INTERNAL_H */
index cc386e44368346c2309d2f60aab3cad10a5cefb0..89544c3a1a2995d0daf817adbc7ad2d588ccf76d 100644 (file)
 #include <string.h>
 
 #include "lkc.h"
+#include "preprocess.h"
+
 #include "parser.tab.h"
 
 #define YY_DECL                static int yylex1(void)
 
 #define START_STRSIZE  16
 
-static struct {
-       struct file *file;
-       int lineno;
-} current_pos;
+/* The Kconfig file currently being parsed.  */
+const char *cur_filename;
+
+/*
+ * The line number of the current statement. This does not match yylineno.
+ * yylineno is used by the lexer, while cur_lineno is used by the parser.
+ */
+int cur_lineno;
 
 static int prev_prev_token = T_EOL;
 static int prev_token = T_EOL;
@@ -33,6 +39,9 @@ static int text_size, text_asize;
 struct buffer {
        struct buffer *parent;
        YY_BUFFER_STATE state;
+       int yylineno;
+       const char *filename;
+       int source_lineno;
 };
 
 static struct buffer *current_buf;
@@ -77,7 +86,7 @@ static void warn_ignored_character(char chr)
 {
        fprintf(stderr,
                "%s:%d:warning: ignoring unsupported character '%c'\n",
-               current_file->name, yylineno, chr);
+               cur_filename, yylineno, chr);
 }
 %}
 
@@ -180,7 +189,7 @@ n   [A-Za-z0-9_-]
        \n      {
                fprintf(stderr,
                        "%s:%d:warning: multi-line strings not supported\n",
-                       zconf_curname(), zconf_lineno());
+                       cur_filename, cur_lineno);
                unput('\n');
                BEGIN(INITIAL);
                yylval.string = text;
@@ -246,9 +255,9 @@ n   [A-Za-z0-9_-]
 
        if (prev_token != T_EOL && prev_token != T_HELPTEXT)
                fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
-                       current_file->name, yylineno);
+                       cur_filename, yylineno);
 
-       if (current_file) {
+       if (current_buf) {
                zconf_endfile();
                return T_EOL;
        }
@@ -267,19 +276,17 @@ repeat:
        token = yylex1();
 
        if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
-               if (token == T_EOL) {
+               if (token == T_EOL)
                        /* Do not pass unneeded T_EOL to the parser. */
                        goto repeat;
-               } else {
+               else
                        /*
-                        * For the parser, update file/lineno at the first token
+                        * For the parser, update lineno at the first token
                         * of each statement. Generally, \n is a statement
                         * terminator in Kconfig, but it is not always true
                         * because \n could be escaped by a backslash.
                         */
-                       current_pos.file = current_file;
-                       current_pos.lineno = yylineno;
-               }
+                       cur_lineno = yylineno;
        }
 
        if (prev_prev_token == T_EOL && prev_token == T_WORD &&
@@ -302,8 +309,11 @@ static char *expand_token(const char *in, size_t n)
        new_string();
        append_string(in, n);
 
-       /* get the whole line because we do not know the end of token. */
-       while ((c = input()) != EOF) {
+       /*
+        * get the whole line because we do not know the end of token.
+        * input() returns 0 (not EOF!) when it reachs the end of file.
+        */
+       while ((c = input()) != 0) {
                if (c == '\n') {
                        unput(c);
                        break;
@@ -391,78 +401,60 @@ void zconf_initscan(const char *name)
                exit(1);
        }
 
-       current_buf = xmalloc(sizeof(*current_buf));
-       memset(current_buf, 0, sizeof(*current_buf));
-
-       current_file = file_lookup(name);
+       cur_filename = file_lookup(name);
        yylineno = 1;
 }
 
 void zconf_nextfile(const char *name)
 {
-       struct file *iter;
-       struct file *file = file_lookup(name);
        struct buffer *buf = xmalloc(sizeof(*buf));
-       memset(buf, 0, sizeof(*buf));
+       bool recur_include = false;
 
-       current_buf->state = YY_CURRENT_BUFFER;
-       yyin = zconf_fopen(file->name);
+       buf->state = YY_CURRENT_BUFFER;
+       buf->yylineno = yylineno;
+       buf->filename = cur_filename;
+       buf->source_lineno = cur_lineno;
+       buf->parent = current_buf;
+       current_buf = buf;
+       yyin = zconf_fopen(name);
        if (!yyin) {
                fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
-                       zconf_curname(), zconf_lineno(), file->name);
+                       cur_filename, cur_lineno, name);
                exit(1);
        }
        yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
-       buf->parent = current_buf;
-       current_buf = buf;
 
-       current_file->lineno = yylineno;
-       file->parent = current_file;
-
-       for (iter = current_file; iter; iter = iter->parent) {
-               if (!strcmp(iter->name, file->name)) {
-                       fprintf(stderr,
-                               "Recursive inclusion detected.\n"
-                               "Inclusion path:\n"
-                               "  current file : %s\n", file->name);
-                       iter = file;
-                       do {
-                               iter = iter->parent;
-                               fprintf(stderr, "  included from: %s:%d\n",
-                                       iter->name, iter->lineno - 1);
-                       } while (strcmp(iter->name, file->name));
-                       exit(1);
-               }
+       for (buf = current_buf; buf; buf = buf->parent) {
+               if (!strcmp(buf->filename, name))
+                       recur_include = true;
        }
 
-       yylineno = 1;
-       current_file = file;
-}
-
-static void zconf_endfile(void)
-{
-       struct buffer *parent;
-
-       current_file = current_file->parent;
-       if (current_file)
-               yylineno = current_file->lineno;
+       if (recur_include) {
+               fprintf(stderr,
+                       "Recursive inclusion detected.\n"
+                       "Inclusion path:\n"
+                       "  current file : %s\n", name);
 
-       parent = current_buf->parent;
-       if (parent) {
-               fclose(yyin);
-               yy_delete_buffer(YY_CURRENT_BUFFER);
-               yy_switch_to_buffer(parent->state);
+               for (buf = current_buf; buf; buf = buf->parent)
+                       fprintf(stderr, "  included from: %s:%d\n",
+                               buf->filename, buf->source_lineno);
+               exit(1);
        }
-       free(current_buf);
-       current_buf = parent;
-}
 
-int zconf_lineno(void)
-{
-       return current_pos.lineno;
+       yylineno = 1;
+       cur_filename = file_lookup(name);
 }
 
-const char *zconf_curname(void)
+static void zconf_endfile(void)
 {
-       return current_pos.file ? current_pos.file->name : "<none>";
+       struct buffer *tmp;
+
+       fclose(yyin);
+       yy_delete_buffer(YY_CURRENT_BUFFER);
+       yy_switch_to_buffer(current_buf->state);
+       yylineno = current_buf->yylineno;
+       cur_filename = current_buf->filename;
+       tmp = current_buf;
+       current_buf = current_buf->parent;
+       free(tmp);
 }
index 45cb237ab7ef7a9f17779647220da6a30afd06fc..882859ddf9f4f94cba26f3d5ab41fe9be04448d4 100644 (file)
@@ -2,29 +2,39 @@
 #ifndef LIST_H
 #define LIST_H
 
-/*
- * Copied from include/linux/...
- */
+#include <stddef.h>
 
-#undef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#include "list_types.h"
+
+/* Are two types/vars the same type (ignoring qualifiers)? */
+#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
 
 /**
  * container_of - cast a member of a structure out to the containing structure
- * @ptr:        the pointer to the member.
- * @type:       the type of the container struct this is embedded in.
- * @member:     the name of the member within the struct.
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
  *
  */
-#define container_of(ptr, type, member) ({                      \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
-
+#define container_of(ptr, type, member) ({                             \
+       void *__mptr = (void *)(ptr);                                   \
+       _Static_assert(__same_type(*(ptr), ((type *)0)->member) ||      \
+                     __same_type(*(ptr), void),                        \
+                     "pointer type mismatch in container_of()");       \
+       ((type *)(__mptr - offsetof(type, member))); })
 
-struct list_head {
-       struct list_head *next, *prev;
-};
+#define LIST_POISON1  ((void *) 0x100)
+#define LIST_POISON2  ((void *) 0x122)
 
+/*
+ * Circular doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
 
 #define LIST_HEAD_INIT(name) { &(name), &(name) }
 
@@ -32,45 +42,16 @@ struct list_head {
        struct list_head name = LIST_HEAD_INIT(name)
 
 /**
- * list_entry - get the struct for this entry
- * @ptr:       the &struct list_head pointer.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_head within the struct.
- */
-#define list_entry(ptr, type, member) \
-       container_of(ptr, type, member)
-
-/**
- * list_for_each_entry -       iterate over list of given type
- * @pos:       the type * to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the list_head within the struct.
- */
-#define list_for_each_entry(pos, head, member)                         \
-       for (pos = list_entry((head)->next, typeof(*pos), member);      \
-            &pos->member != (head);    \
-            pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:       the type * to use as a loop cursor.
- * @n:         another type * to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the list_head within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member)                 \
-       for (pos = list_entry((head)->next, typeof(*pos), member),      \
-               n = list_entry(pos->member.next, typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
+ * INIT_LIST_HEAD - Initialize a list_head structure
+ * @list: list_head structure to be initialized.
+ *
+ * Initializes the list_head to point to itself.  If it is a list header,
+ * the result is an empty list.
  */
-static inline int list_empty(const struct list_head *head)
+static inline void INIT_LIST_HEAD(struct list_head *list)
 {
-       return head->next == head;
+       list->next = list;
+       list->prev = list;
 }
 
 /*
@@ -79,14 +60,27 @@ static inline int list_empty(const struct list_head *head)
  * This is only for internal list manipulation where we know
  * the prev/next entries already!
  */
-static inline void __list_add(struct list_head *_new,
+static inline void __list_add(struct list_head *new,
                              struct list_head *prev,
                              struct list_head *next)
 {
-       next->prev = _new;
-       _new->next = next;
-       _new->prev = prev;
-       prev->next = _new;
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
 }
 
 /**
@@ -97,9 +91,9 @@ static inline void __list_add(struct list_head *_new,
  * Insert a new entry before the specified head.
  * This is useful for implementing queues.
  */
-static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
 {
-       __list_add(_new, head->prev, head);
+       __list_add(new, head->prev, head);
 }
 
 /*
@@ -115,8 +109,11 @@ static inline void __list_del(struct list_head *prev, struct list_head *next)
        prev->next = next;
 }
 
-#define LIST_POISON1  ((void *) 0x00100100)
-#define LIST_POISON2  ((void *) 0x00200200)
+static inline void __list_del_entry(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+}
+
 /**
  * list_del - deletes entry from list.
  * @entry: the element to delete from the list.
@@ -125,8 +122,135 @@ static inline void __list_del(struct list_head *prev, struct list_head *next)
  */
 static inline void list_del(struct list_head *entry)
 {
-       __list_del(entry->prev, entry->next);
-       entry->next = (struct list_head*)LIST_POISON1;
-       entry->prev = (struct list_head*)LIST_POISON2;
+       __list_del_entry(entry);
+       entry->next = LIST_POISON1;
+       entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_is_head - tests whether @list is the list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_head(const struct list_head *list, const struct list_head *head)
+{
+       return list == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+       return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:       the list head to take the element from.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+       list_entry((ptr)->next, type, member)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos:       the type * to cursor
+ * @member:    the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+       list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_entry_is_head - test if the entry points to the head of the list
+ * @pos:       the type * to cursor
+ * @head:      the head for your list.
+ * @member:    the name of the list_head within the struct.
+ */
+#define list_entry_is_head(pos, head, member)                          \
+       (&pos->member == (head))
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the list_head within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                         \
+       for (pos = list_first_entry(head, typeof(*pos), member);        \
+            !list_entry_is_head(pos, head, member);                    \
+            pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type. Safe against removal of list entry
+ * @pos:       the type * to use as a loop cursor.
+ * @n:         another type * to use as temporary storage
+ * @head:      the head for your list.
+ * @member:    the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)                 \
+       for (pos = list_first_entry(head, typeof(*pos), member),        \
+               n = list_next_entry(pos, member);                       \
+            !list_entry_is_head(pos, head, member);                    \
+            pos = n, n = list_next_entry(n, member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+#define HLIST_HEAD_INIT { .first = NULL }
+
+/**
+ * hlist_add_head - add a new entry at the beginning of the hlist
+ * @n: new entry to be added
+ * @h: hlist head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+       struct hlist_node *first = h->first;
+
+       n->next = first;
+       if (first)
+               first->pprev = &n->next;
+       h->first = n;
+       n->pprev = &h->first;
 }
-#endif
+
+#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define hlist_entry_safe(ptr, type, member) \
+       ({ typeof(ptr) ____ptr = (ptr); \
+          ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+       })
+
+/**
+ * hlist_for_each_entry        - iterate over list of given type
+ * @pos:       the type * to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(pos, head, member)                                \
+       for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+            pos;                                                       \
+            pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#endif /* LIST_H */
diff --git a/scripts/kconfig/list_types.h b/scripts/kconfig/list_types.h
new file mode 100644 (file)
index 0000000..d935b7c
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LIST_TYPES_H
+#define LIST_TYPES_H
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+struct hlist_head {
+       struct hlist_node *first;
+};
+
+struct hlist_node {
+       struct hlist_node *next, **pprev;
+};
+
+#endif /* LIST_TYPES_H */
index 5cdc8f5e6446ab55e42ce21dfbe728b0ab22aee7..e69d7c59d930272e177618e440c42bee1e8bbce6 100644 (file)
@@ -36,10 +36,9 @@ void zconf_starthelp(void);
 FILE *zconf_fopen(const char *name);
 void zconf_initscan(const char *name);
 void zconf_nextfile(const char *name);
-int zconf_lineno(void);
-const char *zconf_curname(void);
 
 /* confdata.c */
+extern struct gstr autoconf_cmd;
 const char *conf_get_configname(void);
 void set_all_choice_values(struct symbol *csym);
 
@@ -53,7 +52,8 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
 }
 
 /* util.c */
-struct file *file_lookup(const char *name);
+unsigned int strhash(const char *s);
+const char *file_lookup(const char *name);
 void *xmalloc(size_t size);
 void *xcalloc(size_t nmemb, size_t size);
 void *xrealloc(void *p, size_t size);
index a4ae5e9eadadb8758b5911d0f38c028b0622d937..2807fa584c2b01a37e7fb13bd2c4d570b22798fe 100644 (file)
@@ -18,8 +18,6 @@ void conf_set_message_callback(void (*fn)(const char *s));
 bool conf_errors(void);
 
 /* symbol.c */
-extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
-
 struct symbol * sym_lookup(const char *name, int flags);
 struct symbol * sym_find(const char *name);
 void print_symbol_for_listconfig(struct symbol *sym);
@@ -40,19 +38,6 @@ const char * sym_get_string_value(struct symbol *sym);
 
 const char * prop_get_type_name(enum prop_type type);
 
-/* preprocess.c */
-enum variable_flavor {
-       VAR_SIMPLE,
-       VAR_RECURSIVE,
-       VAR_APPEND,
-};
-void env_write_dep(FILE *f, const char *auto_conf_name);
-void variable_add(const char *name, const char *value,
-                 enum variable_flavor flavor);
-void variable_all_del(void);
-char *expand_dollar(const char **str);
-char *expand_one_token(const char **str);
-
 /* expr.c */
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);
 
index fd161cfff121fd15e45aebce45bbc38f311d3709..31d0a89fbeb7ac69e2348b902047226cd9551ba0 100644 (file)
@@ -188,9 +188,8 @@ do_resize:
 
        print_buttons(dialog, height, width, 0);
 
-       wnoutrefresh(dialog);
-       wnoutrefresh(list);
-       doupdate();
+       wmove(list, choice, check_x + 1);
+       wrefresh(list);
 
        while (key != KEY_ESC) {
                key = wgetch(dialog);
index a501abf9fa313b04faf379aff9244f7e8bb1d180..2d15ba893fbf8945147e15b43190bd60cbf0ecfa 100644 (file)
@@ -91,10 +91,6 @@ struct dialog_info {
        struct dialog_color button_label_active;
        struct dialog_color button_label_inactive;
        struct dialog_color inputbox;
-       struct dialog_color inputbox_border;
-       struct dialog_color searchbox;
-       struct dialog_color searchbox_title;
-       struct dialog_color searchbox_border;
        struct dialog_color position_indicator;
        struct dialog_color menubox;
        struct dialog_color menubox_border;
index 3f78fb265136381c8b4dbdc1b611f2d4d47d7548..3fb7508b68a240f69e31f06c5f9c753fc7129a34 100644 (file)
@@ -29,10 +29,6 @@ static void set_mono_theme(void)
        dlg.button_label_active.atr = A_REVERSE;
        dlg.button_label_inactive.atr = A_NORMAL;
        dlg.inputbox.atr = A_NORMAL;
-       dlg.inputbox_border.atr = A_NORMAL;
-       dlg.searchbox.atr = A_NORMAL;
-       dlg.searchbox_title.atr = A_BOLD;
-       dlg.searchbox_border.atr = A_NORMAL;
        dlg.position_indicator.atr = A_BOLD;
        dlg.menubox.atr = A_NORMAL;
        dlg.menubox_border.atr = A_NORMAL;
@@ -69,10 +65,6 @@ static void set_classic_theme(void)
        DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
        DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
        DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
-       DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
-       DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
-       DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
-       DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
        DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
        DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
        DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
@@ -101,14 +93,9 @@ static void set_blackbg_theme(void)
        DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
        DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
        DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
-       DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+       DLG_COLOR(button_label_inactive, COLOR_WHITE,  COLOR_BLACK, false);
 
        DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
-       DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
-
-       DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
-       DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
-       DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
 
        DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
 
@@ -136,7 +123,6 @@ static void set_bluetitle_theme(void)
        DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
        DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
        DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
-       DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
        DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
        DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
        DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
@@ -189,10 +175,6 @@ static void init_dialog_colors(void)
        init_one_color(&dlg.button_label_active);
        init_one_color(&dlg.button_label_inactive);
        init_one_color(&dlg.inputbox);
-       init_one_color(&dlg.inputbox_border);
-       init_one_color(&dlg.searchbox);
-       init_one_color(&dlg.searchbox_title);
-       init_one_color(&dlg.searchbox_border);
        init_one_color(&dlg.position_indicator);
        init_one_color(&dlg.menubox);
        init_one_color(&dlg.menubox_border);
index 5df32148a86951f78dca309db7d06d77f2364259..f4bb391d50cf997c0a66ca3e54ceb062f6cea54e 100644 (file)
@@ -19,6 +19,7 @@
 #include <signal.h>
 #include <unistd.h>
 
+#include "list.h"
 #include "lkc.h"
 #include "lxdialog/dialog.h"
 #include "mnconf-common.h"
index 2cce8b651f6154197af3b5332a64ea3ecdac344d..8498481e6afe36786b969efb6551528c1156ea05 100644 (file)
 
 #include "lkc.h"
 #include "internal.h"
+#include "list.h"
 
 static const char nohelp_text[] = "There is no help available for this option.";
 
 struct menu rootmenu;
 static struct menu **last_entry_ptr;
 
-struct file *file_list;
-struct file *current_file;
-
 void menu_warn(struct menu *menu, const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
-       fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+       fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
        vfprintf(stderr, fmt, ap);
        fprintf(stderr, "\n");
        va_end(ap);
@@ -33,7 +31,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
-       fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+       fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
        vfprintf(stderr, fmt, ap);
        fprintf(stderr, "\n");
        va_end(ap);
@@ -53,14 +51,16 @@ void menu_add_entry(struct symbol *sym)
        memset(menu, 0, sizeof(*menu));
        menu->sym = sym;
        menu->parent = current_menu;
-       menu->file = current_file;
-       menu->lineno = zconf_lineno();
+       menu->filename = cur_filename;
+       menu->lineno = cur_lineno;
 
        *last_entry_ptr = menu;
        last_entry_ptr = &menu->next;
        current_entry = menu;
-       if (sym)
+       if (sym) {
                menu_add_symbol(P_SYMBOL, sym, NULL);
+               list_add_tail(&menu->link, &sym->menus);
+       }
 }
 
 struct menu *menu_add_menu(void)
@@ -134,8 +134,8 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
        prop = xmalloc(sizeof(*prop));
        memset(prop, 0, sizeof(*prop));
        prop->type = type;
-       prop->file = current_file;
-       prop->lineno = zconf_lineno();
+       prop->filename = cur_filename;
+       prop->lineno = cur_lineno;
        prop->menu = current_entry;
        prop->expr = expr;
        prop->visible.expr = dep;
@@ -307,12 +307,6 @@ void menu_finalize(struct menu *parent)
                                        }
                                }
                        }
-                       /* set the type of the remaining choice values */
-                       for (menu = parent->list; menu; menu = menu->next) {
-                               current_entry = menu;
-                               if (menu->sym && menu->sym->type == S_UNKNOWN)
-                                       menu_set_type(sym->type);
-                       }
 
                        /*
                         * Use the choice itself as the parent dependency of
@@ -567,9 +561,6 @@ void menu_finalize(struct menu *parent)
                if (sym->type == S_UNKNOWN)
                        menu_warn(parent, "config symbol defined without type");
 
-               if (sym_is_choice(sym) && !parent->prompt)
-                       menu_warn(parent, "choice must have a prompt");
-
                /* Check properties connected to this symbol */
                sym_check_prop(sym);
                sym->flags |= SYMBOL_WARNED;
@@ -676,7 +667,7 @@ struct menu *menu_get_parent_menu(struct menu *menu)
 static void get_def_str(struct gstr *r, struct menu *menu)
 {
        str_printf(r, "Defined at %s:%d\n",
-                  menu->file->name, menu->lineno);
+                  menu->filename, menu->lineno);
 }
 
 static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
@@ -777,6 +768,7 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
                    struct list_head *head)
 {
        struct property *prop;
+       struct menu *menu;
 
        if (sym && sym->name) {
                str_printf(r, "Symbol: %s [=%s]\n", sym->name,
@@ -793,17 +785,17 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
        }
 
        /* Print the definitions with prompts before the ones without */
-       for_all_properties(sym, prop, P_SYMBOL) {
-               if (prop->menu->prompt) {
-                       get_def_str(r, prop->menu);
-                       get_prompt_str(r, prop->menu->prompt, head);
+       list_for_each_entry(menu, &sym->menus, link) {
+               if (menu->prompt) {
+                       get_def_str(r, menu);
+                       get_prompt_str(r, menu->prompt, head);
                }
        }
 
-       for_all_properties(sym, prop, P_SYMBOL) {
-               if (!prop->menu->prompt) {
-                       get_def_str(r, prop->menu);
-                       get_dep_str(r, prop->menu->dep, "  Depends on: ");
+       list_for_each_entry(menu, &sym->menus, link) {
+               if (!menu->prompt) {
+                       get_def_str(r, menu);
+                       get_dep_str(r, menu->dep, "  Depends on: ");
                }
        }
 
index 1148163cfa7e71c037ba28eab8183cf304fc5b85..9d22b0f3197b8740c29d10af7de341c7b1d1c14c 100644 (file)
@@ -11,6 +11,7 @@
 #include <strings.h>
 #include <stdlib.h>
 
+#include "list.h"
 #include "lkc.h"
 #include "mnconf-common.h"
 #include "nconf.h"
index 2af7ce4e15315722e76113c55003beab0baba526..b45bfaf0a02b1234f49dd328a350a1de8f2641df 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "lkc.h"
 #include "internal.h"
+#include "preprocess.h"
 
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
@@ -27,8 +28,6 @@ static void zconf_error(const char *err, ...);
 static bool zconf_endtoken(const char *tokenname,
                           const char *expected_tokenname);
 
-struct symbol *symbol_hash[SYMBOL_HASHSIZE];
-
 struct menu *current_menu, *current_entry;
 
 %}
@@ -95,12 +94,12 @@ struct menu *current_menu, *current_entry;
 %type <expr> if_expr
 %type <string> end
 %type <menu> if_entry menu_entry choice_entry
-%type <string> word_opt assign_val
+%type <string> assign_val
 %type <flavor> assign_op
 
 %destructor {
        fprintf(stderr, "%s:%d: missing end statement for this entry\n",
-               $$->file->name, $$->lineno);
+               $$->filename, $$->lineno);
        if (current_menu == $$)
                menu_end_menu();
 } if_entry menu_entry choice_entry
@@ -143,19 +142,19 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL
 {
        $2->flags |= SYMBOL_OPTIONAL;
        menu_add_entry($2);
-       printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name);
+       printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
 };
 
 config_stmt: config_entry_start config_option_list
 {
-       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
 };
 
 menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
 {
        $2->flags |= SYMBOL_OPTIONAL;
        menu_add_entry($2);
-       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name);
+       printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
 };
 
 menuconfig_stmt: menuconfig_entry_start config_option_list
@@ -164,7 +163,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
                current_entry->prompt->type = P_MENU;
        else
                zconfprint("warning: menuconfig statement without prompt");
-       printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
 };
 
 config_option_list:
@@ -177,15 +176,13 @@ config_option_list:
 config_option: type prompt_stmt_opt T_EOL
 {
        menu_set_type($1);
-       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
-               zconf_curname(), zconf_lineno(),
-               $1);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
 };
 
 config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
 {
        menu_add_prompt(P_PROMPT, $2, $3);
-       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
 };
 
 config_option: default expr if_expr T_EOL
@@ -193,27 +190,26 @@ config_option: default expr if_expr T_EOL
        menu_add_expr(P_DEFAULT, $2, $3);
        if ($1 != S_UNKNOWN)
                menu_set_type($1);
-       printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
-               zconf_curname(), zconf_lineno(),
+       printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno,
                $1);
 };
 
 config_option: T_SELECT nonconst_symbol if_expr T_EOL
 {
        menu_add_symbol(P_SELECT, $2, $3);
-       printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);
 };
 
 config_option: T_IMPLY nonconst_symbol if_expr T_EOL
 {
        menu_add_symbol(P_IMPLY, $2, $3);
-       printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);
 };
 
 config_option: T_RANGE symbol symbol if_expr T_EOL
 {
        menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
-       printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);
 };
 
 config_option: T_MODULES T_EOL
@@ -226,18 +222,23 @@ config_option: T_MODULES T_EOL
 
 /* choice entry */
 
-choice: T_CHOICE word_opt T_EOL
+choice: T_CHOICE T_EOL
 {
-       struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+       struct symbol *sym = sym_lookup(NULL, SYMBOL_CHOICE);
        sym->flags |= SYMBOL_NO_WRITE;
        menu_add_entry(sym);
        menu_add_expr(P_CHOICE, NULL, NULL);
-       free($2);
-       printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
 };
 
 choice_entry: choice choice_option_list
 {
+       if (!current_entry->prompt) {
+               fprintf(stderr, "%s:%d: error: choice must have a prompt\n",
+                       current_entry->filename, current_entry->lineno);
+               yynerrs++;
+       }
+
        $$ = menu_add_menu();
 };
 
@@ -245,7 +246,7 @@ choice_end: end
 {
        if (zconf_endtoken($1, "choice")) {
                menu_end_menu();
-               printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+               printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
        }
 };
 
@@ -262,27 +263,25 @@ choice_option_list:
 choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
 {
        menu_add_prompt(P_PROMPT, $2, $3);
-       printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
 };
 
 choice_option: logic_type prompt_stmt_opt T_EOL
 {
        menu_set_type($1);
-       printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
-              zconf_curname(), zconf_lineno(), $1);
+       printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
 };
 
 choice_option: T_OPTIONAL T_EOL
 {
        current_entry->sym->flags |= SYMBOL_OPTIONAL;
-       printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:optional\n", cur_filename, cur_lineno);
 };
 
 choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
 {
        menu_add_symbol(P_DEFAULT, $2, $3);
-       printd(DEBUG_PARSE, "%s:%d:default\n",
-              zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);
 };
 
 type:
@@ -304,7 +303,7 @@ default:
 
 if_entry: T_IF expr T_EOL
 {
-       printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
        menu_add_entry(NULL);
        menu_add_dep($2);
        $$ = menu_add_menu();
@@ -314,7 +313,7 @@ if_end: end
 {
        if (zconf_endtoken($1, "if")) {
                menu_end_menu();
-               printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+               printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno);
        }
 };
 
@@ -330,7 +329,7 @@ menu: T_MENU T_WORD_QUOTE T_EOL
 {
        menu_add_entry(NULL);
        menu_add_prompt(P_MENU, $2, NULL);
-       printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
 };
 
 menu_entry: menu menu_option_list
@@ -342,7 +341,7 @@ menu_end: end
 {
        if (zconf_endtoken($1, "menu")) {
                menu_end_menu();
-               printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+               printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno);
        }
 };
 
@@ -357,7 +356,7 @@ menu_option_list:
 
 source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
 {
-       printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+       printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2);
        zconf_nextfile($2);
        free($2);
 };
@@ -368,7 +367,7 @@ comment: T_COMMENT T_WORD_QUOTE T_EOL
 {
        menu_add_entry(NULL);
        menu_add_prompt(P_COMMENT, $2, NULL);
-       printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
 };
 
 comment_stmt: comment comment_option_list
@@ -383,7 +382,7 @@ comment_option_list:
 
 help_start: T_HELP T_EOL
 {
-       printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno);
        zconf_starthelp();
 };
 
@@ -408,7 +407,7 @@ help: help_start T_HELPTEXT
 depends: T_DEPENDS T_ON expr T_EOL
 {
        menu_add_dep($3);
-       printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+       printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
 };
 
 /* visibility option */
@@ -455,9 +454,6 @@ symbol:       nonconst_symbol
        | T_WORD_QUOTE  { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
 ;
 
-word_opt: /* empty */                  { $$ = NULL; }
-       | T_WORD
-
 /* assignment statement */
 
 assignment_stmt:  T_WORD assign_op assign_val T_EOL    { variable_add($1, $3, $2); free($1); free($3); }
@@ -477,8 +473,11 @@ assign_val:
 
 void conf_parse(const char *name)
 {
-       struct symbol *sym;
-       int i;
+       struct menu *menu;
+
+       autoconf_cmd = str_new();
+
+       str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
 
        zconf_initscan(name);
 
@@ -488,13 +487,28 @@ void conf_parse(const char *name)
                yydebug = 1;
        yyparse();
 
+       /*
+        * FIXME:
+        * cur_filename and cur_lineno are used even after yyparse();
+        * menu_finalize() calls menu_add_symbol(). This should be fixed.
+        */
+       cur_filename = "<none>";
+       cur_lineno = 0;
+
+       str_printf(&autoconf_cmd,
+                  "\n"
+                  "$(autoconfig): $(deps_config)\n"
+                  "$(deps_config): ;\n");
+
+       env_write_dep(&autoconf_cmd);
+
        /* Variables are expanded in the parse phase. We can free them here. */
        variable_all_del();
 
        if (yynerrs)
                exit(1);
        if (!modules_sym)
-               modules_sym = sym_find( "n" );
+               modules_sym = &symbol_no;
 
        if (!menu_has_prompt(&rootmenu)) {
                current_entry = &rootmenu;
@@ -502,10 +516,23 @@ void conf_parse(const char *name)
        }
 
        menu_finalize(&rootmenu);
-       for_all_symbols(i, sym) {
-               if (sym_check_deps(sym))
+
+       menu = &rootmenu;
+       while (menu) {
+               if (menu->sym && sym_check_deps(menu->sym))
                        yynerrs++;
+
+               if (menu->list) {
+                       menu = menu->list;
+                       continue;
+               }
+
+               while (!menu->next && menu->parent)
+                       menu = menu->parent;
+
+               menu = menu->next;
        }
+
        if (yynerrs)
                exit(1);
        conf_set_changed(true);
@@ -520,11 +547,11 @@ static bool zconf_endtoken(const char *tokenname,
                yynerrs++;
                return false;
        }
-       if (current_menu->file != current_file) {
+       if (strcmp(current_menu->filename, cur_filename)) {
                zconf_error("'%s' in different file than '%s'",
                            tokenname, expected_tokenname);
                fprintf(stderr, "%s:%d: location of the '%s'\n",
-                       current_menu->file->name, current_menu->lineno,
+                       current_menu->filename, current_menu->lineno,
                        expected_tokenname);
                yynerrs++;
                return false;
@@ -536,7 +563,7 @@ static void zconfprint(const char *err, ...)
 {
        va_list ap;
 
-       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
        va_start(ap, err);
        vfprintf(stderr, err, ap);
        va_end(ap);
@@ -548,7 +575,7 @@ static void zconf_error(const char *err, ...)
        va_list ap;
 
        yynerrs++;
-       fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+       fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
        va_start(ap, err);
        vfprintf(stderr, err, ap);
        va_end(ap);
@@ -557,7 +584,7 @@ static void zconf_error(const char *err, ...)
 
 static void yyerror(const char *err)
 {
-       fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+       fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);
 }
 
 static void print_quoted_string(FILE *out, const char *str)
index d1f5bcff4b62d68d83e6134b0c883876619f07a2..f0a4a218c4a5178a87722cc12e6ed6cb71baa82d 100644 (file)
@@ -9,10 +9,11 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "array_size.h"
+#include "internal.h"
 #include "list.h"
 #include "lkc.h"
-
-#define ARRAY_SIZE(arr)                (sizeof(arr) / sizeof((arr)[0]))
+#include "preprocess.h"
 
 static char *expand_string_with_args(const char *in, int argc, char *argv[]);
 static char *expand_string(const char *in);
@@ -21,7 +22,7 @@ static void __attribute__((noreturn)) pperror(const char *format, ...)
 {
        va_list ap;
 
-       fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
+       fprintf(stderr, "%s:%d: ", cur_filename, yylineno);
        va_start(ap, format);
        vfprintf(stderr, format, ap);
        va_end(ap);
@@ -87,14 +88,17 @@ static char *env_expand(const char *name)
        return xstrdup(value);
 }
 
-void env_write_dep(FILE *f, const char *autoconfig_name)
+void env_write_dep(struct gstr *s)
 {
        struct env *e, *tmp;
 
        list_for_each_entry_safe(e, tmp, &env_list, node) {
-               fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
-               fprintf(f, "%s: FORCE\n", autoconfig_name);
-               fprintf(f, "endif\n");
+               str_printf(s,
+                          "\n"
+                          "ifneq \"$(%s)\" \"%s\"\n"
+                          "$(autoconfig): FORCE\n"
+                          "endif\n",
+                          e->name, e->value);
                env_del(e);
        }
 }
@@ -119,7 +123,7 @@ static char *do_error_if(int argc, char *argv[])
 
 static char *do_filename(int argc, char *argv[])
 {
-       return xstrdup(current_file->name);
+       return xstrdup(cur_filename);
 }
 
 static char *do_info(int argc, char *argv[])
@@ -181,8 +185,7 @@ static char *do_shell(int argc, char *argv[])
 static char *do_warning_if(int argc, char *argv[])
 {
        if (!strcmp(argv[0], "y"))
-               fprintf(stderr, "%s:%d: %s\n",
-                       current_file->name, yylineno, argv[1]);
+               fprintf(stderr, "%s:%d: %s\n", cur_filename, yylineno, argv[1]);
 
        return xstrdup("");
 }
diff --git a/scripts/kconfig/preprocess.h b/scripts/kconfig/preprocess.h
new file mode 100644 (file)
index 0000000..a7e4a55
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef PREPROCESS_H
+#define PREPROCESS_H
+
+enum variable_flavor {
+       VAR_SIMPLE,
+       VAR_RECURSIVE,
+       VAR_APPEND,
+};
+
+struct gstr;
+void env_write_dep(struct gstr *gs);
+void variable_add(const char *name, const char *value,
+                 enum variable_flavor flavor);
+void variable_all_del(void);
+char *expand_dollar(const char **str);
+char *expand_one_token(const char **str);
+
+#endif /* PREPROCESS_H */
index 620a3527c767af47e6cac0f36ee7533171626f2f..c6c42c0f4e5d588b49da9c38d494c57b2f4233c0 100644 (file)
@@ -1058,7 +1058,7 @@ void ConfigInfoView::menuInfo(void)
                                stream << "<br><br>";
                        }
 
-                       stream << "defined at " << _menu->file->name << ":"
+                       stream << "defined at " << _menu->filename << ":"
                               << _menu->lineno << "<br><br>";
                }
        }
index e9e9fb8d86746460c893a51a2989ca4061fc8e52..81fe1884ef8ae30f0051905ef2495ad324dc86b1 100644 (file)
@@ -9,23 +9,27 @@
 #include <string.h>
 #include <regex.h>
 
+#include "internal.h"
 #include "lkc.h"
 
 struct symbol symbol_yes = {
        .name = "y",
        .curr = { "y", yes },
+       .menus = LIST_HEAD_INIT(symbol_yes.menus),
        .flags = SYMBOL_CONST|SYMBOL_VALID,
 };
 
 struct symbol symbol_mod = {
        .name = "m",
        .curr = { "m", mod },
+       .menus = LIST_HEAD_INIT(symbol_mod.menus),
        .flags = SYMBOL_CONST|SYMBOL_VALID,
 };
 
 struct symbol symbol_no = {
        .name = "n",
        .curr = { "n", no },
+       .menus = LIST_HEAD_INIT(symbol_no.menus),
        .flags = SYMBOL_CONST|SYMBOL_VALID,
 };
 
@@ -160,9 +164,8 @@ static void sym_set_changed(struct symbol *sym)
 static void sym_set_all_changed(void)
 {
        struct symbol *sym;
-       int i;
 
-       for_all_symbols(i, sym)
+       for_all_symbols(sym)
                sym_set_changed(sym);
 }
 
@@ -475,9 +478,8 @@ void sym_calc_value(struct symbol *sym)
 void sym_clear_all_valid(void)
 {
        struct symbol *sym;
-       int i;
 
-       for_all_symbols(i, sym)
+       for_all_symbols(sym)
                sym->flags &= ~SYMBOL_VALID;
        conf_set_changed(true);
        sym_calc_value(modules_sym);
@@ -803,14 +805,7 @@ bool sym_is_changeable(struct symbol *sym)
        return sym->visible > sym->rev_dep.tri;
 }
 
-static unsigned strhash(const char *s)
-{
-       /* fnv32 hash */
-       unsigned hash = 2166136261U;
-       for (; *s; s++)
-               hash = (hash ^ *s) * 0x01000193;
-       return hash;
-}
+HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE);
 
 struct symbol *sym_lookup(const char *name, int flags)
 {
@@ -826,9 +821,9 @@ struct symbol *sym_lookup(const char *name, int flags)
                        case 'n': return &symbol_no;
                        }
                }
-               hash = strhash(name) % SYMBOL_HASHSIZE;
+               hash = strhash(name);
 
-               for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+               hash_for_each_possible(sym_hashtable, symbol, node, hash) {
                        if (symbol->name &&
                            !strcmp(symbol->name, name) &&
                            (flags ? symbol->flags & flags
@@ -846,9 +841,9 @@ struct symbol *sym_lookup(const char *name, int flags)
        symbol->name = new_name;
        symbol->type = S_UNKNOWN;
        symbol->flags = flags;
+       INIT_LIST_HEAD(&symbol->menus);
 
-       symbol->next = symbol_hash[hash];
-       symbol_hash[hash] = symbol;
+       hash_add(sym_hashtable, &symbol->node, hash);
 
        return symbol;
 }
@@ -868,9 +863,9 @@ struct symbol *sym_find(const char *name)
                case 'n': return &symbol_no;
                }
        }
-       hash = strhash(name) % SYMBOL_HASHSIZE;
+       hash = strhash(name);
 
-       for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+       hash_for_each_possible(sym_hashtable, symbol, node, hash) {
                if (symbol->name &&
                    !strcmp(symbol->name, name) &&
                    !(symbol->flags & SYMBOL_CONST))
@@ -930,7 +925,7 @@ struct symbol **sym_re_search(const char *pattern)
        if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
                return NULL;
 
-       for_all_symbols(i, sym) {
+       for_all_symbols(sym) {
                if (sym->flags & SYMBOL_CONST || !sym->name)
                        continue;
                if (regexec(&re, sym->name, 1, match, 0))
@@ -1041,42 +1036,42 @@ static void sym_check_print_recursive(struct symbol *last_sym)
                }
                if (stack->sym == last_sym)
                        fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
-                               prop->file->name, prop->lineno);
+                               prop->filename, prop->lineno);
 
                if (sym_is_choice(sym)) {
                        fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
-                               menu->file->name, menu->lineno,
+                               menu->filename, menu->lineno,
                                sym->name ? sym->name : "<choice>",
                                next_sym->name ? next_sym->name : "<choice>");
                } else if (sym_is_choice_value(sym)) {
                        fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
-                               menu->file->name, menu->lineno,
+                               menu->filename, menu->lineno,
                                sym->name ? sym->name : "<choice>",
                                next_sym->name ? next_sym->name : "<choice>");
                } else if (stack->expr == &sym->dir_dep.expr) {
                        fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
-                               prop->file->name, prop->lineno,
+                               prop->filename, prop->lineno,
                                sym->name ? sym->name : "<choice>",
                                next_sym->name ? next_sym->name : "<choice>");
                } else if (stack->expr == &sym->rev_dep.expr) {
                        fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
-                               prop->file->name, prop->lineno,
+                               prop->filename, prop->lineno,
                                sym->name ? sym->name : "<choice>",
                                next_sym->name ? next_sym->name : "<choice>");
                } else if (stack->expr == &sym->implied.expr) {
                        fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n",
-                               prop->file->name, prop->lineno,
+                               prop->filename, prop->lineno,
                                sym->name ? sym->name : "<choice>",
                                next_sym->name ? next_sym->name : "<choice>");
                } else if (stack->expr) {
                        fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
-                               prop->file->name, prop->lineno,
+                               prop->filename, prop->lineno,
                                sym->name ? sym->name : "<choice>",
                                prop_get_type_name(prop->type),
                                next_sym->name ? next_sym->name : "<choice>");
                } else {
                        fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n",
-                               prop->file->name, prop->lineno,
+                               prop->filename, prop->lineno,
                                sym->name ? sym->name : "<choice>",
                                prop_get_type_name(prop->type),
                                next_sym->name ? next_sym->name : "<choice>");
diff --git a/scripts/kconfig/tests/choice_randomize/Kconfig b/scripts/kconfig/tests/choice_randomize/Kconfig
new file mode 100644 (file)
index 0000000..93a1699
--- /dev/null
@@ -0,0 +1,22 @@
+choice
+       prompt "choose A or B"
+
+config A
+       bool "A"
+
+config B
+       bool "B"
+
+endchoice
+
+choice
+       prompt "choose X or Y"
+       depends on B
+
+config X
+       bool "X"
+
+config Y
+       bool "Y"
+
+endchoice
diff --git a/scripts/kconfig/tests/choice_randomize/__init__.py b/scripts/kconfig/tests/choice_randomize/__init__.py
new file mode 100644 (file)
index 0000000..d380045
--- /dev/null
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+"""
+Randomize all dependent choices
+
+This is a somewhat tricky case for randconfig; the visibility of one choice is
+determined by a member of another choice. Randconfig should be able to generate
+all possible patterns.
+"""
+
+
+def test(conf):
+
+    expected0 = False
+    expected1 = False
+    expected2 = False
+
+    for i in range(100):
+        assert conf.randconfig(seed=i) == 0
+
+        if conf.config_matches('expected_config0'):
+            expected0 = True
+        elif conf.config_matches('expected_config1'):
+            expected1 = True
+        elif conf.config_matches('expected_config2'):
+            expected2 = True
+        else:
+            assert False
+
+        if expected0 and expected1 and expected2:
+            break
+
+    assert expected0
+    assert expected1
+    assert expected2
diff --git a/scripts/kconfig/tests/choice_randomize/expected_config0 b/scripts/kconfig/tests/choice_randomize/expected_config0
new file mode 100644 (file)
index 0000000..f692273
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_A=y
+# CONFIG_B is not set
diff --git a/scripts/kconfig/tests/choice_randomize/expected_config1 b/scripts/kconfig/tests/choice_randomize/expected_config1
new file mode 100644 (file)
index 0000000..bf83784
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_A is not set
+CONFIG_B=y
+CONFIG_X=y
+# CONFIG_Y is not set
diff --git a/scripts/kconfig/tests/choice_randomize/expected_config2 b/scripts/kconfig/tests/choice_randomize/expected_config2
new file mode 100644 (file)
index 0000000..38f93a8
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_A is not set
+CONFIG_B=y
+# CONFIG_X is not set
+CONFIG_Y=y
diff --git a/scripts/kconfig/tests/choice_randomize2/Kconfig b/scripts/kconfig/tests/choice_randomize2/Kconfig
new file mode 100644 (file)
index 0000000..530cf2e
--- /dev/null
@@ -0,0 +1,32 @@
+choice
+       prompt "This is always invisible"
+       depends on n
+
+config DUMMY
+       bool "DUMMY"
+
+endchoice
+
+choice
+       prompt "Choose A or B"
+
+config A
+       bool "A"
+
+config B
+       bool "B"
+
+endchoice
+
+config FOO
+       bool "FOO"
+       depends on A
+
+choice
+       prompt "Choose X"
+       depends on FOO
+
+config X
+       bool "X"
+
+endchoice
diff --git a/scripts/kconfig/tests/choice_randomize2/__init__.py b/scripts/kconfig/tests/choice_randomize2/__init__.py
new file mode 100644 (file)
index 0000000..2066757
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+"""
+Randomize choices with correct dependencies
+
+When shuffling a choice may potentially disrupt certain dependencies, symbol
+values must be recalculated.
+
+Related Linux commits:
+  - c8fb7d7e48d11520ad24808cfce7afb7b9c9f798
+"""
+
+
+def test(conf):
+    for i in range(20):
+        assert conf.randconfig(seed=i) == 0
+        assert (conf.config_matches('expected_config0') or
+                conf.config_matches('expected_config1') or
+                conf.config_matches('expected_config2'))
diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config0 b/scripts/kconfig/tests/choice_randomize2/expected_config0
new file mode 100644 (file)
index 0000000..5c9e1c1
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_A=y
+# CONFIG_B is not set
+CONFIG_FOO=y
+CONFIG_X=y
diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config1 b/scripts/kconfig/tests/choice_randomize2/expected_config1
new file mode 100644 (file)
index 0000000..5b975d9
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_A=y
+# CONFIG_B is not set
+# CONFIG_FOO is not set
diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config2 b/scripts/kconfig/tests/choice_randomize2/expected_config2
new file mode 100644 (file)
index 0000000..5a5ebb9
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_A is not set
+CONFIG_B=y
index af8774a5697c8d0b83a577f4de702505242d74fd..2a2a7e2da06087524badbe3c5a12ad2c8c9ae8b8 100644 (file)
@@ -154,12 +154,10 @@ class Conf:
         defconfig_path = os.path.join(self._test_dir, defconfig)
         return self._run_conf('--defconfig={}'.format(defconfig_path))
 
-    def _allconfig(self, mode, all_config):
+    def _allconfig(self, mode, all_config, extra_env={}):
         if all_config:
             all_config_path = os.path.join(self._test_dir, all_config)
-            extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
-        else:
-            extra_env = {}
+            extra_env['KCONFIG_ALLCONFIG'] = all_config_path
 
         return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
 
@@ -195,13 +193,19 @@ class Conf:
         """
         return self._allconfig('alldef', all_config)
 
-    def randconfig(self, all_config=None):
+    def randconfig(self, all_config=None, seed=None):
         """Run randconfig.
 
         all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+        seed: the seed for randconfig (optional)
         returncode: exit status of the Kconfig executable
         """
-        return self._allconfig('rand', all_config)
+        if seed is not None:
+            extra_env = {'KCONFIG_SEED': hex(seed)}
+        else:
+            extra_env = {}
+
+        return self._allconfig('rand', all_config, extra_env=extra_env)
 
     def savedefconfig(self, dot_config):
         """Run savedefconfig.
index c9f4abf9a79160652691f465b67a2e0029ec6645..05d4ced703206f8d10ed0d34f78a4957bb53b678 100644 (file)
@@ -1,10 +1,10 @@
-Kconfig:11:error: recursive dependency detected!
-Kconfig:11:    symbol B is selected by B
+Kconfig:5:error: recursive dependency detected!
+Kconfig:5:     symbol A depends on A
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
 
-Kconfig:5:error: recursive dependency detected!
-Kconfig:5:     symbol A depends on A
+Kconfig:11:error: recursive dependency detected!
+Kconfig:11:    symbol B is selected by B
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
 
@@ -14,9 +14,9 @@ Kconfig:21:   symbol C2 depends on C1
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
 
-Kconfig:32:error: recursive dependency detected!
-Kconfig:32:    symbol D2 is selected by D1
+Kconfig:27:error: recursive dependency detected!
 Kconfig:27:    symbol D1 depends on D2
+Kconfig:32:    symbol D2 is selected by D1
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
 
@@ -26,13 +26,13 @@ Kconfig:42: symbol E2 is implied by E1
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
 
-Kconfig:60:error: recursive dependency detected!
-Kconfig:60:    symbol G depends on G
+Kconfig:49:error: recursive dependency detected!
+Kconfig:49:    symbol F1 default value contains F2
+Kconfig:51:    symbol F2 depends on F1
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
 
-Kconfig:51:error: recursive dependency detected!
-Kconfig:51:    symbol F2 depends on F1
-Kconfig:49:    symbol F1 default value contains F2
+Kconfig:60:error: recursive dependency detected!
+Kconfig:60:    symbol G depends on G
 For a resolution refer to Documentation/kbuild/kconfig-language.rst
 subsection "Kconfig recursive dependency limitations"
index 92e5b2b9761d70966279ac0159769adf580110fa..439c131b424e7e6f82abbd0788c59cb90f6b3a52 100644 (file)
@@ -7,25 +7,50 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+
+#include "hashtable.h"
 #include "lkc.h"
 
+unsigned int strhash(const char *s)
+{
+       /* fnv32 hash */
+       unsigned int hash = 2166136261U;
+
+       for (; *s; s++)
+               hash = (hash ^ *s) * 0x01000193;
+       return hash;
+}
+
+/* hash table of all parsed Kconfig files */
+static HASHTABLE_DEFINE(file_hashtable, 1U << 11);
+
+struct file {
+       struct hlist_node node;
+       char name[];
+};
+
 /* file already present in list? If not add it */
-struct file *file_lookup(const char *name)
+const char *file_lookup(const char *name)
 {
        struct file *file;
+       size_t len;
+       int hash = strhash(name);
 
-       for (file = file_list; file; file = file->next) {
-               if (!strcmp(name, file->name)) {
-                       return file;
-               }
-       }
+       hash_for_each_possible(file_hashtable, file, node, hash)
+               if (!strcmp(name, file->name))
+                       return file->name;
 
-       file = xmalloc(sizeof(*file));
+       len = strlen(name);
+       file = xmalloc(sizeof(*file) + len + 1);
        memset(file, 0, sizeof(*file));
-       file->name = xstrdup(name);
-       file->next = file_list;
-       file_list = file;
-       return file;
+       memcpy(file->name, name, len);
+       file->name[len] = '\0';
+
+       hash_add(file_hashtable, &file->node, hash);
+
+       str_printf(&autoconf_cmd, "\t%s \\\n", name);
+
+       return file->name;
 }
 
 /* Allocate initial growable string */
index bf7c4b4b5ff45694322af0d6b221b6735ea1a739..6b37039c9e927bc3ffcad77b82e3e9f95d7bf0a7 100644 (file)
@@ -1050,7 +1050,9 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
        sec_mismatch_count++;
 
        warn("%s: section mismatch in reference: %s+0x%x (section: %s) -> %s (section: %s)\n",
-            modname, fromsym, (unsigned int)(faddr - from->st_value), fromsec, tosym, tosec);
+            modname, fromsym,
+            (unsigned int)(faddr - (from ? from->st_value : 0)),
+            fromsec, tosym, tosec);
 
        if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) {
                if (match(tosec, mismatch->bad_tosec))
index bf96a3c2460814febe85a0a49fe2e9a8e90ea1ad..e797ad360f7a5b0493892630b330c8084a7770b0 100755 (executable)
@@ -24,24 +24,10 @@ if_enabled_echo() {
        fi
 }
 
-create_package() {
-       export DH_OPTIONS="-p${1}"
-
-       dh_installdocs
-       dh_installchangelogs
-       dh_compress
-       dh_fixperms
-       dh_gencontrol
-       dh_md5sums
-       dh_builddeb -- ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS}
-}
-
 install_linux_image () {
        pname=$1
        pdir=debian/$1
 
-       rm -rf ${pdir}
-
        # Only some architectures with OF support have this target
        if is_enabled CONFIG_OF_EARLY_FLATTREE && [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then
                ${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/usr/lib/linux-image-${KERNELRELEASE}" dtbs_install
@@ -109,8 +95,6 @@ install_linux_image () {
 install_linux_image_dbg () {
        pdir=debian/$1
 
-       rm -rf ${pdir}
-
        # Parse modules.order directly because 'make modules_install' may sign,
        # compress modules, and then run unneeded depmod.
        while read -r mod; do
@@ -140,8 +124,6 @@ install_kernel_headers () {
        pdir=debian/$1
        version=${1#linux-headers-}
 
-       rm -rf $pdir
-
        "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
 
        mkdir -p $pdir/lib/modules/$version/
@@ -151,8 +133,6 @@ install_kernel_headers () {
 install_libc_headers () {
        pdir=debian/$1
 
-       rm -rf $pdir
-
        $MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH=$pdir/usr
 
        # move asm headers to /usr/include/<libc-machine>/asm to match the structure
@@ -161,21 +141,15 @@ install_libc_headers () {
        mv "$pdir/usr/include/asm" "$pdir/usr/include/${DEB_HOST_MULTIARCH}"
 }
 
-rm -f debian/files
-
-packages_enabled=$(dh_listpackages)
-
-for package in ${packages_enabled}
-do
-       case ${package} in
-       *-dbg)
-               install_linux_image_dbg "${package}";;
-       linux-image-*|user-mode-linux-*)
-               install_linux_image "${package}";;
-       linux-libc-dev)
-               install_libc_headers "${package}";;
-       linux-headers-*)
-               install_kernel_headers "${package}";;
-       esac
-       create_package "${package}"
-done
+package=$1
+
+case "${package}" in
+*-dbg)
+       install_linux_image_dbg "${package}";;
+linux-image-*|user-mode-linux-*)
+       install_linux_image "${package}";;
+linux-libc-dev)
+       install_libc_headers "${package}";;
+linux-headers-*)
+       install_kernel_headers "${package}";;
+esac
index 09830778006227f5854580bba5099e21b09b8d1e..ca07243bd5cdf6e02c99bff0c5cb681111fa2fae 100755 (executable)
@@ -11,28 +11,73 @@ ifneq (,$(filter-out parallel=1,$(filter parallel=%,$(DEB_BUILD_OPTIONS))))
     MAKEFLAGS += -j$(NUMJOBS)
 endif
 
+# When KBUILD_VERBOSE is undefined (presumably you are directly working with
+# the debianized tree), show verbose logs unless DEB_BUILD_OPTION=terse is set.
+ifeq ($(origin KBUILD_VERBOSE),undefined)
+    ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS)))
+        export KBUILD_VERBOSE := 1
+    else
+        Q := @
+    endif
+endif
+
 revision = $(lastword $(subst -, ,$(shell dpkg-parsechangelog -S Version)))
 CROSS_COMPILE ?= $(filter-out $(DEB_BUILD_GNU_TYPE)-, $(DEB_HOST_GNU_TYPE)-)
 make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(revision) $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE))
 
+binary-targets := $(addprefix binary-, image image-dbg headers libc-dev)
+
+all-packages = $(shell dh_listpackages)
+image-package = $(filter linux-image-% user-%, $(filter-out %-dbg, $(all-packages)))
+image-dbg-package = $(filter %-dbg, $(all-packages))
+libc-dev-package = $(filter linux-libc-dev, $(all-packages))
+headers-package = $(filter linux-headers-%, $(all-packages))
+
+mk-files = $(patsubst binary-%,debian/%.files,$1)
+package = $($(@:binary-%=%-package))
+
+# DH_OPTION is an environment variable common for all debhelper commands.
+# We could 'export' it, but here it is passed from the command line to clarify
+# which package is being processed in the build log.
+DH_OPTIONS = -p$(package)
+
+define binary
+       $(Q)dh_testdir $(DH_OPTIONS)
+       $(Q)dh_testroot $(DH_OPTIONS)
+       $(Q)dh_prep $(DH_OPTIONS)
+       $(Q)+$(MAKE) $(make-opts) run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb $(package)'
+       $(Q)dh_installdocs $(DH_OPTIONS)
+       $(Q)dh_installchangelogs $(DH_OPTIONS)
+       $(Q)dh_compress $(DH_OPTIONS)
+       $(Q)dh_fixperms $(DH_OPTIONS)
+       $(Q)dh_gencontrol $(DH_OPTIONS) -- -f$(call mk-files,$@)
+       $(Q)dh_md5sums $(DH_OPTIONS)
+       $(Q)dh_builddeb $(DH_OPTIONS) -- $(addprefix -Z,$(KDEB_COMPRESS))
+endef
+
+.PHONY: $(binary-targets)
+$(binary-targets): build-arch
+       $(Q)truncate -s0 $(call mk-files,$@)
+       $(if $(package),$(binary))
+
 .PHONY: binary binary-indep binary-arch
 binary: binary-arch binary-indep
 binary-indep: build-indep
-binary-arch: build-arch
-       $(MAKE) $(make-opts) \
-       run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb'
+binary-arch: $(binary-targets)
+       $(Q)cat $(call mk-files,$^) > debian/files
 
 .PHONY: build build-indep build-arch
 build: build-arch build-indep
 build-indep:
 build-arch:
-       $(MAKE) $(make-opts) olddefconfig
-       $(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all
+       $(Q)$(MAKE) $(make-opts) olddefconfig
+       $(Q)$(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all
 
 .PHONY: clean
 clean:
-       rm -rf debian/files debian/linux-* debian/deb-env.vars*
-       $(MAKE) ARCH=$(ARCH) clean
+       $(Q)dh_clean
+       $(Q)rm -rf debian/deb-env.vars* debian/*.files
+       $(Q)$(MAKE) ARCH=$(ARCH) clean
 
 # If DEB_HOST_ARCH is empty, it is likely that debian/rules was executed
 # directly. Run 'dpkg-architecture --print-set --print-format=make' to
@@ -41,6 +86,6 @@ ifndef DEB_HOST_ARCH
 include debian/deb-env.vars
 
 debian/deb-env.vars:
-       dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp
-       mv $@.tmp $@
+       $(Q)dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp
+       $(Q)mv $@.tmp $@
 endif
index f58726671fb37424308c678126e5edd4a22dc5f3..e095eb1e290ec0be0e960d6c4c2b411f4c8a9030 100644 (file)
@@ -61,11 +61,37 @@ cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEAS
 %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install
 cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE}
 cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config
+if %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='test -d ${srctree}/arch/${SRCARCH}/boot/dts' 2>/dev/null; then
+       %{make} %{makeflags} INSTALL_DTBS_PATH=%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb dtbs_install
+fi
 ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build
 %if %{with_devel}
 %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}'
 %endif
 
+{
+       for x in System.map config kernel modules.builtin \
+                       modules.builtin.modinfo modules.order vmlinuz; do
+               echo "/lib/modules/%{KERNELRELEASE}/${x}"
+       done
+
+       for x in alias alias.bin builtin.alias.bin builtin.bin dep dep.bin \
+                                       devname softdep symbols symbols.bin; do
+               echo "%ghost /lib/modules/%{KERNELRELEASE}/modules.${x}"
+       done
+
+       for x in System.map config vmlinuz; do
+               echo "%ghost /boot/${x}-%{KERNELRELEASE}"
+       done
+
+       if [ -d "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" ];then
+               echo "/lib/modules/%{KERNELRELEASE}/dtb"
+               find "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" -printf "%%%ghost /boot/dtb-%{KERNELRELEASE}/%%P\n"
+       fi
+
+       echo "%exclude /lib/modules/%{KERNELRELEASE}/build"
+} > %{buildroot}/kernel.list
+
 %clean
 rm -rf %{buildroot}
 
@@ -78,23 +104,23 @@ for file in vmlinuz System.map config; do
                cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}"
        fi
 done
+if [ -d "/lib/modules/%{KERNELRELEASE}/dtb" ] && \
+   ! diff -rq "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}" >/dev/null 2>&1; then
+       rm -rf "/boot/dtb-%{KERNELRELEASE}"
+       cp -r "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}"
+fi
+if [ ! -e "/lib/modules/%{KERNELRELEASE}/modules.dep" ]; then
+       /usr/sbin/depmod %{KERNELRELEASE}
+fi
 
 %preun
-if [ -x /sbin/new-kernel-pkg ]; then
-new-kernel-pkg --remove %{KERNELRELEASE} --rminitrd --initrdfile=/boot/initramfs-%{KERNELRELEASE}.img
-elif [ -x /usr/bin/kernel-install ]; then
+if [ -x /usr/bin/kernel-install ]; then
 kernel-install remove %{KERNELRELEASE}
 fi
 
-%postun
-if [ -x /sbin/update-bootloader ]; then
-/sbin/update-bootloader --remove %{KERNELRELEASE}
-fi
-
-%files
+%files -f %{buildroot}/kernel.list
 %defattr (-, root, root)
-/lib/modules/%{KERNELRELEASE}
-%exclude /lib/modules/%{KERNELRELEASE}/build
+%exclude /kernel.list
 
 %files headers
 %defattr (-, root, root)
index 8367fd4853716af763cfe648e5619f6364d2ce1d..fb0c60044f7b3b1a4a8fd478cf68306a9443ef5d 100644 (file)
@@ -1275,12 +1275,12 @@ static int snd_ctl_elem_read(struct snd_card *card,
 static int snd_ctl_elem_read_user(struct snd_card *card,
                                  struct snd_ctl_elem_value __user *_control)
 {
-       struct snd_ctl_elem_value *control;
+       struct snd_ctl_elem_value *control __free(kfree) = NULL;
        int result;
 
        control = memdup_user(_control, sizeof(*control));
        if (IS_ERR(control))
-               return PTR_ERR(control);
+               return PTR_ERR(no_free_ptr(control));
 
        result = snd_ctl_elem_read(card, control);
        if (result < 0)
index d6e5aafd697c7e4e06ae8692e935de4bc206c192..36409a56c675e77facc31a5c0873e4f757480b16 100644 (file)
@@ -100,8 +100,8 @@ static void snd_serial_generic_write_wakeup(struct serdev_device *serdev)
        snd_serial_generic_tx_wakeup(drvdata);
 }
 
-static ssize_t snd_serial_generic_receive_buf(struct serdev_device *serdev,
-                                             const u8 *buf, size_t count)
+static size_t snd_serial_generic_receive_buf(struct serdev_device *serdev,
+                                            const u8 *buf, size_t count)
 {
        int ret;
        struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);
index e904f62e195267faab2a1ed67dcab4fa75f2d8f8..a17c36a36aa5375fd8295911a2ffc707cb14263e 100644 (file)
@@ -2645,6 +2645,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
        SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
@@ -6964,6 +6965,25 @@ static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
        }
 }
 
+static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
+                                             const struct hda_fixup *fix, int action)
+{
+       u32 caps;
+       u8 nsteps, offs;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
+       nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
+       offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
+       caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
+       caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
+
+       if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
+               codec_warn(codec, "failed to override amp caps for NID 0x3\n");
+}
+
 static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
                                                  const struct hda_fixup *fix,
                                                  int action)
@@ -7104,6 +7124,38 @@ static void alc_fixup_headset_mic(struct hda_codec *codec,
        }
 }
 
+static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       /*
+        * The Pin Complex 0x14 for the treble speakers is wrongly reported as
+        * unconnected.
+        * The Pin Complex 0x17 for the bass speakers has the lowest association
+        * and sequence values so shift it up a bit to squeeze 0x14 in.
+        */
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 }, // top/treble
+               { 0x17, 0x90170111 }, // bottom/bass
+               { }
+       };
+
+       /*
+        * Force DAC 0x02 for the bass speakers 0x17.
+        */
+       static const hda_nid_t conn[] = { 0x02 };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       }
+
+       cs35l41_fixup_i2c_two(codec, fix, action);
+       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc245_fixup_hp_gpio_led(codec, fix, action);
+}
+
 
 enum {
        ALC269_FIXUP_GPIO2,
@@ -7382,6 +7434,8 @@ enum {
        ALC294_FIXUP_CS35L41_I2C_2,
        ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED,
        ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
+       ALC256_FIXUP_HEADPHONE_AMP_VOL,
+       ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9581,6 +9635,14 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc256_fixup_acer_sfg16_micmute_led,
        },
+       [ALC256_FIXUP_HEADPHONE_AMP_VOL] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_decrease_headphone_amp_val,
+       },
+       [ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_spectre_x360_eu0xxx,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9944,7 +10006,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre 14", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
        SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -10115,12 +10177,14 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x1558, 0x0353, "Clevo V35[05]SN[CDE]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -10319,6 +10383,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
        SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1854, 0x0440, "LG CQ6", ALC256_FIXUP_HEADPHONE_AMP_VOL),
+       SND_PCI_QUIRK(0x1854, 0x0441, "LG CQ6 AIO", ALC256_FIXUP_HEADPHONE_AMP_VOL),
        SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
        SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
index 90360f8b3e81b9374680058256f59efd96ad822d..69c68d8e7a6b54fc1fcfc3fac3a73d58403071f5 100644 (file)
@@ -199,13 +199,6 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "21HY"),
                }
        },
-       {
-               .driver_data = &acp6x_card,
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "21J2"),
-               }
-       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -318,6 +311,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "E1504FA"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "M7600RE"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
index 694b8e31390248b88e4bc8aba843316244f0bdb4..7af6a349b1d41fb60d9450a312927e4774889a34 100644 (file)
@@ -162,7 +162,6 @@ static int snd_acp6x_probe(struct pci_dev *pci,
        /* Yellow Carp device check */
        switch (pci->revision) {
        case 0x60:
-       case 0x63:
        case 0x6f:
                break;
        default:
index 420bbf588efeaf1c0cc1d7700fa3d572ad6e816e..e100cc9f5c1929e3fa3c1111b0757c099873e333 100644 (file)
@@ -1429,7 +1429,7 @@ err_unprepare_mclk:
        return ret;
 }
 
-static void __exit adc3xxx_i2c_remove(struct i2c_client *client)
+static void adc3xxx_i2c_remove(struct i2c_client *client)
 {
        struct adc3xxx *adc3xxx = i2c_get_clientdata(client);
 
@@ -1452,7 +1452,7 @@ static struct i2c_driver adc3xxx_i2c_driver = {
                   .of_match_table = tlv320adc3xxx_of_match,
                  },
        .probe = adc3xxx_i2c_probe,
-       .remove = __exit_p(adc3xxx_i2c_remove),
+       .remove = adc3xxx_i2c_remove,
        .id_table = adc3xxx_i2c_id,
 };
 
index 860e66ec85e8a3748c4769e691e4201fe1b12695..9fa020ef7eab9bb565b9c66527ac1f8b35b65303 100644 (file)
@@ -25,8 +25,6 @@
 #define DEFAULT_MCLK_FS                                256
 #define CH_GRP_MAX                             4  /* The max channel 8 / 2 */
 #define MULTIPLEX_CH_MAX                       10
-#define CLK_PPM_MIN                            -1000
-#define CLK_PPM_MAX                            1000
 
 #define TRCM_TXRX 0
 #define TRCM_TX 1
@@ -53,20 +51,6 @@ struct rk_i2s_tdm_dev {
        struct clk *hclk;
        struct clk *mclk_tx;
        struct clk *mclk_rx;
-       /* The mclk_tx_src is parent of mclk_tx */
-       struct clk *mclk_tx_src;
-       /* The mclk_rx_src is parent of mclk_rx */
-       struct clk *mclk_rx_src;
-       /*
-        * The mclk_root0 and mclk_root1 are root parent and supplies for
-        * the different FS.
-        *
-        * e.g:
-        * mclk_root0 is VPLL0, used for FS=48000Hz
-        * mclk_root1 is VPLL1, used for FS=44100Hz
-        */
-       struct clk *mclk_root0;
-       struct clk *mclk_root1;
        struct regmap *regmap;
        struct regmap *grf;
        struct snd_dmaengine_dai_dma_data capture_dma_data;
@@ -76,19 +60,11 @@ struct rk_i2s_tdm_dev {
        const struct rk_i2s_soc_data *soc_data;
        bool is_master_mode;
        bool io_multiplex;
-       bool mclk_calibrate;
        bool tdm_mode;
-       unsigned int mclk_rx_freq;
-       unsigned int mclk_tx_freq;
-       unsigned int mclk_root0_freq;
-       unsigned int mclk_root1_freq;
-       unsigned int mclk_root0_initial_freq;
-       unsigned int mclk_root1_initial_freq;
        unsigned int frame_width;
        unsigned int clk_trcm;
        unsigned int i2s_sdis[CH_GRP_MAX];
        unsigned int i2s_sdos[CH_GRP_MAX];
-       int clk_ppm;
        int refcount;
        spinlock_t lock; /* xfer lock */
        bool has_playback;
@@ -114,12 +90,6 @@ static void i2s_tdm_disable_unprepare_mclk(struct rk_i2s_tdm_dev *i2s_tdm)
 {
        clk_disable_unprepare(i2s_tdm->mclk_tx);
        clk_disable_unprepare(i2s_tdm->mclk_rx);
-       if (i2s_tdm->mclk_calibrate) {
-               clk_disable_unprepare(i2s_tdm->mclk_tx_src);
-               clk_disable_unprepare(i2s_tdm->mclk_rx_src);
-               clk_disable_unprepare(i2s_tdm->mclk_root0);
-               clk_disable_unprepare(i2s_tdm->mclk_root1);
-       }
 }
 
 /**
@@ -142,29 +112,9 @@ static int i2s_tdm_prepare_enable_mclk(struct rk_i2s_tdm_dev *i2s_tdm)
        ret = clk_prepare_enable(i2s_tdm->mclk_rx);
        if (ret)
                goto err_mclk_rx;
-       if (i2s_tdm->mclk_calibrate) {
-               ret = clk_prepare_enable(i2s_tdm->mclk_tx_src);
-               if (ret)
-                       goto err_mclk_rx;
-               ret = clk_prepare_enable(i2s_tdm->mclk_rx_src);
-               if (ret)
-                       goto err_mclk_rx_src;
-               ret = clk_prepare_enable(i2s_tdm->mclk_root0);
-               if (ret)
-                       goto err_mclk_root0;
-               ret = clk_prepare_enable(i2s_tdm->mclk_root1);
-               if (ret)
-                       goto err_mclk_root1;
-       }
 
        return 0;
 
-err_mclk_root1:
-       clk_disable_unprepare(i2s_tdm->mclk_root0);
-err_mclk_root0:
-       clk_disable_unprepare(i2s_tdm->mclk_rx_src);
-err_mclk_rx_src:
-       clk_disable_unprepare(i2s_tdm->mclk_tx_src);
 err_mclk_rx:
        clk_disable_unprepare(i2s_tdm->mclk_tx);
 err_mclk_tx:
@@ -564,159 +514,6 @@ static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream,
                           I2S_XFER_RXS_START);
 }
 
-static int rockchip_i2s_tdm_clk_set_rate(struct rk_i2s_tdm_dev *i2s_tdm,
-                                        struct clk *clk, unsigned long rate,
-                                        int ppm)
-{
-       unsigned long rate_target;
-       int delta, ret;
-
-       if (ppm == i2s_tdm->clk_ppm)
-               return 0;
-
-       if (ppm < 0)
-               delta = -1;
-       else
-               delta = 1;
-
-       delta *= (int)div64_u64((u64)rate * (u64)abs(ppm) + 500000,
-                               1000000);
-
-       rate_target = rate + delta;
-
-       if (!rate_target)
-               return -EINVAL;
-
-       ret = clk_set_rate(clk, rate_target);
-       if (ret)
-               return ret;
-
-       i2s_tdm->clk_ppm = ppm;
-
-       return 0;
-}
-
-static int rockchip_i2s_tdm_calibrate_mclk(struct rk_i2s_tdm_dev *i2s_tdm,
-                                          struct snd_pcm_substream *substream,
-                                          unsigned int lrck_freq)
-{
-       struct clk *mclk_root;
-       struct clk *mclk_parent;
-       unsigned int mclk_root_freq;
-       unsigned int mclk_root_initial_freq;
-       unsigned int mclk_parent_freq;
-       unsigned int div, delta;
-       u64 ppm;
-       int ret;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               mclk_parent = i2s_tdm->mclk_tx_src;
-       else
-               mclk_parent = i2s_tdm->mclk_rx_src;
-
-       switch (lrck_freq) {
-       case 8000:
-       case 16000:
-       case 24000:
-       case 32000:
-       case 48000:
-       case 64000:
-       case 96000:
-       case 192000:
-               mclk_root = i2s_tdm->mclk_root0;
-               mclk_root_freq = i2s_tdm->mclk_root0_freq;
-               mclk_root_initial_freq = i2s_tdm->mclk_root0_initial_freq;
-               mclk_parent_freq = DEFAULT_MCLK_FS * 192000;
-               break;
-       case 11025:
-       case 22050:
-       case 44100:
-       case 88200:
-       case 176400:
-               mclk_root = i2s_tdm->mclk_root1;
-               mclk_root_freq = i2s_tdm->mclk_root1_freq;
-               mclk_root_initial_freq = i2s_tdm->mclk_root1_initial_freq;
-               mclk_parent_freq = DEFAULT_MCLK_FS * 176400;
-               break;
-       default:
-               dev_err(i2s_tdm->dev, "Invalid LRCK frequency: %u Hz\n",
-                       lrck_freq);
-               return -EINVAL;
-       }
-
-       ret = clk_set_parent(mclk_parent, mclk_root);
-       if (ret)
-               return ret;
-
-       ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, mclk_root,
-                                           mclk_root_freq, 0);
-       if (ret)
-               return ret;
-
-       delta = abs(mclk_root_freq % mclk_parent_freq - mclk_parent_freq);
-       ppm = div64_u64((uint64_t)delta * 1000000, (uint64_t)mclk_root_freq);
-
-       if (ppm) {
-               div = DIV_ROUND_CLOSEST(mclk_root_initial_freq, mclk_parent_freq);
-               if (!div)
-                       return -EINVAL;
-
-               mclk_root_freq = mclk_parent_freq * round_up(div, 2);
-
-               ret = clk_set_rate(mclk_root, mclk_root_freq);
-               if (ret)
-                       return ret;
-
-               i2s_tdm->mclk_root0_freq = clk_get_rate(i2s_tdm->mclk_root0);
-               i2s_tdm->mclk_root1_freq = clk_get_rate(i2s_tdm->mclk_root1);
-       }
-
-       return clk_set_rate(mclk_parent, mclk_parent_freq);
-}
-
-static int rockchip_i2s_tdm_set_mclk(struct rk_i2s_tdm_dev *i2s_tdm,
-                                    struct snd_pcm_substream *substream,
-                                    struct clk **mclk)
-{
-       unsigned int mclk_freq;
-       int ret;
-
-       if (i2s_tdm->clk_trcm) {
-               if (i2s_tdm->mclk_tx_freq != i2s_tdm->mclk_rx_freq) {
-                       dev_err(i2s_tdm->dev,
-                               "clk_trcm, tx: %d and rx: %d should be the same\n",
-                               i2s_tdm->mclk_tx_freq,
-                               i2s_tdm->mclk_rx_freq);
-                       return -EINVAL;
-               }
-
-               ret = clk_set_rate(i2s_tdm->mclk_tx, i2s_tdm->mclk_tx_freq);
-               if (ret)
-                       return ret;
-
-               ret = clk_set_rate(i2s_tdm->mclk_rx, i2s_tdm->mclk_rx_freq);
-               if (ret)
-                       return ret;
-
-               /* mclk_rx is also ok. */
-               *mclk = i2s_tdm->mclk_tx;
-       } else {
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       *mclk = i2s_tdm->mclk_tx;
-                       mclk_freq = i2s_tdm->mclk_tx_freq;
-               } else {
-                       *mclk = i2s_tdm->mclk_rx;
-                       mclk_freq = i2s_tdm->mclk_rx_freq;
-               }
-
-               ret = clk_set_rate(*mclk, mclk_freq);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
 static int rockchip_i2s_ch_to_io(unsigned int ch, bool substream_capture)
 {
        if (substream_capture) {
@@ -853,19 +650,17 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_soc_dai *dai)
 {
        struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
-       struct clk *mclk;
-       int ret = 0;
        unsigned int val = 0;
        unsigned int mclk_rate, bclk_rate, div_bclk = 4, div_lrck = 64;
+       int err;
 
        if (i2s_tdm->is_master_mode) {
-               if (i2s_tdm->mclk_calibrate)
-                       rockchip_i2s_tdm_calibrate_mclk(i2s_tdm, substream,
-                                                       params_rate(params));
+               struct clk *mclk = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+                       i2s_tdm->mclk_tx : i2s_tdm->mclk_rx;
 
-               ret = rockchip_i2s_tdm_set_mclk(i2s_tdm, substream, &mclk);
-               if (ret)
-                       return ret;
+               err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params));
+               if (err)
+                       return err;
 
                mclk_rate = clk_get_rate(mclk);
                bclk_rate = i2s_tdm->frame_width * params_rate(params);
@@ -973,96 +768,6 @@ static int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,
-                                      unsigned int freq, int dir)
-{
-       struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai);
-
-       /* Put set mclk rate into rockchip_i2s_tdm_set_mclk() */
-       if (i2s_tdm->clk_trcm) {
-               i2s_tdm->mclk_tx_freq = freq;
-               i2s_tdm->mclk_rx_freq = freq;
-       } else {
-               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       i2s_tdm->mclk_tx_freq = freq;
-               else
-                       i2s_tdm->mclk_rx_freq = freq;
-       }
-
-       dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n",
-               stream ? "rx" : "tx", freq);
-
-       return 0;
-}
-
-static int rockchip_i2s_tdm_clk_compensation_info(struct snd_kcontrol *kcontrol,
-                                                 struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = CLK_PPM_MIN;
-       uinfo->value.integer.max = CLK_PPM_MAX;
-       uinfo->value.integer.step = 1;
-
-       return 0;
-}
-
-static int rockchip_i2s_tdm_clk_compensation_get(struct snd_kcontrol *kcontrol,
-                                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
-       struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
-
-       ucontrol->value.integer.value[0] = i2s_tdm->clk_ppm;
-
-       return 0;
-}
-
-static int rockchip_i2s_tdm_clk_compensation_put(struct snd_kcontrol *kcontrol,
-                                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
-       struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
-       int ret = 0, ppm = 0;
-       int changed = 0;
-       unsigned long old_rate;
-
-       if (ucontrol->value.integer.value[0] < CLK_PPM_MIN ||
-           ucontrol->value.integer.value[0] > CLK_PPM_MAX)
-               return -EINVAL;
-
-       ppm = ucontrol->value.integer.value[0];
-
-       old_rate = clk_get_rate(i2s_tdm->mclk_root0);
-       ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root0,
-                                           i2s_tdm->mclk_root0_freq, ppm);
-       if (ret)
-               return ret;
-       if (old_rate != clk_get_rate(i2s_tdm->mclk_root0))
-               changed = 1;
-
-       if (clk_is_match(i2s_tdm->mclk_root0, i2s_tdm->mclk_root1))
-               return changed;
-
-       old_rate = clk_get_rate(i2s_tdm->mclk_root1);
-       ret = rockchip_i2s_tdm_clk_set_rate(i2s_tdm, i2s_tdm->mclk_root1,
-                                           i2s_tdm->mclk_root1_freq, ppm);
-       if (ret)
-               return ret;
-       if (old_rate != clk_get_rate(i2s_tdm->mclk_root1))
-               changed = 1;
-
-       return changed;
-}
-
-static struct snd_kcontrol_new rockchip_i2s_tdm_compensation_control = {
-       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-       .name = "PCM Clock Compensation in PPM",
-       .info = rockchip_i2s_tdm_clk_compensation_info,
-       .get = rockchip_i2s_tdm_clk_compensation_get,
-       .put = rockchip_i2s_tdm_clk_compensation_put,
-};
-
 static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)
 {
        struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);
@@ -1072,9 +777,6 @@ static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)
        if (i2s_tdm->has_playback)
                snd_soc_dai_dma_data_set_playback(dai, &i2s_tdm->playback_dma_data);
 
-       if (i2s_tdm->mclk_calibrate)
-               snd_soc_add_dai_controls(dai, &rockchip_i2s_tdm_compensation_control, 1);
-
        return 0;
 }
 
@@ -1115,7 +817,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
        .probe = rockchip_i2s_tdm_dai_probe,
        .hw_params = rockchip_i2s_tdm_hw_params,
        .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio,
-       .set_sysclk = rockchip_i2s_tdm_set_sysclk,
        .set_fmt = rockchip_i2s_tdm_set_fmt,
        .set_tdm_slot = rockchip_dai_tdm_slot,
        .trigger = rockchip_i2s_tdm_trigger,
@@ -1444,35 +1145,6 @@ static void rockchip_i2s_tdm_path_config(struct rk_i2s_tdm_dev *i2s_tdm,
                rockchip_i2s_tdm_tx_path_config(i2s_tdm, num);
 }
 
-static int rockchip_i2s_tdm_get_calibrate_mclks(struct rk_i2s_tdm_dev *i2s_tdm)
-{
-       int num_mclks = 0;
-
-       i2s_tdm->mclk_tx_src = devm_clk_get(i2s_tdm->dev, "mclk_tx_src");
-       if (!IS_ERR(i2s_tdm->mclk_tx_src))
-               num_mclks++;
-
-       i2s_tdm->mclk_rx_src = devm_clk_get(i2s_tdm->dev, "mclk_rx_src");
-       if (!IS_ERR(i2s_tdm->mclk_rx_src))
-               num_mclks++;
-
-       i2s_tdm->mclk_root0 = devm_clk_get(i2s_tdm->dev, "mclk_root0");
-       if (!IS_ERR(i2s_tdm->mclk_root0))
-               num_mclks++;
-
-       i2s_tdm->mclk_root1 = devm_clk_get(i2s_tdm->dev, "mclk_root1");
-       if (!IS_ERR(i2s_tdm->mclk_root1))
-               num_mclks++;
-
-       if (num_mclks < 4 && num_mclks != 0)
-               return -ENOENT;
-
-       if (num_mclks == 4)
-               i2s_tdm->mclk_calibrate = 1;
-
-       return 0;
-}
-
 static int rockchip_i2s_tdm_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm,
                                         struct device_node *np,
                                         bool is_rx_path)
@@ -1610,11 +1282,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
        i2s_tdm->io_multiplex =
                of_property_read_bool(node, "rockchip,io-multiplex");
 
-       ret = rockchip_i2s_tdm_get_calibrate_mclks(i2s_tdm);
-       if (ret)
-               return dev_err_probe(i2s_tdm->dev, ret,
-                                    "mclk-calibrate clocks missing");
-
        regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(regs)) {
                return dev_err_probe(i2s_tdm->dev, PTR_ERR(regs),
@@ -1667,13 +1334,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
                goto err_disable_hclk;
        }
 
-       if (i2s_tdm->mclk_calibrate) {
-               i2s_tdm->mclk_root0_initial_freq = clk_get_rate(i2s_tdm->mclk_root0);
-               i2s_tdm->mclk_root1_initial_freq = clk_get_rate(i2s_tdm->mclk_root1);
-               i2s_tdm->mclk_root0_freq = i2s_tdm->mclk_root0_initial_freq;
-               i2s_tdm->mclk_root1_freq = i2s_tdm->mclk_root1_initial_freq;
-       }
-
        pm_runtime_enable(&pdev->dev);
 
        regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
index a38fee48ee005afcbb66b8d4ead712cb5d2c5af8..e692aa3b8b22f84537a3c171e0c3936c3a5f28b8 100644 (file)
@@ -385,11 +385,15 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
 
+       snd_soc_dpcm_mutex_lock(fe);
        ret = dpcm_be_dai_hw_params(fe, stream);
+       snd_soc_dpcm_mutex_unlock(fe);
        if (ret < 0)
                goto out;
 
+       snd_soc_dpcm_mutex_lock(fe);
        ret = dpcm_be_dai_prepare(fe, stream);
+       snd_soc_dpcm_mutex_unlock(fe);
        if (ret < 0)
                goto out;
 
index 1e94edba12eb85706d0f1f0acf7c75ad3a8249eb..2ec13d1634b636455f51ab541773e5587003e14b 100644 (file)
@@ -1219,6 +1219,9 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card,
                        if (!snd_soc_is_matching_component(platform, component))
                                continue;
 
+                       if (snd_soc_component_is_dummy(component) && component->num_dai)
+                               continue;
+
                        snd_soc_rtd_add_component(rtd, component);
                }
        }
index d2d21478399e02d1fd010ad4897b08e58602fd73..aad904839b817cd74d3731d8b06e8739c27bb43e 100644 (file)
@@ -173,7 +173,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
 
        adata = sdev->pdata->hw_pdata;
 
-       if (adata->signed_fw_image)
+       if (adata->quirks && adata->quirks->signed_fw_image)
                size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
        else
                size_fw = adata->fw_bin_size;
index 9b3c26210db38f97581bf0bb5d0346aa2d06fc49..be7dc1e02284ab62f8cbaeffdd70f26a19ff6232 100644 (file)
 #include "acp.h"
 #include "acp-dsp-offset.h"
 
-#define SECURED_FIRMWARE 1
-
 static bool enable_fw_debug;
 module_param(enable_fw_debug, bool, 0444);
 MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
 
+static struct acp_quirk_entry quirk_valve_galileo = {
+       .signed_fw_image = true,
+       .skip_iram_dram_size_mod = true,
+};
+
 const struct dmi_system_id acp_sof_quirk_table[] = {
        {
                /* Steam Deck OLED device */
@@ -33,7 +36,7 @@ const struct dmi_system_id acp_sof_quirk_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
                },
-               .driver_data = (void *)SECURED_FIRMWARE,
+               .driver_data = &quirk_valve_galileo,
        },
        {}
 };
@@ -254,7 +257,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
                }
        }
 
-       if (adata->signed_fw_image)
+       if (adata->quirks && adata->quirks->signed_fw_image)
                snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER);
 
        snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
@@ -278,7 +281,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
        }
 
        /* psp_send_cmd only required for vangogh platform (rev - 5) */
-       if (desc->rev == 5) {
+       if (desc->rev == 5 && !(adata->quirks && adata->quirks->skip_iram_dram_size_mod)) {
                /* Modify IRAM and DRAM size */
                ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | IRAM_DRAM_FENCE_2);
                if (ret)
@@ -738,26 +741,27 @@ skip_soundwire:
        sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
        sdev->debug_box.size = BOX_SIZE_1024;
 
-       adata->signed_fw_image = false;
        dmi_id = dmi_first_match(acp_sof_quirk_table);
-       if (dmi_id && dmi_id->driver_data) {
-               adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
-                                                   "sof-%s-code.bin",
-                                                   chip->name);
-               if (!adata->fw_code_bin) {
-                       ret = -ENOMEM;
-                       goto free_ipc_irq;
+       if (dmi_id) {
+               adata->quirks = dmi_id->driver_data;
+
+               if (adata->quirks->signed_fw_image) {
+                       adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+                                                           "sof-%s-code.bin",
+                                                           chip->name);
+                       if (!adata->fw_code_bin) {
+                               ret = -ENOMEM;
+                               goto free_ipc_irq;
+                       }
+
+                       adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+                                                           "sof-%s-data.bin",
+                                                           chip->name);
+                       if (!adata->fw_data_bin) {
+                               ret = -ENOMEM;
+                               goto free_ipc_irq;
+                       }
                }
-
-               adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
-                                                   "sof-%s-data.bin",
-                                                   chip->name);
-               if (!adata->fw_data_bin) {
-                       ret = -ENOMEM;
-                       goto free_ipc_irq;
-               }
-
-               adata->signed_fw_image = dmi_id->driver_data;
        }
 
        adata->enable_fw_debug = enable_fw_debug;
index 947068da39b5350e0f14d05a47b3e4ba1630a7e0..e229bb6b849d6ba51c137bb5761756f7b6ec8e3f 100644 (file)
@@ -207,6 +207,11 @@ struct sof_amd_acp_desc {
        u64 sdw_acpi_dev_addr;
 };
 
+struct acp_quirk_entry {
+       bool signed_fw_image;
+       bool skip_iram_dram_size_mod;
+};
+
 /* Common device data struct for ACP devices */
 struct acp_dev_data {
        struct snd_sof_dev  *dev;
@@ -236,7 +241,7 @@ struct acp_dev_data {
        u8 *data_buf;
        dma_addr_t sram_dma_addr;
        u8 *sram_data_buf;
-       bool signed_fw_image;
+       struct acp_quirk_entry *quirks;
        struct dma_descriptor dscr_info[ACP_MAX_DESC];
        struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
        struct acp_dsp_stream *dtrace_stream;
index de15d21aa6d982ab218e317a0661f13ba744e982..bc6ffdb5471a58ae4b30b27ba166fd356a974edd 100644 (file)
@@ -143,6 +143,7 @@ EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON);
 int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
 {
        const struct dmi_system_id *dmi_id;
+       struct acp_quirk_entry *quirks;
 
        /* common defaults */
        memcpy(&sof_vangogh_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
@@ -151,8 +152,12 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
        sof_vangogh_ops.num_drv = ARRAY_SIZE(vangogh_sof_dai);
 
        dmi_id = dmi_first_match(acp_sof_quirk_table);
-       if (dmi_id && dmi_id->driver_data)
-               sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware;
+       if (dmi_id) {
+               quirks = dmi_id->driver_data;
+
+               if (quirks->signed_fw_image)
+                       sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware;
+       }
 
        return 0;
 }
diff --git a/tools/arch/loongarch/include/asm/inst.h b/tools/arch/loongarch/include/asm/inst.h
new file mode 100644 (file)
index 0000000..c25b585
--- /dev/null
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_INST_H
+#define _ASM_INST_H
+
+#include <linux/bitops.h>
+
+#define LOONGARCH_INSN_NOP             0x03400000
+
+enum reg0i15_op {
+       break_op        = 0x54,
+};
+
+enum reg0i26_op {
+       b_op            = 0x14,
+       bl_op           = 0x15,
+};
+
+enum reg1i21_op {
+       beqz_op         = 0x10,
+       bnez_op         = 0x11,
+       bceqz_op        = 0x12, /* bits[9:8] = 0x00 */
+       bcnez_op        = 0x12, /* bits[9:8] = 0x01 */
+};
+
+enum reg2_op {
+       ertn_op         = 0x1920e,
+};
+
+enum reg2i12_op {
+       addid_op        = 0x0b,
+       andi_op         = 0x0d,
+       ldd_op          = 0xa3,
+       std_op          = 0xa7,
+};
+
+enum reg2i14_op {
+       ldptrd_op       = 0x26,
+       stptrd_op       = 0x27,
+};
+
+enum reg2i16_op {
+       jirl_op         = 0x13,
+       beq_op          = 0x16,
+       bne_op          = 0x17,
+       blt_op          = 0x18,
+       bge_op          = 0x19,
+       bltu_op         = 0x1a,
+       bgeu_op         = 0x1b,
+};
+
+struct reg0i15_format {
+       unsigned int immediate : 15;
+       unsigned int opcode : 17;
+};
+
+struct reg0i26_format {
+       unsigned int immediate_h : 10;
+       unsigned int immediate_l : 16;
+       unsigned int opcode : 6;
+};
+
+struct reg1i21_format {
+       unsigned int immediate_h  : 5;
+       unsigned int rj : 5;
+       unsigned int immediate_l : 16;
+       unsigned int opcode : 6;
+};
+
+struct reg2_format {
+       unsigned int rd : 5;
+       unsigned int rj : 5;
+       unsigned int opcode : 22;
+};
+
+struct reg2i12_format {
+       unsigned int rd : 5;
+       unsigned int rj : 5;
+       unsigned int immediate : 12;
+       unsigned int opcode : 10;
+};
+
+struct reg2i14_format {
+       unsigned int rd : 5;
+       unsigned int rj : 5;
+       unsigned int immediate : 14;
+       unsigned int opcode : 8;
+};
+
+struct reg2i16_format {
+       unsigned int rd : 5;
+       unsigned int rj : 5;
+       unsigned int immediate : 16;
+       unsigned int opcode : 6;
+};
+
+union loongarch_instruction {
+       unsigned int word;
+       struct reg0i15_format   reg0i15_format;
+       struct reg0i26_format   reg0i26_format;
+       struct reg1i21_format   reg1i21_format;
+       struct reg2_format      reg2_format;
+       struct reg2i12_format   reg2i12_format;
+       struct reg2i14_format   reg2i14_format;
+       struct reg2i16_format   reg2i16_format;
+};
+
+#define LOONGARCH_INSN_SIZE    sizeof(union loongarch_instruction)
+
+enum loongarch_gpr {
+       LOONGARCH_GPR_ZERO = 0,
+       LOONGARCH_GPR_RA = 1,
+       LOONGARCH_GPR_TP = 2,
+       LOONGARCH_GPR_SP = 3,
+       LOONGARCH_GPR_A0 = 4,   /* Reused as V0 for return value */
+       LOONGARCH_GPR_A1,       /* Reused as V1 for return value */
+       LOONGARCH_GPR_A2,
+       LOONGARCH_GPR_A3,
+       LOONGARCH_GPR_A4,
+       LOONGARCH_GPR_A5,
+       LOONGARCH_GPR_A6,
+       LOONGARCH_GPR_A7,
+       LOONGARCH_GPR_T0 = 12,
+       LOONGARCH_GPR_T1,
+       LOONGARCH_GPR_T2,
+       LOONGARCH_GPR_T3,
+       LOONGARCH_GPR_T4,
+       LOONGARCH_GPR_T5,
+       LOONGARCH_GPR_T6,
+       LOONGARCH_GPR_T7,
+       LOONGARCH_GPR_T8,
+       LOONGARCH_GPR_FP = 22,
+       LOONGARCH_GPR_S0 = 23,
+       LOONGARCH_GPR_S1,
+       LOONGARCH_GPR_S2,
+       LOONGARCH_GPR_S3,
+       LOONGARCH_GPR_S4,
+       LOONGARCH_GPR_S5,
+       LOONGARCH_GPR_S6,
+       LOONGARCH_GPR_S7,
+       LOONGARCH_GPR_S8,
+       LOONGARCH_GPR_MAX
+};
+
+#define DEF_EMIT_REG2I16_FORMAT(NAME, OP)                              \
+static inline void emit_##NAME(union loongarch_instruction *insn,      \
+                              enum loongarch_gpr rj,                   \
+                              enum loongarch_gpr rd,                   \
+                              int offset)                              \
+{                                                                      \
+       insn->reg2i16_format.opcode = OP;                               \
+       insn->reg2i16_format.immediate = offset;                        \
+       insn->reg2i16_format.rj = rj;                                   \
+       insn->reg2i16_format.rd = rd;                                   \
+}
+
+DEF_EMIT_REG2I16_FORMAT(jirl, jirl_op)
+
+#endif /* _ASM_INST_H */
diff --git a/tools/arch/loongarch/include/asm/orc_types.h b/tools/arch/loongarch/include/asm/orc_types.h
new file mode 100644 (file)
index 0000000..caf1f71
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _ORC_TYPES_H
+#define _ORC_TYPES_H
+
+#include <linux/types.h>
+
+/*
+ * The ORC_REG_* registers are base registers which are used to find other
+ * registers on the stack.
+ *
+ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the
+ * address of the previous frame: the caller's SP before it called the current
+ * function.
+ *
+ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in
+ * the current frame.
+ *
+ * The most commonly used base registers are SP and FP -- which the previous SP
+ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous FP is
+ * usually based on.
+ *
+ * The rest of the base registers are needed for special cases like entry code
+ * and GCC realigned stacks.
+ */
+#define ORC_REG_UNDEFINED              0
+#define ORC_REG_PREV_SP                        1
+#define ORC_REG_SP                     2
+#define ORC_REG_FP                     3
+#define ORC_REG_MAX                    4
+
+#define ORC_TYPE_UNDEFINED             0
+#define ORC_TYPE_END_OF_STACK          1
+#define ORC_TYPE_CALL                  2
+#define ORC_TYPE_REGS                  3
+#define ORC_TYPE_REGS_PARTIAL          4
+
+#ifndef __ASSEMBLY__
+/*
+ * This struct is more or less a vastly simplified version of the DWARF Call
+ * Frame Information standard.  It contains only the necessary parts of DWARF
+ * CFI, simplified for ease of access by the in-kernel unwinder.  It tells the
+ * unwinder how to find the previous SP and FP (and sometimes entry regs) on
+ * the stack for a given code address.  Each instance of the struct corresponds
+ * to one or more code locations.
+ */
+struct orc_entry {
+       s16             sp_offset;
+       s16             fp_offset;
+       s16             ra_offset;
+       unsigned int    sp_reg:4;
+       unsigned int    fp_reg:4;
+       unsigned int    ra_reg:4;
+       unsigned int    type:3;
+       unsigned int    signal:1;
+};
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ORC_TYPES_H */
index 6a00a6eecaef02bbb911741fc23e39614d8bdc90..c5c5082cb24e5cd05ed3d5f5a7f12c71d853209f 100644 (file)
@@ -376,7 +376,7 @@ int build_channel_array(const char *device_dir, int buffer_idx,
                goto error_close_dir;
        }
 
-       seekdir(dp, 0);
+       rewinddir(dp);
        while (ent = readdir(dp), ent) {
                if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
                           "_en") == 0) {
index f18683b95ea67301e8c9cd6d5bc631074f468e5d..7319f6ced10860e3f0c30c599086384a5268740f 100644 (file)
@@ -87,4 +87,15 @@ static inline __u32 rol32(__u32 word, unsigned int shift)
        return (word << shift) | (word >> ((-shift) & 31));
 }
 
+/**
+ * sign_extend64 - sign extend a 64-bit value using specified bit as sign-bit
+ * @value: value to sign extend
+ * @index: 0 based bit index (0<=index<64) to sign bit
+ */
+static __always_inline __s64 sign_extend64(__u64 value, int index)
+{
+       __u8 shift = 63 - index;
+       return (__s64)(value << shift) >> shift;
+}
+
 #endif
index 4be7144e4803ddf1b8bfd6d85e85af68407c1a51..2cf892774346ceb962e4b01ebce07f617694da35 100644 (file)
@@ -2,7 +2,7 @@
 # Most of this file is copied from tools/lib/traceevent/Makefile
 
 RM ?= rm
-srctree = $(abs_srctree)
+srctree := $(realpath $(srctree))
 
 VERSION_SCRIPT := libbpf.map
 LIBBPF_VERSION := $(shell \
index 07373c5a7afe4fcf3b46e5c2f1d484a79ce0f415..f4e8eb79c1b82bab31775eb48f399b6ffdbd3280 100644 (file)
@@ -20,6 +20,7 @@ CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h)
 CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h)
 CFLAGS_mptcp_pm:=$(call get_hdr_inc,_LINUX_MPTCP_PM_H,mptcp_pm.h)
 CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h)
+CFLAGS_nlctrl:=$(call get_hdr_inc,__LINUX_GENERIC_NETLINK_H,genetlink.h)
 CFLAGS_nfsd:=$(call get_hdr_inc,_LINUX_NFSD_NETLINK_H,nfsd_netlink.h)
 CFLAGS_ovs_datapath:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h)
 CFLAGS_ovs_flow:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h)
index 83b100c1e7f6840c7c33caae8c804e5b5d9f2d46..bf7f7f84ac62591ff74ddbbef5376cc168b86b35 100644 (file)
@@ -57,6 +57,10 @@ ifeq ($(SRCARCH),x86)
        BUILD_ORC := y
 endif
 
+ifeq ($(SRCARCH),loongarch)
+       BUILD_ORC := y
+endif
+
 export BUILD_ORC
 export srctree OUTPUT CFLAGS SRCARCH AWK
 include $(srctree)/tools/build/Makefile.include
diff --git a/tools/objtool/arch/loongarch/Build b/tools/objtool/arch/loongarch/Build
new file mode 100644 (file)
index 0000000..1d4b784
--- /dev/null
@@ -0,0 +1,3 @@
+objtool-y += decode.o
+objtool-y += special.o
+objtool-y += orc.o
diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c
new file mode 100644 (file)
index 0000000..aee479d
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <string.h>
+#include <objtool/check.h>
+#include <objtool/warn.h>
+#include <asm/inst.h>
+#include <asm/orc_types.h>
+#include <linux/objtool_types.h>
+
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH   258
+#endif
+
+int arch_ftrace_match(char *name)
+{
+       return !strcmp(name, "_mcount");
+}
+
+unsigned long arch_jump_destination(struct instruction *insn)
+{
+       return insn->offset + (insn->immediate << 2);
+}
+
+unsigned long arch_dest_reloc_offset(int addend)
+{
+       return addend;
+}
+
+bool arch_pc_relative_reloc(struct reloc *reloc)
+{
+       return false;
+}
+
+bool arch_callee_saved_reg(unsigned char reg)
+{
+       switch (reg) {
+       case CFI_RA:
+       case CFI_FP:
+       case CFI_S0 ... CFI_S8:
+               return true;
+       default:
+               return false;
+       }
+}
+
+int arch_decode_hint_reg(u8 sp_reg, int *base)
+{
+       switch (sp_reg) {
+       case ORC_REG_UNDEFINED:
+               *base = CFI_UNDEFINED;
+               break;
+       case ORC_REG_SP:
+               *base = CFI_SP;
+               break;
+       case ORC_REG_FP:
+               *base = CFI_FP;
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static bool is_loongarch(const struct elf *elf)
+{
+       if (elf->ehdr.e_machine == EM_LOONGARCH)
+               return true;
+
+       WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
+       return false;
+}
+
+#define ADD_OP(op) \
+       if (!(op = calloc(1, sizeof(*op)))) \
+               return -1; \
+       else for (*ops_list = op, ops_list = &op->next; op; op = NULL)
+
+static bool decode_insn_reg0i26_fomat(union loongarch_instruction inst,
+                                     struct instruction *insn)
+{
+       switch (inst.reg0i26_format.opcode) {
+       case b_op:
+               insn->type = INSN_JUMP_UNCONDITIONAL;
+               insn->immediate = sign_extend64(inst.reg0i26_format.immediate_h << 16 |
+                                               inst.reg0i26_format.immediate_l, 25);
+               break;
+       case bl_op:
+               insn->type = INSN_CALL;
+               insn->immediate = sign_extend64(inst.reg0i26_format.immediate_h << 16 |
+                                               inst.reg0i26_format.immediate_l, 25);
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+static bool decode_insn_reg1i21_fomat(union loongarch_instruction inst,
+                                     struct instruction *insn)
+{
+       switch (inst.reg1i21_format.opcode) {
+       case beqz_op:
+       case bnez_op:
+       case bceqz_op:
+               insn->type = INSN_JUMP_CONDITIONAL;
+               insn->immediate = sign_extend64(inst.reg1i21_format.immediate_h << 16 |
+                                               inst.reg1i21_format.immediate_l, 20);
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+static bool decode_insn_reg2i12_fomat(union loongarch_instruction inst,
+                                     struct instruction *insn,
+                                     struct stack_op **ops_list,
+                                     struct stack_op *op)
+{
+       switch (inst.reg2i12_format.opcode) {
+       case addid_op:
+               if ((inst.reg2i12_format.rd == CFI_SP) || (inst.reg2i12_format.rj == CFI_SP)) {
+                       /* addi.d sp,sp,si12 or addi.d fp,sp,si12 */
+                       insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11);
+                       ADD_OP(op) {
+                               op->src.type = OP_SRC_ADD;
+                               op->src.reg = inst.reg2i12_format.rj;
+                               op->src.offset = insn->immediate;
+                               op->dest.type = OP_DEST_REG;
+                               op->dest.reg = inst.reg2i12_format.rd;
+                       }
+               }
+               break;
+       case ldd_op:
+               if (inst.reg2i12_format.rj == CFI_SP) {
+                       /* ld.d rd,sp,si12 */
+                       insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11);
+                       ADD_OP(op) {
+                               op->src.type = OP_SRC_REG_INDIRECT;
+                               op->src.reg = CFI_SP;
+                               op->src.offset = insn->immediate;
+                               op->dest.type = OP_DEST_REG;
+                               op->dest.reg = inst.reg2i12_format.rd;
+                       }
+               }
+               break;
+       case std_op:
+               if (inst.reg2i12_format.rj == CFI_SP) {
+                       /* st.d rd,sp,si12 */
+                       insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11);
+                       ADD_OP(op) {
+                               op->src.type = OP_SRC_REG;
+                               op->src.reg = inst.reg2i12_format.rd;
+                               op->dest.type = OP_DEST_REG_INDIRECT;
+                               op->dest.reg = CFI_SP;
+                               op->dest.offset = insn->immediate;
+                       }
+               }
+               break;
+       case andi_op:
+               if (inst.reg2i12_format.rd == 0 &&
+                   inst.reg2i12_format.rj == 0 &&
+                   inst.reg2i12_format.immediate == 0)
+                       /* andi r0,r0,0 */
+                       insn->type = INSN_NOP;
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+static bool decode_insn_reg2i14_fomat(union loongarch_instruction inst,
+                                     struct instruction *insn,
+                                     struct stack_op **ops_list,
+                                     struct stack_op *op)
+{
+       switch (inst.reg2i14_format.opcode) {
+       case ldptrd_op:
+               if (inst.reg2i14_format.rj == CFI_SP) {
+                       /* ldptr.d rd,sp,si14 */
+                       insn->immediate = sign_extend64(inst.reg2i14_format.immediate, 13);
+                       ADD_OP(op) {
+                               op->src.type = OP_SRC_REG_INDIRECT;
+                               op->src.reg = CFI_SP;
+                               op->src.offset = insn->immediate;
+                               op->dest.type = OP_DEST_REG;
+                               op->dest.reg = inst.reg2i14_format.rd;
+                       }
+               }
+               break;
+       case stptrd_op:
+               if (inst.reg2i14_format.rj == CFI_SP) {
+                       /* stptr.d ra,sp,0 */
+                       if (inst.reg2i14_format.rd == LOONGARCH_GPR_RA &&
+                           inst.reg2i14_format.immediate == 0)
+                               break;
+
+                       /* stptr.d rd,sp,si14 */
+                       insn->immediate = sign_extend64(inst.reg2i14_format.immediate, 13);
+                       ADD_OP(op) {
+                               op->src.type = OP_SRC_REG;
+                               op->src.reg = inst.reg2i14_format.rd;
+                               op->dest.type = OP_DEST_REG_INDIRECT;
+                               op->dest.reg = CFI_SP;
+                               op->dest.offset = insn->immediate;
+                       }
+               }
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+static bool decode_insn_reg2i16_fomat(union loongarch_instruction inst,
+                                     struct instruction *insn)
+{
+       switch (inst.reg2i16_format.opcode) {
+       case jirl_op:
+               if (inst.reg2i16_format.rd == 0 &&
+                   inst.reg2i16_format.rj == CFI_RA &&
+                   inst.reg2i16_format.immediate == 0) {
+                       /* jirl r0,ra,0 */
+                       insn->type = INSN_RETURN;
+               } else if (inst.reg2i16_format.rd == CFI_RA) {
+                       /* jirl ra,rj,offs16 */
+                       insn->type = INSN_CALL_DYNAMIC;
+               } else if (inst.reg2i16_format.rd == CFI_A0 &&
+                          inst.reg2i16_format.immediate == 0) {
+                       /*
+                        * jirl a0,t0,0
+                        * this is a special case in loongarch_suspend_enter,
+                        * just treat it as a call instruction.
+                        */
+                       insn->type = INSN_CALL_DYNAMIC;
+               } else if (inst.reg2i16_format.rd == 0 &&
+                          inst.reg2i16_format.immediate == 0) {
+                       /* jirl r0,rj,0 */
+                       insn->type = INSN_JUMP_DYNAMIC;
+               } else if (inst.reg2i16_format.rd == 0 &&
+                          inst.reg2i16_format.immediate != 0) {
+                       /*
+                        * jirl r0,t0,12
+                        * this is a rare case in JUMP_VIRT_ADDR,
+                        * just ignore it due to it is harmless for tracing.
+                        */
+                       break;
+               } else {
+                       /* jirl rd,rj,offs16 */
+                       insn->type = INSN_JUMP_UNCONDITIONAL;
+                       insn->immediate = sign_extend64(inst.reg2i16_format.immediate, 15);
+               }
+               break;
+       case beq_op:
+       case bne_op:
+       case blt_op:
+       case bge_op:
+       case bltu_op:
+       case bgeu_op:
+               insn->type = INSN_JUMP_CONDITIONAL;
+               insn->immediate = sign_extend64(inst.reg2i16_format.immediate, 15);
+               break;
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
+                           unsigned long offset, unsigned int maxlen,
+                           struct instruction *insn)
+{
+       struct stack_op **ops_list = &insn->stack_ops;
+       const struct elf *elf = file->elf;
+       struct stack_op *op = NULL;
+       union loongarch_instruction inst;
+
+       if (!is_loongarch(elf))
+               return -1;
+
+       if (maxlen < LOONGARCH_INSN_SIZE)
+               return 0;
+
+       insn->len = LOONGARCH_INSN_SIZE;
+       insn->type = INSN_OTHER;
+       insn->immediate = 0;
+
+       inst = *(union loongarch_instruction *)(sec->data->d_buf + offset);
+
+       if (decode_insn_reg0i26_fomat(inst, insn))
+               return 0;
+       if (decode_insn_reg1i21_fomat(inst, insn))
+               return 0;
+       if (decode_insn_reg2i12_fomat(inst, insn, ops_list, op))
+               return 0;
+       if (decode_insn_reg2i14_fomat(inst, insn, ops_list, op))
+               return 0;
+       if (decode_insn_reg2i16_fomat(inst, insn))
+               return 0;
+
+       if (inst.word == 0)
+               insn->type = INSN_NOP;
+       else if (inst.reg0i15_format.opcode == break_op) {
+               /* break */
+               insn->type = INSN_BUG;
+       } else if (inst.reg2_format.opcode == ertn_op) {
+               /* ertn */
+               insn->type = INSN_RETURN;
+       }
+
+       return 0;
+}
+
+const char *arch_nop_insn(int len)
+{
+       static u32 nop;
+
+       if (len != LOONGARCH_INSN_SIZE)
+               WARN("invalid NOP size: %d\n", len);
+
+       nop = LOONGARCH_INSN_NOP;
+
+       return (const char *)&nop;
+}
+
+const char *arch_ret_insn(int len)
+{
+       static u32 ret;
+
+       if (len != LOONGARCH_INSN_SIZE)
+               WARN("invalid RET size: %d\n", len);
+
+       emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0);
+
+       return (const char *)&ret;
+}
+
+void arch_initial_func_cfi_state(struct cfi_init_state *state)
+{
+       int i;
+
+       for (i = 0; i < CFI_NUM_REGS; i++) {
+               state->regs[i].base = CFI_UNDEFINED;
+               state->regs[i].offset = 0;
+       }
+
+       /* initial CFA (call frame address) */
+       state->cfa.base = CFI_SP;
+       state->cfa.offset = 0;
+}
diff --git a/tools/objtool/arch/loongarch/include/arch/cfi_regs.h b/tools/objtool/arch/loongarch/include/arch/cfi_regs.h
new file mode 100644 (file)
index 0000000..d183cc8
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _OBJTOOL_ARCH_CFI_REGS_H
+#define _OBJTOOL_ARCH_CFI_REGS_H
+
+#define CFI_RA         1
+#define CFI_SP         3
+#define CFI_A0         4
+#define CFI_FP         22
+#define CFI_S0         23
+#define CFI_S1         24
+#define CFI_S2         25
+#define CFI_S3         26
+#define CFI_S4         27
+#define CFI_S5         28
+#define CFI_S6         29
+#define CFI_S7         30
+#define CFI_S8         31
+#define CFI_NUM_REGS   32
+
+#define CFI_BP         CFI_FP
+
+#endif /* _OBJTOOL_ARCH_CFI_REGS_H */
diff --git a/tools/objtool/arch/loongarch/include/arch/elf.h b/tools/objtool/arch/loongarch/include/arch/elf.h
new file mode 100644 (file)
index 0000000..9623d66
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _OBJTOOL_ARCH_ELF_H
+#define _OBJTOOL_ARCH_ELF_H
+
+/*
+ * See the following link for more info about ELF Relocation types:
+ * https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_relocations
+ */
+#ifndef R_LARCH_NONE
+#define R_LARCH_NONE           0
+#endif
+#ifndef R_LARCH_32
+#define R_LARCH_32             1
+#endif
+#ifndef R_LARCH_64
+#define R_LARCH_64             2
+#endif
+#ifndef R_LARCH_32_PCREL
+#define R_LARCH_32_PCREL       99
+#endif
+
+#define R_NONE                 R_LARCH_NONE
+#define R_ABS32                        R_LARCH_32
+#define R_ABS64                        R_LARCH_64
+#define R_DATA32               R_LARCH_32_PCREL
+#define R_DATA64               R_LARCH_32_PCREL
+#define R_TEXT32               R_LARCH_32_PCREL
+#define R_TEXT64               R_LARCH_32_PCREL
+
+#endif /* _OBJTOOL_ARCH_ELF_H */
diff --git a/tools/objtool/arch/loongarch/include/arch/special.h b/tools/objtool/arch/loongarch/include/arch/special.h
new file mode 100644 (file)
index 0000000..35fc979
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _OBJTOOL_ARCH_SPECIAL_H
+#define _OBJTOOL_ARCH_SPECIAL_H
+
+/*
+ * See more info about struct exception_table_entry
+ * in arch/loongarch/include/asm/extable.h
+ */
+#define EX_ENTRY_SIZE          12
+#define EX_ORIG_OFFSET         0
+#define EX_NEW_OFFSET          4
+
+/*
+ * See more info about struct jump_entry
+ * in include/linux/jump_label.h
+ */
+#define JUMP_ENTRY_SIZE                16
+#define JUMP_ORIG_OFFSET       0
+#define JUMP_NEW_OFFSET                4
+#define JUMP_KEY_OFFSET                8
+
+/*
+ * See more info about struct alt_instr
+ * in arch/loongarch/include/asm/alternative.h
+ */
+#define ALT_ENTRY_SIZE         12
+#define ALT_ORIG_OFFSET                0
+#define ALT_NEW_OFFSET         4
+#define ALT_FEATURE_OFFSET     8
+#define ALT_ORIG_LEN_OFFSET    10
+#define ALT_NEW_LEN_OFFSET     11
+
+#endif /* _OBJTOOL_ARCH_SPECIAL_H */
diff --git a/tools/objtool/arch/loongarch/orc.c b/tools/objtool/arch/loongarch/orc.c
new file mode 100644 (file)
index 0000000..873536d
--- /dev/null
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/objtool_types.h>
+#include <asm/orc_types.h>
+
+#include <objtool/check.h>
+#include <objtool/orc.h>
+#include <objtool/warn.h>
+#include <objtool/endianness.h>
+
+int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn)
+{
+       struct cfi_reg *fp = &cfi->regs[CFI_FP];
+       struct cfi_reg *ra = &cfi->regs[CFI_RA];
+
+       memset(orc, 0, sizeof(*orc));
+
+       if (!cfi) {
+               /*
+                * This is usually either unreachable nops/traps (which don't
+                * trigger unreachable instruction warnings), or
+                * STACK_FRAME_NON_STANDARD functions.
+                */
+               orc->type = ORC_TYPE_UNDEFINED;
+               return 0;
+       }
+
+       switch (cfi->type) {
+       case UNWIND_HINT_TYPE_UNDEFINED:
+               orc->type = ORC_TYPE_UNDEFINED;
+               return 0;
+       case UNWIND_HINT_TYPE_END_OF_STACK:
+               orc->type = ORC_TYPE_END_OF_STACK;
+               return 0;
+       case UNWIND_HINT_TYPE_CALL:
+               orc->type = ORC_TYPE_CALL;
+               break;
+       case UNWIND_HINT_TYPE_REGS:
+               orc->type = ORC_TYPE_REGS;
+               break;
+       case UNWIND_HINT_TYPE_REGS_PARTIAL:
+               orc->type = ORC_TYPE_REGS_PARTIAL;
+               break;
+       default:
+               WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
+               return -1;
+       }
+
+       orc->signal = cfi->signal;
+
+       switch (cfi->cfa.base) {
+       case CFI_SP:
+               orc->sp_reg = ORC_REG_SP;
+               break;
+       case CFI_FP:
+               orc->sp_reg = ORC_REG_FP;
+               break;
+       default:
+               WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
+               return -1;
+       }
+
+       switch (fp->base) {
+       case CFI_UNDEFINED:
+               orc->fp_reg = ORC_REG_UNDEFINED;
+               orc->fp_offset = 0;
+               break;
+       case CFI_CFA:
+               orc->fp_reg = ORC_REG_PREV_SP;
+               orc->fp_offset = fp->offset;
+               break;
+       case CFI_FP:
+               orc->fp_reg = ORC_REG_FP;
+               break;
+       default:
+               WARN_INSN(insn, "unknown FP base reg %d", fp->base);
+               return -1;
+       }
+
+       switch (ra->base) {
+       case CFI_UNDEFINED:
+               orc->ra_reg = ORC_REG_UNDEFINED;
+               orc->ra_offset = 0;
+               break;
+       case CFI_CFA:
+               orc->ra_reg = ORC_REG_PREV_SP;
+               orc->ra_offset = ra->offset;
+               break;
+       case CFI_FP:
+               orc->ra_reg = ORC_REG_FP;
+               break;
+       default:
+               WARN_INSN(insn, "unknown RA base reg %d", ra->base);
+               return -1;
+       }
+
+       orc->sp_offset = cfi->cfa.offset;
+
+       return 0;
+}
+
+int write_orc_entry(struct elf *elf, struct section *orc_sec,
+                   struct section *ip_sec, unsigned int idx,
+                   struct section *insn_sec, unsigned long insn_off,
+                   struct orc_entry *o)
+{
+       struct orc_entry *orc;
+
+       /* populate ORC data */
+       orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
+       memcpy(orc, o, sizeof(*orc));
+
+       /* populate reloc for ip */
+       if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
+                                    insn_sec, insn_off))
+               return -1;
+
+       return 0;
+}
+
+static const char *reg_name(unsigned int reg)
+{
+       switch (reg) {
+       case ORC_REG_SP:
+               return "sp";
+       case ORC_REG_FP:
+               return "fp";
+       case ORC_REG_PREV_SP:
+               return "prevsp";
+       default:
+               return "?";
+       }
+}
+
+static const char *orc_type_name(unsigned int type)
+{
+       switch (type) {
+       case UNWIND_HINT_TYPE_CALL:
+               return "call";
+       case UNWIND_HINT_TYPE_REGS:
+               return "regs";
+       case UNWIND_HINT_TYPE_REGS_PARTIAL:
+               return "regs (partial)";
+       default:
+               return "?";
+       }
+}
+
+static void print_reg(unsigned int reg, int offset)
+{
+       if (reg == ORC_REG_UNDEFINED)
+               printf(" (und) ");
+       else
+               printf("%s + %3d", reg_name(reg), offset);
+
+}
+
+void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i)
+{
+       printf("type:%s", orc_type_name(orc[i].type));
+
+       printf(" sp:");
+       print_reg(orc[i].sp_reg, orc[i].sp_offset);
+
+       printf(" fp:");
+       print_reg(orc[i].fp_reg, orc[i].fp_offset);
+
+       printf(" ra:");
+       print_reg(orc[i].ra_reg, orc[i].ra_offset);
+
+       printf(" signal:%d\n", orc[i].signal);
+}
diff --git a/tools/objtool/arch/loongarch/special.c b/tools/objtool/arch/loongarch/special.c
new file mode 100644 (file)
index 0000000..9bba1e9
--- /dev/null
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <objtool/special.h>
+
+bool arch_support_alt_relocation(struct special_alt *special_alt,
+                                struct instruction *insn,
+                                struct reloc *reloc)
+{
+       return false;
+}
+
+struct reloc *arch_find_switch_table(struct objtool_file *file,
+                                    struct instruction *insn)
+{
+       return NULL;
+}
index 9f7869b5c5e0caf1c0128e0f177d98e931017583..3dedb2fd8f3a0c3d7502e2536167f5e895fe1d44 100644 (file)
@@ -1,5 +1,6 @@
 objtool-y += special.o
 objtool-y += decode.o
+objtool-y += orc.o
 
 inat_tables_script = ../arch/x86/tools/gen-insn-attr-x86.awk
 inat_tables_maps = ../arch/x86/lib/x86-opcode-map.txt
diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c
new file mode 100644 (file)
index 0000000..b6cd943
--- /dev/null
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/objtool_types.h>
+#include <asm/orc_types.h>
+
+#include <objtool/check.h>
+#include <objtool/orc.h>
+#include <objtool/warn.h>
+#include <objtool/endianness.h>
+
+int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn)
+{
+       struct cfi_reg *bp = &cfi->regs[CFI_BP];
+
+       memset(orc, 0, sizeof(*orc));
+
+       if (!cfi) {
+               /*
+                * This is usually either unreachable nops/traps (which don't
+                * trigger unreachable instruction warnings), or
+                * STACK_FRAME_NON_STANDARD functions.
+                */
+               orc->type = ORC_TYPE_UNDEFINED;
+               return 0;
+       }
+
+       switch (cfi->type) {
+       case UNWIND_HINT_TYPE_UNDEFINED:
+               orc->type = ORC_TYPE_UNDEFINED;
+               return 0;
+       case UNWIND_HINT_TYPE_END_OF_STACK:
+               orc->type = ORC_TYPE_END_OF_STACK;
+               return 0;
+       case UNWIND_HINT_TYPE_CALL:
+               orc->type = ORC_TYPE_CALL;
+               break;
+       case UNWIND_HINT_TYPE_REGS:
+               orc->type = ORC_TYPE_REGS;
+               break;
+       case UNWIND_HINT_TYPE_REGS_PARTIAL:
+               orc->type = ORC_TYPE_REGS_PARTIAL;
+               break;
+       default:
+               WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
+               return -1;
+       }
+
+       orc->signal = cfi->signal;
+
+       switch (cfi->cfa.base) {
+       case CFI_SP:
+               orc->sp_reg = ORC_REG_SP;
+               break;
+       case CFI_SP_INDIRECT:
+               orc->sp_reg = ORC_REG_SP_INDIRECT;
+               break;
+       case CFI_BP:
+               orc->sp_reg = ORC_REG_BP;
+               break;
+       case CFI_BP_INDIRECT:
+               orc->sp_reg = ORC_REG_BP_INDIRECT;
+               break;
+       case CFI_R10:
+               orc->sp_reg = ORC_REG_R10;
+               break;
+       case CFI_R13:
+               orc->sp_reg = ORC_REG_R13;
+               break;
+       case CFI_DI:
+               orc->sp_reg = ORC_REG_DI;
+               break;
+       case CFI_DX:
+               orc->sp_reg = ORC_REG_DX;
+               break;
+       default:
+               WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
+               return -1;
+       }
+
+       switch (bp->base) {
+       case CFI_UNDEFINED:
+               orc->bp_reg = ORC_REG_UNDEFINED;
+               break;
+       case CFI_CFA:
+               orc->bp_reg = ORC_REG_PREV_SP;
+               break;
+       case CFI_BP:
+               orc->bp_reg = ORC_REG_BP;
+               break;
+       default:
+               WARN_INSN(insn, "unknown BP base reg %d", bp->base);
+               return -1;
+       }
+
+       orc->sp_offset = cfi->cfa.offset;
+       orc->bp_offset = bp->offset;
+
+       return 0;
+}
+
+int write_orc_entry(struct elf *elf, struct section *orc_sec,
+                   struct section *ip_sec, unsigned int idx,
+                   struct section *insn_sec, unsigned long insn_off,
+                   struct orc_entry *o)
+{
+       struct orc_entry *orc;
+
+       /* populate ORC data */
+       orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
+       memcpy(orc, o, sizeof(*orc));
+       orc->sp_offset = bswap_if_needed(elf, orc->sp_offset);
+       orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
+
+       /* populate reloc for ip */
+       if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
+                                    insn_sec, insn_off))
+               return -1;
+
+       return 0;
+}
+
+static const char *reg_name(unsigned int reg)
+{
+       switch (reg) {
+       case ORC_REG_PREV_SP:
+               return "prevsp";
+       case ORC_REG_DX:
+               return "dx";
+       case ORC_REG_DI:
+               return "di";
+       case ORC_REG_BP:
+               return "bp";
+       case ORC_REG_SP:
+               return "sp";
+       case ORC_REG_R10:
+               return "r10";
+       case ORC_REG_R13:
+               return "r13";
+       case ORC_REG_BP_INDIRECT:
+               return "bp(ind)";
+       case ORC_REG_SP_INDIRECT:
+               return "sp(ind)";
+       default:
+               return "?";
+       }
+}
+
+static const char *orc_type_name(unsigned int type)
+{
+       switch (type) {
+       case ORC_TYPE_UNDEFINED:
+               return "(und)";
+       case ORC_TYPE_END_OF_STACK:
+               return "end";
+       case ORC_TYPE_CALL:
+               return "call";
+       case ORC_TYPE_REGS:
+               return "regs";
+       case ORC_TYPE_REGS_PARTIAL:
+               return "regs (partial)";
+       default:
+               return "?";
+       }
+}
+
+static void print_reg(unsigned int reg, int offset)
+{
+       if (reg == ORC_REG_BP_INDIRECT)
+               printf("(bp%+d)", offset);
+       else if (reg == ORC_REG_SP_INDIRECT)
+               printf("(sp)%+d", offset);
+       else if (reg == ORC_REG_UNDEFINED)
+               printf("(und)");
+       else
+               printf("%s%+d", reg_name(reg), offset);
+}
+
+void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i)
+{
+       printf("type:%s", orc_type_name(orc[i].type));
+
+       printf(" sp:");
+       print_reg(orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset));
+
+       printf(" bp:");
+       print_reg(orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset));
+
+       printf(" signal:%d\n", orc[i].signal);
+}
index eb7e12ebc1d06afba3ddb9544ef8962f794ddd30..0b10ad00866867d9f4ba6787ca000f43bed230be 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/hashtable.h>
 #include <linux/kernel.h>
 #include <linux/static_call_types.h>
+#include <linux/string.h>
 
 struct alternative {
        struct alternative *next;
@@ -584,7 +585,7 @@ static int add_dead_ends(struct objtool_file *file)
        struct section *rsec;
        struct reloc *reloc;
        struct instruction *insn;
-       s64 addend;
+       unsigned long offset;
 
        /*
         * Check for manually annotated dead ends.
@@ -594,27 +595,28 @@ static int add_dead_ends(struct objtool_file *file)
                goto reachable;
 
        for_each_reloc(rsec, reloc) {
-
-               if (reloc->sym->type != STT_SECTION) {
+               if (reloc->sym->type == STT_SECTION) {
+                       offset = reloc_addend(reloc);
+               } else if (reloc->sym->local_label) {
+                       offset = reloc->sym->offset;
+               } else {
                        WARN("unexpected relocation symbol type in %s", rsec->name);
                        return -1;
                }
 
-               addend = reloc_addend(reloc);
-
-               insn = find_insn(file, reloc->sym->sec, addend);
+               insn = find_insn(file, reloc->sym->sec, offset);
                if (insn)
                        insn = prev_insn_same_sec(file, insn);
-               else if (addend == reloc->sym->sec->sh.sh_size) {
+               else if (offset == reloc->sym->sec->sh.sh_size) {
                        insn = find_last_insn(file, reloc->sym->sec);
                        if (!insn) {
                                WARN("can't find unreachable insn at %s+0x%" PRIx64,
-                                    reloc->sym->sec->name, addend);
+                                    reloc->sym->sec->name, offset);
                                return -1;
                        }
                } else {
                        WARN("can't find unreachable insn at %s+0x%" PRIx64,
-                            reloc->sym->sec->name, addend);
+                            reloc->sym->sec->name, offset);
                        return -1;
                }
 
@@ -633,27 +635,28 @@ reachable:
                return 0;
 
        for_each_reloc(rsec, reloc) {
-
-               if (reloc->sym->type != STT_SECTION) {
+               if (reloc->sym->type == STT_SECTION) {
+                       offset = reloc_addend(reloc);
+               } else if (reloc->sym->local_label) {
+                       offset = reloc->sym->offset;
+               } else {
                        WARN("unexpected relocation symbol type in %s", rsec->name);
                        return -1;
                }
 
-               addend = reloc_addend(reloc);
-
-               insn = find_insn(file, reloc->sym->sec, addend);
+               insn = find_insn(file, reloc->sym->sec, offset);
                if (insn)
                        insn = prev_insn_same_sec(file, insn);
-               else if (addend == reloc->sym->sec->sh.sh_size) {
+               else if (offset == reloc->sym->sec->sh.sh_size) {
                        insn = find_last_insn(file, reloc->sym->sec);
                        if (!insn) {
                                WARN("can't find reachable insn at %s+0x%" PRIx64,
-                                    reloc->sym->sec->name, addend);
+                                    reloc->sym->sec->name, offset);
                                return -1;
                        }
                } else {
                        WARN("can't find reachable insn at %s+0x%" PRIx64,
-                            reloc->sym->sec->name, addend);
+                            reloc->sym->sec->name, offset);
                        return -1;
                }
 
@@ -2224,6 +2227,7 @@ static int read_unwind_hints(struct objtool_file *file)
        struct unwind_hint *hint;
        struct instruction *insn;
        struct reloc *reloc;
+       unsigned long offset;
        int i;
 
        sec = find_section_by_name(file->elf, ".discard.unwind_hints");
@@ -2251,7 +2255,16 @@ static int read_unwind_hints(struct objtool_file *file)
                        return -1;
                }
 
-               insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc));
+               if (reloc->sym->type == STT_SECTION) {
+                       offset = reloc_addend(reloc);
+               } else if (reloc->sym->local_label) {
+                       offset = reloc->sym->offset;
+               } else {
+                       WARN("unexpected relocation symbol type in %s", sec->rsec->name);
+                       return -1;
+               }
+
+               insn = find_insn(file, reloc->sym->sec, offset);
                if (!insn) {
                        WARN("can't find insn for unwind_hints[%d]", i);
                        return -1;
@@ -2522,6 +2535,9 @@ static int classify_symbols(struct objtool_file *file)
        struct symbol *func;
 
        for_each_sym(file, func) {
+               if (func->type == STT_NOTYPE && strstarts(func->name, ".L"))
+                       func->local_label = true;
+
                if (func->bind != STB_GLOBAL)
                        continue;
 
index 9f71e988eca45fd6bc81734b9a52d76b895e9517..2b8a69de4db871e8e8c6d1dc211f7789ec79d0db 100644 (file)
@@ -67,6 +67,7 @@ struct symbol {
        u8 profiling_func    : 1;
        u8 warned            : 1;
        u8 embedded_insn     : 1;
+       u8 local_label       : 1;
        struct list_head pv_target;
        struct reloc *relocs;
 };
diff --git a/tools/objtool/include/objtool/orc.h b/tools/objtool/include/objtool/orc.h
new file mode 100644 (file)
index 0000000..15a32de
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _OBJTOOL_ORC_H
+#define _OBJTOOL_ORC_H
+
+#include <objtool/check.h>
+
+int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn);
+void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i);
+int write_orc_entry(struct elf *elf, struct section *orc_sec,
+                   struct section *ip_sec, unsigned int idx,
+                   struct section *insn_sec, unsigned long insn_off,
+                   struct orc_entry *o);
+
+#endif /* _OBJTOOL_ORC_H */
index 0e183bb1c72051157cb1e6daf30fa12ff3f0ce7c..a62247efb64f2e06c293e129ade3abae4fd456c1 100644 (file)
@@ -6,65 +6,10 @@
 #include <unistd.h>
 #include <asm/orc_types.h>
 #include <objtool/objtool.h>
+#include <objtool/orc.h>
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static const char *reg_name(unsigned int reg)
-{
-       switch (reg) {
-       case ORC_REG_PREV_SP:
-               return "prevsp";
-       case ORC_REG_DX:
-               return "dx";
-       case ORC_REG_DI:
-               return "di";
-       case ORC_REG_BP:
-               return "bp";
-       case ORC_REG_SP:
-               return "sp";
-       case ORC_REG_R10:
-               return "r10";
-       case ORC_REG_R13:
-               return "r13";
-       case ORC_REG_BP_INDIRECT:
-               return "bp(ind)";
-       case ORC_REG_SP_INDIRECT:
-               return "sp(ind)";
-       default:
-               return "?";
-       }
-}
-
-static const char *orc_type_name(unsigned int type)
-{
-       switch (type) {
-       case ORC_TYPE_UNDEFINED:
-               return "(und)";
-       case ORC_TYPE_END_OF_STACK:
-               return "end";
-       case ORC_TYPE_CALL:
-               return "call";
-       case ORC_TYPE_REGS:
-               return "regs";
-       case ORC_TYPE_REGS_PARTIAL:
-               return "regs (partial)";
-       default:
-               return "?";
-       }
-}
-
-static void print_reg(unsigned int reg, int offset)
-{
-       if (reg == ORC_REG_BP_INDIRECT)
-               printf("(bp%+d)", offset);
-       else if (reg == ORC_REG_SP_INDIRECT)
-               printf("(sp)%+d", offset);
-       else if (reg == ORC_REG_UNDEFINED)
-               printf("(und)");
-       else
-               printf("%s%+d", reg_name(reg), offset);
-}
-
 int orc_dump(const char *_objname)
 {
        int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
@@ -205,17 +150,7 @@ int orc_dump(const char *_objname)
                        printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
                }
 
-               printf("type:%s", orc_type_name(orc[i].type));
-
-               printf(" sp:");
-
-               print_reg(orc[i].sp_reg, bswap_if_needed(&dummy_elf, orc[i].sp_offset));
-
-               printf(" bp:");
-
-               print_reg(orc[i].bp_reg, bswap_if_needed(&dummy_elf, orc[i].bp_offset));
-
-               printf(" signal:%d\n", orc[i].signal);
+               orc_print_dump(&dummy_elf, orc, i);
        }
 
        elf_end(elf);
index bae343908867105f25ac35c61083e4d0ecfeca73..922e6aac7cea7c089fb48b37e94a01718b8c00ab 100644 (file)
 #include <asm/orc_types.h>
 
 #include <objtool/check.h>
+#include <objtool/orc.h>
 #include <objtool/warn.h>
 #include <objtool/endianness.h>
 
-static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
-                         struct instruction *insn)
-{
-       struct cfi_reg *bp = &cfi->regs[CFI_BP];
-
-       memset(orc, 0, sizeof(*orc));
-
-       if (!cfi) {
-               /*
-                * This is usually either unreachable nops/traps (which don't
-                * trigger unreachable instruction warnings), or
-                * STACK_FRAME_NON_STANDARD functions.
-                */
-               orc->type = ORC_TYPE_UNDEFINED;
-               return 0;
-       }
-
-       switch (cfi->type) {
-       case UNWIND_HINT_TYPE_UNDEFINED:
-               orc->type = ORC_TYPE_UNDEFINED;
-               return 0;
-       case UNWIND_HINT_TYPE_END_OF_STACK:
-               orc->type = ORC_TYPE_END_OF_STACK;
-               return 0;
-       case UNWIND_HINT_TYPE_CALL:
-               orc->type = ORC_TYPE_CALL;
-               break;
-       case UNWIND_HINT_TYPE_REGS:
-               orc->type = ORC_TYPE_REGS;
-               break;
-       case UNWIND_HINT_TYPE_REGS_PARTIAL:
-               orc->type = ORC_TYPE_REGS_PARTIAL;
-               break;
-       default:
-               WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
-               return -1;
-       }
-
-       orc->signal = cfi->signal;
-
-       switch (cfi->cfa.base) {
-       case CFI_SP:
-               orc->sp_reg = ORC_REG_SP;
-               break;
-       case CFI_SP_INDIRECT:
-               orc->sp_reg = ORC_REG_SP_INDIRECT;
-               break;
-       case CFI_BP:
-               orc->sp_reg = ORC_REG_BP;
-               break;
-       case CFI_BP_INDIRECT:
-               orc->sp_reg = ORC_REG_BP_INDIRECT;
-               break;
-       case CFI_R10:
-               orc->sp_reg = ORC_REG_R10;
-               break;
-       case CFI_R13:
-               orc->sp_reg = ORC_REG_R13;
-               break;
-       case CFI_DI:
-               orc->sp_reg = ORC_REG_DI;
-               break;
-       case CFI_DX:
-               orc->sp_reg = ORC_REG_DX;
-               break;
-       default:
-               WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
-               return -1;
-       }
-
-       switch (bp->base) {
-       case CFI_UNDEFINED:
-               orc->bp_reg = ORC_REG_UNDEFINED;
-               break;
-       case CFI_CFA:
-               orc->bp_reg = ORC_REG_PREV_SP;
-               break;
-       case CFI_BP:
-               orc->bp_reg = ORC_REG_BP;
-               break;
-       default:
-               WARN_INSN(insn, "unknown BP base reg %d", bp->base);
-               return -1;
-       }
-
-       orc->sp_offset = cfi->cfa.offset;
-       orc->bp_offset = bp->offset;
-
-       return 0;
-}
-
-static int write_orc_entry(struct elf *elf, struct section *orc_sec,
-                          struct section *ip_sec, unsigned int idx,
-                          struct section *insn_sec, unsigned long insn_off,
-                          struct orc_entry *o)
-{
-       struct orc_entry *orc;
-
-       /* populate ORC data */
-       orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
-       memcpy(orc, o, sizeof(*orc));
-       orc->sp_offset = bswap_if_needed(elf, orc->sp_offset);
-       orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
-
-       /* populate reloc for ip */
-       if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
-                                    insn_sec, insn_off))
-               return -1;
-
-       return 0;
-}
-
 struct orc_list_entry {
        struct list_head list;
        struct orc_entry orc;
diff --git a/tools/perf/pmu-events/arch/riscv/andes/ax45/firmware.json b/tools/perf/pmu-events/arch/riscv/andes/ax45/firmware.json
new file mode 100644 (file)
index 0000000..9b4a032
--- /dev/null
@@ -0,0 +1,68 @@
+[
+  {
+    "ArchStdEvent": "FW_MISALIGNED_LOAD"
+  },
+  {
+    "ArchStdEvent": "FW_MISALIGNED_STORE"
+  },
+  {
+    "ArchStdEvent": "FW_ACCESS_LOAD"
+  },
+  {
+    "ArchStdEvent": "FW_ACCESS_STORE"
+  },
+  {
+    "ArchStdEvent": "FW_ILLEGAL_INSN"
+  },
+  {
+    "ArchStdEvent": "FW_SET_TIMER"
+  },
+  {
+    "ArchStdEvent": "FW_IPI_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_IPI_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_FENCE_I_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_FENCE_I_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_SFENCE_VMA_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_GVMA_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_VVMA_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT"
+  },
+  {
+    "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED"
+  }
+]
diff --git a/tools/perf/pmu-events/arch/riscv/andes/ax45/instructions.json b/tools/perf/pmu-events/arch/riscv/andes/ax45/instructions.json
new file mode 100644 (file)
index 0000000..713a08c
--- /dev/null
@@ -0,0 +1,127 @@
+[
+       {
+               "EventCode": "0x10",
+               "EventName": "cycle_count",
+               "BriefDescription": "Cycle count"
+       },
+       {
+               "EventCode": "0x20",
+               "EventName": "inst_count",
+               "BriefDescription": "Retired instruction count"
+       },
+       {
+               "EventCode": "0x30",
+               "EventName": "int_load_inst",
+               "BriefDescription": "Integer load instruction count"
+       },
+       {
+               "EventCode": "0x40",
+               "EventName": "int_store_inst",
+               "BriefDescription": "Integer store instruction count"
+       },
+       {
+               "EventCode": "0x50",
+               "EventName": "atomic_inst",
+               "BriefDescription": "Atomic instruction count"
+       },
+       {
+               "EventCode": "0x60",
+               "EventName": "sys_inst",
+               "BriefDescription": "System instruction count"
+       },
+       {
+               "EventCode": "0x70",
+               "EventName": "int_compute_inst",
+               "BriefDescription": "Integer computational instruction count"
+       },
+       {
+               "EventCode": "0x80",
+               "EventName": "condition_br",
+               "BriefDescription": "Conditional branch instruction count"
+       },
+       {
+               "EventCode": "0x90",
+               "EventName": "taken_condition_br",
+               "BriefDescription": "Taken conditional branch instruction count"
+       },
+       {
+               "EventCode": "0xA0",
+               "EventName": "jal_inst",
+               "BriefDescription": "JAL instruction count"
+       },
+       {
+               "EventCode": "0xB0",
+               "EventName": "jalr_inst",
+               "BriefDescription": "JALR instruction count"
+       },
+       {
+               "EventCode": "0xC0",
+               "EventName": "ret_inst",
+               "BriefDescription": "Return instruction count"
+       },
+       {
+               "EventCode": "0xD0",
+               "EventName": "control_trans_inst",
+               "BriefDescription": "Control transfer instruction count"
+       },
+       {
+               "EventCode": "0xE0",
+               "EventName": "ex9_inst",
+               "BriefDescription": "EXEC.IT instruction count"
+       },
+       {
+               "EventCode": "0xF0",
+               "EventName": "int_mul_inst",
+               "BriefDescription": "Integer multiplication instruction count"
+       },
+       {
+               "EventCode": "0x100",
+               "EventName": "int_div_rem_inst",
+               "BriefDescription": "Integer division/remainder instruction count"
+       },
+       {
+               "EventCode": "0x110",
+               "EventName": "float_load_inst",
+               "BriefDescription": "Floating-point load instruction count"
+       },
+       {
+               "EventCode": "0x120",
+               "EventName": "float_store_inst",
+               "BriefDescription": "Floating-point store instruction count"
+       },
+       {
+               "EventCode": "0x130",
+               "EventName": "float_add_sub_inst",
+               "BriefDescription": "Floating-point addition/subtraction instruction count"
+       },
+       {
+               "EventCode": "0x140",
+               "EventName": "float_mul_inst",
+               "BriefDescription": "Floating-point multiplication instruction count"
+       },
+       {
+               "EventCode": "0x150",
+               "EventName": "float_fused_muladd_inst",
+               "BriefDescription": "Floating-point fused multiply-add instruction count"
+       },
+       {
+               "EventCode": "0x160",
+               "EventName": "float_div_sqrt_inst",
+               "BriefDescription": "Floating-point division or square-root instruction count"
+       },
+       {
+               "EventCode": "0x170",
+               "EventName": "other_float_inst",
+               "BriefDescription": "Other floating-point instruction count"
+       },
+       {
+               "EventCode": "0x180",
+               "EventName": "int_mul_add_sub_inst",
+               "BriefDescription": "Integer multiplication and add/sub instruction count"
+       },
+       {
+               "EventCode": "0x190",
+               "EventName": "retired_ops",
+               "BriefDescription": "Retired operation count"
+       }
+]
diff --git a/tools/perf/pmu-events/arch/riscv/andes/ax45/memory.json b/tools/perf/pmu-events/arch/riscv/andes/ax45/memory.json
new file mode 100644 (file)
index 0000000..c7401b5
--- /dev/null
@@ -0,0 +1,57 @@
+[
+       {
+               "EventCode": "0x01",
+               "EventName": "ilm_access",
+               "BriefDescription": "ILM access"
+       },
+       {
+               "EventCode": "0x11",
+               "EventName": "dlm_access",
+               "BriefDescription": "DLM access"
+       },
+       {
+               "EventCode": "0x21",
+               "EventName": "icache_access",
+               "BriefDescription": "ICACHE access"
+       },
+       {
+               "EventCode": "0x31",
+               "EventName": "icache_miss",
+               "BriefDescription": "ICACHE miss"
+       },
+       {
+               "EventCode": "0x41",
+               "EventName": "dcache_access",
+               "BriefDescription": "DCACHE access"
+       },
+       {
+               "EventCode": "0x51",
+               "EventName": "dcache_miss",
+               "BriefDescription": "DCACHE miss"
+       },
+       {
+               "EventCode": "0x61",
+               "EventName": "dcache_load_access",
+               "BriefDescription": "DCACHE load access"
+       },
+       {
+               "EventCode": "0x71",
+               "EventName": "dcache_load_miss",
+               "BriefDescription": "DCACHE load miss"
+       },
+       {
+               "EventCode": "0x81",
+               "EventName": "dcache_store_access",
+               "BriefDescription": "DCACHE store access"
+       },
+       {
+               "EventCode": "0x91",
+               "EventName": "dcache_store_miss",
+               "BriefDescription": "DCACHE store miss"
+       },
+       {
+               "EventCode": "0xA1",
+               "EventName": "dcache_wb",
+               "BriefDescription": "DCACHE writeback"
+       }
+]
diff --git a/tools/perf/pmu-events/arch/riscv/andes/ax45/microarch.json b/tools/perf/pmu-events/arch/riscv/andes/ax45/microarch.json
new file mode 100644 (file)
index 0000000..a6d378c
--- /dev/null
@@ -0,0 +1,77 @@
+[
+       {
+               "EventCode": "0xB1",
+               "EventName": "cycle_wait_icache_fill",
+               "BriefDescription": "Cycles waiting for ICACHE fill data"
+       },
+       {
+               "EventCode": "0xC1",
+               "EventName": "cycle_wait_dcache_fill",
+               "BriefDescription": "Cycles waiting for DCACHE fill data"
+       },
+       {
+               "EventCode": "0xD1",
+               "EventName": "uncached_ifetch_from_bus",
+               "BriefDescription": "Uncached ifetch data access from bus"
+       },
+       {
+               "EventCode": "0xE1",
+               "EventName": "uncached_load_from_bus",
+               "BriefDescription": "Uncached load data access from bus"
+       },
+       {
+               "EventCode": "0xF1",
+               "EventName": "cycle_wait_uncached_ifetch",
+               "BriefDescription": "Cycles waiting for uncached ifetch data from bus"
+       },
+       {
+               "EventCode": "0x101",
+               "EventName": "cycle_wait_uncached_load",
+               "BriefDescription": "Cycles waiting for uncached load data from bus"
+       },
+       {
+               "EventCode": "0x111",
+               "EventName": "main_itlb_access",
+               "BriefDescription": "Main ITLB access"
+       },
+       {
+               "EventCode": "0x121",
+               "EventName": "main_itlb_miss",
+               "BriefDescription": "Main ITLB miss"
+       },
+       {
+               "EventCode": "0x131",
+               "EventName": "main_dtlb_access",
+               "BriefDescription": "Main DTLB access"
+       },
+       {
+               "EventCode": "0x141",
+               "EventName": "main_dtlb_miss",
+               "BriefDescription": "Main DTLB miss"
+       },
+       {
+               "EventCode": "0x151",
+               "EventName": "cycle_wait_itlb_fill",
+               "BriefDescription": "Cycles waiting for Main ITLB fill data"
+       },
+       {
+               "EventCode": "0x161",
+               "EventName": "pipe_stall_cycle_dtlb_miss",
+               "BriefDescription": "Pipeline stall cycles caused by Main DTLB miss"
+       },
+       {
+               "EventCode": "0x02",
+               "EventName": "mispredict_condition_br",
+               "BriefDescription": "Misprediction of conditional branches"
+       },
+       {
+               "EventCode": "0x12",
+               "EventName": "mispredict_take_condition_br",
+               "BriefDescription": "Misprediction of taken conditional branches"
+       },
+       {
+               "EventCode": "0x22",
+               "EventName": "mispredict_target_ret_inst",
+               "BriefDescription": "Misprediction of targets of Return instructions"
+       }
+]
index cfc449b198105ebe5004c0565de85499ff14f319..3d3a809a5446e8e811dcd6cc243c33c58811e0b1 100644 (file)
@@ -17,3 +17,4 @@
 0x489-0x8000000000000007-0x[[:xdigit:]]+,v1,sifive/u74,core
 0x5b7-0x0-0x0,v1,thead/c900-legacy,core
 0x67e-0x80000000db0000[89]0-0x[[:xdigit:]]+,v1,starfive/dubhe-80,core
+0x31e-0x8000000000008a45-0x[[:xdigit:]]+,v1,andes/ax45,core
index cfcb7e2c3813f2dbd3fd5ca9d123a6883713d672..139c330ccf2c3bf995a0c05db14db4f286f7eab6 100644 (file)
@@ -422,13 +422,6 @@ extern long __sys_recvmsg_sock(struct socket *sock, struct msghdr *msg,
                               struct user_msghdr __user *umsg,
                               struct sockaddr __user *uaddr,
                               unsigned int flags);
-extern int sendmsg_copy_msghdr(struct msghdr *msg,
-                              struct user_msghdr __user *umsg, unsigned flags,
-                              struct iovec **iov);
-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(struct msghdr *kmsg,
                         struct user_msghdr *umsg,
                         struct sockaddr __user **save_addr);
index 829f5bdfd2e439346860b076de38d0a36271efa0..eb31cd9c977bfb09324ae28ed731809fc912cc16 100755 (executable)
@@ -792,13 +792,13 @@ sub process_variables {
     my $retval = "";
 
     # We want to check for '\', and it is just easier
-    # to check the previous characet of '$' and not need
+    # to check the previous character of '$' and not need
     # to worry if '$' is the first character. By adding
     # a space to $value, we can just check [^\\]\$ and
     # it will still work.
     $value = " $value";
 
-    while ($value =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
+    while ($value =~ /(.*?[^\\])\$\{([^\{]*?)\}(.*)/) {
        my $begin = $1;
        my $var = $2;
        my $end = $3;
@@ -818,16 +818,20 @@ sub process_variables {
            # we simple convert to 0
            $retval = "${retval}0";
        } else {
-           # put back the origin piece.
-           $retval = "$retval\$\{$var\}";
+           # put back the origin piece, but with $#### to not reprocess it
+           $retval = "$retval\$####\{$var\}";
            # This could be an option that is used later, save
            # it so we don't warn if this option is not one of
            # ktests options.
            $used_options{$var} = 1;
        }
-       $value = $end;
+       $value = "$retval$end";
+       $retval = "";
     }
-    $retval = "$retval$value";
+    $retval = $value;
+
+    # Convert the saved variables with $####{var} back to ${var}
+    $retval =~ s/\$####/\$/g;
 
     # remove the space added in the beginning
     $retval =~ s/ //;
@@ -843,6 +847,7 @@ sub set_value {
     if ($lvalue =~ /^(TEST|BISECT|CONFIG_BISECT)_TYPE(\[.*\])?$/ &&
        $prvalue !~ /^(config_|)bisect$/ &&
        $prvalue !~ /^build$/ &&
+       $prvalue !~ /^make_warnings_file$/ &&
        $buildonly) {
 
        # Note if a test is something other than build, then we
index d117e8a96ded9971149f3a0b13dbf8892c9fa033..e1504833654db447f908c14e4b5a7532b0e602f0 100644 (file)
@@ -13,6 +13,7 @@ TARGETS += core
 TARGETS += cpufreq
 TARGETS += cpu-hotplug
 TARGETS += damon
+TARGETS += devices
 TARGETS += dmabuf-heaps
 TARGETS += drivers/dma-buf
 TARGETS += drivers/s390x/uvdevice
diff --git a/tools/testing/selftests/devices/Makefile b/tools/testing/selftests/devices/Makefile
new file mode 100644 (file)
index 0000000..ca29249
--- /dev/null
@@ -0,0 +1,4 @@
+TEST_PROGS := test_discoverable_devices.py
+TEST_FILES := boards ksft.py
+
+include ../lib.mk
diff --git a/tools/testing/selftests/devices/boards/Dell Inc.,XPS 13 9300.yaml b/tools/testing/selftests/devices/boards/Dell Inc.,XPS 13 9300.yaml
new file mode 100644 (file)
index 0000000..ff932eb
--- /dev/null
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# This is the device definition for the XPS 13 9300.
+# The filename "Dell Inc.,XPS 13 9300" was chosen following the format
+# "Vendor,Product", where Vendor comes from
+# /sys/devices/virtual/dmi/id/sys_vendor, and Product comes from
+# /sys/devices/virtual/dmi/id/product_name.
+#
+# See google,spherion.yaml for more information.
+#
+- type: pci-controller
+  # This machine has a single PCI host controller so it's valid to not have any
+  # key to identify the controller. If it had more than one controller, the UID
+  # of the controller from ACPI could be used to distinguish as follows:
+  #acpi-uid: 0
+  devices:
+    - path: 14.0
+      type: usb-controller
+      usb-version: 2
+      devices:
+        - path: 9
+          name: camera
+          interfaces: [0, 1, 2, 3]
+        - path: 10
+          name: bluetooth
+          interfaces: [0, 1]
+    - path: 2.0
+      name: gpu
+    - path: 4.0
+      name: thermal
+    - path: 12.0
+      name: sensors
+    - path: 14.3
+      name: wifi
+    - path: 1d.0/0.0
+      name: ssd
+    - path: 1d.7/0.0
+      name: sdcard-reader
+    - path: 1f.3
+      name: audio
diff --git a/tools/testing/selftests/devices/boards/google,spherion.yaml b/tools/testing/selftests/devices/boards/google,spherion.yaml
new file mode 100644 (file)
index 0000000..17157ec
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# This is the device definition for the Google Spherion Chromebook.
+# The filename "google,spherion" comes from the Devicetree compatible, so this
+# file will be automatically used when the test is run on that machine.
+#
+# The top-level is a list of controllers, either for USB or PCI(e).
+# Every controller needs to have a 'type' key set to either 'usb-controller' or
+# 'pci-controller'.
+# Every controller needs to be uniquely identified on the platform. To achieve
+# this, several optional keys can be used:
+# - dt-mmio: identify the MMIO address of the controller as defined in the
+#   Devicetree.
+# - usb-version: for USB controllers to differentiate between USB3 and USB2
+#   buses sharing the same controller.
+# - acpi-uid: _UID property of the controller as supplied by the ACPI. Useful to
+#   distinguish between multiple PCI host controllers.
+#
+# The 'devices' key defines a list of devices that are accessible under that
+# controller. A device might be a leaf device or another controller (see
+# 'Dell Inc.,XPS 13 9300.yaml').
+#
+# The 'path' key is needed for every child device (that is, not top-level) to
+# define how to reach this device from the parent controller. For USB devices it
+# follows the format \d(.\d)* and denotes the port in the hub at each level in
+# the USB topology. For PCI devices it follows the format \d.\d(/\d.\d)*
+# denoting the device (identified by device-function pair) at each level in the
+# PCI topology.
+#
+# The 'name' key is used in the leaf devices to name the device for clarity in
+# the test output.
+#
+# For USB leaf devices, the 'interfaces' key should contain a list of the
+# interfaces in that device that should be bound to a driver.
+#
+- type: usb-controller
+  dt-mmio: 11200000
+  usb-version: 2
+  devices:
+    - path: 1.4.1
+      interfaces: [0, 1]
+      name: camera
+    - path: 1.4.2
+      interfaces: [0, 1]
+      name: bluetooth
+- type: pci-controller
+  dt-mmio: 11230000
+  devices:
+    - path: 0.0/0.0
+      name: wifi
diff --git a/tools/testing/selftests/devices/ksft.py b/tools/testing/selftests/devices/ksft.py
new file mode 100644 (file)
index 0000000..cd89fb2
--- /dev/null
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2023 Collabora Ltd
+#
+# Kselftest helpers for outputting in KTAP format. Based on kselftest.h.
+#
+
+import sys
+
+ksft_cnt = {"pass": 0, "fail": 0, "skip": 0}
+ksft_num_tests = 0
+ksft_test_number = 1
+
+KSFT_PASS = 0
+KSFT_FAIL = 1
+KSFT_SKIP = 4
+
+
+def print_header():
+    print("TAP version 13")
+
+
+def set_plan(num_tests):
+    global ksft_num_tests
+    ksft_num_tests = num_tests
+    print("1..{}".format(num_tests))
+
+
+def print_cnts():
+    print(
+        f"# Totals: pass:{ksft_cnt['pass']} fail:{ksft_cnt['fail']} xfail:0 xpass:0 skip:{ksft_cnt['skip']} error:0"
+    )
+
+
+def print_msg(msg):
+    print(f"# {msg}")
+
+
+def _test_print(result, description, directive=None):
+    if directive:
+        directive_str = f"# {directive}"
+    else:
+        directive_str = ""
+
+    global ksft_test_number
+    print(f"{result} {ksft_test_number} {description} {directive_str}")
+    ksft_test_number += 1
+
+
+def test_result_pass(description):
+    _test_print("ok", description)
+    ksft_cnt["pass"] += 1
+
+
+def test_result_fail(description):
+    _test_print("not ok", description)
+    ksft_cnt["fail"] += 1
+
+
+def test_result_skip(description):
+    _test_print("ok", description, "SKIP")
+    ksft_cnt["skip"] += 1
+
+
+def test_result(condition, description=""):
+    if condition:
+        test_result_pass(description)
+    else:
+        test_result_fail(description)
+
+
+def finished():
+    if ksft_cnt["pass"] == ksft_num_tests:
+        exit_code = KSFT_PASS
+    else:
+        exit_code = KSFT_FAIL
+
+    print_cnts()
+
+    sys.exit(exit_code)
+
+
+def exit_fail():
+    print_cnts()
+    sys.exit(KSFT_FAIL)
+
+
+def exit_pass():
+    print_cnts()
+    sys.exit(KSFT_PASS)
diff --git a/tools/testing/selftests/devices/test_discoverable_devices.py b/tools/testing/selftests/devices/test_discoverable_devices.py
new file mode 100755 (executable)
index 0000000..fbae8de
--- /dev/null
@@ -0,0 +1,318 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2023 Collabora Ltd
+#
+# This script tests for presence and driver binding of devices from discoverable
+# buses (ie USB, PCI).
+#
+# The per-platform YAML file defining the devices to be tested is stored inside
+# the boards/ directory and chosen based on DT compatible or DMI IDs (sys_vendor
+# and product_name).
+#
+# See boards/google,spherion.yaml and boards/'Dell Inc.,XPS 13 9300.yaml' for
+# the description and examples of the file structure and vocabulary.
+#
+
+import glob
+import ksft
+import os
+import re
+import sys
+import yaml
+
+pci_controllers = []
+usb_controllers = []
+
+sysfs_usb_devices = "/sys/bus/usb/devices/"
+
+
+def find_pci_controller_dirs():
+    sysfs_devices = "/sys/devices"
+    pci_controller_sysfs_dir = "pci[0-9a-f]{4}:[0-9a-f]{2}"
+
+    dir_regex = re.compile(pci_controller_sysfs_dir)
+    for path, dirs, _ in os.walk(sysfs_devices):
+        for d in dirs:
+            if dir_regex.match(d):
+                pci_controllers.append(os.path.join(path, d))
+
+
+def find_usb_controller_dirs():
+    usb_controller_sysfs_dir = "usb[\d]+"
+
+    dir_regex = re.compile(usb_controller_sysfs_dir)
+    for d in os.scandir(sysfs_usb_devices):
+        if dir_regex.match(d.name):
+            usb_controllers.append(os.path.realpath(d.path))
+
+
+def get_dt_mmio(sysfs_dev_dir):
+    re_dt_mmio = re.compile("OF_FULLNAME=.*@([0-9a-f]+)")
+    dt_mmio = None
+
+    # PCI controllers' sysfs don't have an of_node, so have to read it from the
+    # parent
+    while not dt_mmio:
+        try:
+            with open(os.path.join(sysfs_dev_dir, "uevent")) as f:
+                dt_mmio = re_dt_mmio.search(f.read()).group(1)
+                return dt_mmio
+        except:
+            pass
+        sysfs_dev_dir = os.path.dirname(sysfs_dev_dir)
+
+
+def get_acpi_uid(sysfs_dev_dir):
+    with open(os.path.join(sysfs_dev_dir, "firmware_node", "uid")) as f:
+        return f.read()
+
+
+def get_usb_version(sysfs_dev_dir):
+    re_usb_version = re.compile("PRODUCT=.*/(\d)/.*")
+    with open(os.path.join(sysfs_dev_dir, "uevent")) as f:
+        return int(re_usb_version.search(f.read()).group(1))
+
+
+def get_usb_busnum(sysfs_dev_dir):
+    re_busnum = re.compile("BUSNUM=(.*)")
+    with open(os.path.join(sysfs_dev_dir, "uevent")) as f:
+        return int(re_busnum.search(f.read()).group(1))
+
+
+def find_controller_in_sysfs(controller, parent_sysfs=None):
+    if controller["type"] == "pci-controller":
+        controllers = pci_controllers
+    elif controller["type"] == "usb-controller":
+        controllers = usb_controllers
+
+    result_controllers = []
+
+    for c in controllers:
+        if parent_sysfs and parent_sysfs not in c:
+            continue
+
+        if controller.get("dt-mmio"):
+            if str(controller["dt-mmio"]) != get_dt_mmio(c):
+                continue
+
+        if controller.get("usb-version"):
+            if controller["usb-version"] != get_usb_version(c):
+                continue
+
+        if controller.get("acpi-uid"):
+            if controller["acpi-uid"] != get_acpi_uid(c):
+                continue
+
+        result_controllers.append(c)
+
+    return result_controllers
+
+
+def is_controller(device):
+    return device.get("type") and "controller" in device.get("type")
+
+
+def path_to_dir(parent_sysfs, dev_type, path):
+    if dev_type == "usb-device":
+        usb_dev_sysfs_fmt = "{}-{}"
+        busnum = get_usb_busnum(parent_sysfs)
+        dirname = os.path.join(
+            sysfs_usb_devices, usb_dev_sysfs_fmt.format(busnum, path)
+        )
+        return [os.path.realpath(dirname)]
+    else:
+        pci_dev_sysfs_fmt = "????:??:{}"
+        path_glob = ""
+        for dev_func in path.split("/"):
+            dev_func = dev_func.zfill(4)
+            path_glob = os.path.join(path_glob, pci_dev_sysfs_fmt.format(dev_func))
+
+        dir_list = glob.glob(os.path.join(parent_sysfs, path_glob))
+
+        return dir_list
+
+
+def find_in_sysfs(device, parent_sysfs=None):
+    if parent_sysfs and device.get("path"):
+        pathdirs = path_to_dir(
+            parent_sysfs, device["meta"]["type"], str(device["path"])
+        )
+        if len(pathdirs) != 1:
+            # Early return to report error
+            return pathdirs
+        pathdir = pathdirs[0]
+        sysfs_path = os.path.join(parent_sysfs, pathdir)
+    else:
+        sysfs_path = parent_sysfs
+
+    if is_controller(device):
+        return find_controller_in_sysfs(device, sysfs_path)
+    else:
+        return [sysfs_path]
+
+
+def check_driver_presence(sysfs_dir, current_node):
+    if current_node["meta"]["type"] == "usb-device":
+        usb_intf_fmt = "*-*:*.{}"
+
+        interfaces = []
+        for i in current_node["interfaces"]:
+            interfaces.append((i, usb_intf_fmt.format(i)))
+
+        for intf_num, intf_dir_fmt in interfaces:
+            test_name = f"{current_node['meta']['pathname']}.{intf_num}.driver"
+
+            intf_dirs = glob.glob(os.path.join(sysfs_dir, intf_dir_fmt))
+            if len(intf_dirs) != 1:
+                ksft.test_result_fail(test_name)
+                continue
+            intf_dir = intf_dirs[0]
+
+            driver_link = os.path.join(sysfs_dir, intf_dir, "driver")
+            ksft.test_result(os.path.isdir(driver_link), test_name)
+    else:
+        driver_link = os.path.join(sysfs_dir, "driver")
+        test_name = current_node["meta"]["pathname"] + ".driver"
+        ksft.test_result(os.path.isdir(driver_link), test_name)
+
+
+def generate_pathname(device):
+    pathname = ""
+
+    if device.get("path"):
+        pathname = str(device["path"])
+
+    if device.get("type"):
+        dev_type = device["type"]
+        if device.get("usb-version"):
+            dev_type = dev_type.replace("usb", "usb" + str(device["usb-version"]))
+        if device.get("acpi-uid") is not None:
+            dev_type = dev_type.replace("pci", "pci" + str(device["acpi-uid"]))
+        pathname = pathname + "/" + dev_type
+
+    if device.get("dt-mmio"):
+        pathname += "@" + str(device["dt-mmio"])
+
+    if device.get("name"):
+        pathname = pathname + "/" + device["name"]
+
+    return pathname
+
+
+def fill_meta_keys(child, parent=None):
+    child["meta"] = {}
+
+    if parent:
+        child["meta"]["type"] = parent["type"].replace("controller", "device")
+
+    pathname = generate_pathname(child)
+    if parent:
+        pathname = parent["meta"]["pathname"] + "/" + pathname
+    child["meta"]["pathname"] = pathname
+
+
+def parse_device_tree_node(current_node, parent_sysfs=None):
+    if not parent_sysfs:
+        fill_meta_keys(current_node)
+
+    sysfs_dirs = find_in_sysfs(current_node, parent_sysfs)
+    if len(sysfs_dirs) != 1:
+        if len(sysfs_dirs) == 0:
+            ksft.test_result_fail(
+                f"Couldn't find in sysfs: {current_node['meta']['pathname']}"
+            )
+        else:
+            ksft.test_result_fail(
+                f"Found multiple sysfs entries for {current_node['meta']['pathname']}: {sysfs_dirs}"
+            )
+        return
+    sysfs_dir = sysfs_dirs[0]
+
+    if not is_controller(current_node):
+        ksft.test_result(
+            os.path.exists(sysfs_dir), current_node["meta"]["pathname"] + ".device"
+        )
+        check_driver_presence(sysfs_dir, current_node)
+    else:
+        for child_device in current_node["devices"]:
+            fill_meta_keys(child_device, current_node)
+            parse_device_tree_node(child_device, sysfs_dir)
+
+
+def count_tests(device_trees):
+    test_count = 0
+
+    def parse_node(device):
+        nonlocal test_count
+        if device.get("devices"):
+            for child in device["devices"]:
+                parse_node(child)
+        else:
+            if device.get("interfaces"):
+                test_count += len(device["interfaces"])
+            else:
+                test_count += 1
+            test_count += 1
+
+    for device_tree in device_trees:
+        parse_node(device_tree)
+
+    return test_count
+
+
+def get_board_filenames():
+    filenames = []
+
+    platform_compatible_file = "/proc/device-tree/compatible"
+    if os.path.exists(platform_compatible_file):
+        with open(platform_compatible_file) as f:
+            for line in f:
+                filenames.extend(line.split("\0"))
+    else:
+        dmi_id_dir = "/sys/devices/virtual/dmi/id"
+        vendor_dmi_file = os.path.join(dmi_id_dir, "sys_vendor")
+        product_dmi_file = os.path.join(dmi_id_dir, "product_name")
+
+        with open(vendor_dmi_file) as f:
+            vendor = f.read().replace("\n", "")
+        with open(product_dmi_file) as f:
+            product = f.read().replace("\n", "")
+
+        filenames = [vendor + "," + product]
+
+    return filenames
+
+
+def run_test(yaml_file):
+    ksft.print_msg(f"Using board file: {yaml_file}")
+
+    with open(yaml_file) as f:
+        device_trees = yaml.safe_load(f)
+
+    ksft.set_plan(count_tests(device_trees))
+
+    for device_tree in device_trees:
+        parse_device_tree_node(device_tree)
+
+
+find_pci_controller_dirs()
+find_usb_controller_dirs()
+
+ksft.print_header()
+
+board_file = ""
+for board_filename in get_board_filenames():
+    full_board_filename = os.path.join("boards", board_filename + ".yaml")
+
+    if os.path.exists(full_board_filename):
+        board_file = full_board_filename
+        break
+
+if not board_file:
+    ksft.print_msg("No matching board file found")
+    ksft.exit_fail()
+
+run_test(board_file)
+
+ksft.finished()
index a0bb4524e1e9c66bed9ff99d08232be8c4f409fc..a603f7b0a08f07e5d7ac71cd916791c1a7774572 100755 (executable)
@@ -354,7 +354,7 @@ __ping_ipv4()
 
        # Send 100 packets and verify that at least 100 packets hit the rule,
        # to overcome ARP noise.
-       PING_COUNT=100 PING_TIMEOUT=11 ping_do $dev $dst_ip
+       PING_COUNT=100 PING_TIMEOUT=20 ping_do $dev $dst_ip
        check_err $? "Ping failed"
 
        tc_check_at_least_x_packets "dev $rp1 egress" 101 10 100
@@ -410,7 +410,7 @@ __ping_ipv6()
 
        # Send 100 packets and verify that at least 100 packets hit the rule,
        # to overcome neighbor discovery noise.
-       PING_COUNT=100 PING_TIMEOUT=11 ping6_do $dev $dst_ip
+       PING_COUNT=100 PING_TIMEOUT=20 ping6_do $dev $dst_ip
        check_err $? "Ping failed"
 
        tc_check_at_least_x_packets "dev $rp1 egress" 101 100
index d880df89bc8bd51bca702736bad069aa2639f169..e83fde79f40d0f5bc31353a05714e7fd123fc8f8 100755 (executable)
@@ -457,7 +457,7 @@ __ping_ipv4()
 
        # Send 100 packets and verify that at least 100 packets hit the rule,
        # to overcome ARP noise.
-       PING_COUNT=100 PING_TIMEOUT=11 ping_do $dev $dst_ip
+       PING_COUNT=100 PING_TIMEOUT=20 ping_do $dev $dst_ip
        check_err $? "Ping failed"
 
        tc_check_at_least_x_packets "dev $rp1 egress" 101 10 100
@@ -522,7 +522,7 @@ __ping_ipv6()
 
        # Send 100 packets and verify that at least 100 packets hit the rule,
        # to overcome neighbor discovery noise.
-       PING_COUNT=100 PING_TIMEOUT=11 ping6_do $dev $dst_ip
+       PING_COUNT=100 PING_TIMEOUT=20 ping6_do $dev $dst_ip
        check_err $? "Ping failed"
 
        tc_check_at_least_x_packets "dev $rp1 egress" 101 100
index 9cd5e885e91f74b01007cf14bbdb9808aa04c632..380cb15e942e42f7ef5cc652c0131c4a592d44f2 100755 (executable)
@@ -217,6 +217,7 @@ for family in 4 6; do
        cleanup
 
        create_ns
+       ip netns exec $NS_DST ethtool -K veth$DST generic-receive-offload on
        ip netns exec $NS_DST ethtool -K veth$DST rx-gro-list on
        run_test "GRO frag list" $BM_NET$DST 1 0
        cleanup
@@ -227,6 +228,7 @@ for family in 4 6; do
        # use NAT to circumvent GRO FWD check
        create_ns
        ip -n $NS_DST addr add dev veth$DST $BM_NET$DST_NAT/$SUFFIX
+       ip netns exec $NS_DST ethtool -K veth$DST generic-receive-offload on
        ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
        ip netns exec $NS_DST $IPT -t nat -I PREROUTING -d $BM_NET$DST_NAT \
                                        -j DNAT --to-destination $BM_NET$DST
@@ -240,6 +242,7 @@ for family in 4 6; do
        cleanup
 
        create_vxlan_pair
+       ip netns exec $NS_DST ethtool -K veth$DST generic-receive-offload on
        ip netns exec $NS_DST ethtool -K veth$DST rx-gro-list on
        run_test "GRO frag list over UDP tunnel" $OL_NET$DST 1 1
        cleanup
@@ -247,6 +250,7 @@ for family in 4 6; do
        # use NAT to circumvent GRO FWD check
        create_vxlan_pair
        ip -n $NS_DST addr add dev $VXDEV$DST $OL_NET$DST_NAT/$SUFFIX
+       ip netns exec $NS_DST ethtool -K veth$DST generic-receive-offload on
        ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
        ip netns exec $NS_DST $IPT -t nat -I PREROUTING -d $OL_NET$DST_NAT \
                                        -j DNAT --to-destination $OL_NET$DST
index 5ae85def07395b50c07600f4a31b7ff69578bb9f..3a394b43e274bdf51e735e60349b44d7e66e5dc2 100755 (executable)
@@ -249,9 +249,9 @@ cleanup
 create_ns
 ip -n $NS_DST link set dev veth$DST up
 ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
-chk_gro_flag "gro vs xdp while down - gro flag on" $DST on
+chk_gro_flag "gro vs xdp while down - gro flag off" $DST off
 ip -n $NS_DST link set dev veth$DST down
-chk_gro_flag "                      - after down" $DST on
+chk_gro_flag "                      - after down" $DST off
 ip -n $NS_DST link set dev veth$DST xdp off
 chk_gro_flag "                      - after xdp off" $DST off
 ip -n $NS_DST link set dev veth$DST up
@@ -260,6 +260,21 @@ ip -n $NS_SRC link set dev veth$SRC xdp object ${BPF_FILE} section xdp
 chk_gro_flag "                      - after peer xdp" $DST off
 cleanup
 
+create_ns
+ip -n $NS_DST link set dev veth$DST up
+ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp
+ip netns exec $NS_DST ethtool -K veth$DST generic-receive-offload on
+chk_gro_flag "gro vs xdp while down - gro flag on" $DST on
+ip -n $NS_DST link set dev veth$DST down
+chk_gro_flag "                      - after down" $DST on
+ip -n $NS_DST link set dev veth$DST xdp off
+chk_gro_flag "                      - after xdp off" $DST on
+ip -n $NS_DST link set dev veth$DST up
+chk_gro_flag "                      - after up" $DST on
+ip -n $NS_SRC link set dev veth$SRC xdp object ${BPF_FILE} section xdp
+chk_gro_flag "                      - after peer xdp" $DST on
+cleanup
+
 create_ns
 chk_channels "default channels" $DST 1 1
 
@@ -327,11 +342,14 @@ if [ $CPUS -gt 2 ]; then
 fi
 
 ip -n $NS_DST link set dev veth$DST xdp object ${BPF_FILE} section xdp 2>/dev/null
-chk_gro_flag "with xdp attached - gro flag" $DST on
+chk_gro_flag "with xdp attached - gro flag" $DST off
 chk_gro_flag "        - peer gro flag" $SRC off
 chk_tso_flag "        - tso flag" $SRC off
 chk_tso_flag "        - peer tso flag" $DST on
 ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
+chk_gro "        - no aggregation" 10
+ip netns exec $NS_DST ethtool -K veth$DST generic-receive-offload on
+chk_gro_flag "        - gro flag with GRO on" $DST on
 chk_gro "        - aggregation" 1
 
 
index 1757d19ca89b1bc06e6f9391440f502dd74adcbd..7f7d3eb8b9c9267d6e13a9907ade9bf5ed2f36dc 100644 (file)
@@ -6,30 +6,9 @@
 
 TEST(infinite_rlimit)
 {
-// Only works on 64 bit
-#if __riscv_xlen == 64
-       struct addresses mmap_addresses;
-
        EXPECT_EQ(BOTTOM_UP, memory_layout());
 
-       do_mmaps(&mmap_addresses);
-
-       EXPECT_NE(MAP_FAILED, mmap_addresses.no_hint);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_37_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_38_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_46_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_47_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_55_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_56_addr);
-
-       EXPECT_GT(1UL << 47, (unsigned long)mmap_addresses.no_hint);
-       EXPECT_GT(1UL << 38, (unsigned long)mmap_addresses.on_37_addr);
-       EXPECT_GT(1UL << 38, (unsigned long)mmap_addresses.on_38_addr);
-       EXPECT_GT(1UL << 38, (unsigned long)mmap_addresses.on_46_addr);
-       EXPECT_GT(1UL << 47, (unsigned long)mmap_addresses.on_47_addr);
-       EXPECT_GT(1UL << 47, (unsigned long)mmap_addresses.on_55_addr);
-       EXPECT_GT(1UL << 56, (unsigned long)mmap_addresses.on_56_addr);
-#endif
+       TEST_MMAPS;
 }
 
 TEST_HARNESS_MAIN
index c63c60b9397e7ff9d1949df11c229ae7388388bd..2ba3ec9900064daff126ffd3edcf099d37fd2f18 100644 (file)
@@ -6,30 +6,9 @@
 
 TEST(default_rlimit)
 {
-// Only works on 64 bit
-#if __riscv_xlen == 64
-       struct addresses mmap_addresses;
-
        EXPECT_EQ(TOP_DOWN, memory_layout());
 
-       do_mmaps(&mmap_addresses);
-
-       EXPECT_NE(MAP_FAILED, mmap_addresses.no_hint);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_37_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_38_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_46_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_47_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_55_addr);
-       EXPECT_NE(MAP_FAILED, mmap_addresses.on_56_addr);
-
-       EXPECT_GT(1UL << 47, (unsigned long)mmap_addresses.no_hint);
-       EXPECT_GT(1UL << 38, (unsigned long)mmap_addresses.on_37_addr);
-       EXPECT_GT(1UL << 38, (unsigned long)mmap_addresses.on_38_addr);
-       EXPECT_GT(1UL << 38, (unsigned long)mmap_addresses.on_46_addr);
-       EXPECT_GT(1UL << 47, (unsigned long)mmap_addresses.on_47_addr);
-       EXPECT_GT(1UL << 47, (unsigned long)mmap_addresses.on_55_addr);
-       EXPECT_GT(1UL << 56, (unsigned long)mmap_addresses.on_56_addr);
-#endif
+       TEST_MMAPS;
 }
 
 TEST_HARNESS_MAIN
index 2e0db9c5be6c334f9ed7d0187fae6ed6de950745..3b29ca3bb3d40d1aa11433d7433ba62ad85e7cbe 100644 (file)
@@ -4,63 +4,86 @@
 #include <sys/mman.h>
 #include <sys/resource.h>
 #include <stddef.h>
+#include <strings.h>
+#include "../../kselftest_harness.h"
 
 #define TOP_DOWN 0
 #define BOTTOM_UP 1
 
-struct addresses {
-       int *no_hint;
-       int *on_37_addr;
-       int *on_38_addr;
-       int *on_46_addr;
-       int *on_47_addr;
-       int *on_55_addr;
-       int *on_56_addr;
+#if __riscv_xlen == 64
+uint64_t random_addresses[] = {
+       0x19764f0d73b3a9f0, 0x016049584cecef59, 0x3580bdd3562f4acd,
+       0x1164219f20b17da0, 0x07d97fcb40ff2373, 0x76ec528921272ee7,
+       0x4dd48c38a3de3f70, 0x2e11415055f6997d, 0x14b43334ac476c02,
+       0x375a60795aff19f6, 0x47f3051725b8ee1a, 0x4e697cf240494a9f,
+       0x456b59b5c2f9e9d1, 0x101724379d63cb96, 0x7fe9ad31619528c1,
+       0x2f417247c495c2ea, 0x329a5a5b82943a5e, 0x06d7a9d6adcd3827,
+       0x327b0b9ee37f62d5, 0x17c7b1851dfd9b76, 0x006ebb6456ec2cd9,
+       0x00836cd14146a134, 0x00e5c4dcde7126db, 0x004c29feadf75753,
+       0x00d8b20149ed930c, 0x00d71574c269387a, 0x0006ebe4a82acb7a,
+       0x0016135df51f471b, 0x00758bdb55455160, 0x00d0bdd949b13b32,
+       0x00ecea01e7c5f54b, 0x00e37b071b9948b1, 0x0011fdd00ff57ab3,
+       0x00e407294b52f5ea, 0x00567748c200ed20, 0x000d073084651046,
+       0x00ac896f4365463c, 0x00eb0d49a0b26216, 0x0066a2564a982a31,
+       0x002e0d20237784ae, 0x0000554ff8a77a76, 0x00006ce07a54c012,
+       0x000009570516d799, 0x00000954ca15b84d, 0x0000684f0d453379,
+       0x00002ae5816302b5, 0x0000042403fb54bf, 0x00004bad7392bf30,
+       0x00003e73bfa4b5e3, 0x00005442c29978e0, 0x00002803f11286b6,
+       0x000073875d745fc6, 0x00007cede9cb8240, 0x000027df84cc6a4f,
+       0x00006d7e0e74242a, 0x00004afd0b836e02, 0x000047d0e837cd82,
+       0x00003b42405efeda, 0x00001531bafa4c95, 0x00007172cae34ac4,
+};
+#else
+uint32_t random_addresses[] = {
+       0x8dc302e0, 0x929ab1e0, 0xb47683ba, 0xea519c73, 0xa19f1c90, 0xc49ba213,
+       0x8f57c625, 0xadfe5137, 0x874d4d95, 0xaa20f09d, 0xcf21ebfc, 0xda7737f1,
+       0xcedf392a, 0x83026c14, 0xccedca52, 0xc6ccf826, 0xe0cd9415, 0x997472ca,
+       0xa21a44c1, 0xe82196f5, 0xa23fd66b, 0xc28d5590, 0xd009cdce, 0xcf0be646,
+       0x8fc8c7ff, 0xe2a85984, 0xa3d3236b, 0x89a0619d, 0xc03db924, 0xb5d4cc1b,
+       0xb96ee04c, 0xd191da48, 0xb432a000, 0xaa2bebbc, 0xa2fcb289, 0xb0cca89b,
+       0xb0c18d6a, 0x88f58deb, 0xa4d42d1c, 0xe4d74e86, 0x99902b09, 0x8f786d31,
+       0xbec5e381, 0x9a727e65, 0xa9a65040, 0xa880d789, 0x8f1b335e, 0xfc821c1e,
+       0x97e34be4, 0xbbef84ed, 0xf447d197, 0xfd7ceee2, 0xe632348d, 0xee4590f4,
+       0x958992a5, 0xd57e05d6, 0xfd240970, 0xc5b0dcff, 0xd96da2c2, 0xa7ae041d,
 };
+#endif
 
 // Only works on 64 bit
 #if __riscv_xlen == 64
-static inline void do_mmaps(struct addresses *mmap_addresses)
-{
-       /*
-        * Place all of the hint addresses on the boundaries of mmap
-        * sv39, sv48, sv57
-        * User addresses end at 1<<38, 1<<47, 1<<56 respectively
-        */
-       void *on_37_bits = (void *)(1UL << 37);
-       void *on_38_bits = (void *)(1UL << 38);
-       void *on_46_bits = (void *)(1UL << 46);
-       void *on_47_bits = (void *)(1UL << 47);
-       void *on_55_bits = (void *)(1UL << 55);
-       void *on_56_bits = (void *)(1UL << 56);
+#define PROT (PROT_READ | PROT_WRITE)
+#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS)
 
-       int prot = PROT_READ | PROT_WRITE;
-       int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+/* mmap must return a value that doesn't use more bits than the hint address. */
+static inline unsigned long get_max_value(unsigned long input)
+{
+       unsigned long max_bit = (1UL << (((sizeof(unsigned long) * 8) - 1 -
+                                         __builtin_clzl(input))));
 
-       mmap_addresses->no_hint =
-               mmap(NULL, 5 * sizeof(int), prot, flags, 0, 0);
-       mmap_addresses->on_37_addr =
-               mmap(on_37_bits, 5 * sizeof(int), prot, flags, 0, 0);
-       mmap_addresses->on_38_addr =
-               mmap(on_38_bits, 5 * sizeof(int), prot, flags, 0, 0);
-       mmap_addresses->on_46_addr =
-               mmap(on_46_bits, 5 * sizeof(int), prot, flags, 0, 0);
-       mmap_addresses->on_47_addr =
-               mmap(on_47_bits, 5 * sizeof(int), prot, flags, 0, 0);
-       mmap_addresses->on_55_addr =
-               mmap(on_55_bits, 5 * sizeof(int), prot, flags, 0, 0);
-       mmap_addresses->on_56_addr =
-               mmap(on_56_bits, 5 * sizeof(int), prot, flags, 0, 0);
+       return max_bit + (max_bit - 1);
 }
+
+#define TEST_MMAPS                                                            \
+       ({                                                                    \
+               void *mmap_addr;                                              \
+               for (int i = 0; i < ARRAY_SIZE(random_addresses); i++) {      \
+                       mmap_addr = mmap((void *)random_addresses[i],         \
+                                        5 * sizeof(int), PROT, FLAGS, 0, 0); \
+                       EXPECT_NE(MAP_FAILED, mmap_addr);                     \
+                       EXPECT_GE((void *)get_max_value(random_addresses[i]), \
+                                 mmap_addr);                                 \
+                       mmap_addr = mmap((void *)random_addresses[i],         \
+                                        5 * sizeof(int), PROT, FLAGS, 0, 0); \
+                       EXPECT_NE(MAP_FAILED, mmap_addr);                     \
+                       EXPECT_GE((void *)get_max_value(random_addresses[i]), \
+                                 mmap_addr);                                 \
+               }                                                             \
+       })
 #endif /* __riscv_xlen == 64 */
 
 static inline int memory_layout(void)
 {
-       int prot = PROT_READ | PROT_WRITE;
-       int flags = MAP_PRIVATE | MAP_ANONYMOUS;
-
-       void *value1 = mmap(NULL, sizeof(int), prot, flags, 0, 0);
-       void *value2 = mmap(NULL, sizeof(int), prot, flags, 0, 0);
+       void *value1 = mmap(NULL, sizeof(int), PROT, FLAGS, 0, 0);
+       void *value2 = mmap(NULL, sizeof(int), PROT, FLAGS, 0, 0);
 
        return value2 > value1;
 }
index cef1ff1af2236846d58d2d884221d98297206639..7288a05136ba848edf8269cf0d65cfd3d9365041 100644 (file)
@@ -16,6 +16,8 @@
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <glob.h>
+#include <string.h>
 #include <asm/unistd.h>
 
 #include "../kselftest_harness.h"
 
 const char *data_file = "/sys/kernel/tracing/user_events_data";
 const char *enable_file = "/sys/kernel/tracing/events/user_events/__abi_event/enable";
+const char *multi_dir_glob = "/sys/kernel/tracing/events/user_events_multi/__abi_event.*";
+
+static int wait_for_delete(char *dir)
+{
+       struct stat buf;
+       int i;
+
+       for (i = 0; i < 10000; ++i) {
+               if (stat(dir, &buf) == -1 && errno == ENOENT)
+                       return 0;
+
+               usleep(1000);
+       }
+
+       return -1;
+}
+
+static int find_multi_event_dir(char *unique_field, char *out_dir, int dir_len)
+{
+       char path[256];
+       glob_t buf;
+       int i, ret;
+
+       ret = glob(multi_dir_glob, GLOB_ONLYDIR, NULL, &buf);
+
+       if (ret)
+               return -1;
+
+       ret = -1;
+
+       for (i = 0; i < buf.gl_pathc; ++i) {
+               FILE *fp;
+
+               snprintf(path, sizeof(path), "%s/format", buf.gl_pathv[i]);
+               fp = fopen(path, "r");
+
+               if (!fp)
+                       continue;
+
+               while (fgets(path, sizeof(path), fp) != NULL) {
+                       if (strstr(path, unique_field)) {
+                               fclose(fp);
+                               /* strscpy is not available, use snprintf */
+                               snprintf(out_dir, dir_len, "%s", buf.gl_pathv[i]);
+                               ret = 0;
+                               goto out;
+                       }
+               }
+
+               fclose(fp);
+       }
+out:
+       globfree(&buf);
+
+       return ret;
+}
 
 static bool event_exists(void)
 {
@@ -74,6 +132,39 @@ static int event_delete(void)
        return ret;
 }
 
+static int reg_enable_multi(void *enable, int size, int bit, int flags,
+                           char *args)
+{
+       struct user_reg reg = {0};
+       char full_args[512] = {0};
+       int fd = open(data_file, O_RDWR);
+       int len;
+       int ret;
+
+       if (fd < 0)
+               return -1;
+
+       len = snprintf(full_args, sizeof(full_args), "__abi_event %s", args);
+
+       if (len > sizeof(full_args)) {
+               ret = -E2BIG;
+               goto out;
+       }
+
+       reg.size = sizeof(reg);
+       reg.name_args = (__u64)full_args;
+       reg.flags = USER_EVENT_REG_MULTI_FORMAT | flags;
+       reg.enable_bit = bit;
+       reg.enable_addr = (__u64)enable;
+       reg.enable_size = size;
+
+       ret = ioctl(fd, DIAG_IOCSREG, &reg);
+out:
+       close(fd);
+
+       return ret;
+}
+
 static int reg_enable_flags(void *enable, int size, int bit, int flags)
 {
        struct user_reg reg = {0};
@@ -207,6 +298,49 @@ TEST_F(user, bit_sizes) {
        ASSERT_NE(0, reg_enable(&self->check, 128, 0));
 }
 
+TEST_F(user, multi_format) {
+       char first_dir[256];
+       char second_dir[256];
+       struct stat buf;
+
+       /* Multiple formats for the same name should work */
+       ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 0,
+                                     0, "u32 multi_first"));
+
+       ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 1,
+                                     0, "u64 multi_second"));
+
+       /* Same name with same format should also work */
+       ASSERT_EQ(0, reg_enable_multi(&self->check, sizeof(int), 2,
+                                     0, "u64 multi_second"));
+
+       ASSERT_EQ(0, find_multi_event_dir("multi_first",
+                                         first_dir, sizeof(first_dir)));
+
+       ASSERT_EQ(0, find_multi_event_dir("multi_second",
+                                         second_dir, sizeof(second_dir)));
+
+       /* Should not be found in the same dir */
+       ASSERT_NE(0, strcmp(first_dir, second_dir));
+
+       /* First dir should still exist */
+       ASSERT_EQ(0, stat(first_dir, &buf));
+
+       /* Disabling first register should remove first dir */
+       ASSERT_EQ(0, reg_disable(&self->check, 0));
+       ASSERT_EQ(0, wait_for_delete(first_dir));
+
+       /* Second dir should still exist */
+       ASSERT_EQ(0, stat(second_dir, &buf));
+
+       /* Disabling second register should remove second dir */
+       ASSERT_EQ(0, reg_disable(&self->check, 1));
+       /* Ensure bit 1 and 2 are tied together, should not delete yet */
+       ASSERT_EQ(0, stat(second_dir, &buf));
+       ASSERT_EQ(0, reg_disable(&self->check, 2));
+       ASSERT_EQ(0, wait_for_delete(second_dir));
+}
+
 TEST_F(user, forks) {
        int i;
 
index 2fc36efb166dc9a2f692f38aa7642588cd7b54c7..a7f8e8a95625930aa568bb04a79fe9b05770be76 100644 (file)
@@ -3,6 +3,7 @@ CONFIG_ARCH_RV32I=y
 CONFIG_MMU=y
 CONFIG_FPU=y
 CONFIG_SOC_VIRT=y
+CONFIG_RISCV_ISA_FALLBACK=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
index dc266f3b191557915c27a870c992e871c399e637..daeb3e5e09658526b24b122b63ed05fa9078d212 100644 (file)
@@ -2,6 +2,7 @@ CONFIG_ARCH_RV64I=y
 CONFIG_MMU=y
 CONFIG_FPU=y
 CONFIG_SOC_VIRT=y
+CONFIG_RISCV_ISA_FALLBACK=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
index 0863960761e7c05d8a9422ab0cdc063512315956..2bb8e60f7fdd47d4fc11c3ff17856c18462a4755 100644 (file)
@@ -1,2 +1,5 @@
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
 latency-collector
+fixdep
+feature
+FEATURE-DUMP
diff --git a/tools/tracing/latency/Build b/tools/tracing/latency/Build
new file mode 100644 (file)
index 0000000..0ce65ea
--- /dev/null
@@ -0,0 +1 @@
+latency-collector-y += latency-collector.o
index 40c4ddaf8be164aa56841a64006bdfe438f6a77a..6518b03e05c71b4fa84498f9628adf81a38c9f56 100644 (file)
@@ -1,24 +1,93 @@
-# SPDX-License-Identifier: GPL-2.0
-# Makefile for vm tools
-#
-VAR_CFLAGS := $(shell pkg-config --cflags libtracefs 2>/dev/null)
-VAR_LDLIBS := $(shell pkg-config --libs libtracefs 2>/dev/null)
+# SPDX-License-Identifier: GPL-2.0-only
 
-TARGETS = latency-collector
-CFLAGS = -Wall -Wextra -g -O2 $(VAR_CFLAGS)
-LDFLAGS = -lpthread $(VAR_LDLIBS)
+ifeq ($(srctree),)
+  srctree      := $(patsubst %/,%,$(dir $(CURDIR)))
+  srctree      := $(patsubst %/,%,$(dir $(srctree)))
+  srctree      := $(patsubst %/,%,$(dir $(srctree)))
+endif
 
-all: $(TARGETS)
+include $(srctree)/tools/scripts/Makefile.include
 
-%: %.c
-       $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+# O is an alias for OUTPUT
+OUTPUT         := $(O)
 
-clean:
-       $(RM) latency-collector
+ifeq ($(OUTPUT),)
+  OUTPUT       := $(CURDIR)
+else
+  # subdir is used by the ../Makefile in $(call descend,)
+  ifneq ($(subdir),)
+    OUTPUT     := $(OUTPUT)/$(subdir)
+  endif
+endif
+
+ifneq ($(patsubst %/,,$(lastword $(OUTPUT))),)
+  OUTPUT       := $(OUTPUT)/
+endif
+
+LATENCY-COLLECTOR      := $(OUTPUT)latency-collector
+LATENCY-COLLECTOR_IN   := $(LATENCY-COLLECTOR)-in.o
+
+export CC      := gcc
+export LD      := ld
+export AR      := ar
+export PKG_CONFIG := pkg-config
+
+FEATURE_TESTS  := libtraceevent
+FEATURE_TESTS  += libtracefs
+FEATURE_DISPLAY        := libtraceevent
+FEATURE_DISPLAY        += libtracefs
+
+ifeq ($(V),1)
+  Q            =
+else
+  Q            = @
+endif
+
+all: $(LATENCY-COLLECTOR)
+
+include $(srctree)/tools/build/Makefile.include
+
+# check for dependencies only on required targets
+NON_CONFIG_TARGETS := clean install
 
-prefix ?= /usr/local
-sbindir ?= ${prefix}/sbin
+config         := 1
+ifdef MAKECMDGOALS
+ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
+ config                := 0
+endif
+endif
 
-install: all
-       install -d $(DESTDIR)$(sbindir)
-       install -m 755 -p $(TARGETS) $(DESTDIR)$(sbindir)
+ifeq ($(config),1)
+  include $(srctree)/tools/build/Makefile.feature
+  include Makefile.config
+endif
+
+CFLAGS         += $(INCLUDES) $(LIB_INCLUDES)
+
+export CFLAGS OUTPUT srctree
+
+$(LATENCY-COLLECTOR): $(LATENCY-COLLECTOR_IN)
+       $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(LATENCY-COLLECTOR) $(LATENCY-COLLECTOR_IN) $(EXTLIBS)
+
+latency-collector.%: fixdep FORCE
+       make -f $(srctree)/tools/build/Makefile.build dir=. $@
+
+$(LATENCY-COLLECTOR_IN): fixdep FORCE
+       make $(build)=latency-collector
+
+INSTALL                := install
+MKDIR          := mkdir
+STRIP          := strip
+BINDIR         := /usr/bin
+
+install:
+       @$(MKDIR) -p $(DESTDIR)$(BINDIR)
+       $(call QUIET_INSTALL,latency-collector)$(INSTALL) $(LATENCY-COLLECTOR) -m 755 $(DESTDIR)$(BINDIR)
+       @$(STRIP) $(DESTDIR)$(BINDIR)/latency-collector
+
+clean:
+       $(call QUIET_CLEAN, latency-collector)
+       $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+       $(Q)@rm -f latency-collector fixdep FEATURE-DUMP
+       $(Q)rm -rf feature
+.PHONY: FORCE clean install
diff --git a/tools/tracing/latency/Makefile.config b/tools/tracing/latency/Makefile.config
new file mode 100644 (file)
index 0000000..b25e531
--- /dev/null
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+STOP_ERROR :=
+
+define lib_setup
+  $(eval EXTLIBS += -l$(1))
+  $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
+endef
+
+$(call feature_check,libtraceevent)
+ifeq ($(feature-libtraceevent), 1)
+  $(call detected,CONFIG_LIBTRACEEVENT)
+  $(call lib_setup,traceevent)
+else
+  STOP_ERROR := 1
+  $(info libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel)
+endif
+
+$(call feature_check,libtracefs)
+ifeq ($(feature-libtracefs), 1)
+  $(call detected,CONFIG_LIBTRACEFS)
+  $(call lib_setup,tracefs)
+else
+  STOP_ERROR := 1
+  $(info libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
+endif
+
+ifeq ($(STOP_ERROR),1)
+  $(error Please, check the errors above.)
+endif
index e9df32419b2b5677e2f4f9e7d47a4ad32e7ed982..293f0dbb0ca2ee70cf5df500c7ca8f65f270fcc9 100644 (file)
@@ -1 +1,6 @@
-/rtla
+# SPDX-License-Identifier: GPL-2.0-only
+rtla
+rtla-static
+fixdep
+feature
+FEATURE-DUMP
diff --git a/tools/tracing/rtla/Build b/tools/tracing/rtla/Build
new file mode 100644 (file)
index 0000000..6c9d5b3
--- /dev/null
@@ -0,0 +1 @@
+rtla-y += src/
index afd18c678ff5a584a92e13ae8ee30bcba90f21ca..b5878be361257a41ed31b754c13775920cb7971c 100644 (file)
-NAME   :=      rtla
-# Follow the kernel version
-VERSION :=     $(shell cat VERSION 2> /dev/null || make -sC ../../.. kernelversion | grep -v make)
-
-# From libtracefs:
-# Makefiles suck: This macro sets a default value of $(2) for the
-# variable named by $(1), unless the variable has been set by
-# environment or command line. This is necessary for CC and AR
-# because make sets default values, so the simpler ?= approach
-# won't work as expected.
-define allow-override
-  $(if $(or $(findstring environment,$(origin $(1))),\
-            $(findstring command line,$(origin $(1)))),,\
-    $(eval $(1) = $(2)))
-endef
-
-# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
-$(call allow-override,CC,$(CROSS_COMPILE)gcc)
-$(call allow-override,AR,$(CROSS_COMPILE)ar)
-$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
-$(call allow-override,PKG_CONFIG,pkg-config)
-$(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
-$(call allow-override,LDCONFIG,ldconfig)
-
-INSTALL        =       install
-MKDIR  =       mkdir
-FOPTS  :=      -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
-               -fasynchronous-unwind-tables -fstack-clash-protection
-WOPTS  :=      -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
-
-ifeq ($(CC),clang)
-  FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS))
-  WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS))
+# SPDX-License-Identifier: GPL-2.0-only
+
+ifeq ($(srctree),)
+  srctree      := $(patsubst %/,%,$(dir $(CURDIR)))
+  srctree      := $(patsubst %/,%,$(dir $(srctree)))
+  srctree      := $(patsubst %/,%,$(dir $(srctree)))
 endif
 
-TRACEFS_HEADERS        := $$($(PKG_CONFIG) --cflags libtracefs)
-
-CFLAGS :=      -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS)
-LDFLAGS        :=      -flto=auto -ggdb $(EXTRA_LDFLAGS)
-LIBS   :=      $$($(PKG_CONFIG) --libs libtracefs)
-
-SRC    :=      $(wildcard src/*.c)
-HDR    :=      $(wildcard src/*.h)
-OBJ    :=      $(SRC:.c=.o)
-DIRS   :=      src
-FILES  :=      Makefile README.txt
-CEXT   :=      bz2
-TARBALL        :=      $(NAME)-$(VERSION).tar.$(CEXT)
-TAROPTS        :=      -cvjf $(TARBALL)
-BINDIR :=      /usr/bin
-DATADIR        :=      /usr/share
-DOCDIR :=      $(DATADIR)/doc
-MANDIR :=      $(DATADIR)/man
-LICDIR :=      $(DATADIR)/licenses
-SRCTREE        :=      $(or $(BUILD_SRC),$(CURDIR))
-
-# If running from the tarball, man pages are stored in the Documentation
-# dir. If running from the kernel source, man pages are stored in
-# Documentation/tools/rtla/.
-ifneq ($(wildcard Documentation/.*),)
-DOCSRC =       Documentation/
+include $(srctree)/tools/scripts/Makefile.include
+
+# O is an alias for OUTPUT
+OUTPUT          := $(O)
+
+ifeq ($(OUTPUT),)
+  OUTPUT        := $(CURDIR)
 else
-DOCSRC =       $(SRCTREE)/../../../Documentation/tools/rtla/
+  # subdir is used by the ../Makefile in $(call descend,)
+  ifneq ($(subdir),)
+    OUTPUT        := $(OUTPUT)/$(subdir)
+  endif
+endif
+
+ifneq ($(patsubst %/,,$(lastword $(OUTPUT))),)
+  OUTPUT        := $(OUTPUT)/
 endif
 
-LIBTRACEEVENT_MIN_VERSION = 1.5
-LIBTRACEFS_MIN_VERSION = 1.3
+RTLA           := $(OUTPUT)rtla
+RTLA_IN                := $(RTLA)-in.o
 
-.PHONY:        all warnings show_warnings
-all:   warnings rtla
+VERSION                := $(shell sh -c "make -sC ../../.. kernelversion | grep -v make")
+DOCSRC         := ../../../Documentation/tools/rtla/
 
-TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n")
-ifeq ("$(TEST_LIBTRACEEVENT)", "n")
-WARNINGS = show_warnings
-MISSING_LIBS += echo "**   libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher";
-MISSING_PACKAGES += "libtraceevent-devel"
-MISSING_SOURCE += echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ ";
+FEATURE_TESTS  := libtraceevent
+FEATURE_TESTS  += libtracefs
+FEATURE_DISPLAY        := libtraceevent
+FEATURE_DISPLAY        += libtracefs
+
+ifeq ($(V),1)
+  Q            =
+else
+  Q            = @
 endif
 
-TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n")
-ifeq ("$(TEST_LIBTRACEFS)", "n")
-WARNINGS = show_warnings
-MISSING_LIBS += echo "**   libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher";
-MISSING_PACKAGES += "libtracefs-devel"
-MISSING_SOURCE += echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ ";
+all: $(RTLA)
+
+include $(srctree)/tools/build/Makefile.include
+include Makefile.rtla
+
+# check for dependencies only on required targets
+NON_CONFIG_TARGETS := clean install tarball doc doc_clean doc_install
+
+config         := 1
+ifdef MAKECMDGOALS
+ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
+ config                := 0
+endif
 endif
 
-define show_dependencies
-       @echo "********************************************";                           \
-       echo "** NOTICE: Failed build dependencies";                                    \
-       echo "**";                                                                      \
-       echo "** Required Libraries:";                                                  \
-       $(MISSING_LIBS)                                                                 \
-       echo "**";                                                                      \
-       echo "** Consider installing the latest libtracefs from your";                  \
-       echo "** distribution, e.g., 'dnf install $(MISSING_PACKAGES)' on Fedora,";     \
-       echo "** or from source:";                                                      \
-       echo "**";                                                                      \
-       $(MISSING_SOURCE)                                                               \
-       echo "**";                                                                      \
-       echo "********************************************"
-endef
-
-show_warnings:
-       $(call show_dependencies);
-
-ifneq ("$(WARNINGS)", "")
-ERROR_OUT = $(error Please add the necessary dependencies)
-
-warnings: $(WARNINGS)
-       $(ERROR_OUT)
+ifeq ($(config),1)
+  include $(srctree)/tools/build/Makefile.feature
+  include Makefile.config
 endif
 
-rtla: $(OBJ)
-       $(CC) -o rtla $(LDFLAGS) $(OBJ) $(LIBS)
-
-static: $(OBJ)
-       $(CC) -o rtla-static $(LDFLAGS) --static $(OBJ) $(LIBS) -lpthread -ldl
-
-.PHONY: install
-install: doc_install
-       $(MKDIR) -p $(DESTDIR)$(BINDIR)
-       $(INSTALL) rtla -m 755 $(DESTDIR)$(BINDIR)
-       $(STRIP) $(DESTDIR)$(BINDIR)/rtla
-       @test ! -f $(DESTDIR)$(BINDIR)/osnoise || rm $(DESTDIR)$(BINDIR)/osnoise
-       ln -s rtla $(DESTDIR)$(BINDIR)/osnoise
-       @test ! -f $(DESTDIR)$(BINDIR)/hwnoise || rm $(DESTDIR)$(BINDIR)/hwnoise
-       ln -s rtla $(DESTDIR)$(BINDIR)/hwnoise
-       @test ! -f $(DESTDIR)$(BINDIR)/timerlat || rm $(DESTDIR)$(BINDIR)/timerlat
-       ln -s rtla $(DESTDIR)$(BINDIR)/timerlat
-
-.PHONY: clean tarball
-clean: doc_clean
-       @test ! -f rtla || rm rtla
-       @test ! -f rtla-static || rm rtla-static
-       @test ! -f src/rtla.o || rm src/rtla.o
-       @test ! -f $(TARBALL) || rm -f $(TARBALL)
-       @rm -rf *~ $(OBJ) *.tar.$(CEXT)
-
-tarball: clean
-       rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION)
-       echo $(VERSION) > $(NAME)-$(VERSION)/VERSION
-       cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION)
-       mkdir $(NAME)-$(VERSION)/Documentation/
-       cp -rp $(SRCTREE)/../../../Documentation/tools/rtla/* $(NAME)-$(VERSION)/Documentation/
-       tar $(TAROPTS) --exclude='*~' $(NAME)-$(VERSION)
-       rm -rf $(NAME)-$(VERSION)
-
-.PHONY: doc doc_clean doc_install
-doc:
-       $(MAKE) -C $(DOCSRC)
-
-doc_clean:
-       $(MAKE) -C $(DOCSRC) clean
-
-doc_install:
-       $(MAKE) -C $(DOCSRC) install
+CFLAGS         += $(INCLUDES) $(LIB_INCLUDES)
+
+export CFLAGS OUTPUT srctree
+
+$(RTLA): $(RTLA_IN)
+       $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(EXTLIBS)
+
+static: $(RTLA_IN)
+       $(eval LDFLAGS += -static)
+       $(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN)  $(EXTLIBS)
+
+rtla.%: fixdep FORCE
+       make -f $(srctree)/tools/build/Makefile.build dir=. $@
+
+$(RTLA_IN): fixdep FORCE
+       make $(build)=rtla
+
+clean: doc_clean fixdep-clean
+       $(call QUIET_CLEAN, rtla)
+       $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+       $(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-*
+       $(Q)rm -rf feature
+.PHONY: FORCE clean
diff --git a/tools/tracing/rtla/Makefile.config b/tools/tracing/rtla/Makefile.config
new file mode 100644 (file)
index 0000000..6d4ba77
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+STOP_ERROR :=
+
+LIBTRACEEVENT_MIN_VERSION = 1.5
+LIBTRACEFS_MIN_VERSION = 1.3
+
+define lib_setup
+  $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
+  $(eval EXTLIBS += -l$(1))
+endef
+
+$(call feature_check,libtraceevent)
+ifeq ($(feature-libtraceevent), 1)
+  $(call detected,CONFIG_LIBTRACEEVENT)
+
+  TEST = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 && echo y || echo n")
+  ifeq ($(TEST),n)
+    $(info libtraceevent version is too low, it must be at least $(LIBTRACEEVENT_MIN_VERSION))
+    STOP_ERROR := 1
+  endif
+
+  $(call lib_setup,traceevent)
+else
+  STOP_ERROR := 1
+  $(info libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel)
+endif
+
+$(call feature_check,libtracefs)
+ifeq ($(feature-libtracefs), 1)
+  $(call detected,CONFIG_LIBTRACEFS)
+
+  TEST = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 && echo y || echo n")
+  ifeq ($(TEST),n)
+    $(info libtracefs version is too low, it must be at least $(LIBTRACEFS_MIN_VERSION))
+    STOP_ERROR := 1
+  endif
+
+  $(call lib_setup,tracefs)
+else
+  STOP_ERROR := 1
+  $(info libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
+endif
+
+ifeq ($(STOP_ERROR),1)
+  $(error Please, check the errors above.)
+endif
diff --git a/tools/tracing/rtla/Makefile.rtla b/tools/tracing/rtla/Makefile.rtla
new file mode 100644 (file)
index 0000000..3ff0b89
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
+$(call allow-override,PKG_CONFIG,pkg-config)
+$(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
+$(call allow-override,LDCONFIG,ldconfig)
+export CC AR STRIP PKG_CONFIG LD_SO_CONF_PATH LDCONFIG
+
+FOPTS          := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong   \
+               -fasynchronous-unwind-tables -fstack-clash-protection
+WOPTS          := -O -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2             \
+               -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
+
+ifeq ($(CC),clang)
+  FOPTS                := $(filter-out -flto=auto -ffat-lto-objects, $(FOPTS))
+  WOPTS                := $(filter-out -Wno-maybe-uninitialized, $(WOPTS))
+endif
+
+CFLAGS         := -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(WOPTS) $(CFLAGS)
+LDFLAGS                := -ggdb $(LDFLAGS)
+
+RM             := rm -rf
+LN             := ln -s
+INSTALL                := install
+MKDIR          := mkdir
+STRIP          := strip
+BINDIR         := /usr/bin
+
+.PHONY: install
+install: doc_install
+       @$(MKDIR) -p $(DESTDIR)$(BINDIR)
+       $(call QUIET_INSTALL,rtla)$(INSTALL) rtla -m 755 $(DESTDIR)$(BINDIR)
+       @$(STRIP) $(DESTDIR)$(BINDIR)/rtla
+       @test ! -f $(DESTDIR)$(BINDIR)/osnoise || $(RM) $(DESTDIR)$(BINDIR)/osnoise
+       @$(LN) rtla $(DESTDIR)$(BINDIR)/osnoise
+       @test ! -f $(DESTDIR)$(BINDIR)/hwnoise || $(RM) $(DESTDIR)$(BINDIR)/hwnoise
+       @$(LN) -s rtla $(DESTDIR)$(BINDIR)/hwnoise
+       @test ! -f $(DESTDIR)$(BINDIR)/timerlat || $(RM) $(DESTDIR)$(BINDIR)/timerlat
+       @$(LN) -s rtla $(DESTDIR)$(BINDIR)/timerlat
+
+.PHONY: doc doc_clean doc_install
+doc:
+       $(MAKE) -C $(DOCSRC)
+
+doc_clean:
+       $(MAKE) -C $(DOCSRC) clean
+
+doc_install:
+       $(MAKE) -C $(DOCSRC) install
+
+# This section is neesary for the tarball, when the tarball
+# support is removed, we can delete these entries.
+NAME           := rtla
+DIRS           := src
+FILES          := Makefile README.txt
+CEXT           := bz2
+TARBALL                := $(NAME)-$(VERSION).tar.$(CEXT)
+TAROPTS                := -cvjf $(TARBALL)
+SRCTREE                :=      $(or $(BUILD_SRC),$(CURDIR))
+
+tarball: clean
+       $(RM) $(NAME)-$(VERSION) && $(MKDIR) $(NAME)-$(VERSION)
+       echo $(VERSION) > $(NAME)-$(VERSION)/VERSION
+       cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION)
+       $(MKDIR) $(NAME)-$(VERSION)/Documentation/
+       cp -rp $(SRCTREE)/../../../Documentation/tools/$(NAME)/* $(NAME)-$(VERSION)/Documentation/
+       cp Makefile.standalone $(NAME)-$(VERSION)/Makefile
+       cp Makefile.$(NAME) $(NAME)-$(VERSION)/
+       tar $(TAROPTS) --exclude='*~' $(NAME)-$(VERSION)
+       $(RM) $(NAME)-$(VERSION)
+.PHONY: tarball
diff --git a/tools/tracing/rtla/Makefile.standalone b/tools/tracing/rtla/Makefile.standalone
new file mode 100644 (file)
index 0000000..86d07cb
--- /dev/null
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+VERSION                := $(shell cat VERSION)
+CFLAGS         += $$($(PKG_CONFIG) --cflags libtracefs)
+EXTLIBS                += $$($(PKG_CONFIG) --libs libtracefs)
+
+rtla:
+
+include Makefile.rtla
+
+SRC            := $(wildcard src/*.c)
+HDR            := $(wildcard src/*.h)
+OBJ            := $(SRC:.c=.o)
+DOCSRC         := Documentation/
+
+rtla: $(OBJ)
+       $(CC) -o rtla $(LDFLAGS) $(OBJ) $(LIBS) $(EXTLIBS)
+       $(info This is a deprecated method to compile RTLA, please compile from Linux kernel source)
+
+.PHONY: clean tarball
+clean: doc_clean
+       @test ! -f rtla || rm rtla
+       @test ! -f rtla-static || rm rtla-static
+       @test ! -f src/rtla.o || rm src/rtla.o
+       @test ! -f $(TARBALL) || rm -f $(TARBALL)
+       @rm -rf *~ $(OBJ) *.tar.$(CEXT)
diff --git a/tools/tracing/rtla/sample/timerlat_load.py b/tools/tracing/rtla/sample/timerlat_load.py
new file mode 100644 (file)
index 0000000..8cc5eb2
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2024 Red Hat, Inc. Daniel Bristot de Oliveira <bristot@kernel.org>
+#
+# This is a sample code about how to use timerlat's timer by any workload
+# so rtla can measure and provide auto-analysis for the overall latency (IOW
+# the response time) for a task.
+#
+# Before running it, you need to dispatch timerlat with -U option in a terminal.
+# Then # run this script pinned to a CPU on another terminal. For example:
+#
+# timerlat_load.py 1 -p 95
+#
+# The "Timerlat IRQ" is the IRQ latency, The thread latency is the latency
+# for the python process to get the CPU. The Ret from user Timer Latency is
+# the overall latency. In other words, it is the response time for that
+# activation.
+#
+# This is just an example, the load is reading 20MB of data from /dev/full
+# It is in python because it is easy to read :-)
+
+import argparse
+import sys
+import os
+
+parser = argparse.ArgumentParser(description='user-space timerlat thread in Python')
+parser.add_argument("cpu", help='CPU to run timerlat thread')
+parser.add_argument("-p", "--prio", help='FIFO priority')
+
+args = parser.parse_args()
+
+try:
+    affinity_mask = { int(args.cpu) }
+except:
+    print("Invalid cpu: " + args.cpu)
+    exit(1)
+
+try:
+    os.sched_setaffinity(0, affinity_mask);
+except:
+    print("Error setting affinity")
+    exit(1)
+
+if (args.prio):
+    try:
+        param = os.sched_param(int(args.prio))
+        os.sched_setscheduler(0, os.SCHED_FIFO, param)
+    except:
+        print("Error setting priority")
+        exit(1)
+
+try:
+    timerlat_path = "/sys/kernel/tracing/osnoise/per_cpu/cpu" + args.cpu + "/timerlat_fd"
+    timerlat_fd = open(timerlat_path, 'r')
+except:
+    print("Error opening timerlat fd, did you run timerlat -U?")
+    exit(1)
+
+try:
+    data_fd = open("/dev/full", 'r');
+except:
+    print("Error opening data fd")
+
+while True:
+    try:
+        timerlat_fd.read(1)
+        data_fd.read(20*1024*1024)
+    except:
+        print("Leaving")
+        break
+
+timerlat_fd.close()
+data_fd.close()
diff --git a/tools/tracing/rtla/src/Build b/tools/tracing/rtla/src/Build
new file mode 100644 (file)
index 0000000..dbed9e3
--- /dev/null
@@ -0,0 +1,11 @@
+rtla-y += trace.o
+rtla-y += utils.o
+rtla-y += osnoise.o
+rtla-y += osnoise_top.o
+rtla-y += osnoise_hist.o
+rtla-y += timerlat.o
+rtla-y += timerlat_top.o
+rtla-y += timerlat_hist.o
+rtla-y += timerlat_u.o
+rtla-y += timerlat_aa.o
+rtla-y += rtla.o
index dbf154082f958c146bed6537dc527f83e57993d4..8bd51aab6513a8ab6d0065719247ea52c16b663e 100644 (file)
@@ -39,6 +39,7 @@ struct timerlat_hist_params {
        int                     hk_cpus;
        int                     no_aa;
        int                     dump_tasks;
+       int                     user_workload;
        int                     user_hist;
        cpu_set_t               hk_cpu_set;
        struct sched_attr       sched_param;
@@ -534,6 +535,7 @@ static void timerlat_hist_usage(char *usage)
                "               d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
                "                                                      in nanoseconds",
                "         -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
+               "         -U/--user-load: enable timerlat for user-defined user-space workload",
                NULL,
        };
 
@@ -595,6 +597,7 @@ static struct timerlat_hist_params
                        {"thread",              required_argument,      0, 'T'},
                        {"trace",               optional_argument,      0, 't'},
                        {"user-threads",        no_argument,            0, 'u'},
+                       {"user-load",           no_argument,            0, 'U'},
                        {"event",               required_argument,      0, 'e'},
                        {"no-irq",              no_argument,            0, '0'},
                        {"no-thread",           no_argument,            0, '1'},
@@ -613,7 +616,7 @@ static struct timerlat_hist_params
                /* getopt_long stores the option index here. */
                int option_index = 0;
 
-               c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:u0123456:7:8:9\1",
+               c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:uU0123456:7:8:9\1",
                                 long_options, &option_index);
 
                /* detect the end of the options. */
@@ -724,6 +727,9 @@ static struct timerlat_hist_params
                                params->trace_output = "timerlat_trace.txt";
                        break;
                case 'u':
+                       params->user_workload = 1;
+                       /* fallback: -u implies in -U */
+               case 'U':
                        params->user_hist = 1;
                        break;
                case '0': /* no irq */
@@ -985,7 +991,7 @@ int timerlat_hist_main(int argc, char *argv[])
                }
        }
 
-       if (params->cgroup && !params->user_hist) {
+       if (params->cgroup && !params->user_workload) {
                retval = set_comm_cgroup("timerlat/", params->cgroup_name);
                if (!retval) {
                        err_msg("Failed to move threads to cgroup\n");
@@ -1049,7 +1055,7 @@ int timerlat_hist_main(int argc, char *argv[])
        tool->start_time = time(NULL);
        timerlat_hist_set_signals(params);
 
-       if (params->user_hist) {
+       if (params->user_workload) {
                /* rtla asked to stop */
                params_u.should_run = 1;
                /* all threads left */
@@ -1086,14 +1092,14 @@ int timerlat_hist_main(int argc, char *argv[])
                        break;
 
                /* is there still any user-threads ? */
-               if (params->user_hist) {
+               if (params->user_workload) {
                        if (params_u.stopped_running) {
                                debug_msg("timerlat user-space threads stopped!\n");
                                break;
                        }
                }
        }
-       if (params->user_hist && !params_u.stopped_running) {
+       if (params->user_workload && !params_u.stopped_running) {
                params_u.should_run = 0;
                sleep(1);
        }
index 3e9af2c3868880197dc3075b74d94a15bea07d38..8a3fa64319c6d8fb1297def0ee790275ad121141 100644 (file)
@@ -43,6 +43,7 @@ struct timerlat_top_params {
        int                     cgroup;
        int                     hk_cpus;
        int                     user_top;
+       int                     user_workload;
        cpu_set_t               hk_cpu_set;
        struct sched_attr       sched_param;
        struct trace_events     *events;
@@ -364,6 +365,7 @@ static void timerlat_top_usage(char *usage)
                "               d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
                "                                                      in nanoseconds",
                "         -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads",
+               "         -U/--user-load: enable timerlat for user-defined user-space workload",
                NULL,
        };
 
@@ -423,6 +425,7 @@ static struct timerlat_top_params
                        {"thread",              required_argument,      0, 'T'},
                        {"trace",               optional_argument,      0, 't'},
                        {"user-threads",        no_argument,            0, 'u'},
+                       {"user-load",           no_argument,            0, 'U'},
                        {"trigger",             required_argument,      0, '0'},
                        {"filter",              required_argument,      0, '1'},
                        {"dma-latency",         required_argument,      0, '2'},
@@ -435,7 +438,7 @@ static struct timerlat_top_params
                /* getopt_long stores the option index here. */
                int option_index = 0;
 
-               c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:np:P:qs:t::T:u0:1:2:345:",
+               c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:np:P:qs:t::T:uU0:1:2:345:",
                                 long_options, &option_index);
 
                /* detect the end of the options. */
@@ -552,6 +555,9 @@ static struct timerlat_top_params
 
                        break;
                case 'u':
+                       params->user_workload = true;
+                       /* fallback: -u implies -U */
+               case 'U':
                        params->user_top = true;
                        break;
                case '0': /* trigger */
@@ -869,7 +875,7 @@ int timerlat_top_main(int argc, char *argv[])
        top->start_time = time(NULL);
        timerlat_top_set_signals(params);
 
-       if (params->user_top) {
+       if (params->user_workload) {
                /* rtla asked to stop */
                params_u.should_run = 1;
                /* all threads left */
@@ -912,7 +918,7 @@ int timerlat_top_main(int argc, char *argv[])
                        break;
 
                /* is there still any user-threads ? */
-               if (params->user_top) {
+               if (params->user_workload) {
                        if (params_u.stopped_running) {
                                debug_msg("timerlat user space threads stopped!\n");
                                break;
@@ -920,7 +926,7 @@ int timerlat_top_main(int argc, char *argv[])
                }
        }
 
-       if (params->user_top && !params_u.stopped_running) {
+       if (params->user_workload && !params_u.stopped_running) {
                params_u.should_run = 0;
                sleep(1);
        }
diff --git a/tools/verification/rv/.gitignore b/tools/verification/rv/.gitignore
new file mode 100644 (file)
index 0000000..34a4865
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+rv
+rv-static
+fixdep
+feature
+FEATURE-DUMP
diff --git a/tools/verification/rv/Build b/tools/verification/rv/Build
new file mode 100644 (file)
index 0000000..a44c223
--- /dev/null
@@ -0,0 +1 @@
+rv-y += src/
index 485f8aeddbe033f227faf32139630d2a616cbd66..411d62b3d8eb93abf85526ad33cafd783df86bc1 100644 (file)
-NAME   :=      rv
-# Follow the kernel version
-VERSION :=     $(shell cat VERSION 2> /dev/null || make -sC ../../.. kernelversion | grep -v make)
-
-# From libtracefs:
-# Makefiles suck: This macro sets a default value of $(2) for the
-# variable named by $(1), unless the variable has been set by
-# environment or command line. This is necessary for CC and AR
-# because make sets default values, so the simpler ?= approach
-# won't work as expected.
-define allow-override
-  $(if $(or $(findstring environment,$(origin $(1))),\
-            $(findstring command line,$(origin $(1)))),,\
-    $(eval $(1) = $(2)))
-endef
-
-# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
-$(call allow-override,CC,$(CROSS_COMPILE)gcc)
-$(call allow-override,AR,$(CROSS_COMPILE)ar)
-$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
-$(call allow-override,PKG_CONFIG,pkg-config)
-$(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
-$(call allow-override,LDCONFIG,ldconfig)
-
-INSTALL        =       install
-MKDIR  =       mkdir
-FOPTS  :=      -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \
-               -fasynchronous-unwind-tables -fstack-clash-protection
-WOPTS  :=      -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
-
-ifeq ($(CC),clang)
-  FOPTS := $(filter-out -ffat-lto-objects, $(FOPTS))
-  WOPTS := $(filter-out -Wno-maybe-uninitialized, $(WOPTS))
+# SPDX-License-Identifier: GPL-2.0-only
+
+ifeq ($(srctree),)
+  srctree      := $(patsubst %/,%,$(dir $(CURDIR)))
+  srctree      := $(patsubst %/,%,$(dir $(srctree)))
+  srctree      := $(patsubst %/,%,$(dir $(srctree)))
 endif
 
-TRACEFS_HEADERS        := $$($(PKG_CONFIG) --cflags libtracefs)
-
-CFLAGS :=      -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) $(EXTRA_CFLAGS) -I include
-LDFLAGS        :=      -flto=auto -ggdb $(EXTRA_LDFLAGS)
-LIBS   :=      $$($(PKG_CONFIG) --libs libtracefs)
-
-SRC    :=      $(wildcard src/*.c)
-HDR    :=      $(wildcard src/*.h)
-OBJ    :=      $(SRC:.c=.o)
-DIRS   :=      src
-FILES  :=      Makefile README.txt
-CEXT   :=      bz2
-TARBALL        :=      $(NAME)-$(VERSION).tar.$(CEXT)
-TAROPTS        :=      -cvjf $(TARBALL)
-BINDIR :=      /usr/bin
-DATADIR        :=      /usr/share
-DOCDIR :=      $(DATADIR)/doc
-MANDIR :=      $(DATADIR)/man
-LICDIR :=      $(DATADIR)/licenses
-SRCTREE        :=      $(or $(BUILD_SRC),$(CURDIR))
-
-# If running from the tarball, man pages are stored in the Documentation
-# dir. If running from the kernel source, man pages are stored in
-# Documentation/tools/rv/.
-ifneq ($(wildcard Documentation/.*),)
-DOCSRC =       Documentation/
+include $(srctree)/tools/scripts/Makefile.include
+
+# O is an alias for OUTPUT
+OUTPUT          := $(O)
+
+ifeq ($(OUTPUT),)
+  OUTPUT       := $(CURDIR)/
 else
-DOCSRC =       $(SRCTREE)/../../../Documentation/tools/rv/
+  # subdir is used by the ../Makefile in $(call descend,)
+  ifneq ($(subdir),)
+    OUTPUT        := $(OUTPUT)/$(subdir)
+  endif
+endif
+
+ifneq ($(patsubst %/,,$(lastword $(OUTPUT))),)
+  OUTPUT := $(OUTPUT)/
 endif
 
-LIBTRACEEVENT_MIN_VERSION = 1.5
-LIBTRACEFS_MIN_VERSION = 1.3
+RV             := $(OUTPUT)rv
+RV_IN          := $(RV)-in.o
 
-.PHONY:        all warnings show_warnings
-all:   warnings rv
+VERSION                := $(shell sh -c "make -sC ../../.. kernelversion | grep -v make")
+DOCSRC         := ../../../Documentation/tools/rv/
 
-TEST_LIBTRACEEVENT = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 || echo n")
-ifeq ("$(TEST_LIBTRACEEVENT)", "n")
-WARNINGS = show_warnings
-MISSING_LIBS += echo "**   libtraceevent version $(LIBTRACEEVENT_MIN_VERSION) or higher";
-MISSING_PACKAGES += "libtraceevent-devel"
-MISSING_SOURCE += echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ ";
+FEATURE_TESTS  := libtraceevent
+FEATURE_TESTS  += libtracefs
+FEATURE_DISPLAY        := libtraceevent
+FEATURE_DISPLAY        += libtracefs
+
+ifeq ($(V),1)
+  Q            =
+else
+  Q            = @
 endif
 
-TEST_LIBTRACEFS = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 || echo n")
-ifeq ("$(TEST_LIBTRACEFS)", "n")
-WARNINGS = show_warnings
-MISSING_LIBS += echo "**   libtracefs version $(LIBTRACEFS_MIN_VERSION) or higher";
-MISSING_PACKAGES += "libtracefs-devel"
-MISSING_SOURCE += echo "**  https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ ";
+all: $(RV)
+
+include $(srctree)/tools/build/Makefile.include
+include Makefile.rv
+
+# check for dependencies only on required targets
+NON_CONFIG_TARGETS := clean install doc doc_clean doc_install
+
+config         := 1
+ifdef MAKECMDGOALS
+  ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
+  config       := 0
+endif
 endif
 
-define show_dependencies
-       @echo "********************************************";                           \
-       echo "** NOTICE: Failed build dependencies";                                    \
-       echo "**";                                                                      \
-       echo "** Required Libraries:";                                                  \
-       $(MISSING_LIBS)                                                                 \
-       echo "**";                                                                      \
-       echo "** Consider installing the latest libtracefs from your";                  \
-       echo "** distribution, e.g., 'dnf install $(MISSING_PACKAGES)' on Fedora,";     \
-       echo "** or from source:";                                                      \
-       echo "**";                                                                      \
-       $(MISSING_SOURCE)                                                               \
-       echo "**";                                                                      \
-       echo "********************************************"
-endef
-
-show_warnings:
-       $(call show_dependencies);
-
-ifneq ("$(WARNINGS)", "")
-ERROR_OUT = $(error Please add the necessary dependencies)
-
-warnings: $(WARNINGS)
-       $(ERROR_OUT)
+ifeq ($(config),1)
+  include $(srctree)/tools/build/Makefile.feature
+  include Makefile.config
 endif
 
-rv: $(OBJ)
-       $(CC) -o rv $(LDFLAGS) $(OBJ) $(LIBS)
-
-.PHONY: install
-install: doc_install
-       $(MKDIR) -p $(DESTDIR)$(BINDIR)
-       $(INSTALL) rv -m 755 $(DESTDIR)$(BINDIR)
-       $(STRIP) $(DESTDIR)$(BINDIR)/rv
-
-.PHONY: clean tarball
-clean: doc_clean
-       @test ! -f rv || rm rv
-       @test ! -f $(TARBALL) || rm -f $(TARBALL)
-       @rm -rf *~ $(OBJ) *.tar.$(CEXT)
-
-tarball: clean
-       rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION)
-       echo $(VERSION) > $(NAME)-$(VERSION)/VERSION
-       cp -r $(DIRS) $(FILES) $(NAME)-$(VERSION)
-       mkdir $(NAME)-$(VERSION)/Documentation/
-       cp -rp $(SRCTREE)/../../../Documentation/tools/rv/* $(NAME)-$(VERSION)/Documentation/
-       tar $(TAROPTS) --exclude='*~' $(NAME)-$(VERSION)
-       rm -rf $(NAME)-$(VERSION)
-
-.PHONY: doc doc_clean doc_install
-doc:
-       $(MAKE) -C $(DOCSRC)
-
-doc_clean:
-       $(MAKE) -C $(DOCSRC) clean
-
-doc_install:
-       $(MAKE) -C $(DOCSRC) install
+CFLAGS         += $(INCLUDES) $(LIB_INCLUDES)
+
+export CFLAGS OUTPUT srctree
+
+$(RV): $(RV_IN)
+       $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RV) $(RV_IN) $(EXTLIBS)
+
+static: $(RV_IN)
+       $(eval LDFLAGS += -static)
+       $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RV)-static $(RV_IN) $(EXTLIBS)
+
+rv.%: fixdep FORCE
+       make -f $(srctree)/tools/build/Makefile.build dir=. $@
+
+$(RV_IN): fixdep FORCE
+       make $(build)=rv
+
+clean: doc_clean fixdep-clean
+       $(call QUIET_CLEAN, rv)
+       $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+       $(Q)rm -f rv rv-static fixdep FEATURE-DUMP rv-*
+       $(Q)rm -rf feature
+
+.PHONY: FORCE clean
diff --git a/tools/verification/rv/Makefile.config b/tools/verification/rv/Makefile.config
new file mode 100644 (file)
index 0000000..6d4ba77
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+STOP_ERROR :=
+
+LIBTRACEEVENT_MIN_VERSION = 1.5
+LIBTRACEFS_MIN_VERSION = 1.3
+
+define lib_setup
+  $(eval LIB_INCLUDES += $(shell sh -c "$(PKG_CONFIG) --cflags lib$(1)"))
+  $(eval EXTLIBS += -l$(1))
+endef
+
+$(call feature_check,libtraceevent)
+ifeq ($(feature-libtraceevent), 1)
+  $(call detected,CONFIG_LIBTRACEEVENT)
+
+  TEST = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEEVENT_MIN_VERSION) libtraceevent > /dev/null 2>&1 && echo y || echo n")
+  ifeq ($(TEST),n)
+    $(info libtraceevent version is too low, it must be at least $(LIBTRACEEVENT_MIN_VERSION))
+    STOP_ERROR := 1
+  endif
+
+  $(call lib_setup,traceevent)
+else
+  STOP_ERROR := 1
+  $(info libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel)
+endif
+
+$(call feature_check,libtracefs)
+ifeq ($(feature-libtracefs), 1)
+  $(call detected,CONFIG_LIBTRACEFS)
+
+  TEST = $(shell sh -c "$(PKG_CONFIG) --atleast-version $(LIBTRACEFS_MIN_VERSION) libtracefs > /dev/null 2>&1 && echo y || echo n")
+  ifeq ($(TEST),n)
+    $(info libtracefs version is too low, it must be at least $(LIBTRACEFS_MIN_VERSION))
+    STOP_ERROR := 1
+  endif
+
+  $(call lib_setup,tracefs)
+else
+  STOP_ERROR := 1
+  $(info libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
+endif
+
+ifeq ($(STOP_ERROR),1)
+  $(error Please, check the errors above.)
+endif
diff --git a/tools/verification/rv/Makefile.rv b/tools/verification/rv/Makefile.rv
new file mode 100644 (file)
index 0000000..161baa2
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
+$(call allow-override,PKG_CONFIG,pkg-config)
+$(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/)
+$(call allow-override,LDCONFIG,ldconfig)
+export CC AR STRIP PKG_CONFIG LD_SO_CONF_PATH LDCONFIG
+
+FOPTS          :=-flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong    \
+               -fasynchronous-unwind-tables -fstack-clash-protection
+WOPTS          :=      -O -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2        \
+               -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
+
+ifeq ($(CC),clang)
+  FOPTS                := $(filter-out -flto=auto -ffat-lto-objects, $(FOPTS))
+  WOPTS                := $(filter-out -Wno-maybe-uninitialized, $(WOPTS))
+endif
+
+INCLUDE                := -Iinclude/
+CFLAGS         := -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(WOPTS) $(EXTRA_CFLAGS) $(INCLUDE)
+LDFLAGS                := -ggdb $(EXTRA_LDFLAGS)
+
+INSTALL                := install
+MKDIR          := mkdir
+STRIP          := strip
+BINDIR         := /usr/bin
+
+.PHONY: install
+install: doc_install
+       $(Q)$(MKDIR) -p $(DESTDIR)$(BINDIR)
+       $(call QUIET_INSTALL,rv)$(INSTALL) $(OUTPUT)rv -m 755 $(DESTDIR)$(BINDIR)
+       $(Q)@$(STRIP) $(DESTDIR)$(BINDIR)/rv
+
+.PHONY: doc doc_clean doc_install
+doc:
+       $(MAKE) -C $(DOCSRC)
+
+doc_clean:
+       $(MAKE) -C $(DOCSRC) clean
+
+doc_install:
+       $(MAKE) -C $(DOCSRC) install
diff --git a/tools/verification/rv/src/Build b/tools/verification/rv/src/Build
new file mode 100644 (file)
index 0000000..d781983
--- /dev/null
@@ -0,0 +1,4 @@
+rv-y += trace.o
+rv-y += utils.o
+rv-y += in_kernel.o
+rv-y += rv.o