Merge branches 'pm-cpuidle', 'pm-core' and 'pm-sleep'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 15 Feb 2023 14:59:48 +0000 (15:59 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 15 Feb 2023 14:59:48 +0000 (15:59 +0100)
Merge cpuidle updates, PM core updates and changes related to system
sleep handling for 6.3-rc1:

 - Make the TEO cpuidle governor check CPU utilization in order to refine
   idle state selection (Kajetan Puchalski).

 - Make Kconfig select the haltpoll cpuidle governor when the haltpoll
   cpuidle driver is selected and replace a default_idle() call in that
   driver with arch_cpu_idle() which allows MWAIT to be used (Li
   RongQing).

 - Add Emerald Rapids Xeon support to the intel_idle driver (Artem
   Bityutskiy).

 - Add ARCH_SUSPEND_POSSIBLE dependencies for ARMv4 cpuidle drivers to
   avoid randconfig build failures (Arnd Bergmann).

 - Make kobj_type structures used in the cpuidle sysfs interface
   constant (Thomas Weißschuh).

 - Make the cpuidle driver registration code update microsecond values
   of idle state parameters in accordance with their nanosecond values
   if they are provided (Rafael Wysocki).

 - Make the PSCI cpuidle driver prevent topology CPUs from being
   suspended on PREEMPT_RT (Krzysztof Kozlowski).

 - Document that pm_runtime_force_suspend() cannot be used with
   DPM_FLAG_SMART_SUSPEND (Richard Fitzgerald).

 - Add EXPORT macros for exporting PM functions from drivers (Richard
   Fitzgerald).

 - Drop "select SRCU" from system sleep Kconfig (Paul E. McKenney).

 - Remove /** from non-kernel-doc comments in hibernation code (Randy
   Dunlap).

* pm-cpuidle:
  cpuidle: psci: Do not suspend topology CPUs on PREEMPT_RT
  cpuidle: driver: Update microsecond values of state parameters as needed
  cpuidle: sysfs: make kobj_type structures constant
  cpuidle: add ARCH_SUSPEND_POSSIBLE dependencies
  intel_idle: add Emerald Rapids Xeon support
  cpuidle-haltpoll: Replace default_idle() with arch_cpu_idle()
  cpuidle-haltpoll: select haltpoll governor
  cpuidle: teo: Introduce util-awareness
  cpuidle: teo: Optionally skip polling states in teo_find_shallower_state()

* pm-core:
  PM: Add EXPORT macros for exporting PM functions
  PM: runtime: Document that force_suspend() is incompatible with SMART_SUSPEND

* pm-sleep:
  PM: sleep: Remove "select SRCU"
  PM: hibernate: swap: don't use /** for non-kernel-doc comments

1372 files changed:
.mailmap
CREDITS
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/mm/zswap.rst
Documentation/admin-guide/pm/amd-pstate.rst
Documentation/arm64/silicon-errata.rst
Documentation/conf.py
Documentation/devicetree/bindings/.gitignore
Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml
Documentation/devicetree/bindings/cpufreq/qcom-cpufreq-nvmem.yaml
Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-aes.yaml
Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-sha.yaml
Documentation/devicetree/bindings/crypto/atmel,at91sam9g46-tdes.yaml
Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml
Documentation/devicetree/bindings/display/msm/dsi-phy-10nm.yaml
Documentation/devicetree/bindings/display/msm/dsi-phy-14nm.yaml
Documentation/devicetree/bindings/display/msm/dsi-phy-28nm.yaml
Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml
Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml
Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
Documentation/devicetree/bindings/interconnect/qcom,rpm.yaml
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml
Documentation/devicetree/bindings/opp/opp-v2-kryo-cpu.yaml
Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml [deleted file]
Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml [deleted file]
Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
Documentation/devicetree/bindings/regulator/samsung,s2mps14.yaml
Documentation/devicetree/bindings/riscv/cpus.yaml
Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml
Documentation/devicetree/bindings/soc/qcom/qcom,apr-services.yaml
Documentation/devicetree/bindings/sound/everest,es8326.yaml [changed mode: 0755->0644]
Documentation/devicetree/bindings/sound/mt8186-mt6366-rt1019-rt5682s.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml
Documentation/devicetree/bindings/spi/atmel,at91rm9200-spi.yaml
Documentation/devicetree/bindings/spi/atmel,quadspi.yaml
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
Documentation/filesystems/erofs.rst
Documentation/kbuild/makefiles.rst
Documentation/networking/bridge.rst
Documentation/networking/device_drivers/ethernet/intel/ice.rst
Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
Documentation/networking/nf_conntrack-sysctl.rst
Documentation/networking/rxrpc.rst
Documentation/sphinx/load_config.py
Documentation/virt/kvm/api.rst
Documentation/virt/kvm/locking.rst
Documentation/x86/amd-memory-encryption.rst
MAINTAINERS
Makefile
arch/arm/Makefile
arch/arm/boot/dts/armada-38x.dtsi
arch/arm/boot/dts/armada-39x.dtsi
arch/arm/boot/dts/aspeed-bmc-ibm-bonnell.dts
arch/arm/boot/dts/imx53-ppd.dts
arch/arm/boot/dts/imx6qdl-gw560x.dtsi
arch/arm/boot/dts/imx6ul-pico-dwarf.dts
arch/arm/boot/dts/imx7d-pico-dwarf.dts
arch/arm/boot/dts/imx7d-pico-nymph.dts
arch/arm/boot/dts/imx7d-smegw01.dts
arch/arm/boot/dts/nuvoton-wpcm450.dtsi
arch/arm/boot/dts/qcom-apq8084-ifc6540.dts
arch/arm/boot/dts/qcom-apq8084.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/sam9x60.dtsi
arch/arm/boot/dts/stihxxx-b2120.dtsi
arch/arm/boot/dts/stm32mp151a-prtt1l.dtsi
arch/arm/boot/dts/stm32mp157c-emstamp-argon.dtsi
arch/arm/boot/dts/stm32mp15xx-dhcom-som.dtsi
arch/arm/boot/dts/stm32mp15xx-dhcor-som.dtsi
arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
arch/arm/crypto/Makefile
arch/arm/mach-footbridge/isa-rtc.c
arch/arm/mach-imx/cpu-imx25.c
arch/arm/mach-imx/cpu-imx27.c
arch/arm/mach-imx/cpu-imx31.c
arch/arm/mach-imx/cpu-imx35.c
arch/arm/mach-imx/cpu-imx5.c
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/gpio15xx.c
arch/arm/mach-omap1/io.c
arch/arm/mach-omap1/mcbsp.c
arch/arm/mach-omap1/pm.h
arch/arm/mach-pxa/Kconfig
arch/arm/mm/nommu.c
arch/arm/mm/proc-macros.S
arch/arm64/Kconfig
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-sm1-odroid-hc4.dts
arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts
arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts
arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi
arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi
arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi
arch/arm64/boot/dts/freescale/imx8dxl.dtsi
arch/arm64/boot/dts/freescale/imx8mm-beacon-baseboard.dtsi
arch/arm64/boot/dts/freescale/imx8mm-data-modul-edm-sbc.dts
arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts
arch/arm64/boot/dts/freescale/imx8mm-pinfunc.h
arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rs232-rts.dtso
arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso
arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts
arch/arm64/boot/dts/freescale/imx8mm-verdin-dahlia.dtsi
arch/arm64/boot/dts/freescale/imx8mm-verdin-dev.dtsi
arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
arch/arm64/boot/dts/freescale/imx8mp-evk.dts
arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi
arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/freescale/imx8mq-nitrogen.dts
arch/arm64/boot/dts/freescale/imx8mq-thor96.dts
arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
arch/arm64/boot/dts/marvell/ac5-98dx25xx.dtsi
arch/arm64/boot/dts/mediatek/mt8195.dtsi
arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
arch/arm64/boot/dts/qcom/msm8992.dtsi
arch/arm64/boot/dts/qcom/msm8994-huawei-angler-rev-101.dts
arch/arm64/boot/dts/qcom/sc8280xp.dtsi
arch/arm64/boot/dts/qcom/sm8250.dtsi
arch/arm64/boot/dts/qcom/sm8350.dtsi
arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts
arch/arm64/boot/dts/rockchip/rk3399-op1-opp.dtsi
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3566-box-demo.dts
arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts
arch/arm64/boot/dts/rockchip/rk356x.dtsi
arch/arm64/include/asm/atomic_ll_sc.h
arch/arm64/include/asm/atomic_lse.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/stacktrace.h
arch/arm64/include/asm/uprobes.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/efi-rt-wrapper.S
arch/arm64/kernel/efi.c
arch/arm64/kernel/elfcore.c
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/signal.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/hyp/include/hyp/fault.h
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/mmu.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/vgic/vgic-its.c
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/kvm/vgic/vgic-v4.c
arch/arm64/kvm/vgic/vgic.h
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/mmu.c
arch/arm64/tools/cpucaps
arch/ia64/kernel/elfcore.c
arch/ia64/kernel/sys_ia64.c
arch/loongarch/include/asm/ftrace.h
arch/loongarch/include/asm/inst.h
arch/loongarch/include/asm/unwind.h
arch/loongarch/kernel/Makefile
arch/loongarch/kernel/alternative.c
arch/loongarch/kernel/cpu-probe.c
arch/loongarch/kernel/genex.S
arch/loongarch/kernel/inst.c
arch/loongarch/kernel/process.c
arch/loongarch/kernel/traps.c
arch/loongarch/kernel/unwind.c [new file with mode: 0644]
arch/loongarch/kernel/unwind_guess.c
arch/loongarch/kernel/unwind_prologue.c
arch/loongarch/mm/tlb.c
arch/mips/include/asm/mach-loongson32/cpufreq.h [deleted file]
arch/mips/include/asm/mach-loongson32/platform.h
arch/mips/loongson32/common/platform.c
arch/mips/loongson32/ls1b/board.c
arch/parisc/kernel/firmware.c
arch/parisc/kernel/ptrace.c
arch/powerpc/Kconfig
arch/powerpc/boot/wrapper
arch/powerpc/include/asm/book3s/64/tlbflush.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/imc-pmu.h
arch/powerpc/kernel/dbell.c
arch/powerpc/kernel/head_85xx.S
arch/powerpc/kernel/interrupt.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/time.c
arch/powerpc/kexec/file_load_64.c
arch/powerpc/kvm/booke.c
arch/powerpc/mm/book3s64/hash_utils.c
arch/powerpc/mm/book3s64/radix_pgtable.c
arch/powerpc/perf/imc-pmu.c
arch/riscv/Makefile
arch/riscv/boot/dts/sifive/fu740-c000.dtsi
arch/riscv/include/asm/alternative-macros.h
arch/riscv/include/asm/hwcap.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/vdso/processor.h
arch/riscv/kernel/head.S
arch/riscv/kernel/probes/kprobes.c
arch/riscv/kernel/probes/simulate-insn.c
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/stacktrace.c
arch/riscv/mm/cacheflush.c
arch/riscv/mm/pgtable.c
arch/s390/boot/decompressor.c
arch/s390/configs/debug_defconfig
arch/s390/configs/defconfig
arch/s390/configs/zfcpdump_defconfig
arch/s390/include/asm/cpu_mf.h
arch/s390/include/asm/debug.h
arch/s390/include/asm/percpu.h
arch/s390/kernel/machine_kexec_file.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/setup.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kvm/interrupt.c
arch/sh/include/asm/pgtable-3level.h
arch/sh/kernel/vmlinux.lds.S
arch/x86/Makefile
arch/x86/boot/bioscall.S
arch/x86/boot/compressed/ident_map_64.c
arch/x86/boot/compressed/misc.h
arch/x86/boot/compressed/sev.c
arch/x86/events/intel/core.c
arch/x86/events/intel/cstate.c
arch/x86/events/intel/uncore.c
arch/x86/events/msr.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/debugreg.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr-index.h
arch/x86/include/uapi/asm/svm.h
arch/x86/kernel/cpu/aperfmperf.c
arch/x86/kernel/cpu/resctrl/monitor.c
arch/x86/kernel/cpu/resctrl/rdtgroup.c
arch/x86/kernel/i8259.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/kprobes/core.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/svm/nested.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/xen.c
arch/x86/mm/init.c
arch/x86/mm/pat/memtype.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/xen.c
arch/x86/um/elfcore.c
arch/x86/xen/p2m.c
arch/xtensa/include/asm/processor.h
arch/xtensa/kernel/traps.c
arch/xtensa/mm/fault.c
block/bfq-cgroup.c
block/bfq-iosched.c
block/bfq-iosched.h
block/blk-cgroup.c
block/blk-core.c
block/blk-mq.c
certs/Makefile
drivers/accessibility/speakup/spk_ttyio.c
drivers/acpi/cppc_acpi.c
drivers/acpi/glue.c
drivers/acpi/nfit/core.c
drivers/acpi/prmt.c
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/libata-core.c
drivers/base/power/runtime.c
drivers/base/property.c
drivers/base/test/test_async_driver_probe.c
drivers/block/pktcdvd.c
drivers/block/rnbd/rnbd-clt.c
drivers/block/ublk_drv.c
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/bluetooth/hci_qca.c
drivers/bus/sunxi-rsb.c
drivers/char/tpm/xen-tpmfront.c
drivers/clk/ingenic/jz4760-cgu.c
drivers/clk/microchip/clk-mpfs-ccc.c
drivers/comedi/drivers/adv_pci1760.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Makefile
drivers/cpufreq/amd-pstate.c
drivers/cpufreq/apple-soc-cpufreq.c
drivers/cpufreq/armada-37xx-cpufreq.c
drivers/cpufreq/brcmstb-avs-cpufreq.c
drivers/cpufreq/cppc_cpufreq.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/davinci-cpufreq.c
drivers/cpufreq/loongson1-cpufreq.c [deleted file]
drivers/cpufreq/mediatek-cpufreq-hw.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/qcom-cpufreq-hw.c
drivers/cpufreq/tegra194-cpufreq.c
drivers/crypto/atmel-ecc.c
drivers/crypto/atmel-i2c.c
drivers/crypto/atmel-i2c.h
drivers/cxl/acpi.c
drivers/cxl/core/pmem.c
drivers/cxl/core/region.c
drivers/cxl/pci.c
drivers/cxl/pmem.c
drivers/dax/super.c
drivers/dma-buf/dma-fence.c
drivers/dma/dmaengine.c
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/idxd/device.c
drivers/dma/imx-sdma.c
drivers/dma/lgm/lgm-dma.c
drivers/dma/ptdma/ptdma-dev.c
drivers/dma/ptdma/ptdma.h
drivers/dma/qcom/gpi.c
drivers/dma/tegra186-gpc-dma.c
drivers/dma/tegra210-adma.c
drivers/dma/ti/k3-udma.c
drivers/dma/xilinx/xilinx_dma.c
drivers/edac/edac_device.c
drivers/edac/edac_module.h
drivers/edac/highbank_mc_edac.c
drivers/edac/qcom_edac.c
drivers/firewire/core-cdev.c
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/shmem.c
drivers/firmware/arm_scmi/virtio.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/arm64.c
drivers/firmware/efi/memattr.c
drivers/firmware/efi/runtime-wrappers.c
drivers/firmware/google/coreboot_table.c
drivers/firmware/google/coreboot_table.h
drivers/firmware/google/gsmi.c
drivers/firmware/psci/psci.c
drivers/fpga/intel-m10-bmc-sec-update.c
drivers/fpga/stratix10-soc.c
drivers/gpio/gpio-ep93xx.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpiolib-acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/imu_v11_0.c
drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c
drivers/gpu/drm/amd/amdgpu/soc21.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_svm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c
drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_0.h
drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu13_driver_if_v13_0_7.h
drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h
drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.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/synopsys/dw-hdmi-i2s-audio.c
drivers/gpu/drm/display/drm_dp_mst_topology.c
drivers/gpu/drm/drm_buddy.c
drivers/gpu/drm/drm_client.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fbdev_generic.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/drm_vma_manager.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_cdclk.c
drivers/gpu/drm/i915/display/intel_fbdev.c
drivers/gpu/drm/i915/display/skl_universal_plane.c
drivers/gpu/drm/i915/display/skl_watermark.c
drivers/gpu/drm/i915/gem/i915_gem_context.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_mman.c
drivers/gpu/drm/i915/gem/i915_gem_shmem.c
drivers/gpu/drm/i915/gem/i915_gem_tiling.c
drivers/gpu/drm/i915/gem/selftests/huge_pages.c
drivers/gpu/drm/i915/gt/intel_context.c
drivers/gpu/drm/i915/gt/intel_context.h
drivers/gpu/drm/i915/gt/intel_engine.h
drivers/gpu/drm/i915/gt/intel_engine_cs.c
drivers/gpu/drm/i915/gt/intel_execlists_submission.c
drivers/gpu/drm/i915/gt/intel_execlists_submission.h
drivers/gpu/drm/i915/gt/intel_gt_regs.h
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/gt/intel_reset.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
drivers/gpu/drm/i915/i915_driver.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_switcheroo.c
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/selftests/intel_scheduler_helpers.c
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.h
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
drivers/gpu/drm/msm/dp/dp_aux.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_mdss.c
drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c [deleted file]
drivers/gpu/drm/nouveau/nvkm/core/firmware.c
drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/tu102.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/gv100.c
drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/fb/tu102.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
drivers/gpu/drm/panfrost/Kconfig
drivers/gpu/drm/solomon/ssd130x.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/vc4/vc4_bo.c
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/virtio/virtgpu_ioctl.c
drivers/gpu/drm/vmwgfx/ttm_object.c
drivers/gpu/drm/vmwgfx/ttm_object.h
drivers/gpu/drm/vmwgfx/vmwgfx_bo.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_msg_arm64.h [changed mode: 0755->0644]
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/xen/xen_drm_front.c
drivers/hid/amd-sfh-hid/amd_sfh_client.c
drivers/hid/amd-sfh-hid/amd_sfh_hid.h
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
drivers/hid/hid-betopff.c
drivers/hid/hid-bigbenff.c
drivers/hid/hid-core.c
drivers/hid/hid-elecom.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-playstation.c
drivers/hid/hid-quirks.c
drivers/hid/hid-uclogic-core.c
drivers/hid/hid-uclogic-params.c
drivers/hid/intel-ish-hid/ishtp/dma-if.c
drivers/hv/hv_balloon.c
drivers/i2c/busses/i2c-axxia.c
drivers/i2c/busses/i2c-designware-common.c
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-rk3x.c
drivers/iio/accel/hid-sensor-accel-3d.c
drivers/iio/adc/berlin2-adc.c
drivers/iio/adc/imx8qxp-adc.c
drivers/iio/adc/stm32-dfsdm-adc.c
drivers/iio/adc/twl6030-gpadc.c
drivers/iio/adc/xilinx-ams.c
drivers/iio/gyro/hid-sensor-gyro-3d.c
drivers/iio/imu/fxos8700_core.c
drivers/iio/imu/st_lsm6dsx/Kconfig
drivers/iio/light/cm32181.c
drivers/infiniband/core/umem_dmabuf.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/hfi1/file_ops.c
drivers/infiniband/hw/hfi1/user_exp_rcv.c
drivers/infiniband/hw/hfi1/user_exp_rcv.h
drivers/infiniband/hw/irdma/cm.c
drivers/infiniband/hw/mana/qp.c
drivers/infiniband/hw/usnic/usnic_uiom.c
drivers/infiniband/sw/rxe/rxe_param.h
drivers/infiniband/sw/rxe/rxe_pool.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c
drivers/input/misc/xen-kbdfront.c
drivers/input/mouse/synaptics.c
drivers/input/serio/i8042-acpipnpio.h
drivers/interconnect/qcom/icc-rpm.c
drivers/interconnect/qcom/msm8996.c
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
drivers/iommu/arm/arm-smmu/arm-smmu.c
drivers/iommu/iommu.c
drivers/iommu/iova.c
drivers/iommu/mtk_iommu_v1.c
drivers/md/bcache/bcache_ondisk.h
drivers/md/bcache/journal.c
drivers/md/md.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/v4l2-core/v4l2-ctrls-api.c
drivers/memory/atmel-sdramc.c
drivers/memory/mvebu-devbus.c
drivers/memory/omap-gpmc.c
drivers/memory/tegra/tegra186.c
drivers/misc/fastrpc.c
drivers/misc/mei/bus.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/pci-me.c
drivers/misc/vmw_vmci/vmci_guest.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sunxi-mmc.c
drivers/mtd/parsers/scpart.c
drivers/mtd/parsers/tplink_safeloader.c
drivers/mtd/spi-nor/core.c
drivers/net/bonding/bond_debugfs.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c
drivers/net/dsa/Kconfig
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/microchip/ksz9477_i2c.c
drivers/net/dsa/mt7530.c
drivers/net/ethernet/adi/adin1110.c
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/engleder/tsnep_main.c
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
drivers/net/ethernet/freescale/enetc/enetc.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fman/fman_memac.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_ethtool.c
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
drivers/net/ethernet/intel/ice/ice.h
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_dcb_lib.c
drivers/net/ethernet/intel/ice/ice_dcb_lib.h
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_gnss.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/intel/ice/ice_tc_lib.c
drivers/net/ethernet/intel/ice/ice_vf_mbx.c
drivers/net/ethernet/intel/ice/ice_vf_vsi_vlan_ops.c
drivers/net/ethernet/intel/igc/igc_defines.h
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.c
drivers/net/ethernet/marvell/octeontx2/af/cgx.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.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_vf.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_eth_soc.h
drivers/net/ethernet/mediatek/mtk_ppe.c
drivers/net/ethernet/mediatek/mtk_ppe.h
drivers/net/ethernet/mediatek/mtk_sgmii.c
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c
drivers/net/ethernet/mellanox/mlx5/core/ecpf.c
drivers/net/ethernet/mellanox/mlx5/core/en/htb.c
drivers/net/ethernet/mellanox/mlx5/core/en/params.c
drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c
drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlx5/core/qos.c
drivers/net/ethernet/mellanox/mlx5/core/qos.h
drivers/net/ethernet/mellanox/mlx5/core/sriov.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c
drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c
drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c
drivers/net/ethernet/microsoft/mana/gdma_main.c
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/mscc/ocelot_ptp.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
drivers/net/ethernet/netronome/nfp/nfp_port.h
drivers/net/ethernet/pensando/ionic/ionic_dev.c
drivers/net/ethernet/pensando/ionic/ionic_dev.h
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_lif.h
drivers/net/ethernet/pensando/ionic/ionic_main.c
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/qlogic/qede/qede_fp.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/rswitch.c
drivers/net/ethernet/renesas/rswitch.h
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
drivers/net/ethernet/stmicro/stmmac/dwmac5.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/hyperv/netvsc.c
drivers/net/ipa/data/ipa_data-v4.7.c
drivers/net/ipa/ipa_interrupt.c
drivers/net/ipa/ipa_interrupt.h
drivers/net/ipa/ipa_power.c
drivers/net/mdio/mdio-mux-meson-g12a.c
drivers/net/phy/dp83822.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/meson-gxl.c
drivers/net/phy/phy_device.c
drivers/net/phy/phylink.c
drivers/net/team/team.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/plusb.c
drivers/net/usb/r8152.c
drivers/net/usb/sr9700.c
drivers/net/virtio_net.c
drivers/net/wan/fsl_ucc_hdlc.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/mediatek/mt76/dma.c
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
drivers/net/wireless/mediatek/mt76/tx.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wwan/t7xx/t7xx_hif_dpmaif.c
drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
drivers/net/wwan/t7xx/t7xx_netdev.c
drivers/net/wwan/t7xx/t7xx_pci.c
drivers/net/xen-netback/xenbus.c
drivers/net/xen-netfront.c
drivers/nfc/pn533/usb.c
drivers/nvdimm/Kconfig
drivers/nvdimm/nd.h
drivers/nvdimm/pfn_devs.c
drivers/nvme/host/apple.c
drivers/nvme/host/auth.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/ioctl.c
drivers/nvme/host/pci.c
drivers/nvme/target/fc.c
drivers/nvmem/brcm_nvram.c
drivers/nvmem/core.c
drivers/nvmem/qcom-spmi-sdam.c
drivers/nvmem/sunxi_sid.c
drivers/of/address.c
drivers/of/fdt.c
drivers/of/platform.c
drivers/parisc/pdc_stable.c
drivers/pci/controller/dwc/Kconfig
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aspm.c
drivers/pci/xen-pcifront.c
drivers/perf/arm-cmn.c
drivers/phy/freescale/phy-fsl-imx8m-pcie.c
drivers/phy/phy-can-transceiver.c
drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
drivers/phy/renesas/r8a779f0-ether-serdes.c
drivers/phy/rockchip/phy-rockchip-inno-usb2.c
drivers/phy/sunplus/phy-sunplus-usb2.c
drivers/phy/ti/Kconfig
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/mediatek/pinctrl-mt8195.c
drivers/pinctrl/nomadik/pinctrl-ab8500.c
drivers/pinctrl/nomadik/pinctrl-ab8505.c
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/nomadik/pinctrl-abx500.h
drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c
drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/nomadik/pinctrl-nomadik.h
drivers/pinctrl/pinctrl-amd.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c
drivers/pinctrl/sunplus/sppctl.c
drivers/platform/surface/aggregator/controller.c
drivers/platform/surface/aggregator/ssh_request_layer.c
drivers/platform/x86/amd/Kconfig
drivers/platform/x86/amd/pmc.c
drivers/platform/x86/amd/pmf/auto-mode.c
drivers/platform/x86/amd/pmf/cnqf.c
drivers/platform/x86/amd/pmf/core.c
drivers/platform/x86/amd/pmf/pmf.h
drivers/platform/x86/amd/pmf/sps.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/dell/dell-wmi-base.c
drivers/platform/x86/dell/dell-wmi-privacy.c
drivers/platform/x86/gigabyte-wmi.c
drivers/platform/x86/hp/hp-wmi.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel/int3472/clk_and_regulator.c
drivers/platform/x86/intel/int3472/discrete.c
drivers/platform/x86/intel/pmc/core.c
drivers/platform/x86/simatic-ipc.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/touchscreen_dmi.c
drivers/regulator/da9211-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/reset/Kconfig
drivers/reset/reset-uniphier-glue.c
drivers/rtc/rtc-efi.c
drivers/rtc/rtc-sunplus.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hpsa.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/mpi3mr/Makefile
drivers/scsi/mpi3mr/mpi3mr_fw.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/storvsc_drv.c
drivers/scsi/xen-scsifront.c
drivers/soc/imx/imx8mp-blk-ctrl.c
drivers/soc/imx/soc-imx8m.c
drivers/soc/qcom/apr.c
drivers/soc/qcom/cpr.c
drivers/spi/spi-cadence-xspi.c
drivers/spi/spi-dw-core.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
drivers/target/target_core_tmr.c
drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h
drivers/thermal/thermal_core.c
drivers/thunderbolt/retimer.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tunnel.c
drivers/thunderbolt/xdomain.c
drivers/tty/hvc/hvc_xen.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_exar.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/kgdboc.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/vt/vc_screen.c
drivers/ufs/core/ufshcd.c
drivers/usb/cdns3/cdns3-gadget.c
drivers/usb/chipidea/core.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/core/usb-acpi.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/fotg210/fotg210-udc.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/legacy/webcam.c
drivers/usb/gadget/udc/bcm63xx_udc.c
drivers/usb/gadget/udc/fsl_qe_udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/goku_udc.c
drivers/usb/gadget/udc/gr_udc.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/max3420_udc.c
drivers/usb/gadget/udc/mv_u3d_core.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/pch_udc.c
drivers/usb/gadget/udc/snps_udc_core.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/xen-hcd.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/iowarrior.c
drivers/usb/misc/onboard_usb_hub.c
drivers/usb/musb/omap2430.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/option.c
drivers/usb/storage/uas-detect.h
drivers/usb/storage/unusual_uas.h
drivers/usb/typec/altmodes/displayport.c
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h
drivers/vdpa/ifcvf/ifcvf_main.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/fbdev/atmel_lcdfb.c
drivers/video/fbdev/aty/aty128fb.c
drivers/video/fbdev/aty/atyfb_base.c
drivers/video/fbdev/aty/radeon_backlight.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmon.c
drivers/video/fbdev/mx3fb.c
drivers/video/fbdev/nvidia/nv_backlight.c
drivers/video/fbdev/nvidia/nvidia.c
drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c
drivers/video/fbdev/omap2/omapfb/dss/display-sysfs.c
drivers/video/fbdev/omap2/omapfb/dss/manager-sysfs.c
drivers/video/fbdev/omap2/omapfb/dss/overlay-sysfs.c
drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
drivers/video/fbdev/riva/fbdev.c
drivers/video/fbdev/xen-fbfront.c
drivers/w1/w1.c
drivers/w1/w1_int.c
drivers/watchdog/diag288_wdt.c
drivers/xen/pvcalls-back.c
drivers/xen/pvcalls-front.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-scsiback.c
fs/affs/file.c
fs/afs/cmservice.c
fs/afs/rxrpc.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/fs.h
fs/btrfs/qgroup.c
fs/btrfs/raid56.c
fs/btrfs/send.c
fs/btrfs/space-info.c
fs/btrfs/tree-log.c
fs/btrfs/tree-log.h
fs/btrfs/volumes.c
fs/btrfs/zlib.c
fs/btrfs/zoned.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.h
fs/cifs/cifsencrypt.c
fs/cifs/connect.c
fs/cifs/dfs_cache.c
fs/cifs/dfs_cache.h
fs/cifs/file.c
fs/cifs/link.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2pdu.c
fs/cifs/smbdirect.c
fs/coredump.c
fs/erofs/super.c
fs/erofs/zdata.c
fs/erofs/zmap.c
fs/ext4/xattr.c
fs/freevxfs/Kconfig
fs/fscache/volume.c
fs/fuse/acl.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/fuse/xattr.c
fs/gfs2/log.c
fs/ksmbd/auth.c
fs/ksmbd/connection.c
fs/ksmbd/ksmbd_netlink.h
fs/ksmbd/ndr.c
fs/ksmbd/server.h
fs/ksmbd/smb2pdu.c
fs/ksmbd/smb2pdu.h
fs/ksmbd/transport_ipc.c
fs/ksmbd/transport_tcp.c
fs/nfsd/filecache.c
fs/nfsd/filecache.h
fs/nfsd/netns.h
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfsproc.c
fs/nfsd/trace.h
fs/nilfs2/btree.c
fs/overlayfs/copy_up.c
fs/proc/task_mmu.c
fs/squashfs/squashfs_fs.h
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/xattr.h
fs/squashfs/xattr_id.c
fs/userfaultfd.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/xfs_extent_busy.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_qm.c
fs/xfs/xfs_reflink.c
fs/zonefs/super.c
include/acpi/acpi_bus.h
include/acpi/cppc_acpi.h
include/drm/drm_client.h
include/drm/drm_fb_helper.h
include/drm/drm_vma_manager.h
include/kunit/test.h
include/kvm/arm_vgic.h
include/linux/amd-pstate.h
include/linux/apple-gmux.h
include/linux/bpf.h
include/linux/ceph/libceph.h
include/linux/cpufreq.h
include/linux/efi.h
include/linux/elfcore.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/highmem-internal.h
include/linux/hugetlb.h
include/linux/memcontrol.h
include/linux/mlx5/driver.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mtd/spi-nor.h
include/linux/nvmem-provider.h
include/linux/page_ref.h
include/linux/platform_data/x86/simatic-ipc.h
include/linux/pm.h
include/linux/soc/ti/omap1-io.h
include/linux/spinlock.h
include/linux/stmmac.h
include/linux/swap.h
include/linux/tpm_eventlog.h
include/linux/trace_events.h
include/linux/usb.h
include/linux/util_macros.h
include/net/af_rxrpc.h
include/net/mac80211.h
include/net/mana/gdma.h
include/net/sch_generic.h
include/scsi/libiscsi.h
include/scsi/scsi_transport_iscsi.h
include/soc/bcm2835/raspberrypi-firmware.h
include/trace/events/rxrpc.h
include/trace/stages/stage4_event_fields.h
include/uapi/drm/virtgpu_drm.h
include/uapi/linux/ip.h
include/uapi/linux/ipv6.h
include/uapi/linux/netfilter/nf_conntrack_sctp.h
include/uapi/linux/netfilter/nfnetlink_cttimeout.h
include/uapi/linux/psci.h
include/ufs/ufshcd.h
include/xen/xenbus.h
init/Kconfig
init/Makefile
init/version-timestamp.c
io_uring/fdinfo.c
io_uring/io-wq.c
io_uring/io_uring.c
io_uring/msg_ring.c
io_uring/net.c
io_uring/poll.c
io_uring/rw.c
kernel/bpf/bpf_lsm.c
kernel/bpf/btf.c
kernel/bpf/hashtab.c
kernel/bpf/memalloc.c
kernel/bpf/offload.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup/cpuset.c
kernel/events/core.c
kernel/gen_kheaders.sh
kernel/irq/irqdomain.c
kernel/irq/msi.c
kernel/kallsyms_selftest.c
kernel/kcsan/kcsan_test.c
kernel/locking/rtmutex.c
kernel/module/main.c
kernel/power/Kconfig
kernel/power/swap.c
kernel/printk/printk.c
kernel/sched/core.c
kernel/sched/fair.c
kernel/sys.c
kernel/time/tick-oneshot.c
kernel/time/time.c
kernel/time/timekeeping.c
kernel/trace/Kconfig
kernel/trace/bpf_trace.c
kernel/trace/ftrace.c
kernel/trace/rv/rv.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_events_hist.c
kernel/trace/trace_export.c
kernel/trace/trace_osnoise.c
kernel/trace/trace_output.c
lib/Kconfig.debug
lib/Kconfig.kcsan
lib/dec_and_lock.c
lib/kunit/assert.c
lib/kunit/test.c
lib/lockref.c
lib/maple_tree.c
lib/memcpy_kunit.c
lib/nlattr.c
lib/scatterlist.c
lib/test_maple_tree.c
lib/win_minmax.c
mm/compaction.c
mm/hugetlb.c
mm/kasan/report.c
mm/khugepaged.c
mm/kmemleak.c
mm/madvise.c
mm/memcontrol.c
mm/memory.c
mm/mempolicy.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
mm/swapfile.c
mm/vmscan.c
mm/zsmalloc.c
net/9p/trans_xen.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c
net/bluetooth/iso.c
net/bluetooth/mgmt_util.h
net/bluetooth/rfcomm/sock.c
net/bridge/br_netfilter_hooks.c
net/can/isotp.c
net/can/j1939/address-claim.c
net/can/j1939/transport.c
net/can/raw.c
net/core/devlink.c
net/core/gro.c
net/core/neighbour.c
net/core/net_namespace.c
net/core/skbuff.c
net/core/sock.c
net/core/sock_map.c
net/ethtool/rss.c
net/ipv4/af_inet.c
net/ipv4/fib_semantics.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_hashtables.c
net/ipv4/inet_timewait_sock.c
net/ipv4/metrics.c
net/ipv4/tcp.c
net/ipv4/tcp_bpf.c
net/ipv4/tcp_ulp.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ip6_output.c
net/ipv6/raw.c
net/l2tp/l2tp_core.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac802154/rx.c
net/mctp/af_mctp.c
net/mctp/route.c
net/mptcp/pm.c
net/mptcp/pm_netlink.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/mptcp/sockopt.c
net/mptcp/subflow.c
net/netfilter/ipset/ip_set_bitmap_ip.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nft_payload.c
net/netfilter/nft_set_rbtree.c
net/netlink/af_netlink.c
net/netrom/af_netrom.c
net/netrom/nr_timer.c
net/nfc/llcp_core.c
net/openvswitch/datapath.c
net/qrtr/ns.c
net/rds/message.c
net/rose/af_rose.c
net/rxrpc/Makefile
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_accept.c
net/rxrpc/call_event.c
net/rxrpc/call_object.c
net/rxrpc/call_state.c [new file with mode: 0644]
net/rxrpc/conn_client.c
net/rxrpc/conn_event.c
net/rxrpc/conn_object.c
net/rxrpc/conn_service.c
net/rxrpc/input.c
net/rxrpc/insecure.c
net/rxrpc/io_thread.c
net/rxrpc/local_object.c
net/rxrpc/net_ns.c
net/rxrpc/output.c
net/rxrpc/peer_object.c
net/rxrpc/proc.c
net/rxrpc/recvmsg.c
net/rxrpc/rxkad.c
net/rxrpc/rxperf.c
net/rxrpc/security.c
net/rxrpc/sendmsg.c
net/sched/act_mpls.c
net/sched/sch_api.c
net/sched/sch_gred.c
net/sched/sch_htb.c
net/sched/sch_taprio.c
net/sctp/bind_addr.c
net/sctp/transport.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/tipc/node.c
net/tls/tls_sw.c
net/x25/af_x25.c
net/xfrm/xfrm_compat.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_interface_core.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
rust/kernel/print.rs
samples/ftrace/ftrace-direct-multi-modify.c
samples/ftrace/ftrace-direct-multi.c
scripts/Makefile.modinst
scripts/Makefile.vmlinux
scripts/atomic/atomics.tbl [changed mode: 0755->0644]
scripts/gcc-plugins/gcc-common.h
scripts/jobserver-exec
scripts/kconfig/.gitignore
scripts/kconfig/Makefile
scripts/package/mkspec
scripts/tracing/ftrace-bisect.sh
security/tomoyo/Kconfig
security/tomoyo/Makefile
sound/core/control.c
sound/core/control_led.c
sound/core/memalloc.c
sound/firewire/motu/motu-hwdep.c
sound/pci/hda/cs35l41_hda.c
sound/pci/hda/hda_bind.c
sound/pci/hda/hda_codec.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_via.c
sound/pci/lx6464es/lx_core.c
sound/soc/amd/acp-es8336.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/es8326.c [changed mode: 0755->0644]
sound/soc/codecs/es8326.h [changed mode: 0755->0644]
sound/soc/codecs/rt715-sdca-sdw.c
sound/soc/codecs/rt9120.c
sound/soc/codecs/tas5805m.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wsa883x.c
sound/soc/fsl/fsl-asoc-card.c
sound/soc/fsl/fsl_micfil.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_ssi.c
sound/soc/intel/avs/core.c
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/bytcht_es8316.c
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5651.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/sof_cs42l42.c
sound/soc/intel/boards/sof_es8336.c
sound/soc/intel/boards/sof_nau8825.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_ssp_amp.c
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-rpl-match.c
sound/soc/mediatek/Kconfig
sound/soc/mediatek/mt8186/mt8186-mt6366-rt1019-rt5682s.c
sound/soc/qcom/Kconfig
sound/soc/qcom/Makefile
sound/soc/qcom/common.c
sound/soc/qcom/common.h
sound/soc/qcom/lpass-cpu.c
sound/soc/qcom/sc8280xp.c
sound/soc/qcom/sdw.c [new file with mode: 0644]
sound/soc/qcom/sdw.h [new file with mode: 0644]
sound/soc/qcom/sm8250.c
sound/soc/soc-topology.c
sound/soc/sof/amd/acp.c
sound/soc/sof/debug.c
sound/soc/sof/ipc4-mtrace.c
sound/soc/sof/pm.c
sound/soc/sof/sof-audio.c
sound/synth/emux/emux_nrpn.c
sound/usb/implicit.c
sound/usb/pcm.c
sound/usb/quirks.c
sound/usb/stream.c
sound/xen/xen_snd_front.c
tools/arch/arm64/include/asm/cputype.h
tools/arch/arm64/include/uapi/asm/kvm.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/gpio/gpio-event-mon.c
tools/include/linux/build_bug.h
tools/include/nolibc/arch-mips.h
tools/include/nolibc/arch-riscv.h
tools/include/nolibc/ctype.h
tools/include/nolibc/errno.h
tools/include/nolibc/signal.h
tools/include/nolibc/stdio.h
tools/include/nolibc/stdlib.h
tools/include/nolibc/string.h
tools/include/nolibc/sys.h
tools/include/nolibc/time.h
tools/include/nolibc/types.h
tools/include/nolibc/unistd.h
tools/include/uapi/linux/kvm.h
tools/objtool/check.c
tools/perf/Makefile.config
tools/perf/Makefile.perf
tools/perf/builtin-kmem.c
tools/perf/builtin-trace.c
tools/perf/tests/bpf-script-test-prologue.c
tools/perf/tests/make
tools/perf/tests/shell/buildid.sh
tools/perf/trace/beauty/include/linux/socket.h
tools/perf/util/auxtrace.c
tools/perf/util/bpf_counter.h
tools/perf/util/build-id.c
tools/perf/util/expr.l
tools/testing/selftests/amd-pstate/Makefile
tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
tools/testing/selftests/bpf/verifier/search_pruning.c
tools/testing/selftests/cgroup/test_cpuset_prs.sh
tools/testing/selftests/drivers/net/ocelot/tc_flower_chains.sh
tools/testing/selftests/filesystems/fat/run_fat_tests.sh [changed mode: 0644->0755]
tools/testing/selftests/kvm/aarch64/page_fault_test.c
tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c
tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c
tools/testing/selftests/lib.mk
tools/testing/selftests/net/af_unix/test_unix_oob.c
tools/testing/selftests/net/cmsg_ipv6.sh
tools/testing/selftests/net/forwarding/lib.sh
tools/testing/selftests/net/l2_tos_ttl_inherit.sh
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/net/mptcp/userspace_pm.sh
tools/testing/selftests/net/test_vxlan_vnifiltering.sh
tools/testing/selftests/net/toeplitz.c
tools/testing/selftests/net/udpgso_bench.sh
tools/testing/selftests/net/udpgso_bench_rx.c
tools/testing/selftests/net/udpgso_bench_tx.c
tools/testing/selftests/netfilter/nft_trans_stress.sh
tools/testing/selftests/netfilter/settings [new file with mode: 0644]
tools/testing/selftests/proc/proc-empty-vm.c
tools/testing/selftests/proc/proc-pid-vm.c
tools/testing/selftests/vm/hugetlb-madvise.c
tools/virtio/linux/bug.h
tools/virtio/linux/build_bug.h [new file with mode: 0644]
tools/virtio/linux/cpumask.h [new file with mode: 0644]
tools/virtio/linux/gfp.h [new file with mode: 0644]
tools/virtio/linux/kernel.h
tools/virtio/linux/kmsan.h [new file with mode: 0644]
tools/virtio/linux/scatterlist.h
tools/virtio/linux/topology.h [new file with mode: 0644]
virt/kvm/kvm_main.c
virt/kvm/vfio.c

index ccba4cf..318e63f 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -130,6 +130,7 @@ Domen Puncer <domen@coderock.org>
 Douglas Gilbert <dougg@torque.net>
 Ed L. Cashin <ecashin@coraid.com>
 Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
+Eugen Hristev <eugen.hristev@collabora.com> <eugen.hristev@microchip.com>
 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> <ezequiel@collabora.com>
 Felipe W Damasio <felipewd@terra.com.br>
@@ -214,6 +215,7 @@ Jisheng Zhang <jszhang@kernel.org> <jszhang@marvell.com>
 Jisheng Zhang <jszhang@kernel.org> <Jisheng.Zhang@synaptics.com>
 Johan Hovold <johan@kernel.org> <jhovold@gmail.com>
 Johan Hovold <johan@kernel.org> <johan@hovoldconsulting.com>
+John Crispin <john@phrozen.org> <blogic@openwrt.org>
 John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
 John Stultz <johnstul@us.ibm.com>
 Jordan Crouse <jordan@cosmicpenguin.net> <jcrouse@codeaurora.org>
@@ -371,6 +373,7 @@ Rémi Denis-Courmont <rdenis@simphalempin.com>
 Ricardo Ribalda <ribalda@kernel.org> <ricardo@ribalda.com>
 Ricardo Ribalda <ribalda@kernel.org> Ricardo Ribalda Delgado <ribalda@kernel.org>
 Ricardo Ribalda <ribalda@kernel.org> <ricardo.ribalda@gmail.com>
+Robert Foss <rfoss@kernel.org> <robert.foss@linaro.org>
 Roman Gushchin <roman.gushchin@linux.dev> <guro@fb.com>
 Roman Gushchin <roman.gushchin@linux.dev> <guroan@gmail.com>
 Roman Gushchin <roman.gushchin@linux.dev> <klamm@yandex-team.ru>
@@ -422,6 +425,7 @@ Tony Luck <tony.luck@intel.com>
 TripleX Chung <xxx.phy@gmail.com> <triplex@zh-kernel.org>
 TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
 Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
+Tudor Ambarus <tudor.ambarus@linaro.org> <tudor.ambarus@microchip.com>
 Tycho Andersen <tycho@tycho.pizza> <tycho@tycho.ws>
 Tzung-Bi Shih <tzungbi@kernel.org> <tzungbi@google.com>
 Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
diff --git a/CREDITS b/CREDITS
index 4e302a4..5f5d70c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1173,6 +1173,10 @@ D: Future Domain TMC-16x0 SCSI driver (author)
 D: APM driver (early port)
 D: DRM drivers (author of several)
 
+N: Veaceslav Falico
+E: vfalico@gmail.com
+D: Co-maintainer and co-author of the network bonding driver.
+
 N: János Farkas
 E: chexum@shadow.banki.hu
 D: romfs, various (mostly networking) fixes
@@ -2489,6 +2493,13 @@ D: XF86_Mach8
 D: XF86_8514
 D: cfdisk (curses based disk partitioning program)
 
+N: Mat Martineau
+E: mat@martineau.name
+D: MPTCP subsystem co-maintainer 2020-2023
+D: Keyctl restricted keyring and Diffie-Hellman UAPI
+D: Bluetooth L2CAP ERTM mode and AMP
+S: USA
+
 N: John S. Marvin
 E: jsm@fc.hp.com
 D: PA-RISC port
@@ -4172,6 +4183,10 @@ S: B-1206 Jingmao Guojigongyu
 S: 16 Baliqiao Nanjie, Beijing 101100
 S: People's Repulic of China
 
+N: Vlad Yasevich
+E: vyasevich@gmail.com
+D: SCTP protocol maintainer.
+
 N: Aviad Yehezkel
 E: aviadye@nvidia.com
 D: Kernel TLS implementation and offload support.
index c8ae7c8..74cec76 100644 (file)
@@ -1245,13 +1245,17 @@ PAGE_SIZE multiple when read back.
        This is a simple interface to trigger memory reclaim in the
        target cgroup.
 
-       This file accepts a string which contains the number of bytes to
-       reclaim.
+       This file accepts a single key, the number of bytes to reclaim.
+       No nested keys are currently supported.
 
        Example::
 
          echo "1G" > memory.reclaim
 
+       The interface can be later extended with nested keys to
+       configure the reclaim behavior. For example, specify the
+       type of memory to reclaim from (anon, file, ..).
+
        Please note that the kernel can over or under reclaim from
        the target cgroup. If less bytes are reclaimed than the
        specified amount, -EAGAIN is returned.
@@ -1263,13 +1267,6 @@ PAGE_SIZE multiple when read back.
        This means that the networking layer will not adapt based on
        reclaim induced by memory.reclaim.
 
-       This file also allows the user to specify the nodes to reclaim from,
-       via the 'nodes=' key, for example::
-
-         echo "1G nodes=0,1" > memory.reclaim
-
-       The above instructs the kernel to reclaim memory from nodes 0,1.
-
   memory.peak
        A read-only single value file which exists on non-root
        cgroups.
index 6cfa6e3..e3618df 100644 (file)
                          management firmware translates the requests into actual
                          hardware states (core frequency, data fabric and memory
                          clocks etc.)
+                       active
+                         Use amd_pstate_epp driver instance as the scaling driver,
+                         driver provides a hint to the hardware if software wants
+                         to bias toward performance (0x0) or energy efficiency (0xff)
+                         to the CPPC firmware. then CPPC power algorithm will
+                         calculate the runtime workload and adjust the realtime cores
+                         frequency.
index f67de48..6dd74a1 100644 (file)
@@ -70,9 +70,7 @@ e.g. ``zswap.zpool=zbud``. It can also be changed at runtime using the sysfs
 The zbud type zpool allocates exactly 1 page to store 2 compressed pages, which
 means the compression ratio will always be 2:1 or worse (because of half-full
 zbud pages).  The zsmalloc type zpool has a more complex compressed page
-storage method, and it can achieve greater storage densities.  However,
-zsmalloc does not implement compressed page eviction, so once zswap fills it
-cannot evict the oldest page, it can only reject new pages.
+storage method, and it can achieve greater storage densities.
 
 When a swap page is passed from frontswap to zswap, zswap maintains a mapping
 of the swap entry, a combination of the swap type and swap offset, to the zpool
index 5376d53..d143e72 100644 (file)
@@ -230,8 +230,8 @@ with :c:macro:`MSR_AMD_CPPC_ENABLE` or ``cppc_set_enable``, it will respond
 to the request from AMD P-States.
 
 
-User Space Interface in ``sysfs``
-==================================
+User Space Interface in ``sysfs`` - Per-policy control
+======================================================
 
 ``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
 control its functionality at the system level. They are located in the
@@ -262,6 +262,25 @@ lowest non-linear performance in `AMD CPPC Performance Capability
 <perf_cap_>`_.)
 This attribute is read-only.
 
+``energy_performance_available_preferences``
+
+A list of all the supported EPP preferences that could be used for
+``energy_performance_preference`` on this system.
+These profiles represent different hints that are provided
+to the low-level firmware about the user's desired energy vs efficiency
+tradeoff.  ``default`` represents the epp value is set by platform
+firmware. This attribute is read-only.
+
+``energy_performance_preference``
+
+The current energy performance preference can be read from this attribute.
+and user can change current preference according to energy or performance needs
+Please get all support profiles list from
+``energy_performance_available_preferences`` attribute, all the profiles are
+integer values defined between 0 to 255 when EPP feature is enabled by platform
+firmware, if EPP feature is disabled, driver will ignore the written value
+This attribute is read-write.
+
 Other performance and frequency values can be read back from
 ``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`.
 
@@ -280,8 +299,30 @@ module which supports the new AMD P-States mechanism on most of the future AMD
 platforms. The AMD P-States mechanism is the more performance and energy
 efficiency frequency management method on AMD processors.
 
-Kernel Module Options for ``amd-pstate``
-=========================================
+
+AMD Pstate Driver Operation Modes
+=================================
+
+``amd_pstate`` CPPC has two operation modes: CPPC Autonomous(active) mode and
+CPPC non-autonomous(passive) mode.
+active mode and passive mode can be chosen by different kernel parameters.
+When in Autonomous mode, CPPC ignores requests done in the Desired Performance
+Target register and takes into account only the values set to the Minimum requested
+performance, Maximum requested performance, and Energy Performance Preference
+registers. When Autonomous is disabled, it only considers the Desired Performance Target.
+
+Active Mode
+------------
+
+``amd_pstate=active``
+
+This is the low-level firmware control mode which is implemented by ``amd_pstate_epp``
+driver with ``amd_pstate=active`` passed to the kernel in the command line.
+In this mode, ``amd_pstate_epp`` driver provides a hint to the hardware if software
+wants to bias toward performance (0x0) or energy efficiency (0xff) to the CPPC firmware.
+then CPPC power algorithm will calculate the runtime workload and adjust the realtime
+cores frequency according to the power supply and thermal, core voltage and some other
+hardware conditions.
 
 Passive Mode
 ------------
@@ -298,6 +339,35 @@ processor must provide at least nominal performance requested and go higher if c
 operating conditions allow.
 
 
+User Space Interface in ``sysfs`` - General
+===========================================
+
+Global Attributes
+-----------------
+
+``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
+control its functionality at the system level.  They are located in the
+``/sys/devices/system/cpu/amd-pstate/`` directory and affect all CPUs.
+
+``status``
+       Operation mode of the driver: "active", "passive" or "disable".
+
+       "active"
+               The driver is functional and in the ``active mode``
+
+       "passive"
+               The driver is functional and in the ``passive mode``
+
+       "disable"
+               The driver is unregistered and not functional now.
+
+        This attribute can be written to in order to change the driver's
+        operation mode or to unregister it.  The string written to it must be
+        one of the possible values of it and, if successful, writing one of
+        these values to the sysfs file will cause the driver to switch over
+        to the operation mode represented by that string - or to be
+        unregistered in the "disable" case.
+
 ``cpupower`` tool support for ``amd-pstate``
 ===============================================
 
index 808ade4..ec5f889 100644 (file)
@@ -120,6 +120,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-A710     | #2224489        | ARM64_ERRATUM_2224489       |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Cortex-A715     | #2645198        | ARM64_ERRATUM_2645198       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-X2       | #2119858        | ARM64_ERRATUM_2119858       |
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Cortex-X2       | #2224489        | ARM64_ERRATUM_2224489       |
index a5c45df..d927737 100644 (file)
@@ -31,6 +31,12 @@ def have_command(cmd):
 # Get Sphinx version
 major, minor, patch = sphinx.version_info[:3]
 
+#
+# Warn about older versions that we don't want to support for much
+# longer.
+#
+if (major < 2) or (major == 2 and minor < 4):
+    print('WARNING: support for Sphinx < 2.4 will be removed soon.')
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -339,7 +345,11 @@ html_use_smartypants = False
 
 # Custom sidebar templates, maps document names to template names.
 # Note that the RTD theme ignores this
-html_sidebars = { '**': ["about.html", 'searchbox.html', 'localtoc.html', 'sourcelink.html']}
+html_sidebars = { '**': ['searchbox.html', 'localtoc.html', 'sourcelink.html']}
+
+# about.html is available for alabaster theme. Add it at the front.
+if html_theme == 'alabaster':
+    html_sidebars['**'].insert(0, 'about.html')
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = 'TheLinuxKerneldoc'
index a777199..51ddb26 100644 (file)
@@ -2,3 +2,8 @@
 *.example.dts
 /processed-schema*.yaml
 /processed-schema*.json
+
+#
+# We don't want to ignore the following even if they are dot-files
+#
+!.yamllint
index 903b311..e4aa8c6 100644 (file)
@@ -26,8 +26,13 @@ properties:
         items:
           - enum:
               - qcom,qdu1000-cpufreq-epss
+              - qcom,sc7280-cpufreq-epss
+              - qcom,sc8280xp-cpufreq-epss
               - qcom,sm6375-cpufreq-epss
               - qcom,sm8250-cpufreq-epss
+              - qcom,sm8350-cpufreq-epss
+              - qcom,sm8450-cpufreq-epss
+              - qcom,sm8550-cpufreq-epss
           - const: qcom,cpufreq-epss
 
   reg:
@@ -54,6 +59,17 @@ properties:
       - const: xo
       - const: alternate
 
+  interrupts:
+    minItems: 1
+    maxItems: 3
+
+  interrupt-names:
+    minItems: 1
+    items:
+      - const: dcvsh-irq-0
+      - const: dcvsh-irq-1
+      - const: dcvsh-irq-2
+
   '#freq-domain-cells':
     const: 1
 
index 9c086ea..6f5e790 100644 (file)
@@ -17,6 +17,9 @@ description: |
   on the CPU OPP in use. The CPUFreq driver sets the CPR power domain level
   according to the required OPPs defined in the CPU OPP tables.
 
+  For old implementation efuses are parsed to select the correct opp table and
+  voltage and CPR is not supported/used.
+
 select:
   properties:
     compatible:
@@ -33,37 +36,65 @@ select:
   required:
     - compatible
 
-properties:
-  cpus:
-    type: object
-
-    patternProperties:
-      '^cpu@[0-9a-f]+$':
-        type: object
-
-        properties:
-          power-domains:
-            maxItems: 1
-
-          power-domain-names:
-            items:
-              - const: cpr
-
-        required:
-          - power-domains
-          - power-domain-names
-
 patternProperties:
   '^opp-table(-[a-z0-9]+)?$':
-    if:
+    allOf:
+      - if:
+          properties:
+            compatible:
+              const: operating-points-v2-kryo-cpu
+        then:
+          $ref: /schemas/opp/opp-v2-kryo-cpu.yaml#
+
+      - if:
+          properties:
+            compatible:
+              const: operating-points-v2-qcom-level
+        then:
+          $ref: /schemas/opp/opp-v2-qcom-level.yaml#
+
+    unevaluatedProperties: false
+
+allOf:
+  - if:
       properties:
         compatible:
-          const: operating-points-v2-kryo-cpu
+          contains:
+            enum:
+              - qcom,qcs404
+
     then:
+      properties:
+        cpus:
+          type: object
+
+          patternProperties:
+            '^cpu@[0-9a-f]+$':
+              type: object
+
+              properties:
+                power-domains:
+                  maxItems: 1
+
+                power-domain-names:
+                  items:
+                    - const: cpr
+
+              required:
+                - power-domains
+                - power-domain-names
+
       patternProperties:
-        '^opp-?[0-9]+$':
-          required:
-            - required-opps
+        '^opp-table(-[a-z0-9]+)?$':
+          if:
+            properties:
+              compatible:
+                const: operating-points-v2-kryo-cpu
+          then:
+            patternProperties:
+              '^opp-?[0-9]+$':
+                required:
+                  - required-opps
 
 additionalProperties: true
 
index 0ccaab1..0b7383b 100644 (file)
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Atmel Advanced Encryption Standard (AES) HW cryptographic accelerator
 
 maintainers:
-  - Tudor Ambarus <tudor.ambarus@microchip.com>
+  - Tudor Ambarus <tudor.ambarus@linaro.org>
 
 properties:
   compatible:
index 5163c51..ee2ffb0 100644 (file)
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Atmel Secure Hash Algorithm (SHA) HW cryptographic accelerator
 
 maintainers:
-  - Tudor Ambarus <tudor.ambarus@microchip.com>
+  - Tudor Ambarus <tudor.ambarus@linaro.org>
 
 properties:
   compatible:
index fcc5adf..3d6ed24 100644 (file)
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Atmel Triple Data Encryption Standard (TDES) HW cryptographic accelerator
 
 maintainers:
-  - Tudor Ambarus <tudor.ambarus@microchip.com>
+  - Tudor Ambarus <tudor.ambarus@linaro.org>
 
 properties:
   compatible:
index f2c1437..6e2fd6e 100644 (file)
@@ -32,7 +32,7 @@ properties:
       - description: Display byte clock
       - description: Display byte interface clock
       - description: Display pixel clock
-      - description: Display escape clock
+      - description: Display core clock
       - description: Display AHB clock
       - description: Display AXI clock
 
@@ -137,8 +137,6 @@ required:
   - phys
   - assigned-clocks
   - assigned-clock-parents
-  - power-domains
-  - operating-points-v2
   - ports
 
 additionalProperties: false
index 3d8540a..2f1fd14 100644 (file)
@@ -34,6 +34,10 @@ properties:
   vddio-supply:
     description: Phandle to vdd-io regulator device node.
 
+  qcom,dsi-phy-regulator-ldo-mode:
+    type: boolean
+    description: Indicates if the LDO mode PHY regulator is wanted.
+
 required:
   - compatible
   - reg
index d6f043a..4795e13 100644 (file)
@@ -72,7 +72,7 @@ examples:
     #include <dt-bindings/interconnect/qcom,qcm2290.h>
     #include <dt-bindings/power/qcom-rpmpd.h>
 
-    mdss@5e00000 {
+    display-subsystem@5e00000 {
         #address-cells = <1>;
         #size-cells = <1>;
         compatible = "qcom,qcm2290-mdss";
index a86d7f5..886858e 100644 (file)
@@ -62,7 +62,7 @@ examples:
     #include <dt-bindings/interrupt-controller/arm-gic.h>
     #include <dt-bindings/power/qcom-rpmpd.h>
 
-    mdss@5e00000 {
+    display-subsystem@5e00000 {
         #address-cells = <1>;
         #size-cells = <1>;
         compatible = "qcom,sm6115-mdss";
index c46378e..92e8999 100644 (file)
@@ -16,7 +16,7 @@ properties:
   compatible:
     items:
       - enum:
-          - renesas,i2c-r9a09g011  # RZ/V2M
+          - renesas,r9a09g011-i2c  # RZ/V2M
       - const: renesas,rzv2m-i2c
 
   reg:
@@ -66,7 +66,7 @@ examples:
     #include <dt-bindings/interrupt-controller/arm-gic.h>
 
     i2c0: i2c@a4030000 {
-        compatible = "renesas,i2c-r9a09g011", "renesas,rzv2m-i2c";
+        compatible = "renesas,r9a09g011-i2c", "renesas,rzv2m-i2c";
         reg = <0xa4030000 0x80>;
         interrupts = <GIC_SPI 232 IRQ_TYPE_EDGE_RISING>,
                      <GIC_SPI 236 IRQ_TYPE_EDGE_RISING>;
index 4b37aa8..5e6be4e 100644 (file)
@@ -84,7 +84,6 @@ allOf:
               - qcom,msm8939-pcnoc
               - qcom,msm8939-snoc
               - qcom,msm8996-a1noc
-              - qcom,msm8996-a2noc
               - qcom,msm8996-bimc
               - qcom,msm8996-cnoc
               - qcom,msm8996-pnoc
@@ -186,6 +185,29 @@ allOf:
       required:
         - power-domains
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,msm8996-a2noc
+
+    then:
+      properties:
+        clock-names:
+          items:
+            - const: bus
+            - const: bus_a
+            - const: aggre2_ufs_axi
+            - const: ufs_axi
+
+        clocks:
+          items:
+            - description: Bus Clock
+            - description: Bus A Clock
+            - description: Aggregate2 NoC UFS AXI Clock
+            - description: UFS AXI Clock
+
   - if:
       properties:
         compatible:
index 9f7d3e1..8449e14 100644 (file)
@@ -108,7 +108,7 @@ properties:
 
   msi-controller:
     description:
-      Only present if the Message Based Interrupt functionnality is
+      Only present if the Message Based Interrupt functionality is
       being exposed by the HW, and the mbi-ranges property present.
 
   mbi-ranges:
index 60cf3cb..c1bd185 100644 (file)
@@ -50,12 +50,22 @@ patternProperties:
       opp-supported-hw:
         description: |
           A single 32 bit bitmap value, representing compatible HW.
-          Bitmap:
+          Bitmap for MSM8996 format:
           0:  MSM8996, speedbin 0
           1:  MSM8996, speedbin 1
           2:  MSM8996, speedbin 2
-          3-31:  unused
-        maximum: 0x7
+          3:  MSM8996, speedbin 3
+          4-31:  unused
+
+          Bitmap for MSM8996SG format (speedbin shifted of 4 left):
+          0-3:  unused
+          4:  MSM8996SG, speedbin 0
+          5:  MSM8996SG, speedbin 1
+          6:  MSM8996SG, speedbin 2
+          7-31:  unused
+        enum: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+               0x9, 0xd, 0xe, 0xf,
+               0x10, 0x20, 0x30, 0x70]
 
       clock-latency-ns: true
 
diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml
new file mode 100644 (file)
index 0000000..bb01c6b
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb2-phy.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic G12A USB2 PHY
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+
+properties:
+  compatible:
+    enum:
+      - amlogic,g12a-usb2-phy
+      - amlogic,a1-usb2-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: xtal
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: phy
+
+  "#phy-cells":
+    const: 0
+
+  phy-supply:
+    description:
+      Phandle to a regulator that provides power to the PHY. This
+      regulator will be managed during the PHY power on/off sequence.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - "#phy-cells"
+
+if:
+  properties:
+    compatible:
+      enum:
+        - amlogic,meson-a1-usb-ctrl
+
+then:
+  properties:
+    power-domains:
+      maxItems: 1
+  required:
+    - power-domains
+
+additionalProperties: false
+
+examples:
+  - |
+    phy@36000 {
+          compatible = "amlogic,g12a-usb2-phy";
+          reg = <0x36000 0x2000>;
+          clocks = <&xtal>;
+          clock-names = "xtal";
+          resets = <&phy_reset>;
+          reset-names = "phy";
+          #phy-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml
new file mode 100644 (file)
index 0000000..129d26e
--- /dev/null
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb3-pcie-phy.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic G12A USB3 + PCIE Combo PHY
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+
+properties:
+  compatible:
+    enum:
+      - amlogic,g12a-usb3-pcie-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: ref_clk
+
+  resets:
+    maxItems: 1
+
+  reset-names:
+    items:
+      - const: phy
+
+  "#phy-cells":
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    phy@46000 {
+          compatible = "amlogic,g12a-usb3-pcie-phy";
+          reg = <0x46000 0x2000>;
+          clocks = <&ref_clk>;
+          clock-names = "ref_clk";
+          resets = <&phy_reset>;
+          reset-names = "phy";
+          #phy-cells = <1>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
deleted file mode 100644 (file)
index f3a5fba..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-# Copyright 2019 BayLibre, SAS
-%YAML 1.2
----
-$id: "http://devicetree.org/schemas/phy/amlogic,meson-g12a-usb2-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
-
-title: Amlogic G12A USB2 PHY
-
-maintainers:
-  - Neil Armstrong <neil.armstrong@linaro.org>
-
-properties:
-  compatible:
-    enum:
-      - amlogic,meson-g12a-usb2-phy
-      - amlogic,meson-a1-usb2-phy
-
-  reg:
-    maxItems: 1
-
-  clocks:
-    maxItems: 1
-
-  clock-names:
-    items:
-      - const: xtal
-
-  resets:
-    maxItems: 1
-
-  reset-names:
-    items:
-      - const: phy
-
-  "#phy-cells":
-    const: 0
-
-  phy-supply:
-    description:
-      Phandle to a regulator that provides power to the PHY. This
-      regulator will be managed during the PHY power on/off sequence.
-
-required:
-  - compatible
-  - reg
-  - clocks
-  - clock-names
-  - resets
-  - reset-names
-  - "#phy-cells"
-
-if:
-  properties:
-    compatible:
-      enum:
-        - amlogic,meson-a1-usb-ctrl
-
-then:
-  properties:
-    power-domains:
-      maxItems: 1
-  required:
-    - power-domains
-
-additionalProperties: false
-
-examples:
-  - |
-    phy@36000 {
-          compatible = "amlogic,meson-g12a-usb2-phy";
-          reg = <0x36000 0x2000>;
-          clocks = <&xtal>;
-          clock-names = "xtal";
-          resets = <&phy_reset>;
-          reset-names = "phy";
-          #phy-cells = <0>;
-    };
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml
deleted file mode 100644 (file)
index 868b4e6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-# Copyright 2019 BayLibre, SAS
-%YAML 1.2
----
-$id: "http://devicetree.org/schemas/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
-
-title: Amlogic G12A USB3 + PCIE Combo PHY
-
-maintainers:
-  - Neil Armstrong <neil.armstrong@linaro.org>
-
-properties:
-  compatible:
-    enum:
-      - amlogic,meson-g12a-usb3-pcie-phy
-
-  reg:
-    maxItems: 1
-
-  clocks:
-    maxItems: 1
-
-  clock-names:
-    items:
-      - const: ref_clk
-
-  resets:
-    maxItems: 1
-
-  reset-names:
-    items:
-      - const: phy
-
-  "#phy-cells":
-    const: 1
-
-required:
-  - compatible
-  - reg
-  - clocks
-  - clock-names
-  - resets
-  - reset-names
-  - "#phy-cells"
-
-additionalProperties: false
-
-examples:
-  - |
-    phy@46000 {
-          compatible = "amlogic,meson-g12a-usb3-pcie-phy";
-          reg = <0x46000 0x2000>;
-          clocks = <&ref_clk>;
-          clock-names = "ref_clk";
-          resets = <&phy_reset>;
-          reset-names = "phy";
-          #phy-cells = <1>;
-    };
index abcc437..ca6a083 100644 (file)
@@ -16,7 +16,6 @@ properties:
   compatible:
     enum:
       - qcom,usb-hs-28nm-femtophy
-      - qcom,usb-hs-28nm-mdm9607
 
   reg:
     maxItems: 1
index 01f9d4e..a7feb49 100644 (file)
@@ -19,8 +19,8 @@ description: |
   additional information and example.
 
 patternProperties:
-  # 25 LDOs
-  "^LDO([1-9]|[1][0-9]|2[0-5])$":
+  # 25 LDOs, without LDO10-12
+  "^LDO([1-9]|1[3-9]|2[0-5])$":
     type: object
     $ref: regulator.yaml#
     unevaluatedProperties: false
@@ -30,6 +30,23 @@ patternProperties:
     required:
       - regulator-name
 
+  "^LDO(1[0-2])$":
+    type: object
+    $ref: regulator.yaml#
+    unevaluatedProperties: false
+    description:
+      Properties for single LDO regulator.
+
+    properties:
+      samsung,ext-control-gpios:
+        maxItems: 1
+        description:
+          LDO10, LDO11 and LDO12 can be configured to external control over
+          GPIO.
+
+    required:
+      - regulator-name
+
   # 5 bucks
   "^BUCK[1-5]$":
     type: object
index c672076..a2884e3 100644 (file)
@@ -83,7 +83,7 @@ properties:
       insensitive, letters in the riscv,isa string must be all
       lowercase to simplify parsing.
     $ref: "/schemas/types.yaml#/definitions/string"
-    pattern: ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$
+    pattern: ^rv(?:64|32)imaf?d?q?c?b?k?j?p?v?h?(?:[hsxz](?:[a-z])+)?(?:_[hsxz](?:[a-z])+)*$
 
   # RISC-V requires 'timebase-frequency' in /cpus, so disallow it here
   timebase-frequency: false
index 0a7aa29..21c8ea0 100644 (file)
@@ -40,6 +40,8 @@ properties:
     description:
       Indicates that the setting of RTC time is allowed by the host CPU.
 
+  wakeup-source: true
+
 required:
   - compatible
   - reg
index 2905554..bdf482d 100644 (file)
@@ -39,8 +39,8 @@ properties:
   qcom,protection-domain:
     $ref: /schemas/types.yaml#/definitions/string-array
     description: |
-      Protection domain service name and path for APR service
-      possible values are::
+      Protection domain service name and path for APR service (if supported).
+      Possible values are::
       "avs/audio", "msm/adsp/audio_pd".
       "kernel/elf_loader", "msm/modem/wlan_pd".
       "tms/servreg", "msm/adsp/audio_pd".
@@ -49,6 +49,5 @@ properties:
 
 required:
   - reg
-  - qcom,protection-domain
 
 additionalProperties: true
index 9d31399..aa23b00 100644 (file)
@@ -16,6 +16,7 @@ properties:
   compatible:
     enum:
       - mediatek,mt8186-mt6366-rt1019-rt5682s-sound
+      - mediatek,mt8186-mt6366-rt5682s-max98360-sound
 
   mediatek,platform:
     $ref: "/schemas/types.yaml#/definitions/phandle"
index 66431aa..da5f709 100644 (file)
@@ -30,7 +30,9 @@ properties:
     const: 0
 
   clocks:
-    maxItems: 5
+    oneOf:
+      - maxItems: 3
+      - maxItems: 5
 
   clock-names:
     oneOf:
index 2bf8d08..66cbb1f 100644 (file)
@@ -9,9 +9,6 @@ title: LPASS(Low Power Audio Subsystem) VA Macro audio codec
 maintainers:
   - Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
 
-allOf:
-  - $ref: dai-common.yaml#
-
 properties:
   compatible:
     enum:
@@ -30,15 +27,12 @@ properties:
     const: 0
 
   clocks:
-    maxItems: 5
+    minItems: 5
+    maxItems: 6
 
   clock-names:
-    items:
-      - const: mclk
-      - const: npl
-      - const: macro
-      - const: dcodec
-      - const: fsgen
+    minItems: 5
+    maxItems: 6
 
   clock-output-names:
     maxItems: 1
@@ -55,10 +49,51 @@ required:
   - reg
   - "#sound-dai-cells"
 
+allOf:
+  - $ref: dai-common.yaml#
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - qcom,sc7280-lpass-wsa-macro
+            - qcom,sm8450-lpass-wsa-macro
+            - qcom,sc8280xp-lpass-wsa-macro
+    then:
+      properties:
+        clocks:
+          maxItems: 5
+        clock-names:
+          items:
+            - const: mclk
+            - const: npl
+            - const: macro
+            - const: dcodec
+            - const: fsgen
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - qcom,sm8250-lpass-wsa-macro
+    then:
+      properties:
+        clocks:
+          minItems: 6
+        clock-names:
+          items:
+            - const: mclk
+            - const: npl
+            - const: macro
+            - const: dcodec
+            - const: va
+            - const: fsgen
+
 unevaluatedProperties: false
 
 examples:
   - |
+    #include <dt-bindings/clock/qcom,sm8250-lpass-aoncc.h>
     #include <dt-bindings/sound/qcom,q6afe.h>
     codec@3240000 {
       compatible = "qcom,sm8250-lpass-wsa-macro";
@@ -69,7 +104,8 @@ examples:
                <&audiocc 0>,
                <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
                <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+               <&aoncc LPASS_CDC_VA_MCLK>,
                <&vamacro>;
-      clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
+      clock-names = "mclk", "npl", "macro", "dcodec", "va", "fsgen";
       clock-output-names = "mclk";
     };
index 4dd973e..6c57dd6 100644 (file)
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Atmel SPI device
 
 maintainers:
-  - Tudor Ambarus <tudor.ambarus@microchip.com>
+  - Tudor Ambarus <tudor.ambarus@linaro.org>
 
 allOf:
   - $ref: spi-controller.yaml#
index 1d493ad..b0d99bc 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Atmel Quad Serial Peripheral Interface (QSPI)
 
 maintainers:
-  - Tudor Ambarus <tudor.ambarus@microchip.com>
+  - Tudor Ambarus <tudor.ambarus@linaro.org>
 
 allOf:
   - $ref: spi-controller.yaml#
index ead2ccc..9a60c06 100644 (file)
@@ -44,9 +44,9 @@ properties:
     description:
       Maximum SPI clocking speed of the device in Hz.
 
-  spi-cs-setup-ns:
+  spi-cs-setup-delay-ns:
     description:
-      Delay in nanosecods to be introduced by the controller after CS is
+      Delay in nanoseconds to be introduced by the controller after CS is
       asserted.
 
   spi-rx-bus-width:
index 067fd16..a43aacf 100644 (file)
@@ -120,6 +120,8 @@ dax={always,never}     Use direct access (no page cache).  See
 dax                    A legacy option which is an alias for ``dax=always``.
 device=%s              Specify a path to an extra device to be used together.
 fsid=%s                Specify a filesystem image ID for Fscache back-end.
+domain_id=%s           Specify a domain ID in fscache mode so that different images
+                       with the same blobs under a given domain ID can share storage.
 ===================    =========================================================
 
 Sysfs Entries
index 6b7368d..38bc74e 100644 (file)
@@ -1042,7 +1042,7 @@ $(clean-files).
 
 When executing "make clean", the file "crc32table.h" will be deleted.
 Kbuild will assume files to be in the same relative directory as the
-Makefile, except if prefixed with $(objtree).
+Makefile.
 
 To exclude certain files or directories from make clean, use the
 $(no-clean-files) variable.
index 4aef9cd..c859f3c 100644 (file)
@@ -8,7 +8,7 @@ In order to use the Ethernet bridging functionality, you'll need the
 userspace tools.
 
 Documentation for Linux bridging is on:
-   http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge
+   https://wiki.linuxfoundation.org/networking/bridge
 
 The bridge-utilities are maintained at:
    git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git
index dc2e60c..b481b81 100644 (file)
@@ -819,7 +819,7 @@ NAPI
 ----
 This driver supports NAPI (Rx polling mode).
 For more information on NAPI, see
-https://www.linuxfoundation.org/collaborate/workgroups/networking/napi
+https://wiki.linuxfoundation.org/networking/napi
 
 
 MACVLAN
index eaa87db..d052ef4 100644 (file)
@@ -16,5 +16,5 @@ Contents
 
 Support
 =======
-If you got any problem, contact Wangxun support team via support@trustnetic.com
+If you got any problem, contact Wangxun support team via nic-support@net-swift.com
 and Cc: netdev.
index 49db1d1..8b1045c 100644 (file)
@@ -173,7 +173,9 @@ nf_conntrack_sctp_timeout_cookie_echoed - INTEGER (seconds)
        default 3
 
 nf_conntrack_sctp_timeout_established - INTEGER (seconds)
-       default 432000 (5 days)
+       default 210
+
+       Default is set to (hb_interval * path_max_retrans + rto_max)
 
 nf_conntrack_sctp_timeout_shutdown_sent - INTEGER (seconds)
        default 0.3
@@ -190,12 +192,6 @@ nf_conntrack_sctp_timeout_heartbeat_sent - INTEGER (seconds)
        This timeout is used to setup conntrack entry on secondary paths.
        Default is set to hb_interval.
 
-nf_conntrack_sctp_timeout_heartbeat_acked - INTEGER (seconds)
-       default 210
-
-       This timeout is used to setup conntrack entry on secondary paths.
-       Default is set to (hb_interval * path_max_retrans + rto_max)
-
 nf_conntrack_udp_timeout - INTEGER (seconds)
        default 30
 
index 39494a6..e1af544 100644 (file)
@@ -880,8 +880,8 @@ The kernel interface functions are as follows:
 
      notify_end_rx can be NULL or it can be used to specify a function to be
      called when the call changes state to end the Tx phase.  This function is
-     called with the call-state spinlock held to prevent any reply or final ACK
-     from being delivered first.
+     called with a spinlock held to prevent the last DATA packet from being
+     transmitted until the function returns.
 
  (#) Receive data from a call::
 
index eeb394b..8b416bf 100644 (file)
@@ -3,7 +3,7 @@
 
 import os
 import sys
-from sphinx.util.pycompat import execfile_
+from sphinx.util.osutil import fs_encoding
 
 # ------------------------------------------------------------------------------
 def loadConfig(namespace):
@@ -48,7 +48,9 @@ def loadConfig(namespace):
             sys.stdout.write("load additional sphinx-config: %s\n" % config_file)
             config = namespace.copy()
             config['__file__'] = config_file
-            execfile_(config_file, config)
+            with open(config_file, 'rb') as f:
+                code = compile(f.read(), fs_encoding, 'exec')
+                exec(code, config)
             del config['__file__']
             namespace.update(config)
         else:
index deb494f..0a67cb7 100644 (file)
@@ -1354,6 +1354,14 @@ the memory region are automatically reflected into the guest.  For example, an
 mmap() that affects the region will be made visible immediately.  Another
 example is madvise(MADV_DROP).
 
+Note: On arm64, a write generated by the page-table walker (to update
+the Access and Dirty flags, for example) never results in a
+KVM_EXIT_MMIO exit when the slot has the KVM_MEM_READONLY flag. This
+is because KVM cannot provide the data that would be written by the
+page-table walker, making it impossible to emulate the access.
+Instead, an abort (data abort if the cause of the page-table update
+was a load or a store, instruction abort if it was an instruction
+fetch) is injected in the guest.
 
 4.36 KVM_SET_TSS_ADDR
 ---------------------
@@ -8062,9 +8070,13 @@ considering the state as complete. VMM needs to ensure that the dirty
 state is final and avoid missing dirty pages from another ioctl ordered
 after the bitmap collection.
 
-NOTE: One example of using the backup bitmap is saving arm64 vgic/its
-tables through KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_SAVE_TABLES} command on
-KVM device "kvm-arm-vgic-its" when dirty ring is enabled.
+NOTE: Multiple examples of using the backup bitmap: (1) save vgic/its
+tables through command KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_SAVE_TABLES} on
+KVM device "kvm-arm-vgic-its". (2) restore vgic/its tables through
+command KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_RESTORE_TABLES} on KVM device
+"kvm-arm-vgic-its". VGICv3 LPI pending status is restored. (3) save
+vgic3 pending table through KVM_DEV_ARM_VGIC_{GRP_CTRL, SAVE_PENDING_TABLES}
+command on KVM device "kvm-arm-vgic-v3".
 
 8.30 KVM_CAP_XEN_HVM
 --------------------
@@ -8310,6 +8322,20 @@ CPU[EAX=1]:ECX[24] (TSC_DEADLINE) is not reported by ``KVM_GET_SUPPORTED_CPUID``
 It can be enabled if ``KVM_CAP_TSC_DEADLINE_TIMER`` is present and the kernel
 has enabled in-kernel emulation of the local APIC.
 
+CPU topology
+~~~~~~~~~~~~
+
+Several CPUID values include topology information for the host CPU:
+0x0b and 0x1f for Intel systems, 0x8000001e for AMD systems.  Different
+versions of KVM return different values for this information and userspace
+should not rely on it.  Currently they return all zeroes.
+
+If userspace wishes to set up a guest topology, it should be careful that
+the values of these three leaves differ for each CPU.  In particular,
+the APIC ID is found in EDX for all subleaves of 0x0b and 0x1f, and in EAX
+for 0x8000001e; the latter also encodes the core id and node id in bits
+7:0 of EBX and ECX respectively.
+
 Obsolete ioctls and capabilities
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
index a3ca76f..a014679 100644 (file)
@@ -24,21 +24,22 @@ The acquisition orders for mutexes are as follows:
 
 For SRCU:
 
-- ``synchronize_srcu(&kvm->srcu)`` is called _inside_
-  the kvm->slots_lock critical section, therefore kvm->slots_lock
-  cannot be taken inside a kvm->srcu read-side critical section.
-  Instead, kvm->slots_arch_lock is released before the call
-  to ``synchronize_srcu()`` and _can_ be taken inside a
-  kvm->srcu read-side critical section.
-
-- kvm->lock is taken inside kvm->srcu, therefore
-  ``synchronize_srcu(&kvm->srcu)`` cannot be called inside
-  a kvm->lock critical section.  If you cannot delay the
-  call until after kvm->lock is released, use ``call_srcu``.
+- ``synchronize_srcu(&kvm->srcu)`` is called inside critical sections
+  for kvm->lock, vcpu->mutex and kvm->slots_lock.  These locks _cannot_
+  be taken inside a kvm->srcu read-side critical section; that is, the
+  following is broken::
+
+      srcu_read_lock(&kvm->srcu);
+      mutex_lock(&kvm->slots_lock);
+
+- kvm->slots_arch_lock instead is released before the call to
+  ``synchronize_srcu()``.  It _can_ therefore be taken inside a
+  kvm->srcu read-side critical section, for example while processing
+  a vmexit.
 
 On x86:
 
-- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock
+- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock and kvm->arch.xen.xen_lock
 
 - kvm->arch.mmu_lock is an rwlock.  kvm->arch.tdp_mmu_pages_lock and
   kvm->arch.mmu_unsync_pages_lock are taken inside kvm->arch.mmu_lock, and
index a1940eb..934310c 100644 (file)
@@ -95,3 +95,39 @@ by supplying mem_encrypt=on on the kernel command line.  However, if BIOS does
 not enable SME, then Linux will not be able to activate memory encryption, even
 if configured to do so by default or the mem_encrypt=on command line parameter
 is specified.
+
+Secure Nested Paging (SNP)
+==========================
+
+SEV-SNP introduces new features (SEV_FEATURES[1:63]) which can be enabled
+by the hypervisor for security enhancements. Some of these features need
+guest side implementation to function correctly. The below table lists the
+expected guest behavior with various possible scenarios of guest/hypervisor
+SNP feature support.
+
++-----------------+---------------+---------------+------------------+
+| Feature Enabled | Guest needs   | Guest has     | Guest boot       |
+| by the HV       | implementation| implementation| behaviour        |
++=================+===============+===============+==================+
+|      No         |      No       |      No       |     Boot         |
+|                 |               |               |                  |
++-----------------+---------------+---------------+------------------+
+|      No         |      Yes      |      No       |     Boot         |
+|                 |               |               |                  |
++-----------------+---------------+---------------+------------------+
+|      No         |      Yes      |      Yes      |     Boot         |
+|                 |               |               |                  |
++-----------------+---------------+---------------+------------------+
+|      Yes        |      No       |      No       | Boot with        |
+|                 |               |               | feature enabled  |
++-----------------+---------------+---------------+------------------+
+|      Yes        |      Yes      |      No       | Graceful boot    |
+|                 |               |               | failure          |
++-----------------+---------------+---------------+------------------+
+|      Yes        |      Yes      |      Yes      | Boot with        |
+|                 |               |               | feature enabled  |
++-----------------+---------------+---------------+------------------+
+
+More details in AMD64 APM[1] Vol 2: 15.34.10 SEV_STATUS MSR
+
+[1] https://www.amd.com/system/files/TechDocs/40332.pdf
index a36df9e..39ff1a7 100644 (file)
@@ -383,7 +383,7 @@ ACPI COMPONENT ARCHITECTURE (ACPICA)
 M:     Robert Moore <robert.moore@intel.com>
 M:     "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
 L:     linux-acpi@vger.kernel.org
-L:     devel@acpica.org
+L:     acpica-devel@lists.linuxfoundation.org
 S:     Supported
 W:     https://acpica.org/
 W:     https://github.com/acpica/acpica/
@@ -1097,14 +1097,12 @@ S:      Maintained
 F:     drivers/dma/ptdma/
 
 AMD SEATTLE DEVICE TREE SUPPORT
-M:     Brijesh Singh <brijeshkumar.singh@amd.com>
 M:     Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
 M:     Tom Lendacky <thomas.lendacky@amd.com>
 S:     Supported
 F:     arch/arm64/boot/dts/amd/
 
 AMD XGBE DRIVER
-M:     Tom Lendacky <thomas.lendacky@amd.com>
 M:     "Shyam Sundar S K" <Shyam-sundar.S-k@amd.com>
 L:     netdev@vger.kernel.org
 S:     Supported
@@ -2213,6 +2211,9 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
 X:     drivers/media/i2c/
+F:     arch/arm64/boot/dts/freescale/
+X:     arch/arm64/boot/dts/freescale/fsl-*
+X:     arch/arm64/boot/dts/freescale/qoriq-*
 N:     imx
 N:     mxs
 
@@ -2451,11 +2452,14 @@ F:      drivers/rtc/rtc-mt7622.c
 
 ARM/Mediatek SoC support
 M:     Matthias Brugger <matthias.bgg@gmail.com>
+R:     AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+L:     linux-kernel@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 W:     https://mtk.wiki.kernel.org/
-C:     irc://chat.freenode.net/linux-mediatek
+C:     irc://irc.libera.chat/linux-mediatek
+F:     arch/arm/boot/dts/mt2*
 F:     arch/arm/boot/dts/mt6*
 F:     arch/arm/boot/dts/mt7*
 F:     arch/arm/boot/dts/mt8*
@@ -2463,7 +2467,7 @@ F:        arch/arm/mach-mediatek/
 F:     arch/arm64/boot/dts/mediatek/
 F:     drivers/soc/mediatek/
 N:     mtk
-N:     mt[678]
+N:     mt[2678]
 K:     mediatek
 
 ARM/Mediatek USB3 PHY DRIVER
@@ -3767,7 +3771,6 @@ F:        net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <j.vosburgh@gmail.com>
-M:     Veaceslav Falico <vfalico@gmail.com>
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 S:     Supported
@@ -6948,7 +6951,7 @@ F:        drivers/gpu/drm/atmel-hlcdc/
 DRM DRIVERS FOR BRIDGE CHIPS
 M:     Andrzej Hajda <andrzej.hajda@intel.com>
 M:     Neil Armstrong <neil.armstrong@linaro.org>
-M:     Robert Foss <robert.foss@linaro.org>
+M:     Robert Foss <rfoss@kernel.org>
 R:     Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
 R:     Jonas Karlman <jonas@kwiboo.se>
 R:     Jernej Skrabec <jernej.skrabec@gmail.com>
@@ -7616,7 +7619,6 @@ S:        Maintained
 F:     drivers/firmware/efi/test/
 
 EFI VARIABLE FILESYSTEM
-M:     Matthew Garrett <matthew.garrett@nebula.com>
 M:     Jeremy Kerr <jk@ozlabs.org>
 M:     Ard Biesheuvel <ardb@kernel.org>
 L:     linux-efi@vger.kernel.org
@@ -7895,7 +7897,11 @@ F:       include/linux/extcon/
 
 EXTRA BOOT CONFIG
 M:     Masami Hiramatsu <mhiramat@kernel.org>
+L:     linux-kernel@vger.kernel.org
+L:     linux-trace-kernel@vger.kernel.org
+Q:     https://patchwork.kernel.org/project/linux-trace-kernel/list/
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
 F:     Documentation/admin-guide/bootconfig.rst
 F:     fs/proc/bootconfig.c
 F:     include/linux/bootconfig.h
@@ -8468,16 +8474,16 @@ F:      fs/fscache/
 F:     include/linux/fscache*.h
 
 FSCRYPT: FILE SYSTEM LEVEL ENCRYPTION SUPPORT
+M:     Eric Biggers <ebiggers@kernel.org>
 M:     Theodore Y. Ts'o <tytso@mit.edu>
 M:     Jaegeuk Kim <jaegeuk@kernel.org>
-M:     Eric Biggers <ebiggers@kernel.org>
 L:     linux-fscrypt@vger.kernel.org
 S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-fscrypt/list/
-T:     git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git
+T:     git https://git.kernel.org/pub/scm/fs/fscrypt/linux.git
 F:     Documentation/filesystems/fscrypt.rst
 F:     fs/crypto/
-F:     include/linux/fscrypt*.h
+F:     include/linux/fscrypt.h
 F:     include/uapi/linux/fscrypt.h
 
 FSI SUBSYSTEM
@@ -8520,10 +8526,10 @@ F:      include/linux/fsnotify*.h
 FSVERITY: READ-ONLY FILE-BASED AUTHENTICITY PROTECTION
 M:     Eric Biggers <ebiggers@kernel.org>
 M:     Theodore Y. Ts'o <tytso@mit.edu>
-L:     linux-fscrypt@vger.kernel.org
+L:     fsverity@lists.linux.dev
 S:     Supported
-Q:     https://patchwork.kernel.org/project/linux-fscrypt/list/
-T:     git git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git fsverity
+Q:     https://patchwork.kernel.org/project/fsverity/list/
+T:     git https://git.kernel.org/pub/scm/fs/fsverity/linux.git
 F:     Documentation/filesystems/fsverity.rst
 F:     fs/verity/
 F:     include/linux/fsverity.h
@@ -8571,6 +8577,7 @@ F:        kernel/trace/fgraph.c
 F:     arch/*/*/*/*ftrace*
 F:     arch/*/*/*ftrace*
 F:     include/*/ftrace.h
+F:     samples/ftrace
 
 FUNGIBLE ETHERNET DRIVERS
 M:     Dimitris Michailidis <dmichail@fungible.com>
@@ -9299,7 +9306,7 @@ F:        net/dsa/tag_hellcreek.c
 
 HISILICON DMA DRIVER
 M:     Zhou Wang <wangzhou1@hisilicon.com>
-M:     Jie Hai <haijie1@hisilicon.com>
+M:     Jie Hai <haijie1@huawei.com>
 L:     dmaengine@vger.kernel.org
 S:     Maintained
 F:     drivers/dma/hisi_dma.c
@@ -11356,9 +11363,9 @@ F:      virt/kvm/*
 KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
 M:     Marc Zyngier <maz@kernel.org>
 R:     James Morse <james.morse@arm.com>
-R:     Alexandru Elisei <alexandru.elisei@arm.com>
 R:     Suzuki K Poulose <suzuki.poulose@arm.com>
 R:     Oliver Upton <oliver.upton@linux.dev>
+R:     Zenghui Yu <yuzenghui@huawei.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     kvmarm@lists.linux.dev
 L:     kvmarm@lists.cs.columbia.edu (deprecated, moderated for non-subscribers)
@@ -13620,7 +13627,7 @@ F:      arch/microblaze/
 
 MICROCHIP AT91 DMA DRIVERS
 M:     Ludovic Desroches <ludovic.desroches@microchip.com>
-M:     Tudor Ambarus <tudor.ambarus@microchip.com>
+M:     Tudor Ambarus <tudor.ambarus@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     dmaengine@vger.kernel.org
 S:     Supported
@@ -13665,7 +13672,7 @@ F:      Documentation/devicetree/bindings/media/microchip,csi2dc.yaml
 F:     drivers/media/platform/microchip/microchip-csi2dc.c
 
 MICROCHIP ECC DRIVER
-M:     Tudor Ambarus <tudor.ambarus@microchip.com>
+M:     Tudor Ambarus <tudor.ambarus@linaro.org>
 L:     linux-crypto@vger.kernel.org
 S:     Maintained
 F:     drivers/crypto/atmel-ecc.*
@@ -13762,7 +13769,7 @@ S:      Maintained
 F:     drivers/mmc/host/atmel-mci.c
 
 MICROCHIP NAND DRIVER
-M:     Tudor Ambarus <tudor.ambarus@microchip.com>
+M:     Tudor Ambarus <tudor.ambarus@linaro.org>
 L:     linux-mtd@lists.infradead.org
 S:     Supported
 F:     Documentation/devicetree/bindings/mtd/atmel-nand.txt
@@ -13814,7 +13821,7 @@ S:      Supported
 F:     drivers/power/reset/at91-sama5d2_shdwc.c
 
 MICROCHIP SPI DRIVER
-M:     Tudor Ambarus <tudor.ambarus@microchip.com>
+M:     Tudor Ambarus <tudor.ambarus@linaro.org>
 S:     Supported
 F:     drivers/spi/spi-atmel.*
 
@@ -14601,7 +14608,6 @@ F:      tools/testing/selftests/net/ipsec.c
 
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
-M:     Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
 M:     David Ahern <dsahern@kernel.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
@@ -14634,7 +14640,6 @@ F:      net/netfilter/xt_SECMARK.c
 F:     net/netlabel/
 
 NETWORKING [MPTCP]
-M:     Mat Martineau <mathew.j.martineau@linux.intel.com>
 M:     Matthieu Baerts <matthieu.baerts@tessares.net>
 L:     netdev@vger.kernel.org
 L:     mptcp@lists.linux.dev
@@ -14919,7 +14924,8 @@ T:      git://git.infradead.org/nvme.git
 F:     Documentation/nvme/
 F:     drivers/nvme/host/
 F:     drivers/nvme/common/
-F:     include/linux/nvme*
+F:     include/linux/nvme.h
+F:     include/linux/nvme-*.h
 F:     include/uapi/linux/nvme_ioctl.h
 
 NVM EXPRESS FABRICS AUTHENTICATION
@@ -15658,7 +15664,7 @@ OPENRISC ARCHITECTURE
 M:     Jonas Bonn <jonas@southpole.se>
 M:     Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
 M:     Stafford Horne <shorne@gmail.com>
-L:     openrisc@lists.librecores.org
+L:     linux-openrisc@vger.kernel.org
 S:     Maintained
 W:     http://openrisc.io
 T:     git https://github.com/openrisc/linux.git
@@ -15749,6 +15755,12 @@ S:     Maintained
 W:     https://wireless.wiki.kernel.org/en/users/Drivers/p54
 F:     drivers/net/wireless/intersil/p54/
 
+PACKET SOCKETS
+M:     Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+S:     Maintained
+F:     include/uapi/linux/if_packet.h
+F:     net/packet/af_packet.c
+
 PACKING
 M:     Vladimir Oltean <olteanv@gmail.com>
 L:     netdev@vger.kernel.org
@@ -16108,7 +16120,7 @@ F:      drivers/pci/controller/pci-v3-semi.c
 
 PCI ENDPOINT SUBSYSTEM
 M:     Lorenzo Pieralisi <lpieralisi@kernel.org>
-R:     Krzysztof Wilczyński <kw@linux.com>
+M:     Krzysztof Wilczyński <kw@linux.com>
 R:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 R:     Kishon Vijay Abraham I <kishon@kernel.org>
 L:     linux-pci@vger.kernel.org
@@ -16116,7 +16128,7 @@ S:      Supported
 Q:     https://patchwork.kernel.org/project/linux-pci/list/
 B:     https://bugzilla.kernel.org
 C:     irc://irc.oftc.net/linux-pci
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
 F:     Documentation/PCI/endpoint/*
 F:     Documentation/misc-devices/pci-endpoint-test.rst
 F:     drivers/misc/pci_endpoint_test.c
@@ -16151,7 +16163,7 @@ S:      Supported
 Q:     https://patchwork.kernel.org/project/linux-pci/list/
 B:     https://bugzilla.kernel.org
 C:     irc://irc.oftc.net/linux-pci
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
 F:     Documentation/driver-api/pci/p2pdma.rst
 F:     drivers/pci/p2pdma.c
 F:     include/linux/pci-p2pdma.h
@@ -16173,14 +16185,14 @@ F:    drivers/pci/controller/pci-xgene-msi.c
 
 PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
 M:     Lorenzo Pieralisi <lpieralisi@kernel.org>
+M:     Krzysztof Wilczyński <kw@linux.com>
 R:     Rob Herring <robh@kernel.org>
-R:     Krzysztof Wilczyński <kw@linux.com>
 L:     linux-pci@vger.kernel.org
 S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-pci/list/
 B:     https://bugzilla.kernel.org
 C:     irc://irc.oftc.net/linux-pci
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
 F:     Documentation/devicetree/bindings/pci/
 F:     drivers/pci/controller/
 F:     drivers/pci/pci-bridge-emul.c
@@ -16193,7 +16205,7 @@ S:      Supported
 Q:     https://patchwork.kernel.org/project/linux-pci/list/
 B:     https://bugzilla.kernel.org
 C:     irc://irc.oftc.net/linux-pci
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
 F:     Documentation/PCI/
 F:     Documentation/devicetree/bindings/pci/
 F:     arch/x86/kernel/early-quirks.c
@@ -17237,7 +17249,7 @@ F:      Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml
 F:     drivers/net/wwan/qcom_bam_dmux.c
 
 QUALCOMM CAMERA SUBSYSTEM DRIVER
-M:     Robert Foss <robert.foss@linaro.org>
+M:     Robert Foss <rfoss@kernel.org>
 M:     Todor Tomov <todor.too@gmail.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
@@ -17317,7 +17329,7 @@ F:      drivers/dma/qcom/hidma*
 
 QUALCOMM I2C CCI DRIVER
 M:     Loic Poulain <loic.poulain@linaro.org>
-M:     Robert Foss <robert.foss@linaro.org>
+M:     Robert Foss <rfoss@kernel.org>
 L:     linux-i2c@vger.kernel.org
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -17956,6 +17968,7 @@ M:      Albert Ou <aou@eecs.berkeley.edu>
 L:     linux-riscv@lists.infradead.org
 S:     Supported
 Q:     https://patchwork.kernel.org/project/linux-riscv/list/
+C:     irc://irc.libera.chat/riscv
 P:     Documentation/riscv/patch-acceptance.rst
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git
 F:     arch/riscv/
@@ -18677,9 +18690,9 @@ F:      drivers/target/
 F:     include/target/
 
 SCTP PROTOCOL
-M:     Vlad Yasevich <vyasevich@gmail.com>
 M:     Neil Horman <nhorman@tuxdriver.com>
 M:     Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+M:     Xin Long <lucien.xin@gmail.com>
 L:     linux-sctp@vger.kernel.org
 S:     Maintained
 W:     http://lksctp.sourceforge.net
@@ -19325,6 +19338,13 @@ L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Orphan
 F:     sound/soc/uniphier/
 
+SOCKET TIMESTAMPING
+M:     Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+S:     Maintained
+F:     Documentation/networking/timestamping.rst
+F:     include/uapi/linux/net_tstamp.h
+F:     tools/testing/selftests/net/so_txtime.c
+
 SOEKRIS NET48XX LED SUPPORT
 M:     Chris Boot <bootc@bootc.net>
 S:     Maintained
@@ -19672,7 +19692,7 @@ F:      drivers/clk/spear/
 F:     drivers/pinctrl/spear/
 
 SPI NOR SUBSYSTEM
-M:     Tudor Ambarus <tudor.ambarus@microchip.com>
+M:     Tudor Ambarus <tudor.ambarus@linaro.org>
 M:     Pratyush Yadav <pratyush@kernel.org>
 R:     Michael Walle <michael@walle.cc>
 L:     linux-mtd@lists.infradead.org
@@ -20070,6 +20090,7 @@ F:      drivers/watchdog/sunplus_wdt.c
 SUPERH
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
 M:     Rich Felker <dalias@libc.org>
+M:     John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
 L:     linux-sh@vger.kernel.org
 S:     Maintained
 Q:     http://patchwork.kernel.org/project/linux-sh/list/
@@ -21710,6 +21731,7 @@ F:      include/uapi/linux/uvcvideo.h
 
 USB WEBCAM GADGET
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+M:     Daniel Scally <dan.scally@ideasonboard.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/gadget/function/*uvc*
@@ -21745,6 +21767,13 @@ T:     git git://linuxtv.org/media_tree.git
 F:     Documentation/admin-guide/media/zr364xx*
 F:     drivers/staging/media/deprecated/zr364xx/
 
+USER DATAGRAM PROTOCOL (UDP)
+M:     Willem de Bruijn <willemdebruijn.kernel@gmail.com>
+S:     Maintained
+F:     include/linux/udp.h
+F:     net/ipv4/udp.c
+F:     net/ipv6/udp.c
+
 USER-MODE LINUX (UML)
 M:     Richard Weinberger <richard@nod.at>
 M:     Anton Ivanov <anton.ivanov@cambridgegreys.com>
index 4607163..716a975 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc8
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
@@ -549,7 +549,7 @@ LDFLAGS_MODULE  =
 CFLAGS_KERNEL  =
 RUSTFLAGS_KERNEL =
 AFLAGS_KERNEL  =
-export LDFLAGS_vmlinux =
+LDFLAGS_vmlinux =
 
 # Use USERINCLUDE when you must reference the UAPI directories only.
 USERINCLUDE    := \
@@ -1248,6 +1248,18 @@ vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
        @:
 
 PHONY += vmlinux
+# LDFLAGS_vmlinux in the top Makefile defines linker flags for the top vmlinux,
+# not for decompressors. LDFLAGS_vmlinux in arch/*/boot/compressed/Makefile is
+# unrelated; the decompressors just happen to have the same base name,
+# arch/*/boot/compressed/vmlinux.
+# Export LDFLAGS_vmlinux only to scripts/Makefile.vmlinux.
+#
+# _LDFLAGS_vmlinux is a workaround for the 'private export' bug:
+#   https://savannah.gnu.org/bugs/?61463
+# For Make > 4.4, the following simple code will work:
+#  vmlinux: private export LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
+vmlinux: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
+vmlinux: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
 vmlinux: vmlinux.o $(KBUILD_LDS) modpost
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux
 
@@ -1533,6 +1545,7 @@ endif
 # *.ko are usually independent of vmlinux, but CONFIG_DEBUG_INFOBTF_MODULES
 # is an exception.
 ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+KBUILD_BUILTIN := 1
 modules: vmlinux
 endif
 
index 4067f51..955b036 100644 (file)
@@ -132,7 +132,7 @@ AFLAGS_NOWARN       :=$(call as-option,-Wa$(comma)-mno-warn-deprecated,-Wa$(comma)-W)
 
 ifeq ($(CONFIG_THUMB2_KERNEL),y)
 CFLAGS_ISA     :=-Wa,-mimplicit-it=always $(AFLAGS_NOWARN)
-AFLAGS_ISA     :=$(CFLAGS_ISA) -Wa$(comma)-mthumb -D__thumb2__=2
+AFLAGS_ISA     :=$(CFLAGS_ISA) -Wa$(comma)-mthumb
 CFLAGS_ISA     +=-mthumb
 else
 CFLAGS_ISA     :=$(call cc-option,-marm,) $(AFLAGS_NOWARN)
index 12933ef..446861b 100644 (file)
                        };
 
                        gpio0: gpio@18100 {
-                               compatible = "marvell,armadaxp-gpio",
+                               compatible = "marvell,armada-370-gpio",
                                             "marvell,orion-gpio";
                                reg = <0x18100 0x40>, <0x181c0 0x08>;
                                reg-names = "gpio", "pwm";
                        };
 
                        gpio1: gpio@18140 {
-                               compatible = "marvell,armadaxp-gpio",
+                               compatible = "marvell,armada-370-gpio",
                                             "marvell,orion-gpio";
                                reg = <0x18140 0x40>, <0x181c8 0x08>;
                                reg-names = "gpio", "pwm";
index 1e05208..9d1cac4 100644 (file)
                        };
 
                        gpio0: gpio@18100 {
-                               compatible = "marvell,armadaxp-gpio", "marvell,orion-gpio";
+                               compatible = "marvell,orion-gpio";
                                reg = <0x18100 0x40>;
                                ngpios = <32>;
                                gpio-controller;
                        };
 
                        gpio1: gpio@18140 {
-                               compatible = "marvell,armadaxp-gpio", "marvell,orion-gpio";
+                               compatible = "marvell,orion-gpio";
                                reg = <0x18140 0x40>;
                                ngpios = <28>;
                                gpio-controller;
index d1971dd..7f755e5 100644 (file)
        };
 
        pca9849@75 {
-               compatible = "nxp,pca849";
+               compatible = "nxp,pca9849";
                reg = <0x75>;
                #address-cells = <1>;
                #size-cells = <0>;
index 37d0cff..70c4a48 100644 (file)
        scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
        status = "okay";
 
-       i2c-switch@70 {
+       i2c-mux@70 {
                compatible = "nxp,pca9547";
                #address-cells = <1>;
                #size-cells = <0>;
index 4bc4371..4b81a97 100644 (file)
 &uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
-       uart-has-rtscts;
        rts-gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
index 162dc25..5a74c7f 100644 (file)
@@ -32,7 +32,7 @@
 };
 
 &i2c2 {
-       clock_frequency = <100000>;
+       clock-frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c2>;
        status = "okay";
index 5162fe2..fdc1056 100644 (file)
@@ -32,7 +32,7 @@
 };
 
 &i2c1 {
-       clock_frequency = <100000>;
+       clock-frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
@@ -52,7 +52,7 @@
 };
 
 &i2c4 {
-       clock_frequency = <100000>;
+       clock-frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
index 104a852..5afb167 100644 (file)
@@ -43,7 +43,7 @@
 };
 
 &i2c1 {
-       clock_frequency = <100000>;
+       clock-frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
@@ -64,7 +64,7 @@
 };
 
 &i2c2 {
-       clock_frequency = <100000>;
+       clock-frequency = <100000>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_i2c2>;
        status = "okay";
index 546268b..c0f00f5 100644 (file)
 &usbotg2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usbotg2>;
+       over-current-active-low;
        dr_mode = "host";
        status = "okay";
 };
 
        pinctrl_usbotg2: usbotg2grp {
                fsl,pins = <
-                       MX7D_PAD_UART3_RTS_B__USB_OTG2_OC       0x04
+                       MX7D_PAD_UART3_RTS_B__USB_OTG2_OC       0x5c
                >;
        };
 
index b637241..fd671c7 100644 (file)
                        reg = <0xc8000000 0x1000>, <0xc0000000 0x4000000>;
                        reg-names = "control", "memory";
                        clocks = <&clk 0>;
+                       nuvoton,shm = <&shm>;
                        status = "disabled";
                };
 
index 44cd72f..116e59a 100644 (file)
                serial@f995e000 {
                        status = "okay";
                };
+       };
+};
 
-               sdhci@f9824900 {
-                       bus-width = <8>;
-                       non-removable;
-                       status = "okay";
-               };
+&sdhc_1 {
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+};
 
-               sdhci@f98a4900 {
-                       cd-gpios = <&tlmm 122 GPIO_ACTIVE_LOW>;
-                       bus-width = <4>;
-               };
-       };
+&sdhc_2 {
+       cd-gpios = <&tlmm 122 GPIO_ACTIVE_LOW>;
+       bus-width = <4>;
 };
index fe30abf..4b0d2b4 100644 (file)
                        status = "disabled";
                };
 
-               mmc@f9824900 {
+               sdhc_1: mmc@f9824900 {
                        compatible = "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                        reg-names = "hc", "core";
                        status = "disabled";
                };
 
-               mmc@f98a4900 {
+               sdhc_2: mmc@f98a4900 {
                        compatible = "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4";
                        reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                        reg-names = "hc", "core";
index 487b0e0..2ca76b6 100644 (file)
                clock-names = "dp", "pclk";
                phys = <&edp_phy>;
                phy-names = "dp";
+               power-domains = <&power RK3288_PD_VIO>;
                resets = <&cru SRST_EDP>;
                reset-names = "dp";
                rockchip,grf = <&grf>;
index 8f5477e..37a5d96 100644 (file)
                        mpddrc: mpddrc@ffffe800 {
                                compatible = "microchip,sam9x60-ddramc", "atmel,sama5d3-ddramc";
                                reg = <0xffffe800 0x200>;
-                               clocks = <&pmc PMC_TYPE_SYSTEM 2>, <&pmc PMC_TYPE_CORE PMC_MCK>;
+                               clocks = <&pmc PMC_TYPE_SYSTEM 2>, <&pmc PMC_TYPE_PERIPHERAL 49>;
                                clock-names = "ddrck", "mpddr";
                        };
 
index 920a0ba..8d9a2df 100644 (file)
                                tsin-num = <0>;
                                serial-not-parallel;
                                i2c-bus = <&ssc2>;
-                               reset-gpios = <&pio15 4 GPIO_ACTIVE_HIGH>;
+                               reset-gpios = <&pio15 4 GPIO_ACTIVE_LOW>;
                                dvb-card = <STV0367_TDA18212_NIMA_1>;
                        };
                };
index d865ab5..dd23de8 100644 (file)
 
 &qspi {
        pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
-       pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
+       pinctrl-0 = <&qspi_clk_pins_a
+                    &qspi_bk1_pins_a
+                    &qspi_cs1_pins_a>;
+       pinctrl-1 = <&qspi_clk_sleep_pins_a
+                    &qspi_bk1_sleep_pins_a
+                    &qspi_cs1_sleep_pins_a>;
        reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
        #address-cells = <1>;
        #size-cells = <0>;
index aef02e6..7d11c50 100644 (file)
 
 &qspi {
        pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
-       pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
+       pinctrl-0 = <&qspi_clk_pins_a
+                    &qspi_bk1_pins_a
+                    &qspi_cs1_pins_a>;
+       pinctrl-1 = <&qspi_clk_sleep_pins_a
+                    &qspi_bk1_sleep_pins_a
+                    &qspi_cs1_sleep_pins_a>;
        reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
        #address-cells = <1>;
        #size-cells = <0>;
index 002f221..c06edd2 100644 (file)
 
 &qspi {
        pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
-       pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
+       pinctrl-0 = <&qspi_clk_pins_a
+                    &qspi_bk1_pins_a
+                    &qspi_cs1_pins_a>;
+       pinctrl-1 = <&qspi_clk_sleep_pins_a
+                    &qspi_bk1_sleep_pins_a
+                    &qspi_cs1_sleep_pins_a>;
        reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
        #address-cells = <1>;
        #size-cells = <0>;
index 134a798..bb40fb4 100644 (file)
 
 &qspi {
        pinctrl-names = "default", "sleep";
-       pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a>;
-       pinctrl-1 = <&qspi_clk_sleep_pins_a &qspi_bk1_sleep_pins_a>;
+       pinctrl-0 = <&qspi_clk_pins_a
+                    &qspi_bk1_pins_a
+                    &qspi_cs1_pins_a>;
+       pinctrl-1 = <&qspi_clk_sleep_pins_a
+                    &qspi_bk1_sleep_pins_a
+                    &qspi_cs1_sleep_pins_a>;
        reg = <0x58003000 0x1000>, <0x70000000 0x200000>;
        #address-cells = <1>;
        #size-cells = <0>;
index 42ed4a0..6280c5e 100644 (file)
 };
 
 &i2c2 {
-       tca9548@70 {
+       i2c-mux@70 {
                compatible = "nxp,pca9548";
                pinctrl-0 = <&pinctrl_i2c_mux_reset>;
                pinctrl-names = "default";
index f892977..c00d395 100644 (file)
 };
 
 &i2c2 {
-       tca9548@70 {
+       i2c-mux@70 {
                compatible = "nxp,pca9548";
                pinctrl-0 = <&pinctrl_i2c_mux_reset>;
                pinctrl-names = "default";
index 971e745..13e62c7 100644 (file)
@@ -53,7 +53,12 @@ $(obj)/%-core.S: $(src)/%-armv4.pl
 
 clean-files += poly1305-core.S sha256-core.S sha512-core.S
 
+aflags-thumb2-$(CONFIG_THUMB2_KERNEL)  := -U__thumb2__ -D__thumb2__=1
+
+AFLAGS_sha256-core.o += $(aflags-thumb2-y)
+AFLAGS_sha512-core.o += $(aflags-thumb2-y)
+
 # massage the perlasm code a bit so we only get the NEON routine if we need it
 poly1305-aflags-$(CONFIG_CPU_V7) := -U__LINUX_ARM_ARCH__ -D__LINUX_ARM_ARCH__=5
 poly1305-aflags-$(CONFIG_KERNEL_MODE_NEON) := -U__LINUX_ARM_ARCH__ -D__LINUX_ARM_ARCH__=7
-AFLAGS_poly1305-core.o += $(poly1305-aflags-y)
+AFLAGS_poly1305-core.o += $(poly1305-aflags-y) $(aflags-thumb2-y)
index b8f741a..237b828 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
-#include <linux/bcd.h>
 #include <linux/io.h>
 
 #include "common.h"
index 3e63445..cc86977 100644 (file)
@@ -23,6 +23,7 @@ static int mx25_read_cpu_rev(void)
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx25-iim");
        iim_base = of_iomap(np, 0);
+       of_node_put(np);
        BUG_ON(!iim_base);
        rev = readl(iim_base + MXC_IIMSREV);
        iounmap(iim_base);
index bf70e13..1d28939 100644 (file)
@@ -28,6 +28,7 @@ static int mx27_read_cpu_rev(void)
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx27-ccm");
        ccm_base = of_iomap(np, 0);
+       of_node_put(np);
        BUG_ON(!ccm_base);
        /*
         * now we have access to the IO registers. As we need
index b9c24b8..35c5449 100644 (file)
@@ -39,6 +39,7 @@ static int mx31_read_cpu_rev(void)
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx31-iim");
        iim_base = of_iomap(np, 0);
+       of_node_put(np);
        BUG_ON(!iim_base);
 
        /* read SREV register from IIM module */
index 80e7d8a..1fe75b3 100644 (file)
@@ -21,6 +21,7 @@ static int mx35_read_cpu_rev(void)
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx35-iim");
        iim_base = of_iomap(np, 0);
+       of_node_put(np);
        BUG_ON(!iim_base);
 
        rev = imx_readl(iim_base + MXC_IIMSREV);
index ad56263..a67c89b 100644 (file)
@@ -28,6 +28,7 @@ static u32 imx5_read_srev_reg(const char *compat)
 
        np = of_find_compatible_node(NULL, NULL, compat);
        iim_base = of_iomap(np, 0);
+       of_node_put(np);
        WARN_ON(!iim_base);
 
        srev = readl(iim_base + IIM_SREV) & 0xff;
index 538a960..7ec7ada 100644 (file)
@@ -4,6 +4,7 @@ menuconfig ARCH_OMAP1
        depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
        depends on CPU_LITTLE_ENDIAN
        depends on ATAGS
+       select ARCH_OMAP
        select ARCH_HAS_HOLES_MEMORYMODEL
        select ARCH_OMAP
        select CLKSRC_MMIO
@@ -45,10 +46,6 @@ config ARCH_OMAP16XX
        select CPU_ARM926T
        select OMAP_DM_TIMER
 
-config ARCH_OMAP1_ANY
-       select ARCH_OMAP
-       def_bool ARCH_OMAP730 || ARCH_OMAP850 || ARCH_OMAP15XX || ARCH_OMAP16XX
-
 config ARCH_OMAP
        bool
 
index 506074b..0615cb0 100644 (file)
@@ -3,8 +3,6 @@
 # Makefile for the linux kernel.
 #
 
-ifdef CONFIG_ARCH_OMAP1_ANY
-
 # Common support
 obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
         serial.o devices.o dma.o omap-dma.o fb.o
@@ -59,5 +57,3 @@ obj-$(CONFIG_ARCH_OMAP730)            += gpio7xx.o
 obj-$(CONFIG_ARCH_OMAP850)             += gpio7xx.o
 obj-$(CONFIG_ARCH_OMAP15XX)            += gpio15xx.o
 obj-$(CONFIG_ARCH_OMAP16XX)            += gpio16xx.o
-
-endif
index c675f11..61fa26e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/gpio.h>
 #include <linux/platform_data/gpio-omap.h>
 #include <linux/soc/ti/omap1-soc.h>
+#include <asm/irq.h>
 
 #include "irqs.h"
 
index d2db9b8..0074b01 100644 (file)
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
  */
-static struct map_desc omap_io_desc[] __initdata = {
+#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
+static struct map_desc omap7xx_io_desc[] __initdata = {
        {
                .virtual        = OMAP1_IO_VIRT,
                .pfn            = __phys_to_pfn(OMAP1_IO_PHYS),
                .length         = OMAP1_IO_SIZE,
                .type           = MT_DEVICE
-       }
-};
-
-#if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
-static struct map_desc omap7xx_io_desc[] __initdata = {
+       },
        {
                .virtual        = OMAP7XX_DSP_BASE,
                .pfn            = __phys_to_pfn(OMAP7XX_DSP_START),
@@ -49,6 +46,12 @@ static struct map_desc omap7xx_io_desc[] __initdata = {
 
 #ifdef CONFIG_ARCH_OMAP15XX
 static struct map_desc omap1510_io_desc[] __initdata = {
+       {
+               .virtual        = OMAP1_IO_VIRT,
+               .pfn            = __phys_to_pfn(OMAP1_IO_PHYS),
+               .length         = OMAP1_IO_SIZE,
+               .type           = MT_DEVICE
+       },
        {
                .virtual        = OMAP1510_DSP_BASE,
                .pfn            = __phys_to_pfn(OMAP1510_DSP_START),
@@ -65,6 +68,12 @@ static struct map_desc omap1510_io_desc[] __initdata = {
 
 #if defined(CONFIG_ARCH_OMAP16XX)
 static struct map_desc omap16xx_io_desc[] __initdata = {
+       {
+               .virtual        = OMAP1_IO_VIRT,
+               .pfn            = __phys_to_pfn(OMAP1_IO_PHYS),
+               .length         = OMAP1_IO_SIZE,
+               .type           = MT_DEVICE
+       },
        {
                .virtual        = OMAP16XX_DSP_BASE,
                .pfn            = __phys_to_pfn(OMAP16XX_DSP_START),
@@ -79,18 +88,9 @@ static struct map_desc omap16xx_io_desc[] __initdata = {
 };
 #endif
 
-/*
- * Maps common IO regions for omap1
- */
-static void __init omap1_map_common_io(void)
-{
-       iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
-}
-
 #if defined (CONFIG_ARCH_OMAP730) || defined (CONFIG_ARCH_OMAP850)
 void __init omap7xx_map_io(void)
 {
-       omap1_map_common_io();
        iotable_init(omap7xx_io_desc, ARRAY_SIZE(omap7xx_io_desc));
 }
 #endif
@@ -98,7 +98,6 @@ void __init omap7xx_map_io(void)
 #ifdef CONFIG_ARCH_OMAP15XX
 void __init omap15xx_map_io(void)
 {
-       omap1_map_common_io();
        iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
 }
 #endif
@@ -106,7 +105,6 @@ void __init omap15xx_map_io(void)
 #if defined(CONFIG_ARCH_OMAP16XX)
 void __init omap16xx_map_io(void)
 {
-       omap1_map_common_io();
        iotable_init(omap16xx_io_desc, ARRAY_SIZE(omap16xx_io_desc));
 }
 #endif
index 05c25c4..b1632cb 100644 (file)
@@ -89,7 +89,6 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
 #define OMAP1610_MCBSP2_BASE   0xfffb1000
 #define OMAP1610_MCBSP3_BASE   0xe1017000
 
-#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
 struct resource omap7xx_mcbsp_res[][6] = {
        {
                {
@@ -159,14 +158,7 @@ static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = {
 };
 #define OMAP7XX_MCBSP_RES_SZ           ARRAY_SIZE(omap7xx_mcbsp_res[1])
 #define OMAP7XX_MCBSP_COUNT            ARRAY_SIZE(omap7xx_mcbsp_res)
-#else
-#define omap7xx_mcbsp_res_0            NULL
-#define omap7xx_mcbsp_pdata            NULL
-#define OMAP7XX_MCBSP_RES_SZ           0
-#define OMAP7XX_MCBSP_COUNT            0
-#endif
 
-#ifdef CONFIG_ARCH_OMAP15XX
 struct resource omap15xx_mcbsp_res[][6] = {
        {
                {
@@ -266,14 +258,7 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
 };
 #define OMAP15XX_MCBSP_RES_SZ          ARRAY_SIZE(omap15xx_mcbsp_res[1])
 #define OMAP15XX_MCBSP_COUNT           ARRAY_SIZE(omap15xx_mcbsp_res)
-#else
-#define omap15xx_mcbsp_res_0           NULL
-#define omap15xx_mcbsp_pdata           NULL
-#define OMAP15XX_MCBSP_RES_SZ          0
-#define OMAP15XX_MCBSP_COUNT           0
-#endif
 
-#ifdef CONFIG_ARCH_OMAP16XX
 struct resource omap16xx_mcbsp_res[][6] = {
        {
                {
@@ -373,12 +358,6 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
 };
 #define OMAP16XX_MCBSP_RES_SZ          ARRAY_SIZE(omap16xx_mcbsp_res[1])
 #define OMAP16XX_MCBSP_COUNT           ARRAY_SIZE(omap16xx_mcbsp_res)
-#else
-#define omap16xx_mcbsp_res_0           NULL
-#define omap16xx_mcbsp_pdata           NULL
-#define OMAP16XX_MCBSP_RES_SZ          0
-#define OMAP16XX_MCBSP_COUNT           0
-#endif
 
 static void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
                        struct omap_mcbsp_platform_data *config, int size)
index d916570..0d1f092 100644 (file)
 #define OMAP7XX_IDLECT3                0xfffece24
 #define OMAP7XX_IDLE_LOOP_REQUEST      0x0C00
 
-#if     !defined(CONFIG_ARCH_OMAP730) && \
-       !defined(CONFIG_ARCH_OMAP850) && \
-       !defined(CONFIG_ARCH_OMAP15XX) && \
-       !defined(CONFIG_ARCH_OMAP16XX)
-#warning "Power management for this processor not implemented yet"
-#endif
-
 #ifndef __ASSEMBLER__
 
 #include <linux/clk.h>
index b90d98b..03e25af 100644 (file)
@@ -45,6 +45,8 @@ config MACH_PXA27X_DT
 config MACH_PXA3XX_DT
        bool "Support PXA3xx platforms from device tree"
        select CPU_PXA300
+       select CPU_PXA310
+       select CPU_PXA320
        select PINCTRL
        select POWER_SUPPLY
        select PXA3xx
index c1494a4..53f2d87 100644 (file)
@@ -161,7 +161,7 @@ void __init paging_init(const struct machine_desc *mdesc)
        mpu_setup();
 
        /* allocate the zero page. */
-       zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+       zero_page = (void *)memblock_alloc(PAGE_SIZE, PAGE_SIZE);
        if (!zero_page)
                panic("%s: Failed to allocate %lu bytes align=0x%lx\n",
                      __func__, PAGE_SIZE, PAGE_SIZE);
index fa6999e..e43f6d7 100644 (file)
@@ -6,6 +6,7 @@
  *  VM_EXEC
  */
 #include <asm/asm-offsets.h>
+#include <asm/pgtable.h>
 #include <asm/thread_info.h>
 
 #ifdef CONFIG_CPU_V7M
index 0393480..c5ccca2 100644 (file)
@@ -184,8 +184,6 @@ config ARM64
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_CONTIGUOUS
        select HAVE_DYNAMIC_FTRACE
-       select HAVE_DYNAMIC_FTRACE_WITH_ARGS \
-               if $(cc-option,-fpatchable-function-entry=2)
        select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \
                if DYNAMIC_FTRACE_WITH_ARGS
        select HAVE_EFFICIENT_UNALIGNED_ACCESS
@@ -972,6 +970,22 @@ config ARM64_ERRATUM_2457168
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_2645198
+       bool "Cortex-A715: 2645198: Workaround possible [ESR|FAR]_ELx corruption"
+       default y
+       help
+         This option adds the workaround for ARM Cortex-A715 erratum 2645198.
+
+         If a Cortex-A715 cpu sees a page mapping permissions change from executable
+         to non-executable, it may corrupt the ESR_ELx and FAR_ELx registers on the
+         next instruction abort caused by permission fault.
+
+         Only user-space does executable to non-executable permission transition via
+         mprotect() system call. Workaround the problem by doing a break-before-make
+         TLB invalidation, for all changes to executable user space mappings.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
        bool "Cavium erratum 22375, 24313"
        default y
index 1648e67..417523d 100644 (file)
                        sd_emmc_b: sd@5000 {
                                compatible = "amlogic,meson-axg-mmc";
                                reg = <0x0 0x5000 0x0 0x800>;
-                               interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
+                               interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
                                status = "disabled";
                                clocks = <&clkc CLKID_SD_EMMC_B>,
                                        <&clkc CLKID_SD_EMMC_B_CLK0>,
                        sd_emmc_c: mmc@7000 {
                                compatible = "amlogic,meson-axg-mmc";
                                reg = <0x0 0x7000 0x0 0x800>;
-                               interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
+                               interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
                                status = "disabled";
                                clocks = <&clkc CLKID_SD_EMMC_C>,
                                        <&clkc CLKID_SD_EMMC_C_CLK0>,
index 9dbd508..7f55d97 100644 (file)
                sd_emmc_a: sd@ffe03000 {
                        compatible = "amlogic,meson-axg-mmc";
                        reg = <0x0 0xffe03000 0x0 0x800>;
-                       interrupts = <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                        clocks = <&clkc CLKID_SD_EMMC_A>,
                                 <&clkc CLKID_SD_EMMC_A_CLK0>,
                sd_emmc_b: sd@ffe05000 {
                        compatible = "amlogic,meson-axg-mmc";
                        reg = <0x0 0xffe05000 0x0 0x800>;
-                       interrupts = <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                        clocks = <&clkc CLKID_SD_EMMC_B>,
                                 <&clkc CLKID_SD_EMMC_B_CLK0>,
                sd_emmc_c: mmc@ffe07000 {
                        compatible = "amlogic,meson-axg-mmc";
                        reg = <0x0 0xffe07000 0x0 0x800>;
-                       interrupts = <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>;
+                       interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                        clocks = <&clkc CLKID_SD_EMMC_C>,
                                 <&clkc CLKID_SD_EMMC_C_CLK0>,
index e3c12e0..5eed150 100644 (file)
                        sd_emmc_a: mmc@70000 {
                                compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
                                reg = <0x0 0x70000 0x0 0x800>;
-                               interrupts = <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
+                               interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
                                status = "disabled";
                        };
 
                        sd_emmc_b: mmc@72000 {
                                compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
                                reg = <0x0 0x72000 0x0 0x800>;
-                               interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
+                               interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
                                status = "disabled";
                        };
 
                        sd_emmc_c: mmc@74000 {
                                compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
                                reg = <0x0 0x74000 0x0 0x800>;
-                               interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
+                               interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
                                status = "disabled";
                        };
                };
index e3486f6..a1f0c38 100644 (file)
 };
 
 &usb {
-       phys = <&usb2_phy1>;
-       phy-names = "usb2-phy1";
-};
-
-&usb2_phy0 {
-       status = "disabled";
+       phys = <&usb2_phy0>, <&usb2_phy1>;
+       phy-names = "usb2-phy0", "usb2-phy1";
 };
index 5a8d85a..bbdf989 100644 (file)
 &i2c0 {
        status = "okay";
 
-       pca9547@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                reg = <0x77>;
                #address-cells = <1>;
index 9b726c2..dda27ed 100644 (file)
@@ -89,7 +89,7 @@
 &i2c0 {
        status = "okay";
 
-       pca9547@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                reg = <0x77>;
                #address-cells = <1>;
index b2fcbba..3b0ed93 100644 (file)
@@ -88,7 +88,7 @@
 &i2c0 {
        status = "okay";
 
-       pca9547@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                reg = <0x77>;
                #address-cells = <1>;
index 41d8b15..aa52ff7 100644 (file)
@@ -53,7 +53,7 @@
 &i2c0 {
        status = "okay";
 
-       i2c-switch@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                reg = <0x77>;
                #address-cells = <1>;
index 1bfbce6..ee8e932 100644 (file)
 &i2c0 {
        status = "okay";
 
-       i2c-switch@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                reg = <0x77>;
                #address-cells = <1>;
index ef6c896..d4867d6 100644 (file)
 &i2c3 {
        status = "okay";
 
-       i2c-switch@70 {
+       i2c-mux@70 {
                compatible = "nxp,pca9540";
                #address-cells = <1>;
                #size-cells = <0>;
index f598669..52c5a43 100644 (file)
 
 &i2c0 {
        status = "okay";
-       pca9547@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                reg = <0x77>;
                #address-cells = <1>;
index 3d9647b..537cecb 100644 (file)
@@ -44,7 +44,7 @@
 
 &i2c0 {
        status = "okay";
-       pca9547@75 {
+       i2c-mux@75 {
                compatible = "nxp,pca9547";
                reg = <0x75>;
                #address-cells = <1>;
index afb4552..d32a52a 100644 (file)
@@ -54,7 +54,7 @@
 &i2c0 {
        status = "okay";
 
-       i2c-switch@77 {
+       i2c-mux@77 {
                compatible = "nxp,pca9547";
                #address-cells = <1>;
                #size-cells = <0>;
index 0c64b91..214f21b 100644 (file)
 
                sc_pwrkey: keys {
                        compatible = "fsl,imx8qxp-sc-key", "fsl,imx-sc-key";
-                       linux,keycode = <KEY_POWER>;
+                       linux,keycodes = <KEY_POWER>;
                        wakeup-source;
                };
 
index 03266bd..169f047 100644 (file)
 &ecspi2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_espi2>;
-       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
        status = "okay";
 
        eeprom@0 {
                        MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK            0x82
                        MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI            0x82
                        MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO            0x82
-                       MX8MM_IOMUXC_ECSPI1_SS0_GPIO5_IO9               0x41
+                       MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13              0x41
                >;
        };
 
index 24f61db..9889319 100644 (file)
@@ -88,6 +88,7 @@
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_watchdog_gpio>;
                compatible = "linux,wdt-gpio";
+               always-running;
                gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
                hw_algo = "level";
                /* Reset triggers in 2..3 seconds */
                compatible = "rohm,bd71847";
                reg = <0x4b>;
                #clock-cells = <0>;
-               clocks = <&clk_xtal32k 0>;
+               clocks = <&clk_xtal32k>;
                clock-output-names = "clk-32k-out";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_pmic>;
index 74c0989..6357078 100644 (file)
        pinctrl-0 = <&pinctrl_i2c3>;
        status = "okay";
 
-       i2cmux@70 {
+       i2c-mux@70 {
                compatible = "nxp,pca9540";
                reg = <0x70>;
                #address-cells = <1>;
index 83c8f71..b1f1109 100644 (file)
 #define MX8MM_IOMUXC_UART1_RXD_GPIO5_IO22                                   0x234 0x49C 0x000 0x5 0x0
 #define MX8MM_IOMUXC_UART1_RXD_TPSMP_HDATA24                                0x234 0x49C 0x000 0x7 0x0
 #define MX8MM_IOMUXC_UART1_TXD_UART1_DCE_TX                                 0x238 0x4A0 0x000 0x0 0x0
-#define MX8MM_IOMUXC_UART1_TXD_UART1_DTE_RX                                 0x238 0x4A0 0x4F4 0x0 0x0
+#define MX8MM_IOMUXC_UART1_TXD_UART1_DTE_RX                                 0x238 0x4A0 0x4F4 0x0 0x1
 #define MX8MM_IOMUXC_UART1_TXD_ECSPI3_MOSI                                  0x238 0x4A0 0x000 0x1 0x0
 #define MX8MM_IOMUXC_UART1_TXD_GPIO5_IO23                                   0x238 0x4A0 0x000 0x5 0x0
 #define MX8MM_IOMUXC_UART1_TXD_TPSMP_HDATA25                                0x238 0x4A0 0x000 0x7 0x0
index 3ea73a6..f6ad1a4 100644 (file)
@@ -33,7 +33,6 @@
        pinctrl-0 = <&pinctrl_uart2>;
        rts-gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
        cts-gpios = <&gpio5 28 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
index 2fa635e..1f8ea20 100644 (file)
@@ -33,7 +33,6 @@
        pinctrl-0 = <&pinctrl_uart2>;
        rts-gpios = <&gpio5 29 GPIO_ACTIVE_LOW>;
        cts-gpios = <&gpio5 28 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
index 244ef8d..7761d56 100644 (file)
        pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_bten>;
        cts-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
        rts-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 
        bluetooth {
index 750a1f0..64b366e 100644 (file)
        dtr-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
        dsr-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
        dcd-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>;
        cts-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
        rts-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_uart4>, <&pinctrl_uart4_gpio>;
        cts-gpios = <&gpio5 11 GPIO_ACTIVE_LOW>;
        rts-gpios = <&gpio5 12 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
 &usbotg2 {
        dr_mode = "host";
        vbus-supply = <&reg_usb2_vbus>;
+       over-current-active-low;
        status = "okay";
 };
 
index 32872b0..e8bc1fc 100644 (file)
        pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart1_gpio>;
        rts-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>;
        cts-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
        pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>;
        rts-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
        cts-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 
        bluetooth {
        dtr-gpios = <&gpio4 3 GPIO_ACTIVE_LOW>;
        dsr-gpios = <&gpio4 4 GPIO_ACTIVE_LOW>;
        dcd-gpios = <&gpio4 6 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
index 8ce5622..acc2ba8 100644 (file)
        dtr-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
        dsr-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
        dcd-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 };
 
index c2a5c2f..7c3f5c5 100644 (file)
@@ -9,6 +9,7 @@
                simple-audio-card,bitclock-master = <&dailink_master>;
                simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&dailink_master>;
+               simple-audio-card,mclk-fs = <256>;
                simple-audio-card,name = "imx8mm-wm8904";
                simple-audio-card,routing =
                        "Headphone Jack", "HPOUTL",
index 73cc3fa..b2bcd22 100644 (file)
@@ -11,6 +11,7 @@
                simple-audio-card,bitclock-master = <&dailink_master>;
                simple-audio-card,format = "i2s";
                simple-audio-card,frame-master = <&dailink_master>;
+               simple-audio-card,mclk-fs = <256>;
                simple-audio-card,name = "imx8mm-nau8822";
                simple-audio-card,routing =
                        "Headphones", "LHP",
index 0d454e0..702d876 100644 (file)
@@ -98,6 +98,7 @@
                off-on-delay = <500000>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_reg_eth>;
+               regulator-always-on;
                regulator-boot-on;
                regulator-max-microvolt = <3300000>;
                regulator-min-microvolt = <3300000>;
index b9444e4..7c12518 100644 (file)
        pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>;
        rts-gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
        cts-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 
        bluetooth {
index d4c7ca1..f2d9343 100644 (file)
@@ -36,8 +36,8 @@
 
        pcie0_refclk: pcie0-refclk {
                compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <100000000>;
+               #clock-cells = <0>;
+               clock-frequency = <100000000>;
        };
 
        reg_can1_stby: regulator-can1-stby {
index 79b290a..ecc4bce 100644 (file)
@@ -99,7 +99,6 @@
 
                regulators {
                        buck1: BUCK1 {
-                               regulator-compatible = "BUCK1";
                                regulator-min-microvolt = <600000>;
                                regulator-max-microvolt = <2187500>;
                                regulator-boot-on;
                        };
 
                        buck2: BUCK2 {
-                               regulator-compatible = "BUCK2";
                                regulator-min-microvolt = <600000>;
                                regulator-max-microvolt = <2187500>;
                                regulator-boot-on;
                        };
 
                        buck4: BUCK4 {
-                               regulator-compatible = "BUCK4";
                                regulator-min-microvolt = <600000>;
                                regulator-max-microvolt = <3400000>;
                                regulator-boot-on;
                        };
 
                        buck5: BUCK5 {
-                               regulator-compatible = "BUCK5";
                                regulator-min-microvolt = <600000>;
                                regulator-max-microvolt = <3400000>;
                                regulator-boot-on;
                        };
 
                        buck6: BUCK6 {
-                               regulator-compatible = "BUCK6";
                                regulator-min-microvolt = <600000>;
                                regulator-max-microvolt = <3400000>;
                                regulator-boot-on;
                        };
 
                        ldo1: LDO1 {
-                               regulator-compatible = "LDO1";
                                regulator-min-microvolt = <1600000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
                        };
 
                        ldo2: LDO2 {
-                               regulator-compatible = "LDO2";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <1150000>;
                                regulator-boot-on;
                        };
 
                        ldo3: LDO3 {
-                               regulator-compatible = "LDO3";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
                        };
 
                        ldo4: LDO4 {
-                               regulator-compatible = "LDO4";
                                regulator-min-microvolt = <800000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
                        ldo5: LDO5 {
-                               regulator-compatible = "LDO5";
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
index ceeca49..8eb7d5e 100644 (file)
        pinctrl-0 = <&pinctrl_uart3>, <&pinctrl_uart3_gpio>;
        cts-gpios = <&gpio3 21 GPIO_ACTIVE_LOW>;
        rts-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>;
-       uart-has-rtscts;
        status = "okay";
 
        bluetooth {
index 7a6e622..03034b4 100644 (file)
                                compatible = "fsl,imx8mp-gpc";
                                reg = <0x303a0000 0x1000>;
                                interrupt-parent = <&gic>;
+                               interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-controller;
                                #interrupt-cells = <3>;
 
                                                reg = <IMX8MP_POWER_DOMAIN_MIPI_PHY2>;
                                        };
 
-                                       pgc_hsiomix: power-domains@17 {
+                                       pgc_hsiomix: power-domain@17 {
                                                #power-domain-cells = <0>;
                                                reg = <IMX8MP_POWER_DOMAIN_HSIOMIX>;
                                                clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
                        reg = <0x32f10100 0x8>,
                              <0x381f0000 0x20>;
                        clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
-                                <&clk IMX8MP_CLK_USB_ROOT>;
+                                <&clk IMX8MP_CLK_USB_SUSP>;
                        clock-names = "hsio", "suspend";
                        interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
                        power-domains = <&hsio_blk_ctrl IMX8MP_HSIOBLK_PD_USB>;
                        usb_dwc3_0: usb@38100000 {
                                compatible = "snps,dwc3";
                                reg = <0x38100000 0x10000>;
-                               clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
+                               clocks = <&clk IMX8MP_CLK_USB_ROOT>,
                                         <&clk IMX8MP_CLK_USB_CORE_REF>,
-                                        <&clk IMX8MP_CLK_USB_ROOT>;
+                                        <&clk IMX8MP_CLK_USB_SUSP>;
                                clock-names = "bus_early", "ref", "suspend";
                                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
                                phys = <&usb3_phy0>, <&usb3_phy0>;
                        reg = <0x32f10108 0x8>,
                              <0x382f0000 0x20>;
                        clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
-                                <&clk IMX8MP_CLK_USB_ROOT>;
+                                <&clk IMX8MP_CLK_USB_SUSP>;
                        clock-names = "hsio", "suspend";
                        interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
                        power-domains = <&hsio_blk_ctrl IMX8MP_HSIOBLK_PD_USB>;
                        usb_dwc3_1: usb@38200000 {
                                compatible = "snps,dwc3";
                                reg = <0x38200000 0x10000>;
-                               clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
+                               clocks = <&clk IMX8MP_CLK_USB_ROOT>,
                                         <&clk IMX8MP_CLK_USB_CORE_REF>,
-                                        <&clk IMX8MP_CLK_USB_ROOT>;
+                                        <&clk IMX8MP_CLK_USB_SUSP>;
                                clock-names = "bus_early", "ref", "suspend";
                                interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
                                phys = <&usb3_phy1>, <&usb3_phy1>;
index 9dda2a1..8614c18 100644 (file)
        pinctrl-0 = <&pinctrl_i2c1>;
        status = "okay";
 
-       i2cmux@70 {
+       i2c-mux@70 {
                compatible = "nxp,pca9546";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_i2c1_pca9546>;
        pinctrl-0 = <&pinctrl_i2c4>;
        status = "okay";
 
-       pca9546: i2cmux@70 {
+       pca9546: i2c-mux@70 {
                compatible = "nxp,pca9546";
                reg = <0x70>;
                #address-cells = <1>;
index 5d5aa65..6e61827 100644 (file)
        bus-width = <4>;
        non-removable;
        no-sd;
-       no-emmc;
+       no-mmc;
        status = "okay";
 
        brcmf: wifi@1 {
        cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
        bus-width = <4>;
        no-sdio;
-       no-emmc;
+       no-mmc;
        disable-wp;
        status = "okay";
 };
index 07d8dd8..afa8833 100644 (file)
@@ -61,7 +61,7 @@
        pinctrl-0 = <&pinctrl_lpi2c1 &pinctrl_ioexp_rst>;
        status = "okay";
 
-       i2c-switch@71 {
+       i2c-mux@71 {
                compatible = "nxp,pca9646", "nxp,pca9546";
                #address-cells = <1>;
                #size-cells = <0>;
index 69786c3..27f9a9f 100644 (file)
@@ -74,7 +74,7 @@
 
        pinctrl_usdhc1: usdhc1grp {
                fsl,pins = <
-                       MX93_PAD_SD1_CLK__USDHC1_CLK            0x17fe
+                       MX93_PAD_SD1_CLK__USDHC1_CLK            0x15fe
                        MX93_PAD_SD1_CMD__USDHC1_CMD            0x13fe
                        MX93_PAD_SD1_DATA0__USDHC1_DATA0        0x13fe
                        MX93_PAD_SD1_DATA1__USDHC1_DATA1        0x13fe
@@ -84,7 +84,7 @@
                        MX93_PAD_SD1_DATA5__USDHC1_DATA5        0x13fe
                        MX93_PAD_SD1_DATA6__USDHC1_DATA6        0x13fe
                        MX93_PAD_SD1_DATA7__USDHC1_DATA7        0x13fe
-                       MX93_PAD_SD1_STROBE__USDHC1_STROBE      0x17fe
+                       MX93_PAD_SD1_STROBE__USDHC1_STROBE      0x15fe
                >;
        };
 
 
        pinctrl_usdhc2: usdhc2grp {
                fsl,pins = <
-                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x17fe
+                       MX93_PAD_SD2_CLK__USDHC2_CLK            0x15fe
                        MX93_PAD_SD2_CMD__USDHC2_CMD            0x13fe
                        MX93_PAD_SD2_DATA0__USDHC2_DATA0        0x13fe
                        MX93_PAD_SD2_DATA1__USDHC2_DATA1        0x13fe
index 7308f7b..8bce640 100644 (file)
@@ -98,7 +98,7 @@
 
                        uart1: serial@12100 {
                                compatible = "snps,dw-apb-uart";
-                               reg = <0x11000 0x100>;
+                               reg = <0x12100 0x100>;
                                reg-shift = <2>;
                                interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
                                reg-io-width = <1>;
index 5d31536..c10cfeb 100644 (file)
                };
 
                vdosys0: syscon@1c01a000 {
-                       compatible = "mediatek,mt8195-mmsys", "syscon";
+                       compatible = "mediatek,mt8195-vdosys0", "mediatek,mt8195-mmsys", "syscon";
                        reg = <0 0x1c01a000 0 0x1000>;
                        mboxes = <&gce0 0 CMDQ_THR_PRIO_4>;
                        #clock-cells = <1>;
                };
 
                vdosys1: syscon@1c100000 {
-                       compatible = "mediatek,mt8195-mmsys", "syscon";
+                       compatible = "mediatek,mt8195-vdosys1", "syscon";
                        reg = <0 0x1c100000 0 0x1000>;
                        #clock-cells = <1>;
                };
index 87c90e9..79de9cc 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2015, LGE Inc. All rights reserved.
  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
  * Copyright (c) 2021, Petr Vorel <petr.vorel@gmail.com>
+ * Copyright (c) 2022, Dominik Kobinski <dominikkobinski314@gmail.com>
  */
 
 /dts-v1/;
                        reg = <0 0x03400000 0 0x1200000>;
                        no-map;
                };
+
+               removed_region: reserved@5000000 {
+                       reg = <0 0x05000000 0 0x2200000>;
+                       no-map;
+               };
        };
 };
 
index b242c27..fcca1ba 100644 (file)
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/gpio-keys.h>
 
+/delete-node/ &adsp_mem;
+/delete-node/ &audio_mem;
+/delete-node/ &mpss_mem;
+/delete-node/ &peripheral_region;
+/delete-node/ &rmtfs_mem;
+
 / {
        model = "Xiaomi Mi 4C";
        compatible = "xiaomi,libra", "qcom,msm8992";
                #size-cells = <2>;
                ranges;
 
-               /* This is for getting crash logs using Android downstream kernels */
-               ramoops@dfc00000 {
-                       compatible = "ramoops";
-                       reg = <0x0 0xdfc00000 0x0 0x40000>;
-                       console-size = <0x10000>;
-                       record-size = <0x10000>;
-                       ftrace-size = <0x10000>;
-                       pmsg-size = <0x20000>;
+               memory_hole: hole@6400000 {
+                       reg = <0 0x06400000 0 0x600000>;
+                       no-map;
+               };
+
+               memory_hole2: hole2@6c00000 {
+                       reg = <0 0x06c00000 0 0x2400000>;
+                       no-map;
+               };
+
+               mpss_mem: mpss@9000000 {
+                       reg = <0 0x09000000 0 0x5a00000>;
+                       no-map;
+               };
+
+               tzapp: tzapp@ea00000 {
+                       reg = <0 0x0ea00000 0 0x1900000>;
+                       no-map;
+               };
+
+               mdm_rfsa_mem: mdm-rfsa@ca0b0000 {
+                       reg = <0 0xca0b0000 0 0x10000>;
+                       no-map;
+               };
+
+               rmtfs_mem: rmtfs@ca100000 {
+                       compatible = "qcom,rmtfs-mem";
+                       reg = <0 0xca100000 0 0x180000>;
+                       no-map;
+
+                       qcom,client-id = <1>;
                };
 
-               modem_region: modem_region@9000000 {
-                       reg = <0x0 0x9000000 0x0 0x5a00000>;
+               audio_mem: audio@cb400000 {
+                       reg = <0 0xcb000000 0 0x400000>;
+                       no-mem;
+               };
+
+               qseecom_mem: qseecom@cb400000 {
+                       reg = <0 0xcb400000 0 0x1c00000>;
+                       no-mem;
+               };
+
+               adsp_rfsa_mem: adsp-rfsa@cd000000 {
+                       reg = <0 0xcd000000 0 0x10000>;
                        no-map;
                };
 
-               tzapp: modem_region@ea00000 {
-                       reg = <0x0 0xea00000 0x0 0x1900000>;
+               sensor_rfsa_mem: sensor-rfsa@cd010000 {
+                       reg = <0 0xcd010000 0 0x10000>;
                        no-map;
                };
+
+               ramoops@dfc00000 {
+                       compatible = "ramoops";
+                       reg = <0 0xdfc00000 0 0x40000>;
+                       console-size = <0x10000>;
+                       record-size = <0x10000>;
+                       ftrace-size = <0x10000>;
+                       pmsg-size = <0x20000>;
+               };
        };
 };
 
        status = "okay";
 };
 
-&peripheral_region {
-       reg = <0x0 0x7400000 0x0 0x1c00000>;
-       no-map;
-};
-
 &pm8994_spmi_regulators {
        VDD_APC0: s8 {
                regulator-min-microvolt = <680000>;
index 10adb49..02fc379 100644 (file)
        compatible = "qcom,rpmcc-msm8992", "qcom,rpmcc";
 };
 
-&tcsr_mutex {
-       compatible = "qcom,sfpb-mutex";
-};
-
 &timer {
        interrupts = <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
                             <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
index 85abff0..7b0f621 100644 (file)
@@ -9,9 +9,6 @@
 
 #include "msm8994.dtsi"
 
-/* Angler's firmware does not report where the memory is allocated */
-/delete-node/ &cont_splash_mem;
-
 / {
        model = "Huawei Nexus 6P";
        compatible = "huawei,angler", "qcom,msm8994";
        chosen {
                stdout-path = "serial0:115200n8";
        };
+
+       reserved-memory {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges;
+
+               tzapp_mem: tzapp@4800000 {
+                       reg = <0 0x04800000 0 0x1900000>;
+                       no-map;
+               };
+
+               removed_region: reserved@6300000 {
+                       reg = <0 0x06300000 0 0xD00000>;
+                       no-map;
+               };
+       };
 };
 
 &blsp1_uart2 {
index 109c9d2..71cf81a 100644 (file)
@@ -10,6 +10,7 @@
 #include <dt-bindings/interconnect/qcom,sc8280xp.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/mailbox/qcom-ipcc.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
 #include <dt-bindings/power/qcom-rpmpd.h>
 #include <dt-bindings/soc/qcom,rpmh-rsc.h>
 #include <dt-bindings/thermal/thermal.h>
                                 <0>,
                                 <0>,
                                 <0>,
-                                <&usb_0_ssphy>,
+                                <&usb_0_qmpphy QMP_USB43DP_USB3_PIPE_CLK>,
                                 <0>,
                                 <0>,
                                 <0>,
                                 <0>,
                                 <0>,
                                 <0>,
-                                <&usb_1_ssphy>,
+                                <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>,
                                 <0>,
                                 <0>,
                                 <0>,
                        };
                };
 
-               usb_0_qmpphy: phy-wrapper@88ec000 {
+               usb_0_qmpphy: phy@88eb000 {
                        compatible = "qcom,sc8280xp-qmp-usb43dp-phy";
-                       reg = <0 0x088ec000 0 0x1e4>,
-                             <0 0x088eb000 0 0x40>,
-                             <0 0x088ed000 0 0x1c8>;
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       reg = <0 0x088eb000 0 0x4000>;
 
                        clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>,
-                                <&rpmhcc RPMH_CXO_CLK>,
                                 <&gcc GCC_USB4_EUD_CLKREF_CLK>,
-                                <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>;
-                       clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+                                <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>,
+                                <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+                       clock-names = "aux", "ref", "com_aux", "usb3_pipe";
+
+                       power-domains = <&gcc USB30_PRIM_GDSC>;
 
                        resets = <&gcc GCC_USB3_PHY_PRIM_BCR>,
-                                <&gcc GCC_USB3_DP_PHY_PRIM_BCR>;
+                                <&gcc GCC_USB4_DP_PHY_PRIM_BCR>;
                        reset-names = "phy", "common";
 
-                       power-domains = <&gcc USB30_PRIM_GDSC>;
+                       #clock-cells = <1>;
+                       #phy-cells = <1>;
 
                        status = "disabled";
-
-                       usb_0_ssphy: usb3-phy@88eb400 {
-                               reg = <0 0x088eb400 0 0x100>,
-                                     <0 0x088eb600 0 0x3ec>,
-                                     <0 0x088ec400 0 0x364>,
-                                     <0 0x088eba00 0 0x100>,
-                                     <0 0x088ebc00 0 0x3ec>,
-                                     <0 0x088ec200 0 0x18>;
-                               #phy-cells = <0>;
-                               #clock-cells = <0>;
-                               clocks = <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
-                               clock-names = "pipe0";
-                               clock-output-names = "usb0_phy_pipe_clk_src";
-                       };
                };
 
                usb_1_hsphy: phy@8902000 {
                        status = "disabled";
                };
 
-               usb_1_qmpphy: phy-wrapper@8904000 {
+               usb_1_qmpphy: phy@8903000 {
                        compatible = "qcom,sc8280xp-qmp-usb43dp-phy";
-                       reg = <0 0x08904000 0 0x1e4>,
-                             <0 0x08903000 0 0x40>,
-                             <0 0x08905000 0 0x1c8>;
-                       #address-cells = <2>;
-                       #size-cells = <2>;
-                       ranges;
+                       reg = <0 0x08903000 0 0x4000>;
 
                        clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
-                                <&rpmhcc RPMH_CXO_CLK>,
                                 <&gcc GCC_USB4_CLKREF_CLK>,
-                                <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>;
-                       clock-names = "aux", "ref_clk_src", "ref", "com_aux";
+                                <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
+                                <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
+                       clock-names = "aux", "ref", "com_aux", "usb3_pipe";
+
+                       power-domains = <&gcc USB30_SEC_GDSC>;
 
                        resets = <&gcc GCC_USB3_PHY_SEC_BCR>,
                                 <&gcc GCC_USB4_1_DP_PHY_PRIM_BCR>;
                        reset-names = "phy", "common";
 
-                       power-domains = <&gcc USB30_SEC_GDSC>;
+                       #clock-cells = <1>;
+                       #phy-cells = <1>;
 
                        status = "disabled";
-
-                       usb_1_ssphy: usb3-phy@8903400 {
-                               reg = <0 0x08903400 0 0x100>,
-                                     <0 0x08903600 0 0x3ec>,
-                                     <0 0x08904400 0 0x364>,
-                                     <0 0x08903a00 0 0x100>,
-                                     <0 0x08903c00 0 0x3ec>,
-                                     <0 0x08904200 0 0x18>;
-                               #phy-cells = <0>;
-                               #clock-cells = <0>;
-                               clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
-                               clock-names = "pipe0";
-                               clock-output-names = "usb1_phy_pipe_clk_src";
-                       };
                };
 
                pmu@9091000 {
                                reg = <0 0x0a600000 0 0xcd00>;
                                interrupts = <GIC_SPI 803 IRQ_TYPE_LEVEL_HIGH>;
                                iommus = <&apps_smmu 0x820 0x0>;
-                               phys = <&usb_0_hsphy>, <&usb_0_ssphy>;
+                               phys = <&usb_0_hsphy>, <&usb_0_qmpphy QMP_USB43DP_USB3_PHY>;
                                phy-names = "usb2-phy", "usb3-phy";
                        };
                };
                                reg = <0 0x0a800000 0 0xcd00>;
                                interrupts = <GIC_SPI 810 IRQ_TYPE_LEVEL_HIGH>;
                                iommus = <&apps_smmu 0x860 0x0>;
-                               phys = <&usb_1_hsphy>, <&usb_1_ssphy>;
+                               phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>;
                                phy-names = "usb2-phy", "usb3-phy";
                        };
                };
index dab5579..9270328 100644 (file)
                                exit-latency-us = <6562>;
                                min-residency-us = <9987>;
                                local-timer-stop;
-                               status = "disabled";
                        };
                };
        };
index 245dce2..fb3cd20 100644 (file)
                                 <&rpmhcc RPMH_CXO_CLK>;
                        clock-names = "iface", "core", "xo";
                        resets = <&gcc GCC_SDCC2_BCR>;
-                       interconnects = <&aggre2_noc MASTER_SDCC_2 0 &mc_virt SLAVE_EBI1 0>,
-                                       <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_SDCC_2 0>;
+                       interconnects = <&aggre2_noc MASTER_SDCC_2 &mc_virt SLAVE_EBI1>,
+                                       <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_SDCC_2>;
                        interconnect-names = "sdhc-ddr","cpu-sdhc";
                        iommus = <&apps_smmu 0x4a0 0x0>;
                        power-domains = <&rpmhpd SM8350_CX>;
index aa22a0c..5d5d957 100644 (file)
@@ -96,7 +96,6 @@
                        linux,default-trigger = "heartbeat";
                        gpios = <&rk805 1 GPIO_ACTIVE_LOW>;
                        default-state = "on";
-                       mode = <0x23>;
                };
 
                user_led: led-1 {
                        linux,default-trigger = "mmc1";
                        gpios = <&rk805 0 GPIO_ACTIVE_LOW>;
                        default-state = "off";
-                       mode = <0x05>;
                };
        };
 };
index 6e29e74..783120e 100644 (file)
                };
        };
 
-       dmc_opp_table: dmc_opp_table {
+       dmc_opp_table: opp-table-3 {
                compatible = "operating-points-v2";
 
                opp00 {
index 04403a7..a0795a2 100644 (file)
        };
 };
 
+&cpu_alert0 {
+       temperature = <65000>;
+};
+&cpu_alert1 {
+       temperature = <68000>;
+};
+
 &cpu_l0 {
        cpu-supply = <&vdd_cpu_l>;
 };
index 4391aea..1881b4b 100644 (file)
                clocks = <&cru HCLK_M_CRYPTO0>, <&cru HCLK_S_CRYPTO0>, <&cru SCLK_CRYPTO0>;
                clock-names = "hclk_master", "hclk_slave", "sclk";
                resets = <&cru SRST_CRYPTO0>, <&cru SRST_CRYPTO0_S>, <&cru SRST_CRYPTO0_M>;
-               reset-names = "master", "lave", "crypto";
+               reset-names = "master", "slave", "crypto-rst";
        };
 
        crypto1: crypto@ff8b8000 {
                clocks = <&cru HCLK_M_CRYPTO1>, <&cru HCLK_S_CRYPTO1>, <&cru SCLK_CRYPTO1>;
                clock-names = "hclk_master", "hclk_slave", "sclk";
                resets = <&cru SRST_CRYPTO1>, <&cru SRST_CRYPTO1_S>, <&cru SRST_CRYPTO1_M>;
-               reset-names = "master", "slave", "crypto";
+               reset-names = "master", "slave", "crypto-rst";
        };
 
        i2c1: i2c@ff110000 {
                pcfg_input_pull_up: pcfg-input-pull-up {
                        input-enable;
                        bias-pull-up;
-                       drive-strength = <2>;
                };
 
                pcfg_input_pull_down: pcfg-input-pull-down {
                        input-enable;
                        bias-pull-down;
-                       drive-strength = <2>;
                };
 
                clock {
index 4c7f9ab..d956496 100644 (file)
        };
 };
 
+&pmu_io_domains {
+       pmuio2-supply = <&vcc_3v3>;
+       vccio1-supply = <&vcc_3v3>;
+       vccio3-supply = <&vcc_3v3>;
+       vccio4-supply = <&vcca_1v8>;
+       vccio5-supply = <&vcc_3v3>;
+       vccio6-supply = <&vcca_1v8>;
+       vccio7-supply = <&vcc_3v3>;
+       status = "okay";
+};
+
 &pwm0 {
        status = "okay";
 };
index a1c5fdf..3c9d852 100644 (file)
 };
 
 &i2s1_8ch {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2s1m0_sclktx &i2s1m0_lrcktx &i2s1m0_sdi0 &i2s1m0_sdo0>;
        rockchip,trcm-sync-tx-only;
        status = "okay";
 };
        disable-wp;
        pinctrl-names = "default";
        pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
-       sd-uhs-sdr104;
+       sd-uhs-sdr50;
        vmmc-supply = <&vcc3v3_sd>;
        vqmmc-supply = <&vccio_sd>;
        status = "okay";
 };
 
 &sdmmc2 {
-       supports-sdio;
        bus-width = <4>;
        disable-wp;
        cap-sd-highspeed;
index 5706c3e..c27f1c7 100644 (file)
                clock-names = "aclk_mst", "aclk_slv",
                              "aclk_dbi", "pclk", "aux";
                device_type = "pci";
+               #interrupt-cells = <1>;
                interrupt-map-mask = <0 0 0 7>;
                interrupt-map = <0 0 0 1 &pcie_intc 0>,
                                <0 0 0 2 &pcie_intc 1>,
index 0890e4f..cbb3d96 100644 (file)
@@ -315,7 +315,7 @@ __ll_sc__cmpxchg_double##name(unsigned long old1,                   \
        "       cbnz    %w0, 1b\n"                                      \
        "       " #mb "\n"                                              \
        "2:"                                                            \
-       : "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr)        \
+       : "=&r" (tmp), "=&r" (ret), "+Q" (*(__uint128_t *)ptr)          \
        : "r" (old1), "r" (old2), "r" (new1), "r" (new2)                \
        : cl);                                                          \
                                                                        \
index 52075e9..a94d6da 100644 (file)
@@ -311,7 +311,7 @@ __lse__cmpxchg_double##name(unsigned long old1,                             \
        "       eor     %[old2], %[old2], %[oldval2]\n"                 \
        "       orr     %[old1], %[old1], %[old2]"                      \
        : [old1] "+&r" (x0), [old2] "+&r" (x1),                         \
-         [v] "+Q" (*(unsigned long *)ptr)                              \
+         [v] "+Q" (*(__uint128_t *)ptr)                                \
        : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),             \
          [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)              \
        : cl);                                                          \
index 4e8b66c..683ca3a 100644 (file)
 #define APPLE_CPU_PART_M1_FIRESTORM_PRO        0x025
 #define APPLE_CPU_PART_M1_ICESTORM_MAX 0x028
 #define APPLE_CPU_PART_M1_FIRESTORM_MAX        0x029
+#define APPLE_CPU_PART_M2_BLIZZARD     0x032
+#define APPLE_CPU_PART_M2_AVALANCHE    0x033
 
 #define AMPERE_CPU_PART_AMPERE1                0xAC3
 
 #define MIDR_APPLE_M1_FIRESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO)
 #define MIDR_APPLE_M1_ICESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX)
 #define MIDR_APPLE_M1_FIRESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX)
+#define MIDR_APPLE_M2_BLIZZARD MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD)
+#define MIDR_APPLE_M2_AVALANCHE MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE)
 #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1)
 
 /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
index 31d13a6..de4ff90 100644 (file)
@@ -48,8 +48,17 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
 })
 
 extern spinlock_t efi_rt_lock;
+extern u64 *efi_rt_stack_top;
 efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
 
+/*
+ * efi_rt_stack_top[-1] contains the value the stack pointer had before
+ * switching to the EFI runtime stack.
+ */
+#define current_in_efi()                                               \
+       (!preemptible() && efi_rt_stack_top != NULL &&                  \
+        on_task_stack(current, READ_ONCE(efi_rt_stack_top[-1]), 1))
+
 #define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
 
 /*
index 15b34fb..206de10 100644 (file)
 #define ESR_ELx_FSC_ACCESS     (0x08)
 #define ESR_ELx_FSC_FAULT      (0x04)
 #define ESR_ELx_FSC_PERM       (0x0C)
+#define ESR_ELx_FSC_SEA_TTW0   (0x14)
+#define ESR_ELx_FSC_SEA_TTW1   (0x15)
+#define ESR_ELx_FSC_SEA_TTW2   (0x16)
+#define ESR_ELx_FSC_SEA_TTW3   (0x17)
+#define ESR_ELx_FSC_SECC       (0x18)
+#define ESR_ELx_FSC_SECC_TTW0  (0x1c)
+#define ESR_ELx_FSC_SECC_TTW1  (0x1d)
+#define ESR_ELx_FSC_SECC_TTW2  (0x1e)
+#define ESR_ELx_FSC_SECC_TTW3  (0x1f)
 
 /* ISS field definitions for Data Aborts */
 #define ESR_ELx_ISV_SHIFT      (24)
index d20f5da..6a4a1ab 100644 (file)
@@ -49,6 +49,15 @@ extern pte_t huge_ptep_get(pte_t *ptep);
 
 void __init arm64_hugetlb_cma_reserve(void);
 
+#define huge_ptep_modify_prot_start huge_ptep_modify_prot_start
+extern pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma,
+                                        unsigned long addr, pte_t *ptep);
+
+#define huge_ptep_modify_prot_commit huge_ptep_modify_prot_commit
+extern void huge_ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                        unsigned long addr, pte_t *ptep,
+                                        pte_t old_pte, pte_t new_pte);
+
 #include <asm-generic/hugetlb.h>
 
 #endif /* __ASM_HUGETLB_H */
index 0df3fc3..26b0c97 100644 (file)
                                 BIT(18) |              \
                                 GENMASK(16, 15))
 
-/* For compatibility with fault code shared with 32-bit */
-#define FSC_FAULT      ESR_ELx_FSC_FAULT
-#define FSC_ACCESS     ESR_ELx_FSC_ACCESS
-#define FSC_PERM       ESR_ELx_FSC_PERM
-#define FSC_SEA                ESR_ELx_FSC_EXTABT
-#define FSC_SEA_TTW0   (0x14)
-#define FSC_SEA_TTW1   (0x15)
-#define FSC_SEA_TTW2   (0x16)
-#define FSC_SEA_TTW3   (0x17)
-#define FSC_SECC       (0x18)
-#define FSC_SECC_TTW0  (0x1c)
-#define FSC_SECC_TTW1  (0x1d)
-#define FSC_SECC_TTW2  (0x1e)
-#define FSC_SECC_TTW3  (0x1f)
-
 /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
 #define HPFAR_MASK     (~UL(0xf))
 /*
index 9bdba47..193583d 100644 (file)
@@ -349,16 +349,16 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *v
 static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
 {
        switch (kvm_vcpu_trap_get_fault(vcpu)) {
-       case FSC_SEA:
-       case FSC_SEA_TTW0:
-       case FSC_SEA_TTW1:
-       case FSC_SEA_TTW2:
-       case FSC_SEA_TTW3:
-       case FSC_SECC:
-       case FSC_SECC_TTW0:
-       case FSC_SECC_TTW1:
-       case FSC_SECC_TTW2:
-       case FSC_SECC_TTW3:
+       case ESR_ELx_FSC_EXTABT:
+       case ESR_ELx_FSC_SEA_TTW0:
+       case ESR_ELx_FSC_SEA_TTW1:
+       case ESR_ELx_FSC_SEA_TTW2:
+       case ESR_ELx_FSC_SEA_TTW3:
+       case ESR_ELx_FSC_SECC:
+       case ESR_ELx_FSC_SECC_TTW0:
+       case ESR_ELx_FSC_SECC_TTW1:
+       case ESR_ELx_FSC_SECC_TTW2:
+       case ESR_ELx_FSC_SECC_TTW3:
                return true;
        default:
                return false;
@@ -373,8 +373,26 @@ static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 
 static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
 {
-       if (kvm_vcpu_abt_iss1tw(vcpu))
-               return true;
+       if (kvm_vcpu_abt_iss1tw(vcpu)) {
+               /*
+                * Only a permission fault on a S1PTW should be
+                * considered as a write. Otherwise, page tables baked
+                * in a read-only memslot will result in an exception
+                * being delivered in the guest.
+                *
+                * The drawback is that we end-up faulting twice if the
+                * guest is using any of HW AF/DB: a translation fault
+                * to map the page containing the PT (read only at
+                * first), then a permission fault to allow the flags
+                * to be set.
+                */
+               switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
+               case ESR_ELx_FSC_PERM:
+                       return true;
+               default:
+                       return false;
+               }
+       }
 
        if (kvm_vcpu_trap_is_iabt(vcpu))
                return false;
index b4bbeed..65e7899 100644 (file)
@@ -681,7 +681,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
 #define pud_leaf(pud)          (pud_present(pud) && !pud_table(pud))
 #define pud_valid(pud)         pte_valid(pud_pte(pud))
 #define pud_user(pud)          pte_user(pud_pte(pud))
-
+#define pud_user_exec(pud)     pte_user_exec(pud_pte(pud))
 
 static inline void set_pud(pud_t *pudp, pud_t pud)
 {
@@ -730,6 +730,7 @@ static inline pmd_t *pud_pgtable(pud_t pud)
 #else
 
 #define pud_page_paddr(pud)    ({ BUILD_BUG(); 0; })
+#define pud_user_exec(pud)     pud_user(pud) /* Always 0 with folding */
 
 /* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */
 #define pmd_set_fixmap(addr)           NULL
@@ -862,12 +863,12 @@ static inline bool pte_user_accessible_page(pte_t pte)
 
 static inline bool pmd_user_accessible_page(pmd_t pmd)
 {
-       return pmd_leaf(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
+       return pmd_leaf(pmd) && !pmd_present_invalid(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
 }
 
 static inline bool pud_user_accessible_page(pud_t pud)
 {
-       return pud_leaf(pud) && pud_user(pud);
+       return pud_leaf(pud) && (pud_user(pud) || pud_user_exec(pud));
 }
 #endif
 
@@ -1093,6 +1094,15 @@ static inline bool pud_sect_supported(void)
 }
 
 
+#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+#define ptep_modify_prot_start ptep_modify_prot_start
+extern pte_t ptep_modify_prot_start(struct vm_area_struct *vma,
+                                   unsigned long addr, pte_t *ptep);
+
+#define ptep_modify_prot_commit ptep_modify_prot_commit
+extern void ptep_modify_prot_commit(struct vm_area_struct *vma,
+                                   unsigned long addr, pte_t *ptep,
+                                   pte_t old_pte, pte_t new_pte);
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_PGTABLE_H */
index 4e5354b..66ec8ca 100644 (file)
@@ -106,4 +106,19 @@ static inline struct stack_info stackinfo_get_sdei_critical(void)
 #define stackinfo_get_sdei_critical()  stackinfo_get_unknown()
 #endif
 
+#ifdef CONFIG_EFI
+extern u64 *efi_rt_stack_top;
+
+static inline struct stack_info stackinfo_get_efi(void)
+{
+       unsigned long high = (u64)efi_rt_stack_top;
+       unsigned long low = high - THREAD_SIZE;
+
+       return (struct stack_info) {
+               .low = low,
+               .high = high,
+       };
+}
+#endif
+
 #endif /* __ASM_STACKTRACE_H */
index ba4bff5..2b09495 100644 (file)
@@ -16,7 +16,7 @@
 #define UPROBE_SWBP_INSN_SIZE  AARCH64_INSN_SIZE
 #define UPROBE_XOL_SLOT_BYTES  MAX_UINSN_BYTES
 
-typedef u32 uprobe_opcode_t;
+typedef __le32 uprobe_opcode_t;
 
 struct arch_uprobe_task {
 };
index 89ac000..307faa2 100644 (file)
@@ -661,6 +661,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                CAP_MIDR_RANGE_LIST(trbe_write_out_of_range_cpus),
        },
 #endif
+#ifdef CONFIG_ARM64_ERRATUM_2645198
+       {
+               .desc = "ARM erratum 2645198",
+               .capability = ARM64_WORKAROUND_2645198,
+               ERRATA_MIDR_ALL_VERSIONS(MIDR_CORTEX_A715)
+       },
+#endif
 #ifdef CONFIG_ARM64_ERRATUM_2077057
        {
                .desc = "ARM erratum 2077057",
index a008864..e8ae803 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 
 SYM_FUNC_START(__efi_rt_asm_wrapper)
        stp     x29, x30, [sp, #-112]!
@@ -45,7 +46,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
        mov     x4, x6
        blr     x8
 
+       mov     x16, sp
        mov     sp, x29
+       str     xzr, [x16, #8]                  // clear recorded task SP value
+
        ldp     x1, x2, [sp, #16]
        cmp     x2, x18
        ldp     x29, x30, [sp], #112
@@ -70,6 +74,9 @@ SYM_FUNC_END(__efi_rt_asm_wrapper)
 SYM_CODE_START(__efi_rt_asm_recover)
        mov     sp, x30
 
+       ldr_l   x16, efi_rt_stack_top           // clear recorded task SP value
+       str     xzr, [x16, #-8]
+
        ldp     x19, x20, [sp, #32]
        ldp     x21, x22, [sp, #48]
        ldp     x23, x24, [sp, #64]
index fab05de..b273900 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 
 #include <asm/efi.h>
+#include <asm/stacktrace.h>
 
 static bool region_is_misaligned(const efi_memory_desc_t *md)
 {
@@ -154,7 +155,7 @@ asmlinkage efi_status_t __efi_rt_asm_recover(void);
 bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
 {
         /* Check whether the exception occurred while running the firmware */
-       if (current_work() != &efi_rts_work.work || regs->pc >= TASK_SIZE_64)
+       if (!current_in_efi() || regs->pc >= TASK_SIZE_64)
                return false;
 
        pr_err(FW_BUG "Unable to handle %s in EFI runtime service\n", msg);
index 353009d..2e94d20 100644 (file)
@@ -8,28 +8,27 @@
 #include <asm/cpufeature.h>
 #include <asm/mte.h>
 
-#define for_each_mte_vma(vmi, vma)                                     \
+#define for_each_mte_vma(cprm, i, m)                                   \
        if (system_supports_mte())                                      \
-               for_each_vma(vmi, vma)                                  \
-                       if (vma->vm_flags & VM_MTE)
+               for (i = 0, m = cprm->vma_meta;                         \
+                    i < cprm->vma_count;                               \
+                    i++, m = cprm->vma_meta + i)                       \
+                       if (m->flags & VM_MTE)
 
-static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
+static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
 {
-       if (vma->vm_flags & VM_DONTDUMP)
-               return 0;
-
-       return vma_pages(vma) * MTE_PAGE_TAG_STORAGE;
+       return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
 }
 
 /* Derived from dump_user_range(); start/end must be page-aligned */
 static int mte_dump_tag_range(struct coredump_params *cprm,
-                             unsigned long start, unsigned long end)
+                             unsigned long start, unsigned long len)
 {
        int ret = 1;
        unsigned long addr;
        void *tags = NULL;
 
-       for (addr = start; addr < end; addr += PAGE_SIZE) {
+       for (addr = start; addr < start + len; addr += PAGE_SIZE) {
                struct page *page = get_dump_page(addr);
 
                /*
@@ -65,7 +64,6 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
                mte_save_page_tags(page_address(page), tags);
                put_page(page);
                if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
-                       mte_free_tag_storage(tags);
                        ret = 0;
                        break;
                }
@@ -77,13 +75,13 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
        return ret;
 }
 
-Elf_Half elf_core_extra_phdrs(void)
+Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
 {
-       struct vm_area_struct *vma;
+       int i;
+       struct core_vma_metadata *m;
        int vma_count = 0;
-       VMA_ITERATOR(vmi, current->mm, 0);
 
-       for_each_mte_vma(vmi, vma)
+       for_each_mte_vma(cprm, i, m)
                vma_count++;
 
        return vma_count;
@@ -91,18 +89,18 @@ Elf_Half elf_core_extra_phdrs(void)
 
 int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
 {
-       struct vm_area_struct *vma;
-       VMA_ITERATOR(vmi, current->mm, 0);
+       int i;
+       struct core_vma_metadata *m;
 
-       for_each_mte_vma(vmi, vma) {
+       for_each_mte_vma(cprm, i, m) {
                struct elf_phdr phdr;
 
                phdr.p_type = PT_AARCH64_MEMTAG_MTE;
                phdr.p_offset = offset;
-               phdr.p_vaddr = vma->vm_start;
+               phdr.p_vaddr = m->start;
                phdr.p_paddr = 0;
-               phdr.p_filesz = mte_vma_tag_dump_size(vma);
-               phdr.p_memsz = vma->vm_end - vma->vm_start;
+               phdr.p_filesz = mte_vma_tag_dump_size(m);
+               phdr.p_memsz = m->end - m->start;
                offset += phdr.p_filesz;
                phdr.p_flags = 0;
                phdr.p_align = 0;
@@ -114,28 +112,25 @@ int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
        return 1;
 }
 
-size_t elf_core_extra_data_size(void)
+size_t elf_core_extra_data_size(struct coredump_params *cprm)
 {
-       struct vm_area_struct *vma;
+       int i;
+       struct core_vma_metadata *m;
        size_t data_size = 0;
-       VMA_ITERATOR(vmi, current->mm, 0);
 
-       for_each_mte_vma(vmi, vma)
-               data_size += mte_vma_tag_dump_size(vma);
+       for_each_mte_vma(cprm, i, m)
+               data_size += mte_vma_tag_dump_size(m);
 
        return data_size;
 }
 
 int elf_core_write_extra_data(struct coredump_params *cprm)
 {
-       struct vm_area_struct *vma;
-       VMA_ITERATOR(vmi, current->mm, 0);
-
-       for_each_mte_vma(vmi, vma) {
-               if (vma->vm_flags & VM_DONTDUMP)
-                       continue;
+       int i;
+       struct core_vma_metadata *m;
 
-               if (!mte_dump_tag_range(cprm, vma->vm_start, vma->vm_end))
+       for_each_mte_vma(cprm, i, m) {
+               if (!mte_dump_tag_range(cprm, m->start, m->dump_size))
                        return 0;
        }
 
index dcc81e7..b6ef1af 100644 (file)
@@ -385,7 +385,7 @@ static void task_fpsimd_load(void)
        WARN_ON(!system_supports_fpsimd());
        WARN_ON(!have_cpu_fpsimd_context());
 
-       if (system_supports_sve()) {
+       if (system_supports_sve() || system_supports_sme()) {
                switch (current->thread.fp_type) {
                case FP_STATE_FPSIMD:
                        /* Stop tracking SVE for this task until next use. */
index 2686ab1..0c321ad 100644 (file)
@@ -1357,7 +1357,7 @@ enum aarch64_regset {
 #ifdef CONFIG_ARM64_SVE
        REGSET_SVE,
 #endif
-#ifdef CONFIG_ARM64_SVE
+#ifdef CONFIG_ARM64_SME
        REGSET_SSVE,
        REGSET_ZA,
 #endif
index e0d09bf..be279fd 100644 (file)
@@ -281,7 +281,12 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
 
                vl = task_get_sme_vl(current);
        } else {
-               if (!system_supports_sve())
+               /*
+                * A SME only system use SVE for streaming mode so can
+                * have a SVE formatted context with a zero VL and no
+                * payload data.
+                */
+               if (!system_supports_sve() && !system_supports_sme())
                        return -EINVAL;
 
                vl = task_get_sve_vl(current);
@@ -732,7 +737,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
                        return err;
        }
 
-       if (system_supports_sve()) {
+       if (system_supports_sve() || system_supports_sme()) {
                unsigned int vq = 0;
 
                if (add_all || test_thread_flag(TIF_SVE) ||
index 117e2c1..8315430 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 #include <linux/kernel.h>
+#include <linux/efi.h>
 #include <linux/export.h>
 #include <linux/ftrace.h>
 #include <linux/sched.h>
@@ -12,6 +13,7 @@
 #include <linux/sched/task_stack.h>
 #include <linux/stacktrace.h>
 
+#include <asm/efi.h>
 #include <asm/irq.h>
 #include <asm/stack_pointer.h>
 #include <asm/stacktrace.h>
@@ -186,6 +188,13 @@ void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
                        : stackinfo_get_unknown();              \
        })
 
+#define STACKINFO_EFI                                          \
+       ({                                                      \
+               ((task == current) && current_in_efi())         \
+                       ? stackinfo_get_efi()                   \
+                       : stackinfo_get_unknown();              \
+       })
+
 noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
                              void *cookie, struct task_struct *task,
                              struct pt_regs *regs)
@@ -199,6 +208,9 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
 #if defined(CONFIG_VMAP_STACK) && defined(CONFIG_ARM_SDE_INTERFACE)
                STACKINFO_SDEI(normal),
                STACKINFO_SDEI(critical),
+#endif
+#ifdef CONFIG_EFI
+               STACKINFO_EFI,
 #endif
        };
        struct unwind_state state = {
index 5626ddb..cf4c495 100644 (file)
@@ -1079,7 +1079,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
 
                        /* uaccess failed, don't leave stale tags */
                        if (num_tags != MTE_GRANULES_PER_PAGE)
-                               mte_clear_page_tags(page);
+                               mte_clear_page_tags(maddr);
                        set_page_mte_tagged(page);
 
                        kvm_release_pfn_dirty(pfn);
index 1b8a2dc..9ddcfe2 100644 (file)
@@ -60,7 +60,7 @@ static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault)
         */
        if (!(esr & ESR_ELx_S1PTW) &&
            (cpus_have_final_cap(ARM64_WORKAROUND_834220) ||
-            (esr & ESR_ELx_FSC_TYPE) == FSC_PERM)) {
+            (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM)) {
                if (!__translate_far_to_hpfar(far, &hpfar))
                        return false;
        } else {
index 3330d1b..07d37ff 100644 (file)
@@ -367,7 +367,7 @@ static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
        if (static_branch_unlikely(&vgic_v2_cpuif_trap)) {
                bool valid;
 
-               valid = kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
+               valid = kvm_vcpu_trap_get_fault_type(vcpu) == ESR_ELx_FSC_FAULT &&
                        kvm_vcpu_dabt_isvalid(vcpu) &&
                        !kvm_vcpu_abt_issea(vcpu) &&
                        !kvm_vcpu_abt_iss1tw(vcpu);
index 31d7fa4..a3ee3b6 100644 (file)
@@ -1212,7 +1212,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
        exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
        VM_BUG_ON(write_fault && exec_fault);
 
-       if (fault_status == FSC_PERM && !write_fault && !exec_fault) {
+       if (fault_status == ESR_ELx_FSC_PERM && !write_fault && !exec_fault) {
                kvm_err("Unexpected L2 read permission error\n");
                return -EFAULT;
        }
@@ -1277,7 +1277,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
         * only exception to this is when dirty logging is enabled at runtime
         * and a write fault needs to collapse a block entry into a table.
         */
-       if (fault_status != FSC_PERM || (logging_active && write_fault)) {
+       if (fault_status != ESR_ELx_FSC_PERM ||
+           (logging_active && write_fault)) {
                ret = kvm_mmu_topup_memory_cache(memcache,
                                                 kvm_mmu_cache_min_pages(kvm));
                if (ret)
@@ -1342,7 +1343,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
         * backed by a THP and thus use block mapping if possible.
         */
        if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) {
-               if (fault_status == FSC_PERM && fault_granule > PAGE_SIZE)
+               if (fault_status ==  ESR_ELx_FSC_PERM &&
+                   fault_granule > PAGE_SIZE)
                        vma_pagesize = fault_granule;
                else
                        vma_pagesize = transparent_hugepage_adjust(kvm, memslot,
@@ -1350,7 +1352,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                                                                   &fault_ipa);
        }
 
-       if (fault_status != FSC_PERM && !device && kvm_has_mte(kvm)) {
+       if (fault_status != ESR_ELx_FSC_PERM && !device && kvm_has_mte(kvm)) {
                /* Check the VMM hasn't introduced a new disallowed VMA */
                if (kvm_vma_mte_allowed(vma)) {
                        sanitise_mte_tags(kvm, pfn, vma_pagesize);
@@ -1376,7 +1378,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
         * permissions only if vma_pagesize equals fault_granule. Otherwise,
         * kvm_pgtable_stage2_map() should be called to change block size.
         */
-       if (fault_status == FSC_PERM && vma_pagesize == fault_granule)
+       if (fault_status == ESR_ELx_FSC_PERM && vma_pagesize == fault_granule)
                ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
        else
                ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,
@@ -1441,7 +1443,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
        fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
        is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
 
-       if (fault_status == FSC_FAULT) {
+       if (fault_status == ESR_ELx_FSC_FAULT) {
                /* Beyond sanitised PARange (which is the IPA limit) */
                if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
                        kvm_inject_size_fault(vcpu);
@@ -1476,8 +1478,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
                              kvm_vcpu_get_hfar(vcpu), fault_ipa);
 
        /* Check the stage-2 fault is trans. fault or write fault */
-       if (fault_status != FSC_FAULT && fault_status != FSC_PERM &&
-           fault_status != FSC_ACCESS) {
+       if (fault_status != ESR_ELx_FSC_FAULT &&
+           fault_status != ESR_ELx_FSC_PERM &&
+           fault_status != ESR_ELx_FSC_ACCESS) {
                kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
                        kvm_vcpu_trap_get_class(vcpu),
                        (unsigned long)kvm_vcpu_trap_get_fault(vcpu),
@@ -1539,7 +1542,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
        /* Userspace should not be able to register out-of-bounds IPAs */
        VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->kvm));
 
-       if (fault_status == FSC_ACCESS) {
+       if (fault_status == ESR_ELx_FSC_ACCESS) {
                handle_access_fault(vcpu, fault_ipa);
                ret = 1;
                goto out_unlock;
index d5ee52d..c6cbfe6 100644 (file)
@@ -646,7 +646,7 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
                return;
 
        /* Only preserve PMCR_EL0.N, and reset the rest to 0 */
-       pmcr = read_sysreg(pmcr_el0) & ARMV8_PMU_PMCR_N_MASK;
+       pmcr = read_sysreg(pmcr_el0) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT);
        if (!kvm_supports_32bit_el0())
                pmcr |= ARMV8_PMU_PMCR_LC;
 
index 94a666d..2642e9c 100644 (file)
@@ -2187,7 +2187,7 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
               ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
                ite->collection->collection_id;
        val = cpu_to_le64(val);
-       return kvm_write_guest_lock(kvm, gpa, &val, ite_esz);
+       return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
 }
 
 /**
@@ -2339,7 +2339,7 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
               (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
                (dev->num_eventid_bits - 1));
        val = cpu_to_le64(val);
-       return kvm_write_guest_lock(kvm, ptr, &val, dte_esz);
+       return vgic_write_guest_lock(kvm, ptr, &val, dte_esz);
 }
 
 /**
@@ -2526,7 +2526,7 @@ static int vgic_its_save_cte(struct vgic_its *its,
               ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
               collection->collection_id);
        val = cpu_to_le64(val);
-       return kvm_write_guest_lock(its->dev->kvm, gpa, &val, esz);
+       return vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz);
 }
 
 /*
@@ -2607,7 +2607,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
         */
        val = 0;
        BUG_ON(cte_esz > sizeof(val));
-       ret = kvm_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
+       ret = vgic_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
        return ret;
 }
 
@@ -2743,7 +2743,6 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
 {
        const struct vgic_its_abi *abi = vgic_its_get_abi(its);
-       struct vgic_dist *dist = &kvm->arch.vgic;
        int ret = 0;
 
        if (attr == KVM_DEV_ARM_VGIC_CTRL_INIT) /* Nothing to do */
@@ -2763,9 +2762,7 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
                vgic_its_reset(kvm, its);
                break;
        case KVM_DEV_ARM_ITS_SAVE_TABLES:
-               dist->save_its_tables_in_progress = true;
                ret = abi->save_tables(its);
-               dist->save_its_tables_in_progress = false;
                break;
        case KVM_DEV_ARM_ITS_RESTORE_TABLES:
                ret = abi->restore_tables(its);
@@ -2792,7 +2789,7 @@ bool kvm_arch_allow_write_without_running_vcpu(struct kvm *kvm)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
 
-       return dist->save_its_tables_in_progress;
+       return dist->table_write_in_progress;
 }
 
 static int vgic_its_set_attr(struct kvm_device *dev,
index 826ff6f..684bdfa 100644 (file)
@@ -339,7 +339,7 @@ retry:
        if (status) {
                /* clear consumed data */
                val &= ~(1 << bit_nr);
-               ret = kvm_write_guest_lock(kvm, ptr, &val, 1);
+               ret = vgic_write_guest_lock(kvm, ptr, &val, 1);
                if (ret)
                        return ret;
        }
@@ -350,26 +350,23 @@ retry:
  * The deactivation of the doorbell interrupt will trigger the
  * unmapping of the associated vPE.
  */
-static void unmap_all_vpes(struct vgic_dist *dist)
+static void unmap_all_vpes(struct kvm *kvm)
 {
-       struct irq_desc *desc;
+       struct vgic_dist *dist = &kvm->arch.vgic;
        int i;
 
-       for (i = 0; i < dist->its_vm.nr_vpes; i++) {
-               desc = irq_to_desc(dist->its_vm.vpes[i]->irq);
-               irq_domain_deactivate_irq(irq_desc_get_irq_data(desc));
-       }
+       for (i = 0; i < dist->its_vm.nr_vpes; i++)
+               free_irq(dist->its_vm.vpes[i]->irq, kvm_get_vcpu(kvm, i));
 }
 
-static void map_all_vpes(struct vgic_dist *dist)
+static void map_all_vpes(struct kvm *kvm)
 {
-       struct irq_desc *desc;
+       struct vgic_dist *dist = &kvm->arch.vgic;
        int i;
 
-       for (i = 0; i < dist->its_vm.nr_vpes; i++) {
-               desc = irq_to_desc(dist->its_vm.vpes[i]->irq);
-               irq_domain_activate_irq(irq_desc_get_irq_data(desc), false);
-       }
+       for (i = 0; i < dist->its_vm.nr_vpes; i++)
+               WARN_ON(vgic_v4_request_vpe_irq(kvm_get_vcpu(kvm, i),
+                                               dist->its_vm.vpes[i]->irq));
 }
 
 /**
@@ -394,7 +391,7 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
         * and enabling of the doorbells have already been done.
         */
        if (kvm_vgic_global_state.has_gicv4_1) {
-               unmap_all_vpes(dist);
+               unmap_all_vpes(kvm);
                vlpi_avail = true;
        }
 
@@ -437,14 +434,14 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
                else
                        val &= ~(1 << bit_nr);
 
-               ret = kvm_write_guest_lock(kvm, ptr, &val, 1);
+               ret = vgic_write_guest_lock(kvm, ptr, &val, 1);
                if (ret)
                        goto out;
        }
 
 out:
        if (vlpi_avail)
-               map_all_vpes(dist);
+               map_all_vpes(kvm);
 
        return ret;
 }
@@ -616,6 +613,8 @@ static const struct midr_range broken_seis[] = {
        MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM_PRO),
        MIDR_ALL_VERSIONS(MIDR_APPLE_M1_ICESTORM_MAX),
        MIDR_ALL_VERSIONS(MIDR_APPLE_M1_FIRESTORM_MAX),
+       MIDR_ALL_VERSIONS(MIDR_APPLE_M2_BLIZZARD),
+       MIDR_ALL_VERSIONS(MIDR_APPLE_M2_AVALANCHE),
        {},
 };
 
index ad06ba6..a413718 100644 (file)
@@ -222,6 +222,11 @@ void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val)
        *val = !!(*ptr & mask);
 }
 
+int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq)
+{
+       return request_irq(irq, vgic_v4_doorbell_handler, 0, "vcpu", vcpu);
+}
+
 /**
  * vgic_v4_init - Initialize the GICv4 data structures
  * @kvm:       Pointer to the VM being initialized
@@ -283,8 +288,7 @@ int vgic_v4_init(struct kvm *kvm)
                        irq_flags &= ~IRQ_NOAUTOEN;
                irq_set_status_flags(irq, irq_flags);
 
-               ret = request_irq(irq, vgic_v4_doorbell_handler,
-                                 0, "vcpu", vcpu);
+               ret = vgic_v4_request_vpe_irq(vcpu, irq);
                if (ret) {
                        kvm_err("failed to allocate vcpu IRQ%d\n", irq);
                        /*
index 0c8da72..7f7f3c5 100644 (file)
@@ -6,6 +6,7 @@
 #define __KVM_ARM_VGIC_NEW_H__
 
 #include <linux/irqchip/arm-gic-common.h>
+#include <asm/kvm_mmu.h>
 
 #define PRODUCT_ID_KVM         0x4b    /* ASCII code K */
 #define IMPLEMENTER_ARM                0x43b
@@ -131,6 +132,19 @@ static inline bool vgic_irq_is_multi_sgi(struct vgic_irq *irq)
        return vgic_irq_get_lr_count(irq) > 1;
 }
 
+static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,
+                                       const void *data, unsigned long len)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+       int ret;
+
+       dist->table_write_in_progress = true;
+       ret = kvm_write_guest_lock(kvm, gpa, data, len);
+       dist->table_write_in_progress = false;
+
+       return ret;
+}
+
 /*
  * This struct provides an intermediate representation of the fields contained
  * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
@@ -331,5 +345,6 @@ int vgic_v4_init(struct kvm *kvm);
 void vgic_v4_teardown(struct kvm *kvm);
 void vgic_v4_configure_vsgis(struct kvm *kvm);
 void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val);
+int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq);
 
 #endif
index 35e9a46..95364e8 100644 (file)
@@ -559,3 +559,24 @@ bool __init arch_hugetlb_valid_size(unsigned long size)
 {
        return __hugetlb_valid_size(size);
 }
+
+pte_t huge_ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+       if (IS_ENABLED(CONFIG_ARM64_ERRATUM_2645198) &&
+           cpus_have_const_cap(ARM64_WORKAROUND_2645198)) {
+               /*
+                * Break-before-make (BBM) is required for all user space mappings
+                * when the permission changes from executable to non-executable
+                * in cases where cpu is affected with errata #2645198.
+                */
+               if (pte_user_exec(READ_ONCE(*ptep)))
+                       return huge_ptep_clear_flush(vma, addr, ptep);
+       }
+       return huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
+}
+
+void huge_ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
+                                 pte_t old_pte, pte_t pte)
+{
+       set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+}
index 14c87e8..d77c9f5 100644 (file)
@@ -1630,3 +1630,24 @@ static int __init prevent_bootmem_remove_init(void)
 }
 early_initcall(prevent_bootmem_remove_init);
 #endif
+
+pte_t ptep_modify_prot_start(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+       if (IS_ENABLED(CONFIG_ARM64_ERRATUM_2645198) &&
+           cpus_have_const_cap(ARM64_WORKAROUND_2645198)) {
+               /*
+                * Break-before-make (BBM) is required for all user space mappings
+                * when the permission changes from executable to non-executable
+                * in cases where cpu is affected with errata #2645198.
+                */
+               if (pte_user_exec(READ_ONCE(*ptep)))
+                       return ptep_clear_flush(vma, addr, ptep);
+       }
+       return ptep_get_and_clear(vma->vm_mm, addr, ptep);
+}
+
+void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep,
+                            pte_t old_pte, pte_t pte)
+{
+       set_pte_at(vma->vm_mm, addr, ptep, pte);
+}
index a86ee37..dfeb2c5 100644 (file)
@@ -71,6 +71,7 @@ WORKAROUND_2038923
 WORKAROUND_2064142
 WORKAROUND_2077057
 WORKAROUND_2457168
+WORKAROUND_2645198
 WORKAROUND_2658417
 WORKAROUND_TRBE_OVERWRITE_FILL_MODE
 WORKAROUND_TSB_FLUSH_FAILURE
index 9468052..8895df1 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/elf.h>
 
 
-Elf64_Half elf_core_extra_phdrs(void)
+Elf64_Half elf_core_extra_phdrs(struct coredump_params *cprm)
 {
        return GATE_EHDR->e_phnum;
 }
@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
        return 1;
 }
 
-size_t elf_core_extra_data_size(void)
+size_t elf_core_extra_data_size(struct coredump_params *cprm)
 {
        const struct elf_phdr *const gate_phdrs =
                (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
index f6a502e..6e948d0 100644 (file)
@@ -170,6 +170,9 @@ ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, u
 asmlinkage long
 ia64_clock_getres(const clockid_t which_clock, struct __kernel_timespec __user *tp)
 {
+       struct timespec64 rtn_tp;
+       s64 tick_ns;
+
        /*
         * ia64's clock_gettime() syscall is implemented as a vdso call
         * fsys_clock_gettime(). Currently it handles only
@@ -185,8 +188,8 @@ ia64_clock_getres(const clockid_t which_clock, struct __kernel_timespec __user *
        switch (which_clock) {
        case CLOCK_REALTIME:
        case CLOCK_MONOTONIC:
-               s64 tick_ns = DIV_ROUND_UP(NSEC_PER_SEC, local_cpu_data->itc_freq);
-               struct timespec64 rtn_tp = ns_to_timespec64(tick_ns);
+               tick_ns = DIV_ROUND_UP(NSEC_PER_SEC, local_cpu_data->itc_freq);
+               rtn_tp = ns_to_timespec64(tick_ns);
                return put_timespec64(&rtn_tp, tp);
        }
 
index 90f9d33..3418d32 100644 (file)
@@ -10,8 +10,6 @@
 #define FTRACE_REGS_PLT_IDX    1
 #define NR_FTRACE_PLTS         2
 
-#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
-
 #ifdef CONFIG_FUNCTION_TRACER
 
 #define MCOUNT_INSN_SIZE 4             /* sizeof mcount call */
index c00e151..7eedd83 100644 (file)
@@ -377,14 +377,6 @@ static inline bool unsigned_imm_check(unsigned long val, unsigned int bit)
        return val < (1UL << bit);
 }
 
-static inline unsigned long sign_extend(unsigned long val, unsigned int idx)
-{
-       if (!is_imm_negative(val, idx + 1))
-               return ((1UL << idx) - 1) & val;
-       else
-               return ~((1UL << idx) - 1) | val;
-}
-
 #define DEF_EMIT_REG0I26_FORMAT(NAME, OP)                              \
 static inline void emit_##NAME(union loongarch_instruction *insn,      \
                               int offset)                              \
@@ -401,6 +393,7 @@ static inline void emit_##NAME(union loongarch_instruction *insn,   \
 }
 
 DEF_EMIT_REG0I26_FORMAT(b, b_op)
+DEF_EMIT_REG0I26_FORMAT(bl, bl_op)
 
 #define DEF_EMIT_REG1I20_FORMAT(NAME, OP)                              \
 static inline void emit_##NAME(union loongarch_instruction *insn,      \
index f2b52b9..b9dce87 100644 (file)
@@ -8,7 +8,9 @@
 #define _ASM_UNWIND_H
 
 #include <linux/sched.h>
+#include <linux/ftrace.h>
 
+#include <asm/ptrace.h>
 #include <asm/stacktrace.h>
 
 enum unwinder_type {
@@ -20,11 +22,13 @@ struct unwind_state {
        char type; /* UNWINDER_XXX */
        struct stack_info stack_info;
        struct task_struct *task;
-       bool first, error, is_ftrace;
+       bool first, error, reset;
        int graph_idx;
        unsigned long sp, pc, ra;
 };
 
+bool default_next_frame(struct unwind_state *state);
+
 void unwind_start(struct unwind_state *state,
                  struct task_struct *task, struct pt_regs *regs);
 bool unwind_next_frame(struct unwind_state *state);
@@ -40,4 +44,39 @@ static inline bool unwind_error(struct unwind_state *state)
        return state->error;
 }
 
+#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
+
+static inline unsigned long unwind_graph_addr(struct unwind_state *state,
+                                       unsigned long pc, unsigned long cfa)
+{
+       return ftrace_graph_ret_addr(state->task, &state->graph_idx,
+                                    pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET));
+}
+
+static __always_inline void __unwind_start(struct unwind_state *state,
+                                       struct task_struct *task, struct pt_regs *regs)
+{
+       memset(state, 0, sizeof(*state));
+       if (regs) {
+               state->sp = regs->regs[3];
+               state->pc = regs->csr_era;
+               state->ra = regs->regs[1];
+       } else if (task && task != current) {
+               state->sp = thread_saved_fp(task);
+               state->pc = thread_saved_ra(task);
+               state->ra = 0;
+       } else {
+               state->sp = (unsigned long)__builtin_frame_address(0);
+               state->pc = (unsigned long)__builtin_return_address(0);
+               state->ra = 0;
+       }
+       state->task = task;
+       get_stack_info(state->sp, state->task, &state->stack_info);
+       state->pc = unwind_graph_addr(state, state->pc, state->sp);
+}
+
+static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
+{
+       return unwind_done(state) ? 0 : state->pc;
+}
 #endif /* _ASM_UNWIND_H */
index fcaa024..c8cfbd5 100644 (file)
@@ -8,7 +8,7 @@ extra-y         := vmlinux.lds
 obj-y          += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
                   traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \
                   elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
-                  alternative.o unaligned.o
+                  alternative.o unaligned.o unwind.o
 
 obj-$(CONFIG_ACPI)             += acpi.o
 obj-$(CONFIG_EFI)              += efi.o
index c5aebea..4ad1384 100644 (file)
@@ -74,7 +74,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
        switch (src->reg0i26_format.opcode) {
        case b_op:
        case bl_op:
-               jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 27);
+               jump_addr = cur_pc + sign_extend64((si_h << 16 | si_l) << 2, 27);
                if (in_alt_jump(jump_addr, start, end))
                        return;
                offset = jump_addr - pc;
@@ -93,7 +93,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
                fallthrough;
        case beqz_op:
        case bnez_op:
-               jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 22);
+               jump_addr = cur_pc + sign_extend64((si_h << 16 | si_l) << 2, 22);
                if (in_alt_jump(jump_addr, start, end))
                        return;
                offset = jump_addr - pc;
@@ -112,7 +112,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
        case bge_op:
        case bltu_op:
        case bgeu_op:
-               jump_addr = cur_pc + sign_extend(si << 2, 17);
+               jump_addr = cur_pc + sign_extend64(si << 2, 17);
                if (in_alt_jump(jump_addr, start, end))
                        return;
                offset = jump_addr - pc;
index 255a098..3a3fce2 100644 (file)
@@ -94,7 +94,7 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
        c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR |
                     LOONGARCH_CPU_TLB | LOONGARCH_CPU_VINT | LOONGARCH_CPU_WATCH;
 
-       elf_hwcap |= HWCAP_LOONGARCH_CRC32;
+       elf_hwcap = HWCAP_LOONGARCH_CPUCFG | HWCAP_LOONGARCH_CRC32;
 
        config = read_cpucfg(LOONGARCH_CPUCFG1);
        if (config & CPUCFG1_UAL) {
index 75e5be8..7e5c293 100644 (file)
@@ -67,14 +67,17 @@ SYM_FUNC_END(except_vec_cex)
        .macro  BUILD_HANDLER exception handler prep
        .align  5
        SYM_FUNC_START(handle_\exception)
+       666:
        BACKUP_T0T1
        SAVE_ALL
        build_prep_\prep
        move    a0, sp
        la.abs  t0, do_\handler
        jirl    ra, t0, 0
+       668:
        RESTORE_ALL_AND_RET
        SYM_FUNC_END(handle_\exception)
+       SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
        .endm
 
        BUILD_HANDLER ade ade badv
index 512579d..badc590 100644 (file)
@@ -58,7 +58,6 @@ u32 larch_insn_gen_nop(void)
 u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
 {
        long offset = dest - pc;
-       unsigned int immediate_l, immediate_h;
        union loongarch_instruction insn;
 
        if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
@@ -66,15 +65,7 @@ u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
                return INSN_BREAK;
        }
 
-       offset >>= 2;
-
-       immediate_l = offset & 0xffff;
-       offset >>= 16;
-       immediate_h = offset & 0x3ff;
-
-       insn.reg0i26_format.opcode = b_op;
-       insn.reg0i26_format.immediate_l = immediate_l;
-       insn.reg0i26_format.immediate_h = immediate_h;
+       emit_b(&insn, offset >> 2);
 
        return insn.word;
 }
@@ -82,7 +73,6 @@ u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
 u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
 {
        long offset = dest - pc;
-       unsigned int immediate_l, immediate_h;
        union loongarch_instruction insn;
 
        if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
@@ -90,15 +80,7 @@ u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
                return INSN_BREAK;
        }
 
-       offset >>= 2;
-
-       immediate_l = offset & 0xffff;
-       offset >>= 16;
-       immediate_h = offset & 0x3ff;
-
-       insn.reg0i26_format.opcode = bl_op;
-       insn.reg0i26_format.immediate_l = immediate_l;
-       insn.reg0i26_format.immediate_h = immediate_h;
+       emit_bl(&insn, offset >> 2);
 
        return insn.word;
 }
@@ -107,10 +89,7 @@ u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongar
 {
        union loongarch_instruction insn;
 
-       insn.reg3_format.opcode = or_op;
-       insn.reg3_format.rd = rd;
-       insn.reg3_format.rj = rj;
-       insn.reg3_format.rk = rk;
+       emit_or(&insn, rd, rj, rk);
 
        return insn.word;
 }
@@ -124,9 +103,7 @@ u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm)
 {
        union loongarch_instruction insn;
 
-       insn.reg1i20_format.opcode = lu12iw_op;
-       insn.reg1i20_format.rd = rd;
-       insn.reg1i20_format.immediate = imm;
+       emit_lu12iw(&insn, rd, imm);
 
        return insn.word;
 }
@@ -135,9 +112,7 @@ u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
 {
        union loongarch_instruction insn;
 
-       insn.reg1i20_format.opcode = lu32id_op;
-       insn.reg1i20_format.rd = rd;
-       insn.reg1i20_format.immediate = imm;
+       emit_lu32id(&insn, rd, imm);
 
        return insn.word;
 }
@@ -146,10 +121,7 @@ u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
 {
        union loongarch_instruction insn;
 
-       insn.reg2i12_format.opcode = lu52id_op;
-       insn.reg2i12_format.rd = rd;
-       insn.reg2i12_format.rj = rj;
-       insn.reg2i12_format.immediate = imm;
+       emit_lu52id(&insn, rd, rj, imm);
 
        return insn.word;
 }
@@ -158,10 +130,7 @@ u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned l
 {
        union loongarch_instruction insn;
 
-       insn.reg2i16_format.opcode = jirl_op;
-       insn.reg2i16_format.rd = rd;
-       insn.reg2i16_format.rj = rj;
-       insn.reg2i16_format.immediate = (dest - pc) >> 2;
+       emit_jirl(&insn, rj, rd, (dest - pc) >> 2);
 
        return insn.word;
 }
index c583b1e..edfd220 100644 (file)
@@ -191,20 +191,14 @@ out:
 
 unsigned long __get_wchan(struct task_struct *task)
 {
-       unsigned long pc;
+       unsigned long pc = 0;
        struct unwind_state state;
 
        if (!try_get_task_stack(task))
                return 0;
 
-       unwind_start(&state, task, NULL);
-       state.sp = thread_saved_fp(task);
-       get_stack_info(state.sp, state.task, &state.stack_info);
-       state.pc = thread_saved_ra(task);
-#ifdef CONFIG_UNWINDER_PROLOGUE
-       state.type = UNWINDER_PROLOGUE;
-#endif
-       for (; !unwind_done(&state); unwind_next_frame(&state)) {
+       for (unwind_start(&state, task, NULL);
+            !unwind_done(&state); unwind_next_frame(&state)) {
                pc = unwind_get_return_address(&state);
                if (!pc)
                        break;
index 7ea62fa..c38a146 100644 (file)
@@ -72,9 +72,6 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
        if (!task)
                task = current;
 
-       if (user_mode(regs))
-               state.type = UNWINDER_GUESS;
-
        printk("%sCall Trace:", loglvl);
        for (unwind_start(&state, task, pregs);
              !unwind_done(&state); unwind_next_frame(&state)) {
diff --git a/arch/loongarch/kernel/unwind.c b/arch/loongarch/kernel/unwind.c
new file mode 100644 (file)
index 0000000..a463d69
--- /dev/null
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022-2023 Loongson Technology Corporation Limited
+ */
+#include <linux/kernel.h>
+#include <linux/ftrace.h>
+
+#include <asm/unwind.h>
+
+bool default_next_frame(struct unwind_state *state)
+{
+       struct stack_info *info = &state->stack_info;
+       unsigned long addr;
+
+       if (unwind_done(state))
+               return false;
+
+       do {
+               for (state->sp += sizeof(unsigned long);
+                    state->sp < info->end; state->sp += sizeof(unsigned long)) {
+                       addr = *(unsigned long *)(state->sp);
+                       state->pc = unwind_graph_addr(state, addr, state->sp + 8);
+                       if (__kernel_text_address(state->pc))
+                               return true;
+               }
+
+               state->sp = info->next_sp;
+
+       } while (!get_stack_info(state->sp, state->task, info));
+
+       return false;
+}
index e2d2e4f..98379b7 100644 (file)
@@ -2,37 +2,18 @@
 /*
  * Copyright (C) 2022 Loongson Technology Corporation Limited
  */
-#include <linux/kernel.h>
-#include <linux/ftrace.h>
-
 #include <asm/unwind.h>
 
 unsigned long unwind_get_return_address(struct unwind_state *state)
 {
-       if (unwind_done(state))
-               return 0;
-       else if (state->first)
-               return state->pc;
-
-       return *(unsigned long *)(state->sp);
+       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)
 {
-       memset(state, 0, sizeof(*state));
-
-       if (regs) {
-               state->sp = regs->regs[3];
-               state->pc = regs->csr_era;
-       }
-
-       state->task = task;
-       state->first = true;
-
-       get_stack_info(state->sp, state->task, &state->stack_info);
-
+       __unwind_start(state, task, regs);
        if (!unwind_done(state) && !__kernel_text_address(state->pc))
                unwind_next_frame(state);
 }
@@ -40,30 +21,6 @@ EXPORT_SYMBOL_GPL(unwind_start);
 
 bool unwind_next_frame(struct unwind_state *state)
 {
-       struct stack_info *info = &state->stack_info;
-       unsigned long addr;
-
-       if (unwind_done(state))
-               return false;
-
-       if (state->first)
-               state->first = false;
-
-       do {
-               for (state->sp += sizeof(unsigned long);
-                    state->sp < info->end;
-                    state->sp += sizeof(unsigned long)) {
-                       addr = *(unsigned long *)(state->sp);
-                       state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
-                                       addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
-                       if (__kernel_text_address(addr))
-                               return true;
-               }
-
-               state->sp = info->next_sp;
-
-       } while (!get_stack_info(state->sp, state->task, info));
-
-       return false;
+       return default_next_frame(state);
 }
 EXPORT_SYMBOL_GPL(unwind_next_frame);
index 0f8d145..9095fde 100644 (file)
 /*
  * Copyright (C) 2022 Loongson Technology Corporation Limited
  */
+#include <linux/cpumask.h>
 #include <linux/ftrace.h>
 #include <linux/kallsyms.h>
 
 #include <asm/inst.h>
+#include <asm/loongson.h>
 #include <asm/ptrace.h>
+#include <asm/setup.h>
 #include <asm/unwind.h>
 
-static inline void unwind_state_fixup(struct unwind_state *state)
-{
-#ifdef CONFIG_DYNAMIC_FTRACE
-       static unsigned long ftrace = (unsigned long)ftrace_call + 4;
-
-       if (state->pc == ftrace)
-               state->is_ftrace = true;
+extern const int unwind_hint_ade;
+extern const int unwind_hint_ale;
+extern const int unwind_hint_bp;
+extern const int unwind_hint_fpe;
+extern const int unwind_hint_fpu;
+extern const int unwind_hint_lsx;
+extern const int unwind_hint_lasx;
+extern const int unwind_hint_lbt;
+extern const int unwind_hint_ri;
+extern const int unwind_hint_watch;
+extern unsigned long eentry;
+#ifdef CONFIG_NUMA
+extern unsigned long pcpu_handlers[NR_CPUS];
 #endif
-}
 
-unsigned long unwind_get_return_address(struct unwind_state *state)
+static inline bool scan_handlers(unsigned long entry_offset)
 {
+       int idx, offset;
 
-       if (unwind_done(state))
-               return 0;
-       else if (state->type)
-               return state->pc;
-       else if (state->first)
-               return state->pc;
-
-       return *(unsigned long *)(state->sp);
+       if (entry_offset >= EXCCODE_INT_START * VECSIZE)
+               return false;
 
+       idx = entry_offset / VECSIZE;
+       offset = entry_offset % VECSIZE;
+       switch (idx) {
+       case EXCCODE_ADE:
+               return offset == unwind_hint_ade;
+       case EXCCODE_ALE:
+               return offset == unwind_hint_ale;
+       case EXCCODE_BP:
+               return offset == unwind_hint_bp;
+       case EXCCODE_FPE:
+               return offset == unwind_hint_fpe;
+       case EXCCODE_FPDIS:
+               return offset == unwind_hint_fpu;
+       case EXCCODE_LSXDIS:
+               return offset == unwind_hint_lsx;
+       case EXCCODE_LASXDIS:
+               return offset == unwind_hint_lasx;
+       case EXCCODE_BTDIS:
+               return offset == unwind_hint_lbt;
+       case EXCCODE_INE:
+               return offset == unwind_hint_ri;
+       case EXCCODE_WATCH:
+               return offset == unwind_hint_watch;
+       default:
+               return false;
+       }
 }
-EXPORT_SYMBOL_GPL(unwind_get_return_address);
 
-static bool unwind_by_guess(struct unwind_state *state)
+static inline bool fix_exception(unsigned long pc)
 {
-       struct stack_info *info = &state->stack_info;
-       unsigned long addr;
-
-       for (state->sp += sizeof(unsigned long);
-            state->sp < info->end;
-            state->sp += sizeof(unsigned long)) {
-               addr = *(unsigned long *)(state->sp);
-               state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
-                               addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
-               if (__kernel_text_address(addr))
+#ifdef CONFIG_NUMA
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               if (!pcpu_handlers[cpu])
+                       continue;
+               if (scan_handlers(pc - pcpu_handlers[cpu]))
                        return true;
        }
+#endif
+       return scan_handlers(pc - eentry);
+}
 
+/*
+ * As we meet ftrace_regs_entry, reset first flag like first doing
+ * tracing. Prologue analysis will stop soon because PC is at entry.
+ */
+static inline bool fix_ftrace(unsigned long pc)
+{
+#ifdef CONFIG_DYNAMIC_FTRACE
+       return pc == (unsigned long)ftrace_call + LOONGARCH_INSN_SIZE;
+#else
        return false;
+#endif
 }
 
+static inline bool unwind_state_fixup(struct unwind_state *state)
+{
+       if (!fix_exception(state->pc) && !fix_ftrace(state->pc))
+               return false;
+
+       state->reset = true;
+       return true;
+}
+
+/*
+ * LoongArch function prologue is like follows,
+ *     [instructions not use stack var]
+ *     addi.d sp, sp, -imm
+ *     st.d   xx, sp, offset <- save callee saved regs and
+ *     st.d   yy, sp, offset    save ra if function is nest.
+ *     [others instructions]
+ */
 static bool unwind_by_prologue(struct unwind_state *state)
 {
        long frame_ra = -1;
        unsigned long frame_size = 0;
-       unsigned long size, offset, pc = state->pc;
+       unsigned long size, offset, pc;
        struct pt_regs *regs;
        struct stack_info *info = &state->stack_info;
        union loongarch_instruction *ip, *ip_end;
@@ -64,20 +119,21 @@ static bool unwind_by_prologue(struct unwind_state *state)
        if (state->sp >= info->end || state->sp < info->begin)
                return false;
 
-       if (state->is_ftrace) {
-               /*
-                * As we meet ftrace_regs_entry, reset first flag like first doing
-                * tracing. Prologue analysis will stop soon because PC is at entry.
-                */
+       if (state->reset) {
                regs = (struct pt_regs *)state->sp;
                state->first = true;
-               state->is_ftrace = false;
+               state->reset = false;
                state->pc = regs->csr_era;
                state->ra = regs->regs[1];
                state->sp = regs->regs[3];
                return true;
        }
 
+       /*
+        * When first is not set, the PC is a return address in the previous frame.
+        * We need to adjust its value in case overflow to the next symbol.
+        */
+       pc = state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE);
        if (!kallsyms_lookup_size_offset(pc, &size, &offset))
                return false;
 
@@ -93,6 +149,10 @@ static bool unwind_by_prologue(struct unwind_state *state)
                ip++;
        }
 
+       /*
+        * Can't find stack alloc action, PC may be in a leaf function. Only the
+        * first being true is reasonable, otherwise indicate analysis is broken.
+        */
        if (!frame_size) {
                if (state->first)
                        goto first;
@@ -110,6 +170,7 @@ static bool unwind_by_prologue(struct unwind_state *state)
                ip++;
        }
 
+       /* Can't find save $ra action, PC may be in a leaf function, too. */
        if (frame_ra < 0) {
                if (state->first) {
                        state->sp = state->sp + frame_size;
@@ -118,88 +179,47 @@ static bool unwind_by_prologue(struct unwind_state *state)
                return false;
        }
 
-       if (state->first)
-               state->first = false;
-
        state->pc = *(unsigned long *)(state->sp + frame_ra);
        state->sp = state->sp + frame_size;
        goto out;
 
 first:
-       state->first = false;
-       if (state->pc == state->ra)
-               return false;
-
        state->pc = state->ra;
 
 out:
-       unwind_state_fixup(state);
-       return !!__kernel_text_address(state->pc);
-}
-
-void unwind_start(struct unwind_state *state, struct task_struct *task,
-                   struct pt_regs *regs)
-{
-       memset(state, 0, sizeof(*state));
-
-       if (regs &&  __kernel_text_address(regs->csr_era)) {
-               state->pc = regs->csr_era;
-               state->sp = regs->regs[3];
-               state->ra = regs->regs[1];
-               state->type = UNWINDER_PROLOGUE;
-       }
-
-       state->task = task;
-       state->first = true;
-
-       get_stack_info(state->sp, state->task, &state->stack_info);
-
-       if (!unwind_done(state) && !__kernel_text_address(state->pc))
-               unwind_next_frame(state);
+       state->first = false;
+       return unwind_state_fixup(state) || __kernel_text_address(state->pc);
 }
-EXPORT_SYMBOL_GPL(unwind_start);
 
-bool unwind_next_frame(struct unwind_state *state)
+static bool next_frame(struct unwind_state *state)
 {
-       struct stack_info *info = &state->stack_info;
-       struct pt_regs *regs;
        unsigned long pc;
+       struct pt_regs *regs;
+       struct stack_info *info = &state->stack_info;
 
        if (unwind_done(state))
                return false;
 
        do {
-               switch (state->type) {
-               case UNWINDER_GUESS:
-                       state->first = false;
-                       if (unwind_by_guess(state))
-                               return true;
-                       break;
+               if (unwind_by_prologue(state)) {
+                       state->pc = unwind_graph_addr(state, state->pc, state->sp);
+                       return true;
+               }
+
+               if (info->type == STACK_TYPE_IRQ && info->end == state->sp) {
+                       regs = (struct pt_regs *)info->next_sp;
+                       pc = regs->csr_era;
+
+                       if (user_mode(regs) || !__kernel_text_address(pc))
+                               return false;
+
+                       state->first = true;
+                       state->pc = pc;
+                       state->ra = regs->regs[1];
+                       state->sp = regs->regs[3];
+                       get_stack_info(state->sp, state->task, info);
 
-               case UNWINDER_PROLOGUE:
-                       if (unwind_by_prologue(state)) {
-                               state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
-                                               state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
-                               return true;
-                       }
-
-                       if (info->type == STACK_TYPE_IRQ &&
-                               info->end == state->sp) {
-                               regs = (struct pt_regs *)info->next_sp;
-                               pc = regs->csr_era;
-
-                               if (user_mode(regs) || !__kernel_text_address(pc))
-                                       return false;
-
-                               state->first = true;
-                               state->ra = regs->regs[1];
-                               state->sp = regs->regs[3];
-                               state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
-                                               pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
-                               get_stack_info(state->sp, state->task, info);
-
-                               return true;
-                       }
+                       return true;
                }
 
                state->sp = info->next_sp;
@@ -208,4 +228,36 @@ bool unwind_next_frame(struct unwind_state *state)
 
        return false;
 }
+
+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_PROLOGUE;
+       state->first = true;
+
+       /*
+        * The current PC is not kernel text address, we cannot find its
+        * relative symbol. Thus, prologue analysis will be broken. Luckily,
+        * we can use the default_next_frame().
+        */
+       if (!__kernel_text_address(state->pc)) {
+               state->type = UNWINDER_GUESS;
+               if (!unwind_done(state))
+                       unwind_next_frame(state);
+       }
+}
+EXPORT_SYMBOL_GPL(unwind_start);
+
+bool unwind_next_frame(struct unwind_state *state)
+{
+       return state->type == UNWINDER_PROLOGUE ?
+                       next_frame(state) : default_next_frame(state);
+}
 EXPORT_SYMBOL_GPL(unwind_next_frame);
index da3681f..8bad6b0 100644 (file)
@@ -251,7 +251,7 @@ static void output_pgtable_bits_defines(void)
 }
 
 #ifdef CONFIG_NUMA
-static unsigned long pcpu_handlers[NR_CPUS];
+unsigned long pcpu_handlers[NR_CPUS];
 #endif
 extern long exception_handlers[VECSIZE * 128 / sizeof(long)];
 
diff --git a/arch/mips/include/asm/mach-loongson32/cpufreq.h b/arch/mips/include/asm/mach-loongson32/cpufreq.h
deleted file mode 100644 (file)
index e422a32..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (c) 2014 Zhang, Keguang <keguang.zhang@gmail.com>
- *
- * Loongson 1 CPUFreq platform support.
- */
-
-#ifndef __ASM_MACH_LOONGSON32_CPUFREQ_H
-#define __ASM_MACH_LOONGSON32_CPUFREQ_H
-
-struct plat_ls1x_cpufreq {
-       const char      *clk_name;      /* CPU clk */
-       const char      *osc_clk_name;  /* OSC clk */
-       unsigned int    max_freq;       /* in kHz */
-       unsigned int    min_freq;       /* in kHz */
-};
-
-#endif /* __ASM_MACH_LOONGSON32_CPUFREQ_H */
index eb83e27..86e1a6a 100644 (file)
@@ -12,7 +12,6 @@
 #include <nand.h>
 
 extern struct platform_device ls1x_uart_pdev;
-extern struct platform_device ls1x_cpufreq_pdev;
 extern struct platform_device ls1x_eth0_pdev;
 extern struct platform_device ls1x_eth1_pdev;
 extern struct platform_device ls1x_ehci_pdev;
index 311dc15..64d7979 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <platform.h>
 #include <loongson1.h>
-#include <cpufreq.h>
 #include <dma.h>
 #include <nand.h>
 
@@ -62,21 +61,6 @@ void __init ls1x_serial_set_uartclk(struct platform_device *pdev)
                p->uartclk = clk_get_rate(clk);
 }
 
-/* CPUFreq */
-static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = {
-       .clk_name       = "cpu_clk",
-       .osc_clk_name   = "osc_clk",
-       .max_freq       = 266 * 1000,
-       .min_freq       = 33 * 1000,
-};
-
-struct platform_device ls1x_cpufreq_pdev = {
-       .name           = "ls1x-cpufreq",
-       .dev            = {
-               .platform_data = &ls1x_cpufreq_pdata,
-       },
-};
-
 /* Synopsys Ethernet GMAC */
 static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
        .phy_mask       = 0,
index 727e067..fed8d43 100644 (file)
@@ -35,7 +35,6 @@ static const struct gpio_led_platform_data ls1x_led_pdata __initconst = {
 
 static struct platform_device *ls1b_platform_devices[] __initdata = {
        &ls1x_uart_pdev,
-       &ls1x_cpufreq_pdev,
        &ls1x_eth0_pdev,
        &ls1x_eth1_pdev,
        &ls1x_ehci_pdev,
index 4dfe1f4..6817892 100644 (file)
@@ -1303,7 +1303,7 @@ static char iodc_dbuf[4096] __page_aligned_bss;
  */
 int pdc_iodc_print(const unsigned char *str, unsigned count)
 {
-       unsigned int i;
+       unsigned int i, found = 0;
        unsigned long flags;
 
        count = min_t(unsigned int, count, sizeof(iodc_dbuf));
@@ -1315,6 +1315,7 @@ int pdc_iodc_print(const unsigned char *str, unsigned count)
                        iodc_dbuf[i+0] = '\r';
                        iodc_dbuf[i+1] = '\n';
                        i += 2;
+                       found = 1;
                        goto print;
                default:
                        iodc_dbuf[i] = str[i];
@@ -1330,7 +1331,7 @@ print:
                __pa(pdc_result), 0, __pa(iodc_dbuf), i, 0);
        spin_unlock_irqrestore(&pdc_lock, flags);
 
-       return i;
+       return i - found;
 }
 
 #if !defined(BOOTLOADER)
index 69c6293..ceb45f5 100644 (file)
@@ -126,6 +126,12 @@ long arch_ptrace(struct task_struct *child, long request,
        unsigned long tmp;
        long ret = -EIO;
 
+       unsigned long user_regs_struct_size = sizeof(struct user_regs_struct);
+#ifdef CONFIG_64BIT
+       if (is_compat_task())
+               user_regs_struct_size /= 2;
+#endif
+
        switch (request) {
 
        /* Read the word at location addr in the USER area.  For ptraced
@@ -166,7 +172,7 @@ long arch_ptrace(struct task_struct *child, long request,
                     addr >= sizeof(struct pt_regs))
                        break;
                if (addr == PT_IAOQ0 || addr == PT_IAOQ1) {
-                       data |= 3; /* ensure userspace privilege */
+                       data |= PRIV_USER; /* ensure userspace privilege */
                }
                if ((addr >= PT_GR1 && addr <= PT_GR31) ||
                                addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
@@ -181,14 +187,14 @@ long arch_ptrace(struct task_struct *child, long request,
                return copy_regset_to_user(child,
                                           task_user_regset_view(current),
                                           REGSET_GENERAL,
-                                          0, sizeof(struct user_regs_struct),
+                                          0, user_regs_struct_size,
                                           datap);
 
        case PTRACE_SETREGS:    /* Set all gp regs in the child. */
                return copy_regset_from_user(child,
                                             task_user_regset_view(current),
                                             REGSET_GENERAL,
-                                            0, sizeof(struct user_regs_struct),
+                                            0, user_regs_struct_size,
                                             datap);
 
        case PTRACE_GETFPREGS:  /* Get the child FPU state. */
@@ -285,7 +291,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        if (addr >= sizeof(struct pt_regs))
                                break;
                        if (addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4) {
-                               data |= 3; /* ensure userspace privilege */
+                               data |= PRIV_USER; /* ensure userspace privilege */
                        }
                        if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
                                /* Special case, fp regs are 64 bits anyway */
@@ -302,6 +308,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        }
                }
                break;
+       case PTRACE_GETREGS:
+       case PTRACE_SETREGS:
+       case PTRACE_GETFPREGS:
+       case PTRACE_SETFPREGS:
+               return arch_ptrace(child, request, addr, data);
 
        default:
                ret = compat_ptrace_request(child, request, addr, data);
@@ -484,7 +495,7 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val)
        case RI(iaoq[0]):
        case RI(iaoq[1]):
                        /* set 2 lowest bits to ensure userspace privilege: */
-                       regs->iaoq[num - RI(iaoq[0])] = val | 3;
+                       regs->iaoq[num - RI(iaoq[0])] = val | PRIV_USER;
                        return;
        case RI(sar):   regs->sar = val;
                        return;
index b8c4ac5..7a5f8db 100644 (file)
@@ -163,7 +163,6 @@ config PPC
        select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
        select ARCH_WANT_LD_ORPHAN_WARN
        select ARCH_WANTS_MODULES_DATA_IN_VMALLOC       if PPC_BOOK3S_32 || PPC_8xx
-       select ARCH_WANTS_NO_INSTR
        select ARCH_WEAK_RELEASE_ACQUIRE
        select BINFMT_ELF
        select BUILDTIME_TABLE_SORT
index af04cea..352d7de 100755 (executable)
@@ -210,6 +210,10 @@ ld_version()
        gsub(".*version ", "");
        gsub("-.*", "");
        split($1,a, ".");
+       if( length(a[3]) == "8" )
+               # a[3] is probably a date of format yyyymmdd used for release snapshots. We
+               # can assume it to be zero as it does not signify a new version as such.
+               a[3] = 0;
        print a[1]*100000000 + a[2]*1000000 + a[3]*10000;
        exit
     }'
index dd39313..d5cd162 100644 (file)
@@ -97,6 +97,8 @@ static inline void tlb_flush(struct mmu_gather *tlb)
 {
        if (radix_enabled())
                radix__tlb_flush(tlb);
+
+       return hash__tlb_flush(tlb);
 }
 
 #ifdef CONFIG_SMP
index 77fa88c..eb6d094 100644 (file)
@@ -173,6 +173,15 @@ static inline notrace unsigned long irq_soft_mask_or_return(unsigned long mask)
        return flags;
 }
 
+static inline notrace unsigned long irq_soft_mask_andc_return(unsigned long mask)
+{
+       unsigned long flags = irq_soft_mask_return();
+
+       irq_soft_mask_set(flags & ~mask);
+
+       return flags;
+}
+
 static inline unsigned long arch_local_save_flags(void)
 {
        return irq_soft_mask_return();
@@ -192,7 +201,7 @@ static inline void arch_local_irq_enable(void)
 
 static inline unsigned long arch_local_irq_save(void)
 {
-       return irq_soft_mask_set_return(IRQS_DISABLED);
+       return irq_soft_mask_or_return(IRQS_DISABLED);
 }
 
 static inline bool arch_irqs_disabled_flags(unsigned long flags)
@@ -331,10 +340,11 @@ bool power_pmu_wants_prompt_pmi(void);
  * is a different soft-masked interrupt pending that requires hard
  * masking.
  */
-static inline bool should_hard_irq_enable(void)
+static inline bool should_hard_irq_enable(struct pt_regs *regs)
 {
        if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
-               WARN_ON(irq_soft_mask_return() == IRQS_ENABLED);
+               WARN_ON(irq_soft_mask_return() != IRQS_ALL_DISABLED);
+               WARN_ON(!(get_paca()->irq_happened & PACA_IRQ_HARD_DIS));
                WARN_ON(mfmsr() & MSR_EE);
        }
 
@@ -347,8 +357,17 @@ static inline bool should_hard_irq_enable(void)
         *
         * TODO: Add test for 64e
         */
-       if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && !power_pmu_wants_prompt_pmi())
-               return false;
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
+               if (!power_pmu_wants_prompt_pmi())
+                       return false;
+               /*
+                * If PMIs are disabled then IRQs should be disabled as well,
+                * so we shouldn't see this condition, check for it just in
+                * case because we are about to enable PMIs.
+                */
+               if (WARN_ON_ONCE(regs->softe & IRQS_PMI_DISABLED))
+                       return false;
+       }
 
        if (get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK)
                return false;
@@ -358,18 +377,16 @@ static inline bool should_hard_irq_enable(void)
 
 /*
  * Do the hard enabling, only call this if should_hard_irq_enable is true.
+ * This allows PMI interrupts to profile irq handlers.
  */
 static inline void do_hard_irq_enable(void)
 {
-       if (IS_ENABLED(CONFIG_PPC_IRQ_SOFT_MASK_DEBUG)) {
-               WARN_ON(irq_soft_mask_return() == IRQS_ENABLED);
-               WARN_ON(get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK);
-               WARN_ON(mfmsr() & MSR_EE);
-       }
        /*
-        * This allows PMI interrupts (and watchdog soft-NMIs) through.
-        * There is no other reason to enable this way.
+        * Asynch interrupts come in with IRQS_ALL_DISABLED,
+        * PACA_IRQ_HARD_DIS, and MSR[EE]=0.
         */
+       if (IS_ENABLED(CONFIG_PPC_BOOK3S_64))
+               irq_soft_mask_andc_return(IRQS_PMI_DISABLED);
        get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
        __hard_irq_enable();
 }
@@ -452,7 +469,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
        return !(regs->msr & MSR_EE);
 }
 
-static __always_inline bool should_hard_irq_enable(void)
+static __always_inline bool should_hard_irq_enable(struct pt_regs *regs)
 {
        return false;
 }
index 4f89799..699a885 100644 (file)
@@ -137,7 +137,7 @@ struct imc_pmu {
  * are inited.
  */
 struct imc_pmu_ref {
-       struct mutex lock;
+       spinlock_t lock;
        unsigned int id;
        int refc;
 };
index f55c6fb..5712dd8 100644 (file)
@@ -27,7 +27,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(doorbell_exception)
 
        ppc_msgsync();
 
-       if (should_hard_irq_enable())
+       if (should_hard_irq_enable(regs))
                do_hard_irq_enable();
 
        kvmppc_clear_host_ipi(smp_processor_id());
index d438ca7..fdbee10 100644 (file)
@@ -864,7 +864,7 @@ _GLOBAL(load_up_spe)
  * SPE unavailable trap from kernel - print a message, but let
  * the task use SPE in the kernel until it returns to user mode.
  */
-KernelSPE:
+SYM_FUNC_START_LOCAL(KernelSPE)
        lwz     r3,_MSR(r1)
        oris    r3,r3,MSR_SPE@h
        stw     r3,_MSR(r1)     /* enable use of SPE after return */
@@ -881,6 +881,7 @@ KernelSPE:
 #endif
        .align  4,0
 
+SYM_FUNC_END(KernelSPE)
 #endif /* CONFIG_SPE */
 
 /*
index fc6631a..0ec1581 100644 (file)
@@ -50,16 +50,18 @@ static inline bool exit_must_hard_disable(void)
  */
 static notrace __always_inline bool prep_irq_for_enabled_exit(bool restartable)
 {
+       bool must_hard_disable = (exit_must_hard_disable() || !restartable);
+
        /* This must be done with RI=1 because tracing may touch vmaps */
        trace_hardirqs_on();
 
-       if (exit_must_hard_disable() || !restartable)
+       if (must_hard_disable)
                __hard_EE_RI_disable();
 
 #ifdef CONFIG_PPC64
        /* This pattern matches prep_irq_for_idle */
        if (unlikely(lazy_irq_pending_nocheck())) {
-               if (exit_must_hard_disable() || !restartable) {
+               if (must_hard_disable) {
                        local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
                        __hard_RI_enable();
                }
index c5b9ce8..c9535f2 100644 (file)
@@ -238,7 +238,7 @@ static void __do_irq(struct pt_regs *regs, unsigned long oldsp)
        irq = static_call(ppc_get_irq)();
 
        /* We can hard enable interrupts now to allow perf interrupts */
-       if (should_hard_irq_enable())
+       if (should_hard_irq_enable(regs))
                do_hard_irq_enable();
 
        /* And finally process it */
index d68de36..e26eb66 100644 (file)
@@ -515,7 +515,7 @@ DEFINE_INTERRUPT_HANDLER_ASYNC(timer_interrupt)
        }
 
        /* Conditionally hard-enable interrupts. */
-       if (should_hard_irq_enable()) {
+       if (should_hard_irq_enable(regs)) {
                /*
                 * Ensure a positive value is written to the decrementer, or
                 * else some CPUs will continue to take decrementer exceptions.
index af8854f..9be3e81 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/firmware.h>
 #include <asm/kexec_ranges.h>
 #include <asm/crashdump-ppc64.h>
+#include <asm/mmzone.h>
 #include <asm/prom.h>
 
 struct umem_info {
@@ -989,10 +990,13 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
         * linux,drconf-usable-memory properties. Get an approximate on the
         * number of usable memory entries and use for FDT size estimation.
         */
-       usm_entries = ((memblock_end_of_DRAM() / drmem_lmb_size()) +
-                      (2 * (resource_size(&crashk_res) / drmem_lmb_size())));
-
-       extra_size = (unsigned int)(usm_entries * sizeof(u64));
+       if (drmem_lmb_size()) {
+               usm_entries = ((memory_hotplug_max() / drmem_lmb_size()) +
+                              (2 * (resource_size(&crashk_res) / drmem_lmb_size())));
+               extra_size = (unsigned int)(usm_entries * sizeof(u64));
+       } else {
+               extra_size = 0;
+       }
 
        /*
         * Get the number of CPU nodes in the current DT. This allows to
index 0dce93c..e89281d 100644 (file)
@@ -912,16 +912,15 @@ static int kvmppc_handle_debug(struct kvm_vcpu *vcpu)
 
 static void kvmppc_fill_pt_regs(struct pt_regs *regs)
 {
-       ulong r1, ip, msr, lr;
+       ulong r1, msr, lr;
 
        asm("mr %0, 1" : "=r"(r1));
        asm("mflr %0" : "=r"(lr));
        asm("mfmsr %0" : "=r"(msr));
-       asm("bl 1f; 1: mflr %0" : "=r"(ip));
 
        memset(regs, 0, sizeof(*regs));
        regs->gpr[1] = r1;
-       regs->nip = ip;
+       regs->nip = _THIS_IP_;
        regs->msr = msr;
        regs->link = lr;
 }
index 80a148c..44a35ed 100644 (file)
@@ -1012,7 +1012,7 @@ static void __init hash_init_partition_table(phys_addr_t hash_table,
 
 void hpt_clear_stress(void);
 static struct timer_list stress_hpt_timer;
-void stress_hpt_timer_fn(struct timer_list *timer)
+static void stress_hpt_timer_fn(struct timer_list *timer)
 {
        int next_cpu;
 
index cac727b..26245aa 100644 (file)
@@ -234,6 +234,14 @@ void radix__mark_rodata_ro(void)
        end = (unsigned long)__end_rodata;
 
        radix__change_memory_range(start, end, _PAGE_WRITE);
+
+       for (start = PAGE_OFFSET; start < (unsigned long)_stext; start += PAGE_SIZE) {
+               end = start + PAGE_SIZE;
+               if (overlaps_interrupt_vector_text(start, end))
+                       radix__change_memory_range(start, end, _PAGE_WRITE);
+               else
+                       break;
+       }
 }
 
 void radix__mark_initmem_nx(void)
@@ -262,6 +270,22 @@ print_mapping(unsigned long start, unsigned long end, unsigned long size, bool e
 static unsigned long next_boundary(unsigned long addr, unsigned long end)
 {
 #ifdef CONFIG_STRICT_KERNEL_RWX
+       unsigned long stext_phys;
+
+       stext_phys = __pa_symbol(_stext);
+
+       // Relocatable kernel running at non-zero real address
+       if (stext_phys != 0) {
+               // The end of interrupts code at zero is a rodata boundary
+               unsigned long end_intr = __pa_symbol(__end_interrupts) - stext_phys;
+               if (addr < end_intr)
+                       return end_intr;
+
+               // Start of relocated kernel text is a rodata boundary
+               if (addr < stext_phys)
+                       return stext_phys;
+       }
+
        if (addr < __pa_symbol(__srwx_boundary))
                return __pa_symbol(__srwx_boundary);
 #endif
index d517aba..9d229ef 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/cputhreads.h>
 #include <asm/smp.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 
 /* Nest IMC data structures and variables */
 
@@ -50,7 +51,7 @@ static int trace_imc_mem_size;
  * core and trace-imc
  */
 static struct imc_pmu_ref imc_global_refc = {
-       .lock = __MUTEX_INITIALIZER(imc_global_refc.lock),
+       .lock = __SPIN_LOCK_INITIALIZER(imc_global_refc.lock),
        .id = 0,
        .refc = 0,
 };
@@ -400,7 +401,7 @@ static int ppc_nest_imc_cpu_offline(unsigned int cpu)
                                       get_hard_smp_processor_id(cpu));
                /*
                 * If this is the last cpu in this chip then, skip the reference
-                * count mutex lock and make the reference count on this chip zero.
+                * count lock and make the reference count on this chip zero.
                 */
                ref = get_nest_pmu_ref(cpu);
                if (!ref)
@@ -462,15 +463,15 @@ static void nest_imc_counters_release(struct perf_event *event)
        /*
         * See if we need to disable the nest PMU.
         * If no events are currently in use, then we have to take a
-        * mutex to ensure that we don't race with another task doing
+        * lock to ensure that we don't race with another task doing
         * enable or disable the nest counters.
         */
        ref = get_nest_pmu_ref(event->cpu);
        if (!ref)
                return;
 
-       /* Take the mutex lock for this node and then decrement the reference count */
-       mutex_lock(&ref->lock);
+       /* Take the lock for this node and then decrement the reference count */
+       spin_lock(&ref->lock);
        if (ref->refc == 0) {
                /*
                 * The scenario where this is true is, when perf session is
@@ -482,7 +483,7 @@ static void nest_imc_counters_release(struct perf_event *event)
                 * an OPAL call to disable the engine in that node.
                 *
                 */
-               mutex_unlock(&ref->lock);
+               spin_unlock(&ref->lock);
                return;
        }
        ref->refc--;
@@ -490,7 +491,7 @@ static void nest_imc_counters_release(struct perf_event *event)
                rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,
                                            get_hard_smp_processor_id(event->cpu));
                if (rc) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("nest-imc: Unable to stop the counters for core %d\n", node_id);
                        return;
                }
@@ -498,7 +499,7 @@ static void nest_imc_counters_release(struct perf_event *event)
                WARN(1, "nest-imc: Invalid event reference count\n");
                ref->refc = 0;
        }
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
 }
 
 static int nest_imc_event_init(struct perf_event *event)
@@ -557,26 +558,25 @@ static int nest_imc_event_init(struct perf_event *event)
 
        /*
         * Get the imc_pmu_ref struct for this node.
-        * Take the mutex lock and then increment the count of nest pmu events
-        * inited.
+        * Take the lock and then increment the count of nest pmu events inited.
         */
        ref = get_nest_pmu_ref(event->cpu);
        if (!ref)
                return -EINVAL;
 
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        if (ref->refc == 0) {
                rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_NEST,
                                             get_hard_smp_processor_id(event->cpu));
                if (rc) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("nest-imc: Unable to start the counters for node %d\n",
                                                                        node_id);
                        return rc;
                }
        }
        ++ref->refc;
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
 
        event->destroy = nest_imc_counters_release;
        return 0;
@@ -612,9 +612,8 @@ static int core_imc_mem_init(int cpu, int size)
                return -ENOMEM;
        mem_info->vbase = page_address(page);
 
-       /* Init the mutex */
        core_imc_refc[core_id].id = core_id;
-       mutex_init(&core_imc_refc[core_id].lock);
+       spin_lock_init(&core_imc_refc[core_id].lock);
 
        rc = opal_imc_counters_init(OPAL_IMC_COUNTERS_CORE,
                                __pa((void *)mem_info->vbase),
@@ -703,9 +702,8 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
                perf_pmu_migrate_context(&core_imc_pmu->pmu, cpu, ncpu);
        } else {
                /*
-                * If this is the last cpu in this core then, skip taking refernce
-                * count mutex lock for this core and directly zero "refc" for
-                * this core.
+                * If this is the last cpu in this core then skip taking reference
+                * count lock for this core and directly zero "refc" for this core.
                 */
                opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
                                       get_hard_smp_processor_id(cpu));
@@ -720,11 +718,11 @@ static int ppc_core_imc_cpu_offline(unsigned int cpu)
                 * last cpu in this core and core-imc event running
                 * in this cpu.
                 */
-               mutex_lock(&imc_global_refc.lock);
+               spin_lock(&imc_global_refc.lock);
                if (imc_global_refc.id == IMC_DOMAIN_CORE)
                        imc_global_refc.refc--;
 
-               mutex_unlock(&imc_global_refc.lock);
+               spin_unlock(&imc_global_refc.lock);
        }
        return 0;
 }
@@ -739,7 +737,7 @@ static int core_imc_pmu_cpumask_init(void)
 
 static void reset_global_refc(struct perf_event *event)
 {
-               mutex_lock(&imc_global_refc.lock);
+               spin_lock(&imc_global_refc.lock);
                imc_global_refc.refc--;
 
                /*
@@ -751,7 +749,7 @@ static void reset_global_refc(struct perf_event *event)
                        imc_global_refc.refc = 0;
                        imc_global_refc.id = 0;
                }
-               mutex_unlock(&imc_global_refc.lock);
+               spin_unlock(&imc_global_refc.lock);
 }
 
 static void core_imc_counters_release(struct perf_event *event)
@@ -764,17 +762,17 @@ static void core_imc_counters_release(struct perf_event *event)
        /*
         * See if we need to disable the IMC PMU.
         * If no events are currently in use, then we have to take a
-        * mutex to ensure that we don't race with another task doing
+        * lock to ensure that we don't race with another task doing
         * enable or disable the core counters.
         */
        core_id = event->cpu / threads_per_core;
 
-       /* Take the mutex lock and decrement the refernce count for this core */
+       /* Take the lock and decrement the refernce count for this core */
        ref = &core_imc_refc[core_id];
        if (!ref)
                return;
 
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        if (ref->refc == 0) {
                /*
                 * The scenario where this is true is, when perf session is
@@ -786,7 +784,7 @@ static void core_imc_counters_release(struct perf_event *event)
                 * an OPAL call to disable the engine in that core.
                 *
                 */
-               mutex_unlock(&ref->lock);
+               spin_unlock(&ref->lock);
                return;
        }
        ref->refc--;
@@ -794,7 +792,7 @@ static void core_imc_counters_release(struct perf_event *event)
                rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
                                            get_hard_smp_processor_id(event->cpu));
                if (rc) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("IMC: Unable to stop the counters for core %d\n", core_id);
                        return;
                }
@@ -802,7 +800,7 @@ static void core_imc_counters_release(struct perf_event *event)
                WARN(1, "core-imc: Invalid event reference count\n");
                ref->refc = 0;
        }
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
 
        reset_global_refc(event);
 }
@@ -840,7 +838,6 @@ static int core_imc_event_init(struct perf_event *event)
        if ((!pcmi->vbase))
                return -ENODEV;
 
-       /* Get the core_imc mutex for this core */
        ref = &core_imc_refc[core_id];
        if (!ref)
                return -EINVAL;
@@ -848,22 +845,22 @@ static int core_imc_event_init(struct perf_event *event)
        /*
         * Core pmu units are enabled only when it is used.
         * See if this is triggered for the first time.
-        * If yes, take the mutex lock and enable the core counters.
+        * If yes, take the lock and enable the core counters.
         * If not, just increment the count in core_imc_refc struct.
         */
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        if (ref->refc == 0) {
                rc = opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
                                             get_hard_smp_processor_id(event->cpu));
                if (rc) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("core-imc: Unable to start the counters for core %d\n",
                                                                        core_id);
                        return rc;
                }
        }
        ++ref->refc;
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
 
        /*
         * Since the system can run either in accumulation or trace-mode
@@ -874,7 +871,7 @@ static int core_imc_event_init(struct perf_event *event)
         * to know whether any other trace/thread imc
         * events are running.
         */
-       mutex_lock(&imc_global_refc.lock);
+       spin_lock(&imc_global_refc.lock);
        if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_CORE) {
                /*
                 * No other trace/thread imc events are running in
@@ -883,10 +880,10 @@ static int core_imc_event_init(struct perf_event *event)
                imc_global_refc.id = IMC_DOMAIN_CORE;
                imc_global_refc.refc++;
        } else {
-               mutex_unlock(&imc_global_refc.lock);
+               spin_unlock(&imc_global_refc.lock);
                return -EBUSY;
        }
-       mutex_unlock(&imc_global_refc.lock);
+       spin_unlock(&imc_global_refc.lock);
 
        event->hw.event_base = (u64)pcmi->vbase + (config & IMC_EVENT_OFFSET_MASK);
        event->destroy = core_imc_counters_release;
@@ -958,10 +955,10 @@ static int ppc_thread_imc_cpu_offline(unsigned int cpu)
        mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
 
        /* Reduce the refc if thread-imc event running on this cpu */
-       mutex_lock(&imc_global_refc.lock);
+       spin_lock(&imc_global_refc.lock);
        if (imc_global_refc.id == IMC_DOMAIN_THREAD)
                imc_global_refc.refc--;
-       mutex_unlock(&imc_global_refc.lock);
+       spin_unlock(&imc_global_refc.lock);
 
        return 0;
 }
@@ -1001,7 +998,7 @@ static int thread_imc_event_init(struct perf_event *event)
        if (!target)
                return -EINVAL;
 
-       mutex_lock(&imc_global_refc.lock);
+       spin_lock(&imc_global_refc.lock);
        /*
         * Check if any other trace/core imc events are running in the
         * system, if not set the global id to thread-imc.
@@ -1010,10 +1007,10 @@ static int thread_imc_event_init(struct perf_event *event)
                imc_global_refc.id = IMC_DOMAIN_THREAD;
                imc_global_refc.refc++;
        } else {
-               mutex_unlock(&imc_global_refc.lock);
+               spin_unlock(&imc_global_refc.lock);
                return -EBUSY;
        }
-       mutex_unlock(&imc_global_refc.lock);
+       spin_unlock(&imc_global_refc.lock);
 
        event->pmu->task_ctx_nr = perf_sw_context;
        event->destroy = reset_global_refc;
@@ -1135,25 +1132,25 @@ static int thread_imc_event_add(struct perf_event *event, int flags)
        /*
         * imc pmus are enabled only when it is used.
         * See if this is triggered for the first time.
-        * If yes, take the mutex lock and enable the counters.
+        * If yes, take the lock and enable the counters.
         * If not, just increment the count in ref count struct.
         */
        ref = &core_imc_refc[core_id];
        if (!ref)
                return -EINVAL;
 
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        if (ref->refc == 0) {
                if (opal_imc_counters_start(OPAL_IMC_COUNTERS_CORE,
                    get_hard_smp_processor_id(smp_processor_id()))) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("thread-imc: Unable to start the counter\
                                for core %d\n", core_id);
                        return -EINVAL;
                }
        }
        ++ref->refc;
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
        return 0;
 }
 
@@ -1170,12 +1167,12 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
                return;
        }
 
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        ref->refc--;
        if (ref->refc == 0) {
                if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE,
                    get_hard_smp_processor_id(smp_processor_id()))) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("thread-imc: Unable to stop the counters\
                                for core %d\n", core_id);
                        return;
@@ -1183,7 +1180,7 @@ static void thread_imc_event_del(struct perf_event *event, int flags)
        } else if (ref->refc < 0) {
                ref->refc = 0;
        }
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
 
        /* Set bit 0 of LDBAR to zero, to stop posting updates to memory */
        mtspr(SPRN_LDBAR, (mfspr(SPRN_LDBAR) & (~(1UL << 63))));
@@ -1224,9 +1221,8 @@ static int trace_imc_mem_alloc(int cpu_id, int size)
                }
        }
 
-       /* Init the mutex, if not already */
        trace_imc_refc[core_id].id = core_id;
-       mutex_init(&trace_imc_refc[core_id].lock);
+       spin_lock_init(&trace_imc_refc[core_id].lock);
 
        mtspr(SPRN_LDBAR, 0);
        return 0;
@@ -1246,10 +1242,10 @@ static int ppc_trace_imc_cpu_offline(unsigned int cpu)
         * Reduce the refc if any trace-imc event running
         * on this cpu.
         */
-       mutex_lock(&imc_global_refc.lock);
+       spin_lock(&imc_global_refc.lock);
        if (imc_global_refc.id == IMC_DOMAIN_TRACE)
                imc_global_refc.refc--;
-       mutex_unlock(&imc_global_refc.lock);
+       spin_unlock(&imc_global_refc.lock);
 
        return 0;
 }
@@ -1371,17 +1367,17 @@ static int trace_imc_event_add(struct perf_event *event, int flags)
        }
 
        mtspr(SPRN_LDBAR, ldbar_value);
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        if (ref->refc == 0) {
                if (opal_imc_counters_start(OPAL_IMC_COUNTERS_TRACE,
                                get_hard_smp_processor_id(smp_processor_id()))) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("trace-imc: Unable to start the counters for core %d\n", core_id);
                        return -EINVAL;
                }
        }
        ++ref->refc;
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
        return 0;
 }
 
@@ -1414,19 +1410,19 @@ static void trace_imc_event_del(struct perf_event *event, int flags)
                return;
        }
 
-       mutex_lock(&ref->lock);
+       spin_lock(&ref->lock);
        ref->refc--;
        if (ref->refc == 0) {
                if (opal_imc_counters_stop(OPAL_IMC_COUNTERS_TRACE,
                                get_hard_smp_processor_id(smp_processor_id()))) {
-                       mutex_unlock(&ref->lock);
+                       spin_unlock(&ref->lock);
                        pr_err("trace-imc: Unable to stop the counters for core %d\n", core_id);
                        return;
                }
        } else if (ref->refc < 0) {
                ref->refc = 0;
        }
-       mutex_unlock(&ref->lock);
+       spin_unlock(&ref->lock);
 
        trace_imc_event_stop(event, flags);
 }
@@ -1448,7 +1444,7 @@ static int trace_imc_event_init(struct perf_event *event)
         * no other thread is running any core/thread imc
         * events
         */
-       mutex_lock(&imc_global_refc.lock);
+       spin_lock(&imc_global_refc.lock);
        if (imc_global_refc.id == 0 || imc_global_refc.id == IMC_DOMAIN_TRACE) {
                /*
                 * No core/thread imc events are running in the
@@ -1457,10 +1453,10 @@ static int trace_imc_event_init(struct perf_event *event)
                imc_global_refc.id = IMC_DOMAIN_TRACE;
                imc_global_refc.refc++;
        } else {
-               mutex_unlock(&imc_global_refc.lock);
+               spin_unlock(&imc_global_refc.lock);
                return -EBUSY;
        }
-       mutex_unlock(&imc_global_refc.lock);
+       spin_unlock(&imc_global_refc.lock);
 
        event->hw.idx = -1;
 
@@ -1533,10 +1529,10 @@ static int init_nest_pmu_ref(void)
        i = 0;
        for_each_node(nid) {
                /*
-                * Mutex lock to avoid races while tracking the number of
+                * Take the lock to avoid races while tracking the number of
                 * sessions using the chip's nest pmu units.
                 */
-               mutex_init(&nest_imc_refc[i].lock);
+               spin_lock_init(&nest_imc_refc[i].lock);
 
                /*
                 * Loop to init the "id" with the node_id. Variable "i" initialized to
index faf2c21..8215396 100644 (file)
@@ -80,6 +80,9 @@ ifeq ($(CONFIG_PERF_EVENTS),y)
         KBUILD_CFLAGS += -fno-omit-frame-pointer
 endif
 
+# Avoid generating .eh_frame sections.
+KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -fno-unwind-tables
+
 KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax)
 KBUILD_AFLAGS_MODULE += $(call as-option,-Wa$(comma)-mno-relax)
 
index 43bed6c..5235fd1 100644 (file)
                        bus-range = <0x0 0xff>;
                        ranges = <0x81000000  0x0 0x60080000  0x0 0x60080000 0x0 0x10000>,      /* I/O */
                                 <0x82000000  0x0 0x60090000  0x0 0x60090000 0x0 0xff70000>,    /* mem */
-                                <0x82000000  0x0 0x70000000  0x0 0x70000000 0x0 0x1000000>,    /* mem */
+                                <0x82000000  0x0 0x70000000  0x0 0x70000000 0x0 0x10000000>,    /* mem */
                                 <0xc3000000 0x20 0x00000000 0x20 0x00000000 0x20 0x00000000>;  /* mem prefetchable */
                        num-lanes = <0x8>;
                        interrupts = <56>, <57>, <58>, <59>, <60>, <61>, <62>, <63>, <64>;
index 7226e24..2c0f4c8 100644 (file)
@@ -46,7 +46,7 @@
 
 .macro ALTERNATIVE_CFG_2 old_c, new_c_1, vendor_id_1, errata_id_1, enable_1,   \
                                new_c_2, vendor_id_2, errata_id_2, enable_2
-       ALTERNATIVE_CFG \old_c, \new_c_1, \vendor_id_1, \errata_id_1, \enable_1
+       ALTERNATIVE_CFG "\old_c", "\new_c_1", \vendor_id_1, \errata_id_1, \enable_1
        ALT_NEW_CONTENT \vendor_id_2, \errata_id_2, \enable_2, \new_c_2
 .endm
 
index 86328e3..64ad193 100644 (file)
@@ -70,7 +70,6 @@ static_assert(RISCV_ISA_EXT_ID_MAX <= RISCV_ISA_EXT_MAX);
  */
 enum riscv_isa_ext_key {
        RISCV_ISA_EXT_KEY_FPU,          /* For 'F' and 'D' */
-       RISCV_ISA_EXT_KEY_ZIHINTPAUSE,
        RISCV_ISA_EXT_KEY_SVINVAL,
        RISCV_ISA_EXT_KEY_MAX,
 };
@@ -91,8 +90,6 @@ static __always_inline int riscv_isa_ext2key(int num)
                return RISCV_ISA_EXT_KEY_FPU;
        case RISCV_ISA_EXT_d:
                return RISCV_ISA_EXT_KEY_FPU;
-       case RISCV_ISA_EXT_ZIHINTPAUSE:
-               return RISCV_ISA_EXT_KEY_ZIHINTPAUSE;
        case RISCV_ISA_EXT_SVINVAL:
                return RISCV_ISA_EXT_KEY_SVINVAL;
        default:
index 4eba9a9..3e01f4f 100644 (file)
@@ -721,6 +721,10 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
        page_table_check_pmd_set(vma->vm_mm, address, pmdp, pmd);
        return __pmd(atomic_long_xchg((atomic_long_t *)pmdp, pmd_val(pmd)));
 }
+
+#define pmdp_collapse_flush pmdp_collapse_flush
+extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+                                unsigned long address, pmd_t *pmdp);
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 /*
index fa70cfe..14f5d27 100644 (file)
@@ -4,30 +4,26 @@
 
 #ifndef __ASSEMBLY__
 
-#include <linux/jump_label.h>
 #include <asm/barrier.h>
-#include <asm/hwcap.h>
 
 static inline void cpu_relax(void)
 {
-       if (!static_branch_likely(&riscv_isa_ext_keys[RISCV_ISA_EXT_KEY_ZIHINTPAUSE])) {
 #ifdef __riscv_muldiv
-               int dummy;
-               /* In lieu of a halt instruction, induce a long-latency stall. */
-               __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy));
+       int dummy;
+       /* In lieu of a halt instruction, induce a long-latency stall. */
+       __asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy));
 #endif
-       } else {
-               /*
-                * Reduce instruction retirement.
-                * This assumes the PC changes.
-                */
-#ifdef CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE
-               __asm__ __volatile__ ("pause");
+
+#ifdef __riscv_zihintpause
+       /*
+        * Reduce instruction retirement.
+        * This assumes the PC changes.
+        */
+       __asm__ __volatile__ ("pause");
 #else
-               /* Encoding of the pause instruction */
-               __asm__ __volatile__ (".4byte 0x100000F");
+       /* Encoding of the pause instruction */
+       __asm__ __volatile__ (".4byte 0x100000F");
 #endif
-       }
        barrier();
 }
 
index b865046..4bf6c44 100644 (file)
@@ -326,7 +326,7 @@ clear_bss_done:
        call soc_early_init
        tail start_kernel
 
-#if CONFIG_RISCV_BOOT_SPINWAIT
+#ifdef CONFIG_RISCV_BOOT_SPINWAIT
 .Lsecondary_start:
        /* Set trap vector to spin forever to help debug */
        la a3, .Lsecondary_park
index f21592d..2bedec3 100644 (file)
@@ -48,15 +48,35 @@ static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
        post_kprobe_handler(p, kcb, regs);
 }
 
+static bool __kprobes arch_check_kprobe(struct kprobe *p)
+{
+       unsigned long tmp  = (unsigned long)p->addr - p->offset;
+       unsigned long addr = (unsigned long)p->addr;
+
+       while (tmp <= addr) {
+               if (tmp == addr)
+                       return true;
+
+               tmp += GET_INSN_LENGTH(*(u16 *)tmp);
+       }
+
+       return false;
+}
+
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
-       unsigned long probe_addr = (unsigned long)p->addr;
+       u16 *insn = (u16 *)p->addr;
+
+       if ((unsigned long)insn & 0x1)
+               return -EILSEQ;
 
-       if (probe_addr & 0x1)
+       if (!arch_check_kprobe(p))
                return -EILSEQ;
 
        /* copy instruction */
-       p->opcode = *p->addr;
+       p->opcode = (kprobe_opcode_t)(*insn++);
+       if (GET_INSN_LENGTH(p->opcode) == 4)
+               p->opcode |= (kprobe_opcode_t)(*insn) << 16;
 
        /* decode instruction */
        switch (riscv_probe_decode_insn(p->addr, &p->ainsn.api)) {
index d73e96f..a20568b 100644 (file)
@@ -71,11 +71,11 @@ bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *reg
        u32 rd_index = (opcode >> 7) & 0x1f;
        u32 rs1_index = (opcode >> 15) & 0x1f;
 
-       ret = rv_insn_reg_set_val(regs, rd_index, addr + 4);
+       ret = rv_insn_reg_get_val(regs, rs1_index, &base_addr);
        if (!ret)
                return ret;
 
-       ret = rv_insn_reg_get_val(regs, rs1_index, &base_addr);
+       ret = rv_insn_reg_set_val(regs, rd_index, addr + 4);
        if (!ret)
                return ret;
 
index 3373df4..ddb2afb 100644 (file)
@@ -39,7 +39,6 @@ static DECLARE_COMPLETION(cpu_running);
 
 void __init smp_prepare_boot_cpu(void)
 {
-       init_cpu_topology();
 }
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
@@ -48,6 +47,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        int ret;
        unsigned int curr_cpuid;
 
+       init_cpu_topology();
+
        curr_cpuid = smp_processor_id();
        store_cpu_topology(curr_cpuid);
        numa_store_cpu_info(curr_cpuid);
index 75c8dd6..f9a5a7c 100644 (file)
@@ -32,6 +32,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                fp = (unsigned long)__builtin_frame_address(0);
                sp = current_stack_pointer;
                pc = (unsigned long)walk_stackframe;
+               level = -1;
        } else {
                /* task blocked in __switch_to */
                fp = task->thread.s[0];
@@ -43,7 +44,7 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                unsigned long low, high;
                struct stackframe *frame;
 
-               if (unlikely(!__kernel_text_address(pc) || (level++ >= 1 && !fn(arg, pc))))
+               if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc))))
                        break;
 
                /* Validate frame pointer */
index 3cc07ed..fcd6145 100644 (file)
@@ -90,8 +90,10 @@ void flush_icache_pte(pte_t pte)
        if (PageHuge(page))
                page = compound_head(page);
 
-       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+       if (!test_bit(PG_dcache_clean, &page->flags)) {
                flush_icache_all();
+               set_bit(PG_dcache_clean, &page->flags);
+       }
 }
 #endif /* CONFIG_MMU */
 
index 6645ead..fef4e73 100644 (file)
@@ -81,3 +81,23 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
 }
 
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+                                       unsigned long address, pmd_t *pmdp)
+{
+       pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
+
+       VM_BUG_ON(address & ~HPAGE_PMD_MASK);
+       VM_BUG_ON(pmd_trans_huge(*pmdp));
+       /*
+        * When leaf PTE entries (regular pages) are collapsed into a leaf
+        * PMD entry (huge page), a valid non-leaf PTE is converted into a
+        * valid leaf PTE at the level 1 page table.  Since the sfence.vma
+        * forms that specify an address only apply to leaf PTEs, we need a
+        * global flush here.  collapse_huge_page() assumes these flushes are
+        * eager, so just do the fence here.
+        */
+       flush_tlb_mm(vma->vm_mm);
+       return pmd;
+}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
index e27c214..b519a1f 100644 (file)
@@ -23,9 +23,9 @@
 #define memmove memmove
 #define memzero(s, n) memset((s), 0, (n))
 
-#ifdef CONFIG_KERNEL_BZIP2
+#if defined(CONFIG_KERNEL_BZIP2)
 #define BOOT_HEAP_SIZE 0x400000
-#elif CONFIG_KERNEL_ZSTD
+#elif defined(CONFIG_KERNEL_ZSTD)
 #define BOOT_HEAP_SIZE 0x30000
 #else
 #define BOOT_HEAP_SIZE 0x10000
@@ -80,6 +80,6 @@ void *decompress_kernel(void)
        void *output = (void *)decompress_offset;
 
        __decompress(_compressed_start, _compressed_end - _compressed_start,
-                    NULL, NULL, output, 0, NULL, error);
+                    NULL, NULL, output, vmlinux.image_size, NULL, error);
        return output;
 }
index a7b4e1d..74b35ec 100644 (file)
@@ -190,7 +190,6 @@ CONFIG_NFT_CT=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
-CONFIG_NFT_OBJREF=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NFT_HASH=m
@@ -569,6 +568,7 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 CONFIG_LEGACY_PTY_COUNT=0
+# CONFIG_LEGACY_TIOCSTI is not set
 CONFIG_VIRTIO_CONSOLE=m
 CONFIG_HW_RANDOM_VIRTIO=m
 CONFIG_HANGCHECK_TIMER=m
@@ -660,6 +660,7 @@ CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
 CONFIG_CRAMFS=m
 CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT=y
 CONFIG_SQUASHFS_XATTR=y
 CONFIG_SQUASHFS_LZ4=y
 CONFIG_SQUASHFS_LZO=y
@@ -705,6 +706,7 @@ CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
 CONFIG_SECURITY_LANDLOCK=y
 CONFIG_INTEGRITY_SIGNATURE=y
 CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
+CONFIG_INTEGRITY_PLATFORM_KEYRING=y
 CONFIG_IMA=y
 CONFIG_IMA_DEFAULT_HASH_SHA256=y
 CONFIG_IMA_WRITE_POLICY=y
@@ -781,6 +783,7 @@ CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_SYSTEM_BLACKLIST_KEYRING=y
 CONFIG_CORDIC=m
 CONFIG_CRYPTO_LIB_CURVE25519=m
 CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
@@ -848,7 +851,6 @@ CONFIG_PREEMPT_TRACER=y
 CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_HIST_TRIGGERS=y
 CONFIG_FTRACE_STARTUP_TEST=y
 # CONFIG_EVENT_TRACE_STARTUP_TEST is not set
@@ -870,7 +872,6 @@ CONFIG_FAIL_MAKE_REQUEST=y
 CONFIG_FAIL_IO_TIMEOUT=y
 CONFIG_FAIL_FUTEX=y
 CONFIG_FAULT_INJECTION_DEBUG_FS=y
-CONFIG_FAIL_FUNCTION=y
 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_LKDTM=m
 CONFIG_TEST_MIN_HEAP=y
index 2bc2d0f..cec7126 100644 (file)
@@ -181,7 +181,6 @@ CONFIG_NFT_CT=m
 CONFIG_NFT_LOG=m
 CONFIG_NFT_LIMIT=m
 CONFIG_NFT_NAT=m
-CONFIG_NFT_OBJREF=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
 CONFIG_NFT_HASH=m
@@ -559,6 +558,7 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
 CONFIG_LEGACY_PTY_COUNT=0
+# CONFIG_LEGACY_TIOCSTI is not set
 CONFIG_VIRTIO_CONSOLE=m
 CONFIG_HW_RANDOM_VIRTIO=m
 CONFIG_HANGCHECK_TIMER=m
@@ -645,6 +645,7 @@ CONFIG_CONFIGFS_FS=m
 CONFIG_ECRYPT_FS=m
 CONFIG_CRAMFS=m
 CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT=y
 CONFIG_SQUASHFS_XATTR=y
 CONFIG_SQUASHFS_LZ4=y
 CONFIG_SQUASHFS_LZO=y
@@ -688,6 +689,7 @@ CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
 CONFIG_SECURITY_LANDLOCK=y
 CONFIG_INTEGRITY_SIGNATURE=y
 CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
+CONFIG_INTEGRITY_PLATFORM_KEYRING=y
 CONFIG_IMA=y
 CONFIG_IMA_DEFAULT_HASH_SHA256=y
 CONFIG_IMA_WRITE_POLICY=y
@@ -766,6 +768,7 @@ CONFIG_ZCRYPT=m
 CONFIG_PKEY=m
 CONFIG_CRYPTO_PAES_S390=m
 CONFIG_CRYPTO_DEV_VIRTIO=m
+CONFIG_SYSTEM_BLACKLIST_KEYRING=y
 CONFIG_CORDIC=m
 CONFIG_PRIME_NUMBERS=m
 CONFIG_CRYPTO_LIB_CURVE25519=m
@@ -798,7 +801,6 @@ CONFIG_STACK_TRACER=y
 CONFIG_SCHED_TRACER=y
 CONFIG_FTRACE_SYSCALLS=y
 CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_BPF_KPROBE_OVERRIDE=y
 CONFIG_HIST_TRIGGERS=y
 CONFIG_SAMPLES=y
 CONFIG_SAMPLE_TRACE_PRINTK=m
index ae14ab0..a9c0c81 100644 (file)
@@ -13,7 +13,6 @@ CONFIG_TUNE_ZEC12=y
 # CONFIG_COMPAT is not set
 CONFIG_NR_CPUS=2
 CONFIG_HZ_100=y
-# CONFIG_RELOCATABLE is not set
 # CONFIG_CHSC_SCH is not set
 # CONFIG_SCM_BUS is not set
 CONFIG_CRASH_DUMP=y
@@ -50,6 +49,7 @@ CONFIG_ZFCP=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_SERIO is not set
+# CONFIG_LEGACY_TIOCSTI is not set
 # CONFIG_HVC_IUCV is not set
 # CONFIG_HW_RANDOM_S390 is not set
 # CONFIG_HMC_DRV is not set
index feaba12..efa103b 100644 (file)
@@ -131,19 +131,21 @@ struct hws_combined_entry {
        struct hws_diag_entry   diag;   /* Diagnostic-sampling data entry */
 } __packed;
 
-struct hws_trailer_entry {
-       union {
-               struct {
-                       unsigned int f:1;       /* 0 - Block Full Indicator   */
-                       unsigned int a:1;       /* 1 - Alert request control  */
-                       unsigned int t:1;       /* 2 - Timestamp format       */
-                       unsigned int :29;       /* 3 - 31: Reserved           */
-                       unsigned int bsdes:16;  /* 32-47: size of basic SDE   */
-                       unsigned int dsdes:16;  /* 48-63: size of diagnostic SDE */
-               };
-               unsigned long long flags;       /* 0 - 63: All indicators     */
+union hws_trailer_header {
+       struct {
+               unsigned int f:1;       /* 0 - Block Full Indicator   */
+               unsigned int a:1;       /* 1 - Alert request control  */
+               unsigned int t:1;       /* 2 - Timestamp format       */
+               unsigned int :29;       /* 3 - 31: Reserved           */
+               unsigned int bsdes:16;  /* 32-47: size of basic SDE   */
+               unsigned int dsdes:16;  /* 48-63: size of diagnostic SDE */
+               unsigned long long overflow; /* 64 - Overflow Count   */
        };
-       unsigned long long overflow;     /* 64 - sample Overflow count        */
+       __uint128_t val;
+};
+
+struct hws_trailer_entry {
+       union hws_trailer_header header; /* 0 - 15 Flags + Overflow Count     */
        unsigned char timestamp[16];     /* 16 - 31 timestamp                 */
        unsigned long long reserved1;    /* 32 -Reserved                      */
        unsigned long long reserved2;    /*                                   */
@@ -290,14 +292,11 @@ static inline unsigned long sample_rate_to_freq(struct hws_qsi_info_block *qsi,
        return USEC_PER_SEC * qsi->cpu_speed / rate;
 }
 
-#define SDB_TE_ALERT_REQ_MASK  0x4000000000000000UL
-#define SDB_TE_BUFFER_FULL_MASK 0x8000000000000000UL
-
 /* Return TOD timestamp contained in an trailer entry */
 static inline unsigned long long trailer_timestamp(struct hws_trailer_entry *te)
 {
        /* TOD in STCKE format */
-       if (te->t)
+       if (te->header.t)
                return *((unsigned long long *) &te->timestamp[1]);
 
        /* TOD in STCK format */
index 77f2426..ac665b9 100644 (file)
@@ -4,8 +4,8 @@
  *
  *    Copyright IBM Corp. 1999, 2020
  */
-#ifndef DEBUG_H
-#define DEBUG_H
+#ifndef _ASM_S390_DEBUG_H
+#define _ASM_S390_DEBUG_H
 
 #include <linux/string.h>
 #include <linux/spinlock.h>
@@ -487,4 +487,4 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
 
 #endif /* MODULE */
 
-#endif /* DEBUG_H */
+#endif /* _ASM_S390_DEBUG_H */
index cb5fc06..081837b 100644 (file)
@@ -31,7 +31,7 @@
        pcp_op_T__ *ptr__;                                              \
        preempt_disable_notrace();                                      \
        ptr__ = raw_cpu_ptr(&(pcp));                                    \
-       prev__ = *ptr__;                                                \
+       prev__ = READ_ONCE(*ptr__);                                     \
        do {                                                            \
                old__ = prev__;                                         \
                new__ = old__ op (val);                                 \
index fc6d5f5..2df94d3 100644 (file)
@@ -187,8 +187,6 @@ static int kexec_file_add_ipl_report(struct kimage *image,
 
        data->memsz = ALIGN(data->memsz, PAGE_SIZE);
        buf.mem = data->memsz;
-       if (image->type == KEXEC_TYPE_CRASH)
-               buf.mem += crashk_res.start;
 
        ptr = (void *)ipl_cert_list_addr;
        end = ptr + ipl_cert_list_size;
@@ -225,6 +223,9 @@ static int kexec_file_add_ipl_report(struct kimage *image,
                data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
        *lc_ipl_parmblock_ptr = (__u32)buf.mem;
 
+       if (image->type == KEXEC_TYPE_CRASH)
+               buf.mem += crashk_res.start;
+
        ret = kexec_add_buffer(&buf);
 out:
        return ret;
index 332a499..ce886a0 100644 (file)
@@ -163,14 +163,15 @@ static void free_sampling_buffer(struct sf_buffer *sfb)
 
 static int alloc_sample_data_block(unsigned long *sdbt, gfp_t gfp_flags)
 {
-       unsigned long sdb, *trailer;
+       struct hws_trailer_entry *te;
+       unsigned long sdb;
 
        /* Allocate and initialize sample-data-block */
        sdb = get_zeroed_page(gfp_flags);
        if (!sdb)
                return -ENOMEM;
-       trailer = trailer_entry_ptr(sdb);
-       *trailer = SDB_TE_ALERT_REQ_MASK;
+       te = (struct hws_trailer_entry *)trailer_entry_ptr(sdb);
+       te->header.a = 1;
 
        /* Link SDB into the sample-data-block-table */
        *sdbt = sdb;
@@ -1206,7 +1207,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
                                            "%s: Found unknown"
                                            " sampling data entry: te->f %i"
                                            " basic.def %#4x (%p)\n", __func__,
-                                           te->f, sample->def, sample);
+                                           te->header.f, sample->def, sample);
                        /* Sample slot is not yet written or other record.
                         *
                         * This condition can occur if the buffer was reused
@@ -1217,7 +1218,7 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
                         * that are not full.  Stop processing if the first
                         * invalid format was detected.
                         */
-                       if (!te->f)
+                       if (!te->header.f)
                                break;
                }
 
@@ -1227,6 +1228,16 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
        }
 }
 
+static inline __uint128_t __cdsg(__uint128_t *ptr, __uint128_t old, __uint128_t new)
+{
+       asm volatile(
+               "       cdsg    %[old],%[new],%[ptr]\n"
+               : [old] "+d" (old), [ptr] "+QS" (*ptr)
+               : [new] "d" (new)
+               : "memory", "cc");
+       return old;
+}
+
 /* hw_perf_event_update() - Process sampling buffer
  * @event:     The perf event
  * @flush_all: Flag to also flush partially filled sample-data-blocks
@@ -1243,10 +1254,11 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt,
  */
 static void hw_perf_event_update(struct perf_event *event, int flush_all)
 {
+       unsigned long long event_overflow, sampl_overflow, num_sdb;
+       union hws_trailer_header old, prev, new;
        struct hw_perf_event *hwc = &event->hw;
        struct hws_trailer_entry *te;
        unsigned long *sdbt;
-       unsigned long long event_overflow, sampl_overflow, num_sdb, te_flags;
        int done;
 
        /*
@@ -1266,25 +1278,25 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
                te = (struct hws_trailer_entry *) trailer_entry_ptr(*sdbt);
 
                /* Leave loop if no more work to do (block full indicator) */
-               if (!te->f) {
+               if (!te->header.f) {
                        done = 1;
                        if (!flush_all)
                                break;
                }
 
                /* Check the sample overflow count */
-               if (te->overflow)
+               if (te->header.overflow)
                        /* Account sample overflows and, if a particular limit
                         * is reached, extend the sampling buffer.
                         * For details, see sfb_account_overflows().
                         */
-                       sampl_overflow += te->overflow;
+                       sampl_overflow += te->header.overflow;
 
                /* Timestamps are valid for full sample-data-blocks only */
                debug_sprintf_event(sfdbg, 6, "%s: sdbt %#lx "
                                    "overflow %llu timestamp %#llx\n",
-                                   __func__, (unsigned long)sdbt, te->overflow,
-                                   (te->f) ? trailer_timestamp(te) : 0ULL);
+                                   __func__, (unsigned long)sdbt, te->header.overflow,
+                                   (te->header.f) ? trailer_timestamp(te) : 0ULL);
 
                /* Collect all samples from a single sample-data-block and
                 * flag if an (perf) event overflow happened.  If so, the PMU
@@ -1294,12 +1306,16 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all)
                num_sdb++;
 
                /* Reset trailer (using compare-double-and-swap) */
+               /* READ_ONCE() 16 byte header */
+               prev.val = __cdsg(&te->header.val, 0, 0);
                do {
-                       te_flags = te->flags & ~SDB_TE_BUFFER_FULL_MASK;
-                       te_flags |= SDB_TE_ALERT_REQ_MASK;
-               } while (!cmpxchg_double(&te->flags, &te->overflow,
-                                        te->flags, te->overflow,
-                                        te_flags, 0ULL));
+                       old.val = prev.val;
+                       new.val = prev.val;
+                       new.f = 0;
+                       new.a = 1;
+                       new.overflow = 0;
+                       prev.val = __cdsg(&te->header.val, old.val, new.val);
+               } while (prev.val != old.val);
 
                /* Advance to next sample-data-block */
                sdbt++;
@@ -1384,7 +1400,7 @@ static void aux_output_end(struct perf_output_handle *handle)
        range_scan = AUX_SDB_NUM_ALERT(aux);
        for (i = 0, idx = aux->head; i < range_scan; i++, idx++) {
                te = aux_sdb_trailer(aux, idx);
-               if (!(te->flags & SDB_TE_BUFFER_FULL_MASK))
+               if (!te->header.f)
                        break;
        }
        /* i is num of SDBs which are full */
@@ -1392,7 +1408,7 @@ static void aux_output_end(struct perf_output_handle *handle)
 
        /* Remove alert indicators in the buffer */
        te = aux_sdb_trailer(aux, aux->alert_mark);
-       te->flags &= ~SDB_TE_ALERT_REQ_MASK;
+       te->header.a = 0;
 
        debug_sprintf_event(sfdbg, 6, "%s: SDBs %ld range %ld head %ld\n",
                            __func__, i, range_scan, aux->head);
@@ -1437,9 +1453,9 @@ static int aux_output_begin(struct perf_output_handle *handle,
                idx = aux->empty_mark + 1;
                for (i = 0; i < range_scan; i++, idx++) {
                        te = aux_sdb_trailer(aux, idx);
-                       te->flags &= ~(SDB_TE_BUFFER_FULL_MASK |
-                                      SDB_TE_ALERT_REQ_MASK);
-                       te->overflow = 0;
+                       te->header.f = 0;
+                       te->header.a = 0;
+                       te->header.overflow = 0;
                }
                /* Save the position of empty SDBs */
                aux->empty_mark = aux->head + range - 1;
@@ -1448,7 +1464,7 @@ static int aux_output_begin(struct perf_output_handle *handle,
        /* Set alert indicator */
        aux->alert_mark = aux->head + range/2 - 1;
        te = aux_sdb_trailer(aux, aux->alert_mark);
-       te->flags = te->flags | SDB_TE_ALERT_REQ_MASK;
+       te->header.a = 1;
 
        /* Reset hardware buffer head */
        head = AUX_SDB_INDEX(aux, aux->head);
@@ -1475,14 +1491,17 @@ static int aux_output_begin(struct perf_output_handle *handle,
 static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
                          unsigned long long *overflow)
 {
-       unsigned long long orig_overflow, orig_flags, new_flags;
+       union hws_trailer_header old, prev, new;
        struct hws_trailer_entry *te;
 
        te = aux_sdb_trailer(aux, alert_index);
+       /* READ_ONCE() 16 byte header */
+       prev.val = __cdsg(&te->header.val, 0, 0);
        do {
-               orig_flags = te->flags;
-               *overflow = orig_overflow = te->overflow;
-               if (orig_flags & SDB_TE_BUFFER_FULL_MASK) {
+               old.val = prev.val;
+               new.val = prev.val;
+               *overflow = old.overflow;
+               if (old.f) {
                        /*
                         * SDB is already set by hardware.
                         * Abort and try to set somewhere
@@ -1490,10 +1509,10 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
                         */
                        return false;
                }
-               new_flags = orig_flags | SDB_TE_ALERT_REQ_MASK;
-       } while (!cmpxchg_double(&te->flags, &te->overflow,
-                                orig_flags, orig_overflow,
-                                new_flags, 0ULL));
+               new.a = 1;
+               new.overflow = 0;
+               prev.val = __cdsg(&te->header.val, old.val, new.val);
+       } while (prev.val != old.val);
        return true;
 }
 
@@ -1522,8 +1541,9 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index,
 static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
                             unsigned long long *overflow)
 {
-       unsigned long long orig_overflow, orig_flags, new_flags;
        unsigned long i, range_scan, idx, idx_old;
+       union hws_trailer_header old, prev, new;
+       unsigned long long orig_overflow;
        struct hws_trailer_entry *te;
 
        debug_sprintf_event(sfdbg, 6, "%s: range %ld head %ld alert %ld "
@@ -1554,17 +1574,20 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range,
        idx_old = idx = aux->empty_mark + 1;
        for (i = 0; i < range_scan; i++, idx++) {
                te = aux_sdb_trailer(aux, idx);
+               /* READ_ONCE() 16 byte header */
+               prev.val = __cdsg(&te->header.val, 0, 0);
                do {
-                       orig_flags = te->flags;
-                       orig_overflow = te->overflow;
-                       new_flags = orig_flags & ~SDB_TE_BUFFER_FULL_MASK;
+                       old.val = prev.val;
+                       new.val = prev.val;
+                       orig_overflow = old.overflow;
+                       new.f = 0;
+                       new.overflow = 0;
                        if (idx == aux->alert_mark)
-                               new_flags |= SDB_TE_ALERT_REQ_MASK;
+                               new.a = 1;
                        else
-                               new_flags &= ~SDB_TE_ALERT_REQ_MASK;
-               } while (!cmpxchg_double(&te->flags, &te->overflow,
-                                        orig_flags, orig_overflow,
-                                        new_flags, 0ULL));
+                               new.a = 0;
+                       prev.val = __cdsg(&te->header.val, old.val, new.val);
+               } while (prev.val != old.val);
                *overflow += orig_overflow;
        }
 
index 2b60913..696c9e0 100644 (file)
@@ -508,6 +508,7 @@ static void __init setup_lowcore_dat_on(void)
 {
        struct lowcore *abs_lc;
        unsigned long flags;
+       int i;
 
        __ctl_clear_bit(0, 28);
        S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT;
@@ -523,8 +524,8 @@ static void __init setup_lowcore_dat_on(void)
        abs_lc = get_abs_lowcore(&flags);
        abs_lc->restart_flags = RESTART_FLAG_CTLREGS;
        abs_lc->program_new_psw = S390_lowcore.program_new_psw;
-       memcpy(abs_lc->cregs_save_area, S390_lowcore.cregs_save_area,
-              sizeof(abs_lc->cregs_save_area));
+       for (i = 0; i < 16; i++)
+               abs_lc->cregs_save_area[i] = S390_lowcore.cregs_save_area[i];
        put_abs_lowcore(abs_lc, flags);
 }
 
index 5ea3830..cbf9c1b 100644 (file)
@@ -17,6 +17,8 @@
 /* Handle ro_after_init data on our own. */
 #define RO_AFTER_INIT_DATA
 
+#define RUNTIME_DISCARD_EXIT
+
 #define EMITS_PT_NOTE
 
 #include <asm-generic/vmlinux.lds.h>
@@ -79,6 +81,7 @@ SECTIONS
                _end_amode31_refs = .;
        }
 
+       . = ALIGN(PAGE_SIZE);
        _edata = .;             /* End of data section */
 
        /* will be freed after init */
@@ -193,6 +196,7 @@ SECTIONS
 
        BSS_SECTION(PAGE_SIZE, 4 * PAGE_SIZE, PAGE_SIZE)
 
+       . = ALIGN(PAGE_SIZE);
        _end = . ;
 
        /*
index 1dae78d..ab26aa5 100644 (file)
@@ -83,8 +83,9 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
                struct esca_block *sca = vcpu->kvm->arch.sca;
                union esca_sigp_ctrl *sigp_ctrl =
                        &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-               union esca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+               union esca_sigp_ctrl new_val = {0}, old_val;
 
+               old_val = READ_ONCE(*sigp_ctrl);
                new_val.scn = src_id;
                new_val.c = 1;
                old_val.c = 0;
@@ -95,8 +96,9 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
                struct bsca_block *sca = vcpu->kvm->arch.sca;
                union bsca_sigp_ctrl *sigp_ctrl =
                        &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-               union bsca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+               union bsca_sigp_ctrl new_val = {0}, old_val;
 
+               old_val = READ_ONCE(*sigp_ctrl);
                new_val.scn = src_id;
                new_val.c = 1;
                old_val.c = 0;
@@ -126,16 +128,18 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
                struct esca_block *sca = vcpu->kvm->arch.sca;
                union esca_sigp_ctrl *sigp_ctrl =
                        &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-               union esca_sigp_ctrl old = *sigp_ctrl;
+               union esca_sigp_ctrl old;
 
+               old = READ_ONCE(*sigp_ctrl);
                expect = old.value;
                rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
        } else {
                struct bsca_block *sca = vcpu->kvm->arch.sca;
                union bsca_sigp_ctrl *sigp_ctrl =
                        &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
-               union bsca_sigp_ctrl old = *sigp_ctrl;
+               union bsca_sigp_ctrl old;
 
+               old = READ_ONCE(*sigp_ctrl);
                expect = old.value;
                rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
        }
index a889a3a..d1ce73f 100644 (file)
@@ -28,7 +28,7 @@
 #define pmd_ERROR(e) \
        printk("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
 
-typedef struct {
+typedef union {
        struct {
                unsigned long pmd_low;
                unsigned long pmd_high;
index 3161b9c..b6276a3 100644 (file)
@@ -4,6 +4,7 @@
  * Written by Niibe Yutaka and Paul Mundt
  */
 OUTPUT_ARCH(sh)
+#define RUNTIME_DISCARD_EXIT
 #include <asm/thread_info.h>
 #include <asm/cache.h>
 #include <asm/vmlinux.lds.h>
index 9cf0732..73ed982 100644 (file)
@@ -14,13 +14,13 @@ endif
 
 ifdef CONFIG_CC_IS_GCC
 RETPOLINE_CFLAGS       := $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register)
-RETPOLINE_CFLAGS       += $(call cc-option,-mindirect-branch-cs-prefix)
 RETPOLINE_VDSO_CFLAGS  := $(call cc-option,-mindirect-branch=thunk-inline -mindirect-branch-register)
 endif
 ifdef CONFIG_CC_IS_CLANG
 RETPOLINE_CFLAGS       := -mretpoline-external-thunk
 RETPOLINE_VDSO_CFLAGS  := -mretpoline
 endif
+RETPOLINE_CFLAGS       += $(call cc-option,-mindirect-branch-cs-prefix)
 
 ifdef CONFIG_RETHUNK
 RETHUNK_CFLAGS         := -mfunction-return=thunk-extern
index 5521ea1..aa9b964 100644 (file)
@@ -32,7 +32,7 @@ intcall:
        movw    %dx, %si
        movw    %sp, %di
        movw    $11, %cx
-       rep; movsd
+       rep; movsl
 
        /* Pop full state from the stack */
        popal
@@ -67,7 +67,7 @@ intcall:
        jz      4f
        movw    %sp, %si
        movw    $11, %cx
-       rep; movsd
+       rep; movsl
 4:     addw    $44, %sp
 
        /* Restore state and return */
index d4a314c..321a501 100644 (file)
@@ -180,6 +180,12 @@ void initialize_identity_maps(void *rmode)
 
        /* Load the new page-table. */
        write_cr3(top_level_pgt);
+
+       /*
+        * Now that the required page table mappings are established and a
+        * GHCB can be used, check for SNP guest/HV feature compatibility.
+        */
+       snp_check_features();
 }
 
 static pte_t *split_large_pmd(struct x86_mapping_info *info,
index 62208ec..20118fb 100644 (file)
@@ -126,6 +126,7 @@ static inline void console_init(void)
 
 #ifdef CONFIG_AMD_MEM_ENCRYPT
 void sev_enable(struct boot_params *bp);
+void snp_check_features(void);
 void sev_es_shutdown_ghcb(void);
 extern bool sev_es_check_ghcb_fault(unsigned long address);
 void snp_set_page_private(unsigned long paddr);
@@ -143,6 +144,7 @@ static inline void sev_enable(struct boot_params *bp)
        if (bp)
                bp->cc_blob_address = 0;
 }
+static inline void snp_check_features(void) { }
 static inline void sev_es_shutdown_ghcb(void) { }
 static inline bool sev_es_check_ghcb_fault(unsigned long address)
 {
index c93930d..d63ad8f 100644 (file)
@@ -208,6 +208,23 @@ void sev_es_shutdown_ghcb(void)
                error("Can't unmap GHCB page");
 }
 
+static void __noreturn sev_es_ghcb_terminate(struct ghcb *ghcb, unsigned int set,
+                                            unsigned int reason, u64 exit_info_2)
+{
+       u64 exit_info_1 = SVM_VMGEXIT_TERM_REASON(set, reason);
+
+       vc_ghcb_invalidate(ghcb);
+       ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_TERM_REQUEST);
+       ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
+       ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
+
+       sev_es_wr_ghcb_msr(__pa(ghcb));
+       VMGEXIT();
+
+       while (true)
+               asm volatile("hlt\n" : : : "memory");
+}
+
 bool sev_es_check_ghcb_fault(unsigned long address)
 {
        /* Check whether the fault was on the GHCB page */
@@ -270,6 +287,59 @@ static void enforce_vmpl0(void)
                sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
 }
 
+/*
+ * SNP_FEATURES_IMPL_REQ is the mask of SNP features that will need
+ * guest side implementation for proper functioning of the guest. If any
+ * of these features are enabled in the hypervisor but are lacking guest
+ * side implementation, the behavior of the guest will be undefined. The
+ * guest could fail in non-obvious way making it difficult to debug.
+ *
+ * As the behavior of reserved feature bits is unknown to be on the
+ * safe side add them to the required features mask.
+ */
+#define SNP_FEATURES_IMPL_REQ  (MSR_AMD64_SNP_VTOM |                   \
+                                MSR_AMD64_SNP_REFLECT_VC |             \
+                                MSR_AMD64_SNP_RESTRICTED_INJ |         \
+                                MSR_AMD64_SNP_ALT_INJ |                \
+                                MSR_AMD64_SNP_DEBUG_SWAP |             \
+                                MSR_AMD64_SNP_VMPL_SSS |               \
+                                MSR_AMD64_SNP_SECURE_TSC |             \
+                                MSR_AMD64_SNP_VMGEXIT_PARAM |          \
+                                MSR_AMD64_SNP_VMSA_REG_PROTECTION |    \
+                                MSR_AMD64_SNP_RESERVED_BIT13 |         \
+                                MSR_AMD64_SNP_RESERVED_BIT15 |         \
+                                MSR_AMD64_SNP_RESERVED_MASK)
+
+/*
+ * SNP_FEATURES_PRESENT is the mask of SNP features that are implemented
+ * by the guest kernel. As and when a new feature is implemented in the
+ * guest kernel, a corresponding bit should be added to the mask.
+ */
+#define SNP_FEATURES_PRESENT (0)
+
+void snp_check_features(void)
+{
+       u64 unsupported;
+
+       if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
+               return;
+
+       /*
+        * Terminate the boot if hypervisor has enabled any feature lacking
+        * guest side implementation. Pass on the unsupported features mask through
+        * EXIT_INFO_2 of the GHCB protocol so that those features can be reported
+        * as part of the guest boot failure.
+        */
+       unsupported = sev_status & SNP_FEATURES_IMPL_REQ & ~SNP_FEATURES_PRESENT;
+       if (unsupported) {
+               if (ghcb_version < 2 || (!boot_ghcb && !early_setup_ghcb()))
+                       sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
+
+               sev_es_ghcb_terminate(boot_ghcb, SEV_TERM_SET_GEN,
+                                     GHCB_SNP_UNSUPPORTED, unsupported);
+       }
+}
+
 void sev_enable(struct boot_params *bp)
 {
        unsigned int eax, ebx, ecx, edx;
index dfd2c12..bafdc2b 100644 (file)
@@ -6339,6 +6339,7 @@ __init int intel_pmu_init(void)
                break;
 
        case INTEL_FAM6_SAPPHIRERAPIDS_X:
+       case INTEL_FAM6_EMERALDRAPIDS_X:
                pmem = true;
                x86_pmu.late_ack = true;
                memcpy(hw_cache_event_ids, spr_hw_cache_event_ids, sizeof(hw_cache_event_ids));
index a2834bc..551741e 100644 (file)
@@ -41,6 +41,7 @@
  *     MSR_CORE_C1_RES: CORE C1 Residency Counter
  *                      perf code: 0x00
  *                      Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL,RPL
+ *                                       MTL
  *                      Scope: Core (each processor core has a MSR)
  *     MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter
  *                            perf code: 0x01
  *                            perf code: 0x02
  *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
  *                                             SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
- *                                             TGL,TNT,RKL,ADL,RPL,SPR
+ *                                             TGL,TNT,RKL,ADL,RPL,SPR,MTL
  *                            Scope: Core
  *     MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter
  *                            perf code: 0x03
  *                            Available model: SNB,IVB,HSW,BDW,SKL,CNL,KBL,CML,
- *                                             ICL,TGL,RKL,ADL,RPL
+ *                                             ICL,TGL,RKL,ADL,RPL,MTL
  *                            Scope: Core
  *     MSR_PKG_C2_RESIDENCY:  Package C2 Residency Counter.
  *                            perf code: 0x00
  *                            Available model: SNB,IVB,HSW,BDW,SKL,KNL,GLM,CNL,
  *                                             KBL,CML,ICL,ICX,TGL,TNT,RKL,ADL,
- *                                             RPL,SPR
+ *                                             RPL,SPR,MTL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C3_RESIDENCY:  Package C3 Residency Counter.
  *                            perf code: 0x01
  *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,KNL,
  *                                             GLM,CNL,KBL,CML,ICL,TGL,TNT,RKL,
- *                                             ADL,RPL
+ *                                             ADL,RPL,MTL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C6_RESIDENCY:  Package C6 Residency Counter.
  *                            perf code: 0x02
  *                            Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,
  *                                             SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX,
- *                                             TGL,TNT,RKL,ADL,RPL,SPR
+ *                                             TGL,TNT,RKL,ADL,RPL,SPR,MTL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C7_RESIDENCY:  Package C7 Residency Counter.
  *                            perf code: 0x03
  *                            Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL,CNL,
- *                                             KBL,CML,ICL,TGL,RKL,ADL,RPL
+ *                                             KBL,CML,ICL,TGL,RKL,ADL,RPL,MTL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C8_RESIDENCY:  Package C8 Residency Counter.
  *                            perf code: 0x04
  *                            Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL,
- *                                             ADL,RPL
+ *                                             ADL,RPL,MTL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C9_RESIDENCY:  Package C9 Residency Counter.
  *                            perf code: 0x05
  *                            Available model: HSW ULT,KBL,CNL,CML,ICL,TGL,RKL,
- *                                             ADL,RPL
+ *                                             ADL,RPL,MTL
  *                            Scope: Package (physical package)
  *     MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter.
  *                            perf code: 0x06
  *                            Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL,
- *                                             TNT,RKL,ADL,RPL
+ *                                             TNT,RKL,ADL,RPL,MTL
  *                            Scope: Package (physical package)
  *
  */
@@ -676,6 +677,7 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,           &icx_cstates),
        X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,           &icx_cstates),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &icx_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X,     &icx_cstates),
 
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &icl_cstates),
        X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           &icl_cstates),
@@ -686,6 +688,8 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE,          &adl_cstates),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P,        &adl_cstates),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S,        &adl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE,          &adl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L,        &adl_cstates),
        { },
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
index 6f1ccc5..459b1aa 100644 (file)
@@ -1833,6 +1833,7 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = {
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P,        &adl_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S,        &adl_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X,    &spr_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X,     &spr_uncore_init),
        X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      &snr_uncore_init),
        {},
 };
index ecced3a..c65d890 100644 (file)
@@ -69,6 +69,7 @@ static bool test_intel(int idx, void *data)
        case INTEL_FAM6_BROADWELL_G:
        case INTEL_FAM6_BROADWELL_X:
        case INTEL_FAM6_SAPPHIRERAPIDS_X:
+       case INTEL_FAM6_EMERALDRAPIDS_X:
 
        case INTEL_FAM6_ATOM_SILVERMONT:
        case INTEL_FAM6_ATOM_SILVERMONT_D:
@@ -107,6 +108,8 @@ static bool test_intel(int idx, void *data)
        case INTEL_FAM6_RAPTORLAKE:
        case INTEL_FAM6_RAPTORLAKE_P:
        case INTEL_FAM6_RAPTORLAKE_S:
+       case INTEL_FAM6_METEORLAKE:
+       case INTEL_FAM6_METEORLAKE_L:
                if (idx == PERF_MSR_SMI || idx == PERF_MSR_PPERF)
                        return true;
                break;
index 65064d9..8eb74cf 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/mmu.h>
 #include <asm/mpspec.h>
 #include <asm/x86_init.h>
+#include <asm/cpufeature.h>
 
 #ifdef CONFIG_ACPI_APEI
 # include <asm/pgtable_types.h>
@@ -63,6 +64,13 @@ extern int (*acpi_suspend_lowlevel)(void);
 /* Physical address to resume after wakeup */
 unsigned long acpi_get_wakeup_address(void);
 
+static inline bool acpi_skip_set_wakeup_address(void)
+{
+       return cpu_feature_enabled(X86_FEATURE_XENPV);
+}
+
+#define acpi_skip_set_wakeup_address acpi_skip_set_wakeup_address
+
 /*
  * Check if the CPU can handle C2 and deeper
  */
index b049d95..ca97442 100644 (file)
@@ -39,7 +39,20 @@ static __always_inline unsigned long native_get_debugreg(int regno)
                asm("mov %%db6, %0" :"=r" (val));
                break;
        case 7:
-               asm("mov %%db7, %0" :"=r" (val));
+               /*
+                * Apply __FORCE_ORDER to DR7 reads to forbid re-ordering them
+                * with other code.
+                *
+                * This is needed because a DR7 access can cause a #VC exception
+                * when running under SEV-ES. Taking a #VC exception is not a
+                * safe thing to do just anywhere in the entry code and
+                * re-ordering might place the access into an unsafe location.
+                *
+                * This happened in the NMI handler, where the DR7 read was
+                * re-ordered to happen before the call to sev_es_ist_enter(),
+                * causing stack recursion.
+                */
+               asm volatile("mov %%db7, %0" : "=r" (val) : __FORCE_ORDER);
                break;
        default:
                BUG();
@@ -66,7 +79,16 @@ static __always_inline void native_set_debugreg(int regno, unsigned long value)
                asm("mov %0, %%db6"     ::"r" (value));
                break;
        case 7:
-               asm("mov %0, %%db7"     ::"r" (value));
+               /*
+                * Apply __FORCE_ORDER to DR7 writes to forbid re-ordering them
+                * with other code.
+                *
+                * While is didn't happen with a DR7 write (see the DR7 read
+                * comment above which explains where it happened), add the
+                * __FORCE_ORDER here too to avoid similar problems in the
+                * future.
+                */
+               asm volatile("mov %0, %%db7"    ::"r" (value), __FORCE_ORDER);
                break;
        default:
                BUG();
index 347707d..cbaf174 100644 (file)
 #define INTEL_FAM6_METEORLAKE          0xAC
 #define INTEL_FAM6_METEORLAKE_L                0xAA
 
+#define INTEL_FAM6_LUNARLAKE_M         0xBD
+
 /* "Small Core" Processors (Atom/E-Core) */
 
 #define INTEL_FAM6_ATOM_BONNELL                0x1C /* Diamondville, Pineview */
index f35f1ff..6aaae18 100644 (file)
@@ -1111,6 +1111,7 @@ struct msr_bitmap_range {
 
 /* Xen emulation context */
 struct kvm_xen {
+       struct mutex xen_lock;
        u32 xen_version;
        bool long_mode;
        bool runstate_update_flag;
index 37ff475..d3fe82c 100644 (file)
 #define MSR_AMD64_SEV_ES_ENABLED       BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT)
 #define MSR_AMD64_SEV_SNP_ENABLED      BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)
 
+/* SNP feature bits enabled by the hypervisor */
+#define MSR_AMD64_SNP_VTOM                     BIT_ULL(3)
+#define MSR_AMD64_SNP_REFLECT_VC               BIT_ULL(4)
+#define MSR_AMD64_SNP_RESTRICTED_INJ           BIT_ULL(5)
+#define MSR_AMD64_SNP_ALT_INJ                  BIT_ULL(6)
+#define MSR_AMD64_SNP_DEBUG_SWAP               BIT_ULL(7)
+#define MSR_AMD64_SNP_PREVENT_HOST_IBS         BIT_ULL(8)
+#define MSR_AMD64_SNP_BTB_ISOLATION            BIT_ULL(9)
+#define MSR_AMD64_SNP_VMPL_SSS                 BIT_ULL(10)
+#define MSR_AMD64_SNP_SECURE_TSC               BIT_ULL(11)
+#define MSR_AMD64_SNP_VMGEXIT_PARAM            BIT_ULL(12)
+#define MSR_AMD64_SNP_IBS_VIRT                 BIT_ULL(14)
+#define MSR_AMD64_SNP_VMSA_REG_PROTECTION      BIT_ULL(16)
+#define MSR_AMD64_SNP_SMT_PROTECTION           BIT_ULL(17)
+
+/* SNP feature bits reserved for future use. */
+#define MSR_AMD64_SNP_RESERVED_BIT13           BIT_ULL(13)
+#define MSR_AMD64_SNP_RESERVED_BIT15           BIT_ULL(15)
+#define MSR_AMD64_SNP_RESERVED_MASK            GENMASK_ULL(63, 18)
+
 #define MSR_AMD64_VIRT_SPEC_CTRL       0xc001011f
 
 /* AMD Collaborative Processor Performance Control MSRs */
index f69c168..80e1df4 100644 (file)
 #define SVM_VMGEXIT_AP_CREATE                  1
 #define SVM_VMGEXIT_AP_DESTROY                 2
 #define SVM_VMGEXIT_HV_FEATURES                        0x8000fffd
+#define SVM_VMGEXIT_TERM_REQUEST               0x8000fffe
+#define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code)       \
+       /* SW_EXITINFO1[3:0] */                                 \
+       (((((u64)reason_set) & 0xf)) |                          \
+       /* SW_EXITINFO1[11:4] */                                \
+       ((((u64)reason_code) & 0xff) << 4))
 #define SVM_VMGEXIT_UNSUPPORTED_EVENT          0x8000ffff
 
 /* Exit code reserved for hypervisor/software use */
index 1f60a2b..fdbb5f0 100644 (file)
@@ -330,7 +330,16 @@ static void __init bp_init_freq_invariance(void)
 
 static void disable_freq_invariance_workfn(struct work_struct *work)
 {
+       int cpu;
+
        static_branch_disable(&arch_scale_freq_key);
+
+       /*
+        * Set arch_freq_scale to a default value on all cpus
+        * This negates the effect of scaling
+        */
+       for_each_possible_cpu(cpu)
+               per_cpu(arch_freq_scale, cpu) = SCHED_CAPACITY_SCALE;
 }
 
 static DECLARE_WORK(disable_freq_invariance_work,
index efe0c30..77538ab 100644 (file)
@@ -146,6 +146,30 @@ static inline struct rmid_entry *__rmid_entry(u32 rmid)
        return entry;
 }
 
+static int __rmid_read(u32 rmid, enum resctrl_event_id eventid, u64 *val)
+{
+       u64 msr_val;
+
+       /*
+        * As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
+        * with a valid event code for supported resource type and the bits
+        * IA32_QM_EVTSEL.RMID (bits 41:32) are configured with valid RMID,
+        * IA32_QM_CTR.data (bits 61:0) reports the monitored data.
+        * IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
+        * are error bits.
+        */
+       wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
+       rdmsrl(MSR_IA32_QM_CTR, msr_val);
+
+       if (msr_val & RMID_VAL_ERROR)
+               return -EIO;
+       if (msr_val & RMID_VAL_UNAVAIL)
+               return -EINVAL;
+
+       *val = msr_val;
+       return 0;
+}
+
 static struct arch_mbm_state *get_arch_mbm_state(struct rdt_hw_domain *hw_dom,
                                                 u32 rmid,
                                                 enum resctrl_event_id eventid)
@@ -172,8 +196,12 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d,
        struct arch_mbm_state *am;
 
        am = get_arch_mbm_state(hw_dom, rmid, eventid);
-       if (am)
+       if (am) {
                memset(am, 0, sizeof(*am));
+
+               /* Record any initial, non-zero count value. */
+               __rmid_read(rmid, eventid, &am->prev_msr);
+       }
 }
 
 static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr, unsigned int width)
@@ -191,25 +219,14 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d,
        struct rdt_hw_domain *hw_dom = resctrl_to_arch_dom(d);
        struct arch_mbm_state *am;
        u64 msr_val, chunks;
+       int ret;
 
        if (!cpumask_test_cpu(smp_processor_id(), &d->cpu_mask))
                return -EINVAL;
 
-       /*
-        * As per the SDM, when IA32_QM_EVTSEL.EvtID (bits 7:0) is configured
-        * with a valid event code for supported resource type and the bits
-        * IA32_QM_EVTSEL.RMID (bits 41:32) are configured with valid RMID,
-        * IA32_QM_CTR.data (bits 61:0) reports the monitored data.
-        * IA32_QM_CTR.Error (bit 63) and IA32_QM_CTR.Unavailable (bit 62)
-        * are error bits.
-        */
-       wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
-       rdmsrl(MSR_IA32_QM_CTR, msr_val);
-
-       if (msr_val & RMID_VAL_ERROR)
-               return -EIO;
-       if (msr_val & RMID_VAL_UNAVAIL)
-               return -EINVAL;
+       ret = __rmid_read(rmid, eventid, &msr_val);
+       if (ret)
+               return ret;
 
        am = get_arch_mbm_state(hw_dom, rmid, eventid);
        if (am) {
index e5a48f0..5993da2 100644 (file)
@@ -580,8 +580,10 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
        /*
         * Ensure the task's closid and rmid are written before determining if
         * the task is current that will decide if it will be interrupted.
+        * This pairs with the full barrier between the rq->curr update and
+        * resctrl_sched_in() during context switch.
         */
-       barrier();
+       smp_mb();
 
        /*
         * By now, the task's closid and rmid are set. If the task is current
@@ -2401,6 +2403,14 @@ static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
                        WRITE_ONCE(t->closid, to->closid);
                        WRITE_ONCE(t->rmid, to->mon.rmid);
 
+                       /*
+                        * Order the closid/rmid stores above before the loads
+                        * in task_curr(). This pairs with the full barrier
+                        * between the rq->curr update and resctrl_sched_in()
+                        * during context switch.
+                        */
+                       smp_mb();
+
                        /*
                         * If the task is on a CPU, set the CPU in the mask.
                         * The detection is inaccurate as tasks might move or
index 3aa5304..4d8aff0 100644 (file)
@@ -114,6 +114,7 @@ static void make_8259A_irq(unsigned int irq)
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
        irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
+       irq_set_status_flags(irq, IRQ_LEVEL);
        enable_irq(irq);
        lapic_assign_legacy_vector(irq, true);
 }
index beb1bad..c683666 100644 (file)
@@ -65,8 +65,10 @@ void __init init_ISA_irqs(void)
 
        legacy_pic->init(0);
 
-       for (i = 0; i < nr_legacy_irqs(); i++)
+       for (i = 0; i < nr_legacy_irqs(); i++) {
                irq_set_chip_and_handler(i, chip, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
+       }
 }
 
 void __init init_IRQ(void)
index b36f3c3..695873c 100644 (file)
@@ -625,7 +625,7 @@ static int prepare_emulation(struct kprobe *p, struct insn *insn)
                /* 1 byte conditional jump */
                p->ainsn.emulate_op = kprobe_emulate_jcc;
                p->ainsn.jcc.type = opcode & 0xf;
-               p->ainsn.rel32 = *(char *)insn->immediate.bytes;
+               p->ainsn.rel32 = insn->immediate.value;
                break;
        case 0x0f:
                opcode = insn->opcode.bytes[1];
index b14653b..596061c 100644 (file)
@@ -770,16 +770,22 @@ struct kvm_cpuid_array {
        int nent;
 };
 
+static struct kvm_cpuid_entry2 *get_next_cpuid(struct kvm_cpuid_array *array)
+{
+       if (array->nent >= array->maxnent)
+               return NULL;
+
+       return &array->entries[array->nent++];
+}
+
 static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,
                                              u32 function, u32 index)
 {
-       struct kvm_cpuid_entry2 *entry;
+       struct kvm_cpuid_entry2 *entry = get_next_cpuid(array);
 
-       if (array->nent >= array->maxnent)
+       if (!entry)
                return NULL;
 
-       entry = &array->entries[array->nent++];
-
        memset(entry, 0, sizeof(*entry));
        entry->function = function;
        entry->index = index;
@@ -956,22 +962,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                entry->edx = edx.full;
                break;
        }
-       /*
-        * Per Intel's SDM, the 0x1f is a superset of 0xb,
-        * thus they can be handled by common code.
-        */
        case 0x1f:
        case 0xb:
                /*
-                * Populate entries until the level type (ECX[15:8]) of the
-                * previous entry is zero.  Note, CPUID EAX.{0x1f,0xb}.0 is
-                * the starting entry, filled by the primary do_host_cpuid().
+                * No topology; a valid topology is indicated by the presence
+                * of subleaf 1.
                 */
-               for (i = 1; entry->ecx & 0xff00; ++i) {
-                       entry = do_host_cpuid(array, function, i);
-                       if (!entry)
-                               goto out;
-               }
+               entry->eax = entry->ebx = entry->ecx = 0;
                break;
        case 0xd: {
                u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm();
@@ -1202,6 +1199,9 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
                entry->ebx = entry->ecx = entry->edx = 0;
                break;
        case 0x8000001e:
+               /* Do not return host topology information.  */
+               entry->eax = entry->ebx = entry->ecx = 0;
+               entry->edx = 0; /* reserved */
                break;
        case 0x8000001F:
                if (!kvm_cpu_cap_has(X86_FEATURE_SEV)) {
index bc9cd70..add65dd 100644 (file)
@@ -138,15 +138,13 @@ void recalc_intercepts(struct vcpu_svm *svm)
                c->intercepts[i] = h->intercepts[i];
 
        if (g->int_ctl & V_INTR_MASKING_MASK) {
-               /* We only want the cr8 intercept bits of L1 */
-               vmcb_clr_intercept(c, INTERCEPT_CR8_READ);
-               vmcb_clr_intercept(c, INTERCEPT_CR8_WRITE);
-
                /*
-                * Once running L2 with HF_VINTR_MASK, EFLAGS.IF does not
-                * affect any interrupt we may want to inject; therefore,
-                * interrupt window vmexits are irrelevant to L0.
+                * Once running L2 with HF_VINTR_MASK, EFLAGS.IF and CR8
+                * does not affect any interrupt we may want to inject;
+                * therefore, writes to CR8 are irrelevant to L0, as are
+                * interrupt window vmexits.
                 */
+               vmcb_clr_intercept(c, INTERCEPT_CR8_WRITE);
                vmcb_clr_intercept(c, INTERCEPT_VINTR);
        }
 
index fc9008d..7eec022 100644 (file)
@@ -3440,18 +3440,15 @@ static u32 vmx_segment_access_rights(struct kvm_segment *var)
 {
        u32 ar;
 
-       if (var->unusable || !var->present)
-               ar = 1 << 16;
-       else {
-               ar = var->type & 15;
-               ar |= (var->s & 1) << 4;
-               ar |= (var->dpl & 3) << 5;
-               ar |= (var->present & 1) << 7;
-               ar |= (var->avl & 1) << 12;
-               ar |= (var->l & 1) << 13;
-               ar |= (var->db & 1) << 14;
-               ar |= (var->g & 1) << 15;
-       }
+       ar = var->type & 15;
+       ar |= (var->s & 1) << 4;
+       ar |= (var->dpl & 3) << 5;
+       ar |= (var->present & 1) << 7;
+       ar |= (var->avl & 1) << 12;
+       ar |= (var->l & 1) << 13;
+       ar |= (var->db & 1) << 14;
+       ar |= (var->g & 1) << 15;
+       ar |= (var->unusable || !var->present) << 16;
 
        return ar;
 }
index 2e29bdc..8fd41f5 100644 (file)
@@ -271,7 +271,15 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
         * Attempt to obtain the GPC lock on *both* (if there are two)
         * gfn_to_pfn caches that cover the region.
         */
-       read_lock_irqsave(&gpc1->lock, flags);
+       if (atomic) {
+               local_irq_save(flags);
+               if (!read_trylock(&gpc1->lock)) {
+                       local_irq_restore(flags);
+                       return;
+               }
+       } else {
+               read_lock_irqsave(&gpc1->lock, flags);
+       }
        while (!kvm_gpc_check(gpc1, user_len1)) {
                read_unlock_irqrestore(&gpc1->lock, flags);
 
@@ -304,9 +312,18 @@ static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic)
                 * The guest's runstate_info is split across two pages and we
                 * need to hold and validate both GPCs simultaneously. We can
                 * declare a lock ordering GPC1 > GPC2 because nothing else
-                * takes them more than one at a time.
+                * takes them more than one at a time. Set a subclass on the
+                * gpc1 lock to make lockdep shut up about it.
                 */
-               read_lock(&gpc2->lock);
+               lock_set_subclass(&gpc1->lock.dep_map, 1, _THIS_IP_);
+               if (atomic) {
+                       if (!read_trylock(&gpc2->lock)) {
+                               read_unlock_irqrestore(&gpc1->lock, flags);
+                               return;
+                       }
+               } else {
+                       read_lock(&gpc2->lock);
+               }
 
                if (!kvm_gpc_check(gpc2, user_len2)) {
                        read_unlock(&gpc2->lock);
@@ -590,26 +607,26 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                if (!IS_ENABLED(CONFIG_64BIT) && data->u.long_mode) {
                        r = -EINVAL;
                } else {
-                       mutex_lock(&kvm->lock);
+                       mutex_lock(&kvm->arch.xen.xen_lock);
                        kvm->arch.xen.long_mode = !!data->u.long_mode;
-                       mutex_unlock(&kvm->lock);
+                       mutex_unlock(&kvm->arch.xen.xen_lock);
                        r = 0;
                }
                break;
 
        case KVM_XEN_ATTR_TYPE_SHARED_INFO:
-               mutex_lock(&kvm->lock);
+               mutex_lock(&kvm->arch.xen.xen_lock);
                r = kvm_xen_shared_info_init(kvm, data->u.shared_info.gfn);
-               mutex_unlock(&kvm->lock);
+               mutex_unlock(&kvm->arch.xen.xen_lock);
                break;
 
        case KVM_XEN_ATTR_TYPE_UPCALL_VECTOR:
                if (data->u.vector && data->u.vector < 0x10)
                        r = -EINVAL;
                else {
-                       mutex_lock(&kvm->lock);
+                       mutex_lock(&kvm->arch.xen.xen_lock);
                        kvm->arch.xen.upcall_vector = data->u.vector;
-                       mutex_unlock(&kvm->lock);
+                       mutex_unlock(&kvm->arch.xen.xen_lock);
                        r = 0;
                }
                break;
@@ -619,9 +636,9 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                break;
 
        case KVM_XEN_ATTR_TYPE_XEN_VERSION:
-               mutex_lock(&kvm->lock);
+               mutex_lock(&kvm->arch.xen.xen_lock);
                kvm->arch.xen.xen_version = data->u.xen_version;
-               mutex_unlock(&kvm->lock);
+               mutex_unlock(&kvm->arch.xen.xen_lock);
                r = 0;
                break;
 
@@ -630,9 +647,9 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                        r = -EOPNOTSUPP;
                        break;
                }
-               mutex_lock(&kvm->lock);
+               mutex_lock(&kvm->arch.xen.xen_lock);
                kvm->arch.xen.runstate_update_flag = !!data->u.runstate_update_flag;
-               mutex_unlock(&kvm->lock);
+               mutex_unlock(&kvm->arch.xen.xen_lock);
                r = 0;
                break;
 
@@ -647,7 +664,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
 {
        int r = -ENOENT;
 
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
 
        switch (data->type) {
        case KVM_XEN_ATTR_TYPE_LONG_MODE:
@@ -686,7 +703,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                break;
        }
 
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
        return r;
 }
 
@@ -694,7 +711,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
 {
        int idx, r = -ENOENT;
 
-       mutex_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->arch.xen.xen_lock);
        idx = srcu_read_lock(&vcpu->kvm->srcu);
 
        switch (data->type) {
@@ -922,7 +939,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
        }
 
        srcu_read_unlock(&vcpu->kvm->srcu, idx);
-       mutex_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->arch.xen.xen_lock);
        return r;
 }
 
@@ -930,7 +947,7 @@ int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
 {
        int r = -ENOENT;
 
-       mutex_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->arch.xen.xen_lock);
 
        switch (data->type) {
        case KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO:
@@ -1013,7 +1030,7 @@ int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)
                break;
        }
 
-       mutex_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->arch.xen.xen_lock);
        return r;
 }
 
@@ -1106,7 +1123,7 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
             xhc->blob_size_32 || xhc->blob_size_64))
                return -EINVAL;
 
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
 
        if (xhc->msr && !kvm->arch.xen_hvm_config.msr)
                static_branch_inc(&kvm_xen_enabled.key);
@@ -1115,7 +1132,7 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
 
        memcpy(&kvm->arch.xen_hvm_config, xhc, sizeof(*xhc));
 
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
        return 0;
 }
 
@@ -1658,15 +1675,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *xe, struct kvm *kvm)
                mm_borrowed = true;
        }
 
-       /*
-        * For the irqfd workqueue, using the main kvm->lock mutex is
-        * fine since this function is invoked from kvm_set_irq() with
-        * no other lock held, no srcu. In future if it will be called
-        * directly from a vCPU thread (e.g. on hypercall for an IPI)
-        * then it may need to switch to using a leaf-node mutex for
-        * serializing the shared_info mapping.
-        */
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
 
        /*
         * It is theoretically possible for the page to be unmapped
@@ -1695,7 +1704,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *xe, struct kvm *kvm)
                srcu_read_unlock(&kvm->srcu, idx);
        } while(!rc);
 
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
 
        if (mm_borrowed)
                kthread_unuse_mm(kvm->mm);
@@ -1811,7 +1820,7 @@ static int kvm_xen_eventfd_update(struct kvm *kvm,
        int ret;
 
        /* Protect writes to evtchnfd as well as the idr lookup.  */
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
        evtchnfd = idr_find(&kvm->arch.xen.evtchn_ports, port);
 
        ret = -ENOENT;
@@ -1842,7 +1851,7 @@ static int kvm_xen_eventfd_update(struct kvm *kvm,
        }
        ret = 0;
 out_unlock:
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
        return ret;
 }
 
@@ -1905,10 +1914,10 @@ static int kvm_xen_eventfd_assign(struct kvm *kvm,
                evtchnfd->deliver.port.priority = data->u.evtchn.deliver.port.priority;
        }
 
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
        ret = idr_alloc(&kvm->arch.xen.evtchn_ports, evtchnfd, port, port + 1,
                        GFP_KERNEL);
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
        if (ret >= 0)
                return 0;
 
@@ -1926,9 +1935,9 @@ static int kvm_xen_eventfd_deassign(struct kvm *kvm, u32 port)
 {
        struct evtchnfd *evtchnfd;
 
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
        evtchnfd = idr_remove(&kvm->arch.xen.evtchn_ports, port);
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
 
        if (!evtchnfd)
                return -ENOENT;
@@ -1946,7 +1955,7 @@ static int kvm_xen_eventfd_reset(struct kvm *kvm)
        int i;
        int n = 0;
 
-       mutex_lock(&kvm->lock);
+       mutex_lock(&kvm->arch.xen.xen_lock);
 
        /*
         * Because synchronize_srcu() cannot be called inside the
@@ -1958,7 +1967,7 @@ static int kvm_xen_eventfd_reset(struct kvm *kvm)
 
        all_evtchnfds = kmalloc_array(n, sizeof(struct evtchnfd *), GFP_KERNEL);
        if (!all_evtchnfds) {
-               mutex_unlock(&kvm->lock);
+               mutex_unlock(&kvm->arch.xen.xen_lock);
                return -ENOMEM;
        }
 
@@ -1967,7 +1976,7 @@ static int kvm_xen_eventfd_reset(struct kvm *kvm)
                all_evtchnfds[n++] = evtchnfd;
                idr_remove(&kvm->arch.xen.evtchn_ports, evtchnfd->send_port);
        }
-       mutex_unlock(&kvm->lock);
+       mutex_unlock(&kvm->arch.xen.xen_lock);
 
        synchronize_srcu(&kvm->srcu);
 
@@ -2069,6 +2078,7 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu)
 
 void kvm_xen_init_vm(struct kvm *kvm)
 {
+       mutex_init(&kvm->arch.xen.xen_lock);
        idr_init(&kvm->arch.xen.evtchn_ports);
        kvm_gpc_init(&kvm->arch.xen.shinfo_cache, kvm, NULL, KVM_HOST_USES_PFN);
 }
index d398735..cb258f5 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/pti.h>
 #include <asm/text-patching.h>
 #include <asm/memtype.h>
+#include <asm/paravirt.h>
 
 /*
  * We need to define the tracepoints somewhere, and tlb.c
@@ -804,6 +805,9 @@ void __init poking_init(void)
        poking_mm = mm_alloc();
        BUG_ON(!poking_mm);
 
+       /* Xen PV guests need the PGD to be pinned. */
+       paravirt_arch_dup_mmap(NULL, poking_mm);
+
        /*
         * Randomize the poking address, but make sure that the following page
         * will be mapped at the same PMD. We need 2 pages, so find space for 3,
index 46de9cf..fb4b1b5 100644 (file)
@@ -387,7 +387,8 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end,
                u8 mtrr_type, uniform;
 
                mtrr_type = mtrr_type_lookup(start, end, &uniform);
-               if (mtrr_type != MTRR_TYPE_WRBACK)
+               if (mtrr_type != MTRR_TYPE_WRBACK &&
+                   mtrr_type != MTRR_TYPE_INVALID)
                        return _PAGE_CACHE_MODE_UC_MINUS;
 
                return _PAGE_CACHE_MODE_WB;
index 758cbfe..4b3efaa 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/efi.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/bitmap.h>
@@ -442,17 +443,42 @@ static bool is_acpi_reserved(u64 start, u64 end, enum e820_type not_used)
        return mcfg_res.flags;
 }
 
+static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used)
+{
+#ifdef CONFIG_EFI
+       efi_memory_desc_t *md;
+       u64 size, mmio_start, mmio_end;
+
+       for_each_efi_memory_desc(md) {
+               if (md->type == EFI_MEMORY_MAPPED_IO) {
+                       size = md->num_pages << EFI_PAGE_SHIFT;
+                       mmio_start = md->phys_addr;
+                       mmio_end = mmio_start + size;
+
+                       /*
+                        * N.B. Caller supplies (start, start + size),
+                        * so to match, mmio_end is the first address
+                        * *past* the EFI_MEMORY_MAPPED_IO area.
+                        */
+                       if (mmio_start <= start && end <= mmio_end)
+                               return true;
+               }
+       }
+#endif
+
+       return false;
+}
+
 typedef bool (*check_reserved_t)(u64 start, u64 end, enum e820_type type);
 
 static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
                                     struct pci_mmcfg_region *cfg,
-                                    struct device *dev, int with_e820)
+                                    struct device *dev, const char *method)
 {
        u64 addr = cfg->res.start;
        u64 size = resource_size(&cfg->res);
        u64 old_size = size;
        int num_buses;
-       char *method = with_e820 ? "E820" : "ACPI motherboard resources";
 
        while (!is_reserved(addr, addr + size, E820_TYPE_RESERVED)) {
                size >>= 1;
@@ -464,10 +490,10 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
                return false;
 
        if (dev)
-               dev_info(dev, "MMCONFIG at %pR reserved in %s\n",
+               dev_info(dev, "MMCONFIG at %pR reserved as %s\n",
                         &cfg->res, method);
        else
-               pr_info(PREFIX "MMCONFIG at %pR reserved in %s\n",
+               pr_info(PREFIX "MMCONFIG at %pR reserved as %s\n",
                       &cfg->res, method);
 
        if (old_size != size) {
@@ -500,7 +526,8 @@ static bool __ref
 pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int early)
 {
        if (!early && !acpi_disabled) {
-               if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0))
+               if (is_mmconf_reserved(is_acpi_reserved, cfg, dev,
+                                      "ACPI motherboard resource"))
                        return true;
 
                if (dev)
@@ -513,6 +540,10 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e
                               "MMCONFIG at %pR not reserved in "
                               "ACPI motherboard resources\n",
                               &cfg->res);
+
+               if (is_mmconf_reserved(is_efi_mmio, cfg, dev,
+                                      "EfiMemoryMappedIO"))
+                       return true;
        }
 
        /*
@@ -527,7 +558,8 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e
        /* Don't try to do this check unless configuration
           type 1 is available. how about type 2 ?*/
        if (raw_pci_ops)
-               return is_mmconf_reserved(e820__mapped_all, cfg, dev, 1);
+               return is_mmconf_reserved(e820__mapped_all, cfg, dev,
+                                         "E820 entry");
 
        return false;
 }
index b94f727..8babce7 100644 (file)
@@ -392,6 +392,7 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
        msi_for_each_desc(msidesc, &dev->dev, MSI_DESC_ASSOCIATED) {
                for (i = 0; i < msidesc->nvec_used; i++)
                        xen_destroy_irq(msidesc->irq + i);
+               msidesc->irq = 0;
        }
 }
 
@@ -433,6 +434,7 @@ static struct msi_domain_ops xen_pci_msi_domain_ops = {
 };
 
 static struct msi_domain_info xen_pci_msi_domain_info = {
+       .flags                  = MSI_FLAG_PCI_MSIX | MSI_FLAG_FREE_MSI_DESCS | MSI_FLAG_DEV_SYSFS,
        .ops                    = &xen_pci_msi_domain_ops,
 };
 
index 48a3eb0..650cdbb 100644 (file)
@@ -7,7 +7,7 @@
 #include <asm/elf.h>
 
 
-Elf32_Half elf_core_extra_phdrs(void)
+Elf32_Half elf_core_extra_phdrs(struct coredump_params *cprm)
 {
        return vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0;
 }
@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
        return 1;
 }
 
-size_t elf_core_extra_data_size(void)
+size_t elf_core_extra_data_size(struct coredump_params *cprm)
 {
        if ( vsyscall_ehdr ) {
                const struct elfhdr *const ehdrp =
index 58db86f..9bdc3b6 100644 (file)
@@ -134,11 +134,6 @@ static inline unsigned p2m_mid_index(unsigned long pfn)
        return (pfn / P2M_PER_PAGE) % P2M_MID_PER_PAGE;
 }
 
-static inline unsigned p2m_index(unsigned long pfn)
-{
-       return pfn % P2M_PER_PAGE;
-}
-
 static void p2m_top_mfn_init(unsigned long *top)
 {
        unsigned i;
index 228e4df..a6d09fe 100644 (file)
@@ -154,11 +154,6 @@ struct thread_struct {
        unsigned long ra; /* kernel's a0: return address and window call size */
        unsigned long sp; /* kernel's a1: stack pointer */
 
-       /* struct xtensa_cpuinfo info; */
-
-       unsigned long bad_vaddr; /* last user fault */
-       unsigned long bad_uaddr; /* last kernel fault accessing user space */
-       unsigned long error_code;
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
        struct perf_event *ptrace_bp[XCHAL_NUM_IBREAK];
        struct perf_event *ptrace_wp[XCHAL_NUM_DBREAK];
@@ -176,10 +171,6 @@ struct thread_struct {
 {                                                                      \
        ra:             0,                                              \
        sp:             sizeof(init_stack) + (long) &init_stack,        \
-       /*info:         {0}, */                                         \
-       bad_vaddr:      0,                                              \
-       bad_uaddr:      0,                                              \
-       error_code:     0,                                              \
 }
 
 
index 0c25e03..cd98366 100644 (file)
@@ -362,8 +362,6 @@ static void do_unaligned_user(struct pt_regs *regs)
        __die_if_kernel("Unhandled unaligned exception in kernel",
                        regs, SIGKILL);
 
-       current->thread.bad_vaddr = regs->excvaddr;
-       current->thread.error_code = -3;
        pr_info_ratelimited("Unaligned memory access to %08lx in '%s' "
                            "(pid = %d, pc = %#010lx)\n",
                            regs->excvaddr, current->comm,
index 8c781b0..faf7cf3 100644 (file)
@@ -206,8 +206,6 @@ good_area:
 bad_area:
        mmap_read_unlock(mm);
        if (user_mode(regs)) {
-               current->thread.bad_vaddr = address;
-               current->thread.error_code = is_write;
                force_sig_fault(SIGSEGV, code, (void *) address);
                return;
        }
@@ -232,7 +230,6 @@ do_sigbus:
        /* Send a sigbus, regardless of whether we were in kernel
         * or user mode.
         */
-       current->thread.bad_vaddr = address;
        force_sig_fault(SIGBUS, BUS_ADRERR, (void *) address);
 
        /* Kernel mode? Handle exceptions or die */
@@ -252,7 +249,6 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
        if ((entry = search_exception_tables(regs->pc)) != NULL) {
                pr_debug("%s: Exception at pc=%#010lx (%lx)\n",
                         current->comm, regs->pc, entry->fixup);
-               current->thread.bad_uaddr = address;
                regs->pc = entry->fixup;
                return;
        }
index 1b2829e..0fbde0f 100644 (file)
@@ -316,14 +316,12 @@ struct bfq_group *bfqq_group(struct bfq_queue *bfqq)
 
 static void bfqg_get(struct bfq_group *bfqg)
 {
-       bfqg->ref++;
+       refcount_inc(&bfqg->ref);
 }
 
 static void bfqg_put(struct bfq_group *bfqg)
 {
-       bfqg->ref--;
-
-       if (bfqg->ref == 0)
+       if (refcount_dec_and_test(&bfqg->ref))
                kfree(bfqg);
 }
 
@@ -530,7 +528,7 @@ static struct blkg_policy_data *bfq_pd_alloc(gfp_t gfp, struct request_queue *q,
        }
 
        /* see comments in bfq_bic_update_cgroup for why refcounting */
-       bfqg_get(bfqg);
+       refcount_set(&bfqg->ref, 1);
        return &bfqg->pd;
 }
 
@@ -771,8 +769,8 @@ static void __bfq_bic_change_cgroup(struct bfq_data *bfqd,
                                 * request from the old cgroup.
                                 */
                                bfq_put_cooperator(sync_bfqq);
-                               bfq_release_process_ref(bfqd, sync_bfqq);
                                bic_set_bfqq(bic, NULL, true);
+                               bfq_release_process_ref(bfqd, sync_bfqq);
                        }
                }
        }
index ccf2204..380e9bd 100644 (file)
@@ -5425,9 +5425,11 @@ static void bfq_check_ioprio_change(struct bfq_io_cq *bic, struct bio *bio)
 
        bfqq = bic_to_bfqq(bic, false);
        if (bfqq) {
-               bfq_release_process_ref(bfqd, bfqq);
+               struct bfq_queue *old_bfqq = bfqq;
+
                bfqq = bfq_get_queue(bfqd, bio, false, bic, true);
                bic_set_bfqq(bic, bfqq, false);
+               bfq_release_process_ref(bfqd, old_bfqq);
        }
 
        bfqq = bic_to_bfqq(bic, true);
index 41aa151..466e486 100644 (file)
@@ -928,7 +928,7 @@ struct bfq_group {
        char blkg_path[128];
 
        /* reference counter (see comments in bfq_bic_update_cgroup) */
-       int ref;
+       refcount_t ref;
        /* Is bfq_group still online? */
        bool online;
 
index ce6a2b7..9ac1efb 100644 (file)
@@ -1455,6 +1455,10 @@ retry:
                list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
                        pol->pd_init_fn(blkg->pd[pol->plid]);
 
+       if (pol->pd_online_fn)
+               list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
+                       pol->pd_online_fn(blkg->pd[pol->plid]);
+
        __set_bit(pol->plid, q->blkcg_pols);
        ret = 0;
 
@@ -1997,6 +2001,10 @@ void blk_cgroup_bio_start(struct bio *bio)
        struct blkg_iostat_set *bis;
        unsigned long flags;
 
+       /* Root-level stats are sourced from system-wide IO stats */
+       if (!cgroup_parent(blkcg->css.cgroup))
+               return;
+
        cpu = get_cpu();
        bis = per_cpu_ptr(bio->bi_blkg->iostat_cpu, cpu);
        flags = u64_stats_update_begin_irqsave(&bis->sync);
index 9321767..b509835 100644 (file)
@@ -283,12 +283,9 @@ static void blk_free_queue(struct request_queue *q)
  *
  * Decrements the refcount of the request_queue and free it when the refcount
  * reaches 0.
- *
- * Context: Can sleep.
  */
 void blk_put_queue(struct request_queue *q)
 {
-       might_sleep();
        if (refcount_dec_and_test(&q->refs))
                blk_free_queue(q);
 }
index 2c49b41..9c8dc70 100644 (file)
@@ -2890,6 +2890,7 @@ static inline struct request *blk_mq_get_cached_request(struct request_queue *q,
                struct blk_plug *plug, struct bio **bio, unsigned int nsegs)
 {
        struct request *rq;
+       enum hctx_type type, hctx_type;
 
        if (!plug)
                return NULL;
@@ -2902,7 +2903,10 @@ static inline struct request *blk_mq_get_cached_request(struct request_queue *q,
                return NULL;
        }
 
-       if (blk_mq_get_hctx_type((*bio)->bi_opf) != rq->mq_hctx->type)
+       type = blk_mq_get_hctx_type((*bio)->bi_opf);
+       hctx_type = rq->mq_hctx->type;
+       if (type != hctx_type &&
+           !(type == HCTX_TYPE_READ && hctx_type == HCTX_TYPE_DEFAULT))
                return NULL;
        if (op_is_flush(rq->cmd_flags) != op_is_flush((*bio)->bi_opf))
                return NULL;
@@ -4065,8 +4069,9 @@ EXPORT_SYMBOL(blk_mq_init_queue);
  * blk_mq_destroy_queue - shutdown a request queue
  * @q: request queue to shutdown
  *
- * This shuts down a request queue allocated by blk_mq_init_queue() and drops
- * the initial reference.  All future requests will failed with -ENODEV.
+ * This shuts down a request queue allocated by blk_mq_init_queue(). All future
+ * requests will be failed with -ENODEV. The caller is responsible for dropping
+ * the reference from blk_mq_init_queue() by calling blk_put_queue().
  *
  * Context: can sleep
  */
index 9486ed9..799ad7b 100644 (file)
@@ -23,8 +23,8 @@ $(obj)/blacklist_hash_list: $(CONFIG_SYSTEM_BLACKLIST_HASH_LIST) FORCE
 targets += blacklist_hash_list
 
 quiet_cmd_extract_certs  = CERT    $@
-      cmd_extract_certs  = $(obj)/extract-cert $(extract-cert-in) $@
-extract-cert-in = $(or $(filter-out $(obj)/extract-cert, $(real-prereqs)),"")
+      cmd_extract_certs  = $(obj)/extract-cert "$(extract-cert-in)" $@
+extract-cert-in = $(filter-out $(obj)/extract-cert, $(real-prereqs))
 
 $(obj)/system_certificates.o: $(obj)/x509_certificate_list
 
index 08cf8a1..07373b3 100644 (file)
@@ -354,6 +354,9 @@ void spk_ttyio_release(struct spk_synth *in_synth)
 {
        struct tty_struct *tty = in_synth->dev;
 
+       if (tty == NULL)
+               return;
+
        tty_lock(tty);
 
        if (tty->ops->close)
index 0f17b1c..02d83c8 100644 (file)
@@ -1153,6 +1153,19 @@ int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf)
        return cppc_get_perf(cpunum, NOMINAL_PERF, nominal_perf);
 }
 
+/**
+ * cppc_get_epp_perf - Get the epp register value.
+ * @cpunum: CPU from which to get epp preference value.
+ * @epp_perf: Return address.
+ *
+ * Return: 0 for success, -EIO otherwise.
+ */
+int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
+{
+       return cppc_get_perf(cpunum, ENERGY_PERF, epp_perf);
+}
+EXPORT_SYMBOL_GPL(cppc_get_epp_perf);
+
 /**
  * cppc_get_perf_caps - Get a CPU's performance capabilities.
  * @cpunum: CPU from which to get capabilities info.
@@ -1365,6 +1378,60 @@ out_err:
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs);
 
+/*
+ * Set Energy Performance Preference Register value through
+ * Performance Controls Interface
+ */
+int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
+{
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
+       struct cpc_register_resource *epp_set_reg;
+       struct cpc_register_resource *auto_sel_reg;
+       struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+       struct cppc_pcc_data *pcc_ss_data = NULL;
+       int ret;
+
+       if (!cpc_desc) {
+               pr_debug("No CPC descriptor for CPU:%d\n", cpu);
+               return -ENODEV;
+       }
+
+       auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
+       epp_set_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
+
+       if (CPC_IN_PCC(epp_set_reg) || CPC_IN_PCC(auto_sel_reg)) {
+               if (pcc_ss_id < 0) {
+                       pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
+                       return -ENODEV;
+               }
+
+               if (CPC_SUPPORTED(auto_sel_reg)) {
+                       ret = cpc_write(cpu, auto_sel_reg, enable);
+                       if (ret)
+                               return ret;
+               }
+
+               if (CPC_SUPPORTED(epp_set_reg)) {
+                       ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
+                       if (ret)
+                               return ret;
+               }
+
+               pcc_ss_data = pcc_data[pcc_ss_id];
+
+               down_write(&pcc_ss_data->pcc_lock);
+               /* after writing CPC, transfer the ownership of PCC to platform */
+               ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+               up_write(&pcc_ss_data->pcc_lock);
+       } else {
+               ret = -ENOTSUPP;
+               pr_debug("_CPC in PCC is not supported\n");
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cppc_set_epp_perf);
+
 /**
  * cppc_set_enable - Set to enable CPPC on the processor by writing the
  * Continuous Performance Control package EnableRegister field.
index 204fe94..a194f30 100644 (file)
@@ -75,7 +75,8 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
 }
 
 #define FIND_CHILD_MIN_SCORE   1
-#define FIND_CHILD_MAX_SCORE   2
+#define FIND_CHILD_MID_SCORE   2
+#define FIND_CHILD_MAX_SCORE   3
 
 static int match_any(struct acpi_device *adev, void *not_used)
 {
@@ -96,8 +97,17 @@ static int find_child_checks(struct acpi_device *adev, bool check_children)
                return -ENODEV;
 
        status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
-       if (status == AE_NOT_FOUND)
+       if (status == AE_NOT_FOUND) {
+               /*
+                * Special case: backlight device objects without _STA are
+                * preferred to other objects with the same _ADR value, because
+                * it is more likely that they are actually useful.
+                */
+               if (adev->pnp.type.backlight)
+                       return FIND_CHILD_MID_SCORE;
+
                return FIND_CHILD_MIN_SCORE;
+       }
 
        if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
                return -ENODEV;
index f1cc5ec..4e48d6d 100644 (file)
@@ -3297,8 +3297,8 @@ void acpi_nfit_shutdown(void *data)
 
        mutex_lock(&acpi_desc->init_mutex);
        set_bit(ARS_CANCEL, &acpi_desc->scrub_flags);
-       cancel_delayed_work_sync(&acpi_desc->dwork);
        mutex_unlock(&acpi_desc->init_mutex);
+       cancel_delayed_work_sync(&acpi_desc->dwork);
 
        /*
         * Bounce the nvdimm bus lock to make sure any in-flight
index 998101c..3d4c462 100644 (file)
@@ -236,6 +236,11 @@ static acpi_status acpi_platformrt_space_handler(u32 function,
        efi_status_t status;
        struct prm_context_buffer context;
 
+       if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+               pr_err_ratelimited("PRM: EFI runtime services no longer available\n");
+               return AE_NO_HANDLER;
+       }
+
        /*
         * The returned acpi_status will always be AE_OK. Error values will be
         * saved in the first byte of the PRM message buffer to be used by ASL.
@@ -325,6 +330,11 @@ void __init init_prmt(void)
 
        pr_info("PRM: found %u modules\n", mc);
 
+       if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+               pr_err("PRM: EFI runtime services unavailable\n");
+               return;
+       }
+
        status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
                                                    ACPI_ADR_SPACE_PLATFORM_RT,
                                                    &acpi_platformrt_space_handler,
index 16dcd31..192d178 100644 (file)
@@ -432,6 +432,13 @@ static const struct dmi_system_id asus_laptop[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "S5602ZA"),
                },
        },
+       {
+               .ident = "Asus ExpertBook B2402CBA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "B2402CBA"),
+               },
+       },
        {
                .ident = "Asus ExpertBook B2502",
                .matches = {
index 2743444..0c6f06a 100644 (file)
@@ -1370,9 +1370,12 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                 * Some devices don't reliably have _HIDs & _CIDs, so add
                 * synthetic HIDs to make sure drivers can find them.
                 */
-               if (acpi_is_video_device(handle))
+               if (acpi_is_video_device(handle)) {
                        acpi_add_id(pnp, ACPI_VIDEO_HID);
-               else if (acpi_bay_match(handle))
+                       pnp->type.backlight = 1;
+                       break;
+               }
+               if (acpi_bay_match(handle))
                        acpi_add_id(pnp, ACPI_BAY_HID);
                else if (acpi_dock_match(handle))
                        acpi_add_id(pnp, ACPI_DOCK_HID);
index 0b557c0..4ca6672 100644 (file)
@@ -60,13 +60,17 @@ static struct notifier_block tts_notifier = {
        .priority       = 0,
 };
 
+#ifndef acpi_skip_set_wakeup_address
+#define acpi_skip_set_wakeup_address() false
+#endif
+
 static int acpi_sleep_prepare(u32 acpi_state)
 {
 #ifdef CONFIG_ACPI_SLEEP
        unsigned long acpi_wakeup_address;
 
        /* do we have a wakeup address for S2 and S3? */
-       if (acpi_state == ACPI_STATE_S3) {
+       if (acpi_state == ACPI_STATE_S3 && !acpi_skip_set_wakeup_address()) {
                acpi_wakeup_address = acpi_get_wakeup_address();
                if (!acpi_wakeup_address)
                        return -EFAULT;
index 1b78c74..a8c0260 100644 (file)
@@ -50,6 +50,10 @@ static void acpi_video_parse_cmdline(void)
                acpi_backlight_cmdline = acpi_backlight_video;
        if (!strcmp("native", acpi_video_backlight_string))
                acpi_backlight_cmdline = acpi_backlight_native;
+       if (!strcmp("nvidia_wmi_ec", acpi_video_backlight_string))
+               acpi_backlight_cmdline = acpi_backlight_nvidia_wmi_ec;
+       if (!strcmp("apple_gmux", acpi_video_backlight_string))
+               acpi_backlight_cmdline = acpi_backlight_apple_gmux;
        if (!strcmp("none", acpi_video_backlight_string))
                acpi_backlight_cmdline = acpi_backlight_none;
 }
@@ -106,26 +110,6 @@ static bool nvidia_wmi_ec_supported(void)
 }
 #endif
 
-static bool apple_gmux_backlight_present(void)
-{
-       struct acpi_device *adev;
-       struct device *dev;
-
-       adev = acpi_dev_get_first_match_dev(GMUX_ACPI_HID, NULL, -1);
-       if (!adev)
-               return false;
-
-       dev = acpi_get_first_physical_node(adev);
-       if (!dev)
-               return false;
-
-       /*
-        * drivers/platform/x86/apple-gmux.c only supports old style
-        * Apple GMUX with an IO-resource.
-        */
-       return pnp_get_resource(to_pnp_dev(dev), IORESOURCE_IO, 0) != NULL;
-}
-
 /* Force to use vendor driver when the ACPI device is known to be
  * buggy */
 static int video_detect_force_vendor(const struct dmi_system_id *d)
@@ -511,6 +495,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"),
                },
        },
+       {
+        .callback = video_detect_force_native,
+        /* Acer Aspire 4810T */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 4810T"),
+               },
+       },
        {
         .callback = video_detect_force_native,
         /* Acer Aspire 5738z */
@@ -598,6 +590,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
                },
        },
+       {
+        .callback = video_detect_force_native,
+        /* Asus U46E */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "U46E"),
+               },
+       },
        {
         .callback = video_detect_force_native,
         /* Asus UX303UB */
@@ -606,6 +606,23 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
                },
        },
+       {
+        .callback = video_detect_force_native,
+        /* HP EliteBook 8460p */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8460p"),
+               },
+       },
+       {
+        .callback = video_detect_force_native,
+        /* HP Pavilion g6-1d80nr / B4U19UA */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion g6 Notebook PC"),
+               DMI_MATCH(DMI_PRODUCT_SKU, "B4U19UA"),
+               },
+       },
        {
         .callback = video_detect_force_native,
         /* Samsung N150P */
@@ -754,6 +771,7 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
 {
        static DEFINE_MUTEX(init_mutex);
        static bool nvidia_wmi_ec_present;
+       static bool apple_gmux_present;
        static bool native_available;
        static bool init_done;
        static long video_caps;
@@ -767,6 +785,7 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
                                    ACPI_UINT32_MAX, find_video, NULL,
                                    &video_caps, NULL);
                nvidia_wmi_ec_present = nvidia_wmi_ec_supported();
+               apple_gmux_present = apple_gmux_detect(NULL, NULL);
                init_done = true;
        }
        if (native)
@@ -788,7 +807,7 @@ static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
        if (nvidia_wmi_ec_present)
                return acpi_backlight_nvidia_wmi_ec;
 
-       if (apple_gmux_backlight_present())
+       if (apple_gmux_present)
                return acpi_backlight_apple_gmux;
 
        /* Use ACPI video if available, except when native should be preferred. */
index eceaec3..9695c44 100644 (file)
@@ -640,6 +640,7 @@ config PATA_CS5530
 config PATA_CS5535
        tristate "CS5535 PATA support (Experimental)"
        depends on PCI && (X86_32 || (X86_64 && COMPILE_TEST))
+       depends on !UML
        help
          This option enables support for the NatSemi/AMD CS5535
          companion chip used with the Geode processor family.
index 884ae73..2ea5726 100644 (file)
@@ -3109,7 +3109,7 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
         */
        if (spd > 1)
                mask &= (1 << (spd - 1)) - 1;
-       else
+       else if (link->sata_spd)
                return -EINVAL;
 
        /* were we already at the bottom? */
index 50e726b..b29be7d 100644 (file)
@@ -1864,6 +1864,10 @@ static bool pm_runtime_need_not_resume(struct device *dev)
  * sure the device is put into low power state and it should only be used during
  * system-wide PM transitions to sleep states.  It assumes that the analogous
  * pm_runtime_force_resume() will be used to resume the device.
+ *
+ * Do not use with DPM_FLAG_SMART_SUSPEND as this can lead to an inconsistent
+ * state where this function has called the ->runtime_suspend callback but the
+ * PM core marks the driver as runtime active.
  */
 int pm_runtime_force_suspend(struct device *dev)
 {
index bbb3e49..083a957 100644 (file)
@@ -997,26 +997,32 @@ struct fwnode_handle *
 fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
                               struct fwnode_handle *prev)
 {
+       struct fwnode_handle *ep, *port_parent = NULL;
        const struct fwnode_handle *parent;
-       struct fwnode_handle *ep;
 
        /*
         * If this function is in a loop and the previous iteration returned
         * an endpoint from fwnode->secondary, then we need to use the secondary
         * as parent rather than @fwnode.
         */
-       if (prev)
-               parent = fwnode_graph_get_port_parent(prev);
-       else
+       if (prev) {
+               port_parent = fwnode_graph_get_port_parent(prev);
+               parent = port_parent;
+       } else {
                parent = fwnode;
+       }
        if (IS_ERR_OR_NULL(parent))
                return NULL;
 
        ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev);
        if (ep)
-               return ep;
+               goto out_put_port_parent;
+
+       ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL);
 
-       return fwnode_graph_get_next_endpoint(parent->secondary, NULL);
+out_put_port_parent:
+       fwnode_handle_put(port_parent);
+       return ep;
 }
 EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint);
 
index 4d1976c..929410d 100644 (file)
@@ -145,7 +145,7 @@ static int __init test_async_probe_init(void)
        calltime = ktime_get();
        for_each_online_cpu(cpu) {
                nid = cpu_to_node(cpu);
-               pdev = &sync_dev[sync_id];
+               pdev = &async_dev[async_id];
 
                *pdev = test_platform_device_register_node("test_async_driver",
                                                           async_id,
index 4cea3b0..2f1a925 100644 (file)
@@ -2400,6 +2400,8 @@ static void pkt_submit_bio(struct bio *bio)
        struct bio *split;
 
        bio = bio_split_to_limits(bio);
+       if (!bio)
+               return;
 
        pkt_dbg(2, pd, "start = %6llx stop = %6llx\n",
                (unsigned long long)bio->bi_iter.bi_sector,
index 78334da..5eb8c78 100644 (file)
@@ -1440,7 +1440,7 @@ static struct rnbd_clt_dev *init_dev(struct rnbd_clt_session *sess,
                goto out_alloc;
        }
 
-       ret = ida_alloc_max(&index_ida, 1 << (MINORBITS - RNBD_PART_BITS),
+       ret = ida_alloc_max(&index_ida, (1 << (MINORBITS - RNBD_PART_BITS)) - 1,
                            GFP_KERNEL);
        if (ret < 0) {
                pr_err("Failed to initialize device '%s' from session %s, allocating idr failed, err: %d\n",
index 17b677b..6368b56 100644 (file)
@@ -137,7 +137,7 @@ struct ublk_device {
 
        char    *__queues;
 
-       unsigned short  queue_size;
+       unsigned int    queue_size;
        struct ublksrv_ctrl_dev_info    dev_info;
 
        struct blk_mq_tag_set   tag_set;
@@ -2092,13 +2092,12 @@ static void __exit ublk_exit(void)
        struct ublk_device *ub;
        int id;
 
-       class_destroy(ublk_chr_class);
-
-       misc_deregister(&ublk_misc);
-
        idr_for_each_entry(&ublk_index_idr, ub, id)
                ublk_remove(ub);
 
+       class_destroy(ublk_chr_class);
+       misc_deregister(&ublk_misc);
+
        idr_destroy(&ublk_index_idr);
        unregister_chrdev_region(ublk_chr_devt, UBLK_MINORS);
 }
index c0227df..4807af1 100644 (file)
@@ -524,7 +524,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
        return 0;
 }
 
-static int xen_blkbk_remove(struct xenbus_device *dev)
+static void xen_blkbk_remove(struct xenbus_device *dev)
 {
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
@@ -547,8 +547,6 @@ static int xen_blkbk_remove(struct xenbus_device *dev)
                /* Put the reference we set in xen_blkif_alloc(). */
                xen_blkif_put(be->blkif);
        }
-
-       return 0;
 }
 
 int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
index b284892..23ed258 100644 (file)
@@ -2467,7 +2467,7 @@ static void blkback_changed(struct xenbus_device *dev,
        }
 }
 
-static int blkfront_remove(struct xenbus_device *xbdev)
+static void blkfront_remove(struct xenbus_device *xbdev)
 {
        struct blkfront_info *info = dev_get_drvdata(&xbdev->dev);
 
@@ -2488,7 +2488,6 @@ static int blkfront_remove(struct xenbus_device *xbdev)
        }
 
        kfree(info);
-       return 0;
 }
 
 static int blkfront_is_ready(struct xenbus_device *dev)
index 6eddc23..bbe9cf1 100644 (file)
@@ -2164,10 +2164,17 @@ static void qca_serdev_shutdown(struct device *dev)
        int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
        struct serdev_device *serdev = to_serdev_device(dev);
        struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
+       struct hci_uart *hu = &qcadev->serdev_hu;
+       struct hci_dev *hdev = hu->hdev;
+       struct qca_data *qca = hu->priv;
        const u8 ibs_wake_cmd[] = { 0xFD };
        const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 };
 
        if (qcadev->btsoc_type == QCA_QCA6390) {
+               if (test_bit(QCA_BT_OFF, &qca->flags) ||
+                   !test_bit(HCI_RUNNING, &hdev->flags))
+                       return;
+
                serdev_device_write_flush(serdev);
                ret = serdev_device_write_buf(serdev, ibs_wake_cmd,
                                              sizeof(ibs_wake_cmd));
index 3aa91ae..226e87b 100644 (file)
@@ -857,7 +857,13 @@ static int __init sunxi_rsb_init(void)
                return ret;
        }
 
-       return platform_driver_register(&sunxi_rsb_driver);
+       ret = platform_driver_register(&sunxi_rsb_driver);
+       if (ret) {
+               bus_unregister(&sunxi_rsb_bus);
+               return ret;
+       }
+
+       return 0;
 }
 module_init(sunxi_rsb_init);
 
index 3792918..80cca3b 100644 (file)
@@ -360,14 +360,13 @@ static int tpmfront_probe(struct xenbus_device *dev,
        return tpm_chip_register(priv->chip);
 }
 
-static int tpmfront_remove(struct xenbus_device *dev)
+static void tpmfront_remove(struct xenbus_device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
        struct tpm_private *priv = dev_get_drvdata(&chip->dev);
        tpm_chip_unregister(chip);
        ring_free(priv);
        dev_set_drvdata(&chip->dev, NULL);
-       return 0;
 }
 
 static int tpmfront_resume(struct xenbus_device *dev)
index ecd395a..e407f00 100644 (file)
@@ -58,7 +58,7 @@ jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
                       unsigned long rate, unsigned long parent_rate,
                       unsigned int *pm, unsigned int *pn, unsigned int *pod)
 {
-       unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 2;
+       unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1;
 
        /* The frequency after the N divider must be between 1 and 50 MHz. */
        n = parent_rate / (1 * MHZ);
@@ -66,19 +66,17 @@ jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
        /* The N divider must be >= 2. */
        n = clamp_val(n, 2, 1 << pll_info->n_bits);
 
-       for (;; n >>= 1) {
-               od = (unsigned int)-1;
+       rate /= MHZ;
+       parent_rate /= MHZ;
 
-               do {
-                       m = (rate / MHZ) * (1 << ++od) * n / (parent_rate / MHZ);
-               } while ((m > m_max || m & 1) && (od < 4));
-
-               if (od < 4 && m >= 4 && m <= m_max)
-                       break;
+       for (m = m_max; m >= m_max && n >= 2; n--) {
+               m = rate * n / parent_rate;
+               od = m & 1;
+               m <<= od;
        }
 
        *pm = m;
-       *pn = n;
+       *pn = n + 1;
        *pod = 1 << od;
 }
 
index 32aae88..0ddc73e 100644 (file)
@@ -164,12 +164,11 @@ static int mpfs_ccc_register_outputs(struct device *dev, struct mpfs_ccc_out_hw_
 
        for (unsigned int i = 0; i < num_clks; i++) {
                struct mpfs_ccc_out_hw_clock *out_hw = &out_hws[i];
-               char *name = devm_kzalloc(dev, 23, GFP_KERNEL);
+               char *name = devm_kasprintf(dev, GFP_KERNEL, "%s_out%u", parent->name, i);
 
                if (!name)
                        return -ENOMEM;
 
-               snprintf(name, 23, "%s_out%u", parent->name, i);
                out_hw->divider.hw.init = CLK_HW_INIT_HW(name, &parent->hw, &clk_divider_ops, 0);
                out_hw->divider.reg = data->pll_base[i / MPFS_CCC_OUTPUTS_PER_PLL] +
                        out_hw->reg_offset;
@@ -201,14 +200,13 @@ static int mpfs_ccc_register_plls(struct device *dev, struct mpfs_ccc_pll_hw_clo
 
        for (unsigned int i = 0; i < num_clks; i++) {
                struct mpfs_ccc_pll_hw_clock *pll_hw = &pll_hws[i];
-               char *name = devm_kzalloc(dev, 18, GFP_KERNEL);
 
-               if (!name)
+               pll_hw->name = devm_kasprintf(dev, GFP_KERNEL, "ccc%s_pll%u",
+                                             strchrnul(dev->of_node->full_name, '@'), i);
+               if (!pll_hw->name)
                        return -ENOMEM;
 
                pll_hw->base = data->pll_base[i];
-               snprintf(name, 18, "ccc%s_pll%u", strchrnul(dev->of_node->full_name, '@'), i);
-               pll_hw->name = (const char *)name;
                pll_hw->hw.init = CLK_HW_INIT_PARENTS_DATA_FIXED_SIZE(pll_hw->name,
                                                                      pll_hw->parents,
                                                                      &mpfs_ccc_pll_ops, 0);
index fcfc2e2..27f3890 100644 (file)
@@ -58,7 +58,7 @@
 #define PCI1760_CMD_CLR_IMB2           0x00    /* Clears IMB2 */
 #define PCI1760_CMD_SET_DO             0x01    /* Set output state */
 #define PCI1760_CMD_GET_DO             0x02    /* Read output status */
-#define PCI1760_CMD_GET_STATUS         0x03    /* Read current status */
+#define PCI1760_CMD_GET_STATUS         0x07    /* Read current status */
 #define PCI1760_CMD_GET_FW_VER         0x0e    /* Read firmware version */
 #define PCI1760_CMD_GET_HW_VER         0x0f    /* Read hardware version */
 #define PCI1760_CMD_SET_PWM_HI(x)      (0x10 + (x) * 2) /* Set "hi" period */
index 2a84fc6..76aa133 100644 (file)
@@ -3,7 +3,6 @@ menu "CPU Frequency scaling"
 
 config CPU_FREQ
        bool "CPU Frequency scaling"
-       select SRCU
        help
          CPU Frequency scaling allows you to change the clock speed of 
          CPUs on the fly. This is a nice method to save power, because 
@@ -270,15 +269,6 @@ config LOONGSON2_CPUFREQ
 
          Loongson2F and its successors support this feature.
 
-         If in doubt, say N.
-
-config LOONGSON1_CPUFREQ
-       tristate "Loongson1 CPUFreq Driver"
-       depends on LOONGSON1_LS1B
-       help
-         This option adds a CPUFreq driver for loongson1 processors which
-         support software configurable cpu frequency.
-
          If in doubt, say N.
 endif
 
index 32a7029..4a806cc 100644 (file)
@@ -111,7 +111,6 @@ obj-$(CONFIG_POWERNV_CPUFREQ)               += powernv-cpufreq.o
 obj-$(CONFIG_BMIPS_CPUFREQ)            += bmips-cpufreq.o
 obj-$(CONFIG_IA64_ACPI_CPUFREQ)                += ia64-acpi-cpufreq.o
 obj-$(CONFIG_LOONGSON2_CPUFREQ)                += loongson2_cpufreq.o
-obj-$(CONFIG_LOONGSON1_CPUFREQ)                += loongson1-cpufreq.o
 obj-$(CONFIG_SH_CPU_FREQ)              += sh-cpufreq.o
 obj-$(CONFIG_SPARC_US2E_CPUFREQ)       += sparc-us2e-cpufreq.o
 obj-$(CONFIG_SPARC_US3_CPUFREQ)                += sparc-us3-cpufreq.o
index 204e390..45c8889 100644 (file)
  * we disable it by default to go acpi-cpufreq on these processors and add a
  * module parameter to be able to enable it manually for debugging.
  */
+static struct cpufreq_driver *current_pstate_driver;
 static struct cpufreq_driver amd_pstate_driver;
-static int cppc_load __initdata;
+static struct cpufreq_driver amd_pstate_epp_driver;
+static int cppc_state = AMD_PSTATE_DISABLE;
+struct kobject *amd_pstate_kobj;
+
+/*
+ * AMD Energy Preference Performance (EPP)
+ * The EPP is used in the CCLK DPM controller to drive
+ * the frequency that a core is going to operate during
+ * short periods of activity. EPP values will be utilized for
+ * different OS profiles (balanced, performance, power savings)
+ * display strings corresponding to EPP index in the
+ * energy_perf_strings[]
+ *     index           String
+ *-------------------------------------
+ *     0               default
+ *     1               performance
+ *     2               balance_performance
+ *     3               balance_power
+ *     4               power
+ */
+enum energy_perf_value_index {
+       EPP_INDEX_DEFAULT = 0,
+       EPP_INDEX_PERFORMANCE,
+       EPP_INDEX_BALANCE_PERFORMANCE,
+       EPP_INDEX_BALANCE_POWERSAVE,
+       EPP_INDEX_POWERSAVE,
+};
+
+static const char * const energy_perf_strings[] = {
+       [EPP_INDEX_DEFAULT] = "default",
+       [EPP_INDEX_PERFORMANCE] = "performance",
+       [EPP_INDEX_BALANCE_PERFORMANCE] = "balance_performance",
+       [EPP_INDEX_BALANCE_POWERSAVE] = "balance_power",
+       [EPP_INDEX_POWERSAVE] = "power",
+       NULL
+};
+
+static unsigned int epp_values[] = {
+       [EPP_INDEX_DEFAULT] = 0,
+       [EPP_INDEX_PERFORMANCE] = AMD_CPPC_EPP_PERFORMANCE,
+       [EPP_INDEX_BALANCE_PERFORMANCE] = AMD_CPPC_EPP_BALANCE_PERFORMANCE,
+       [EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_BALANCE_POWERSAVE,
+       [EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_POWERSAVE,
+ };
+
+static inline int get_mode_idx_from_str(const char *str, size_t size)
+{
+       int i;
+
+       for (i=0; i < AMD_PSTATE_MAX; i++) {
+               if (!strncmp(str, amd_pstate_mode_string[i], size))
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static DEFINE_MUTEX(amd_pstate_limits_lock);
+static DEFINE_MUTEX(amd_pstate_driver_lock);
+
+static s16 amd_pstate_get_epp(struct amd_cpudata *cpudata, u64 cppc_req_cached)
+{
+       u64 epp;
+       int ret;
+
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               if (!cppc_req_cached) {
+                       epp = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ,
+                                       &cppc_req_cached);
+                       if (epp)
+                               return epp;
+               }
+               epp = (cppc_req_cached >> 24) & 0xFF;
+       } else {
+               ret = cppc_get_epp_perf(cpudata->cpu, &epp);
+               if (ret < 0) {
+                       pr_debug("Could not retrieve energy perf value (%d)\n", ret);
+                       return -EIO;
+               }
+       }
+
+       return (s16)(epp & 0xff);
+}
+
+static int amd_pstate_get_energy_pref_index(struct amd_cpudata *cpudata)
+{
+       s16 epp;
+       int index = -EINVAL;
+
+       epp = amd_pstate_get_epp(cpudata, 0);
+       if (epp < 0)
+               return epp;
+
+       switch (epp) {
+       case AMD_CPPC_EPP_PERFORMANCE:
+               index = EPP_INDEX_PERFORMANCE;
+               break;
+       case AMD_CPPC_EPP_BALANCE_PERFORMANCE:
+               index = EPP_INDEX_BALANCE_PERFORMANCE;
+               break;
+       case AMD_CPPC_EPP_BALANCE_POWERSAVE:
+               index = EPP_INDEX_BALANCE_POWERSAVE;
+               break;
+       case AMD_CPPC_EPP_POWERSAVE:
+               index = EPP_INDEX_POWERSAVE;
+               break;
+       default:
+               break;
+       }
+
+       return index;
+}
+
+static int amd_pstate_set_epp(struct amd_cpudata *cpudata, u32 epp)
+{
+       int ret;
+       struct cppc_perf_ctrls perf_ctrls;
+
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               u64 value = READ_ONCE(cpudata->cppc_req_cached);
+
+               value &= ~GENMASK_ULL(31, 24);
+               value |= (u64)epp << 24;
+               WRITE_ONCE(cpudata->cppc_req_cached, value);
+
+               ret = wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
+               if (!ret)
+                       cpudata->epp_cached = epp;
+       } else {
+               perf_ctrls.energy_perf = epp;
+               ret = cppc_set_epp_perf(cpudata->cpu, &perf_ctrls, 1);
+               if (ret) {
+                       pr_debug("failed to set energy perf value (%d)\n", ret);
+                       return ret;
+               }
+               cpudata->epp_cached = epp;
+       }
+
+       return ret;
+}
+
+static int amd_pstate_set_energy_pref_index(struct amd_cpudata *cpudata,
+               int pref_index)
+{
+       int epp = -EINVAL;
+       int ret;
+
+       if (!pref_index) {
+               pr_debug("EPP pref_index is invalid\n");
+               return -EINVAL;
+       }
+
+       if (epp == -EINVAL)
+               epp = epp_values[pref_index];
+
+       if (epp > 0 && cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
+               pr_debug("EPP cannot be set under performance policy\n");
+               return -EBUSY;
+       }
+
+       ret = amd_pstate_set_epp(cpudata, epp);
+
+       return ret;
+}
 
 static inline int pstate_enable(bool enable)
 {
@@ -70,11 +233,21 @@ static inline int pstate_enable(bool enable)
 static int cppc_enable(bool enable)
 {
        int cpu, ret = 0;
+       struct cppc_perf_ctrls perf_ctrls;
 
        for_each_present_cpu(cpu) {
                ret = cppc_set_enable(cpu, enable);
                if (ret)
                        return ret;
+
+               /* Enable autonomous mode for EPP */
+               if (cppc_state == AMD_PSTATE_ACTIVE) {
+                       /* Set desired perf as zero to allow EPP firmware control */
+                       perf_ctrls.desired_perf = 0;
+                       ret = cppc_set_perf(cpu, &perf_ctrls);
+                       if (ret)
+                               return ret;
+               }
        }
 
        return ret;
@@ -307,6 +480,7 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
                max_perf = min_perf;
 
        amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true);
+       cpufreq_cpu_put(policy);
 }
 
 static int amd_get_min_freq(struct amd_cpudata *cpudata)
@@ -417,7 +591,7 @@ static void amd_pstate_boost_init(struct amd_cpudata *cpudata)
                return;
 
        cpudata->boost_supported = true;
-       amd_pstate_driver.boost_enabled = true;
+       current_pstate_driver->boost_enabled = true;
 }
 
 static void amd_perf_ctl_reset(unsigned int cpu)
@@ -500,6 +674,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
        policy->driver_data = cpudata;
 
        amd_pstate_boost_init(cpudata);
+       if (!current_pstate_driver->adjust_perf)
+               current_pstate_driver->adjust_perf = amd_pstate_adjust_perf;
 
        return 0;
 
@@ -560,7 +736,7 @@ static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy,
        if (max_freq < 0)
                return max_freq;
 
-       return sprintf(&buf[0], "%u\n", max_freq);
+       return sysfs_emit(buf, "%u\n", max_freq);
 }
 
 static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *policy,
@@ -573,7 +749,7 @@ static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *poli
        if (freq < 0)
                return freq;
 
-       return sprintf(&buf[0], "%u\n", freq);
+       return sysfs_emit(buf, "%u\n", freq);
 }
 
 /*
@@ -588,13 +764,151 @@ static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy,
 
        perf = READ_ONCE(cpudata->highest_perf);
 
-       return sprintf(&buf[0], "%u\n", perf);
+       return sysfs_emit(buf, "%u\n", perf);
+}
+
+static ssize_t show_energy_performance_available_preferences(
+                               struct cpufreq_policy *policy, char *buf)
+{
+       int i = 0;
+       int offset = 0;
+
+       while (energy_perf_strings[i] != NULL)
+               offset += sysfs_emit_at(buf, offset, "%s ", energy_perf_strings[i++]);
+
+       sysfs_emit_at(buf, offset, "\n");
+
+       return offset;
+}
+
+static ssize_t store_energy_performance_preference(
+               struct cpufreq_policy *policy, const char *buf, size_t count)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+       char str_preference[21];
+       ssize_t ret;
+
+       ret = sscanf(buf, "%20s", str_preference);
+       if (ret != 1)
+               return -EINVAL;
+
+       ret = match_string(energy_perf_strings, -1, str_preference);
+       if (ret < 0)
+               return -EINVAL;
+
+       mutex_lock(&amd_pstate_limits_lock);
+       ret = amd_pstate_set_energy_pref_index(cpudata, ret);
+       mutex_unlock(&amd_pstate_limits_lock);
+
+       return ret ?: count;
+}
+
+static ssize_t show_energy_performance_preference(
+                               struct cpufreq_policy *policy, char *buf)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+       int preference;
+
+       preference = amd_pstate_get_energy_pref_index(cpudata);
+       if (preference < 0)
+               return preference;
+
+       return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
+}
+
+static ssize_t amd_pstate_show_status(char *buf)
+{
+       if (!current_pstate_driver)
+               return sysfs_emit(buf, "disable\n");
+
+       return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
+}
+
+static void amd_pstate_driver_cleanup(void)
+{
+       current_pstate_driver = NULL;
+}
+
+static int amd_pstate_update_status(const char *buf, size_t size)
+{
+       int ret = 0;
+       int mode_idx;
+
+       if (size > 7 || size < 6)
+               return -EINVAL;
+       mode_idx = get_mode_idx_from_str(buf, size);
+
+       switch(mode_idx) {
+       case AMD_PSTATE_DISABLE:
+               if (!current_pstate_driver)
+                       return -EINVAL;
+               if (cppc_state == AMD_PSTATE_ACTIVE)
+                       return -EBUSY;
+               cpufreq_unregister_driver(current_pstate_driver);
+               amd_pstate_driver_cleanup();
+               break;
+       case AMD_PSTATE_PASSIVE:
+               if (current_pstate_driver) {
+                       if (current_pstate_driver == &amd_pstate_driver)
+                               return 0;
+                       cpufreq_unregister_driver(current_pstate_driver);
+                       cppc_state = AMD_PSTATE_PASSIVE;
+                       current_pstate_driver = &amd_pstate_driver;
+               }
+
+               ret = cpufreq_register_driver(current_pstate_driver);
+               break;
+       case AMD_PSTATE_ACTIVE:
+               if (current_pstate_driver) {
+                       if (current_pstate_driver == &amd_pstate_epp_driver)
+                               return 0;
+                       cpufreq_unregister_driver(current_pstate_driver);
+                       current_pstate_driver = &amd_pstate_epp_driver;
+                       cppc_state = AMD_PSTATE_ACTIVE;
+               }
+
+               ret = cpufreq_register_driver(current_pstate_driver);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static ssize_t show_status(struct kobject *kobj,
+                          struct kobj_attribute *attr, char *buf)
+{
+       ssize_t ret;
+
+       mutex_lock(&amd_pstate_driver_lock);
+       ret = amd_pstate_show_status(buf);
+       mutex_unlock(&amd_pstate_driver_lock);
+
+       return ret;
+}
+
+static ssize_t store_status(struct kobject *a, struct kobj_attribute *b,
+                           const char *buf, size_t count)
+{
+       char *p = memchr(buf, '\n', count);
+       int ret;
+
+       mutex_lock(&amd_pstate_driver_lock);
+       ret = amd_pstate_update_status(buf, p ? p - buf : count);
+       mutex_unlock(&amd_pstate_driver_lock);
+
+       return ret < 0 ? ret : count;
 }
 
 cpufreq_freq_attr_ro(amd_pstate_max_freq);
 cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
 
 cpufreq_freq_attr_ro(amd_pstate_highest_perf);
+cpufreq_freq_attr_rw(energy_performance_preference);
+cpufreq_freq_attr_ro(energy_performance_available_preferences);
+define_one_global_rw(status);
 
 static struct freq_attr *amd_pstate_attr[] = {
        &amd_pstate_max_freq,
@@ -603,6 +917,313 @@ static struct freq_attr *amd_pstate_attr[] = {
        NULL,
 };
 
+static struct freq_attr *amd_pstate_epp_attr[] = {
+       &amd_pstate_max_freq,
+       &amd_pstate_lowest_nonlinear_freq,
+       &amd_pstate_highest_perf,
+       &energy_performance_preference,
+       &energy_performance_available_preferences,
+       NULL,
+};
+
+static struct attribute *pstate_global_attributes[] = {
+       &status.attr,
+       NULL
+};
+
+static const struct attribute_group amd_pstate_global_attr_group = {
+       .attrs = pstate_global_attributes,
+};
+
+static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
+{
+       int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
+       struct amd_cpudata *cpudata;
+       struct device *dev;
+       u64 value;
+
+       /*
+        * Resetting PERF_CTL_MSR will put the CPU in P0 frequency,
+        * which is ideal for initialization process.
+        */
+       amd_perf_ctl_reset(policy->cpu);
+       dev = get_cpu_device(policy->cpu);
+       if (!dev)
+               return -ENODEV;
+
+       cpudata = kzalloc(sizeof(*cpudata), GFP_KERNEL);
+       if (!cpudata)
+               return -ENOMEM;
+
+       cpudata->cpu = policy->cpu;
+       cpudata->epp_policy = 0;
+
+       ret = amd_pstate_init_perf(cpudata);
+       if (ret)
+               goto free_cpudata1;
+
+       min_freq = amd_get_min_freq(cpudata);
+       max_freq = amd_get_max_freq(cpudata);
+       nominal_freq = amd_get_nominal_freq(cpudata);
+       lowest_nonlinear_freq = amd_get_lowest_nonlinear_freq(cpudata);
+       if (min_freq < 0 || max_freq < 0 || min_freq > max_freq) {
+               dev_err(dev, "min_freq(%d) or max_freq(%d) value is incorrect\n",
+                               min_freq, max_freq);
+               ret = -EINVAL;
+               goto free_cpudata1;
+       }
+
+       policy->cpuinfo.min_freq = min_freq;
+       policy->cpuinfo.max_freq = max_freq;
+       /* It will be updated by governor */
+       policy->cur = policy->cpuinfo.min_freq;
+
+       /* Initial processor data capability frequencies */
+       cpudata->max_freq = max_freq;
+       cpudata->min_freq = min_freq;
+       cpudata->nominal_freq = nominal_freq;
+       cpudata->lowest_nonlinear_freq = lowest_nonlinear_freq;
+
+       policy->driver_data = cpudata;
+
+       cpudata->epp_cached = amd_pstate_get_epp(cpudata, 0);
+
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+
+       /*
+        * Set the policy to powersave to provide a valid fallback value in case
+        * the default cpufreq governor is neither powersave nor performance.
+        */
+       policy->policy = CPUFREQ_POLICY_POWERSAVE;
+
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               policy->fast_switch_possible = true;
+               ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &value);
+               if (ret)
+                       return ret;
+               WRITE_ONCE(cpudata->cppc_req_cached, value);
+
+               ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1, &value);
+               if (ret)
+                       return ret;
+               WRITE_ONCE(cpudata->cppc_cap1_cached, value);
+       }
+       amd_pstate_boost_init(cpudata);
+
+       return 0;
+
+free_cpudata1:
+       kfree(cpudata);
+       return ret;
+}
+
+static int amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
+{
+       pr_debug("CPU %d exiting\n", policy->cpu);
+       policy->fast_switch_possible = false;
+       return 0;
+}
+
+static void amd_pstate_epp_init(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+       struct amd_cpudata *cpudata = policy->driver_data;
+       u32 max_perf, min_perf;
+       u64 value;
+       s16 epp;
+
+       max_perf = READ_ONCE(cpudata->highest_perf);
+       min_perf = READ_ONCE(cpudata->lowest_perf);
+
+       value = READ_ONCE(cpudata->cppc_req_cached);
+
+       if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
+               min_perf = max_perf;
+
+       /* Initial min/max values for CPPC Performance Controls Register */
+       value &= ~AMD_CPPC_MIN_PERF(~0L);
+       value |= AMD_CPPC_MIN_PERF(min_perf);
+
+       value &= ~AMD_CPPC_MAX_PERF(~0L);
+       value |= AMD_CPPC_MAX_PERF(max_perf);
+
+       /* CPPC EPP feature require to set zero to the desire perf bit */
+       value &= ~AMD_CPPC_DES_PERF(~0L);
+       value |= AMD_CPPC_DES_PERF(0);
+
+       if (cpudata->epp_policy == cpudata->policy)
+               goto skip_epp;
+
+       cpudata->epp_policy = cpudata->policy;
+
+       /* Get BIOS pre-defined epp value */
+       epp = amd_pstate_get_epp(cpudata, value);
+       if (epp < 0) {
+               /**
+                * This return value can only be negative for shared_memory
+                * systems where EPP register read/write not supported.
+                */
+               goto skip_epp;
+       }
+
+       if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
+               epp = 0;
+
+       /* Set initial EPP value */
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               value &= ~GENMASK_ULL(31, 24);
+               value |= (u64)epp << 24;
+       }
+
+       WRITE_ONCE(cpudata->cppc_req_cached, value);
+       amd_pstate_set_epp(cpudata, epp);
+skip_epp:
+       cpufreq_cpu_put(policy);
+}
+
+static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+
+       if (!policy->cpuinfo.max_freq)
+               return -ENODEV;
+
+       pr_debug("set_policy: cpuinfo.max %u policy->max %u\n",
+                               policy->cpuinfo.max_freq, policy->max);
+
+       cpudata->policy = policy->policy;
+
+       amd_pstate_epp_init(policy->cpu);
+
+       return 0;
+}
+
+static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
+{
+       struct cppc_perf_ctrls perf_ctrls;
+       u64 value, max_perf;
+       int ret;
+
+       ret = amd_pstate_enable(true);
+       if (ret)
+               pr_err("failed to enable amd pstate during resume, return %d\n", ret);
+
+       value = READ_ONCE(cpudata->cppc_req_cached);
+       max_perf = READ_ONCE(cpudata->highest_perf);
+
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
+       } else {
+               perf_ctrls.max_perf = max_perf;
+               perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(cpudata->epp_cached);
+               cppc_set_perf(cpudata->cpu, &perf_ctrls);
+       }
+}
+
+static int amd_pstate_epp_cpu_online(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+
+       pr_debug("AMD CPU Core %d going online\n", cpudata->cpu);
+
+       if (cppc_state == AMD_PSTATE_ACTIVE) {
+               amd_pstate_epp_reenable(cpudata);
+               cpudata->suspended = false;
+       }
+
+       return 0;
+}
+
+static void amd_pstate_epp_offline(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+       struct cppc_perf_ctrls perf_ctrls;
+       int min_perf;
+       u64 value;
+
+       min_perf = READ_ONCE(cpudata->lowest_perf);
+       value = READ_ONCE(cpudata->cppc_req_cached);
+
+       mutex_lock(&amd_pstate_limits_lock);
+       if (boot_cpu_has(X86_FEATURE_CPPC)) {
+               cpudata->epp_policy = CPUFREQ_POLICY_UNKNOWN;
+
+               /* Set max perf same as min perf */
+               value &= ~AMD_CPPC_MAX_PERF(~0L);
+               value |= AMD_CPPC_MAX_PERF(min_perf);
+               value &= ~AMD_CPPC_MIN_PERF(~0L);
+               value |= AMD_CPPC_MIN_PERF(min_perf);
+               wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
+       } else {
+               perf_ctrls.desired_perf = 0;
+               perf_ctrls.max_perf = min_perf;
+               perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(HWP_EPP_BALANCE_POWERSAVE);
+               cppc_set_perf(cpudata->cpu, &perf_ctrls);
+       }
+       mutex_unlock(&amd_pstate_limits_lock);
+}
+
+static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+
+       pr_debug("AMD CPU Core %d going offline\n", cpudata->cpu);
+
+       if (cpudata->suspended)
+               return 0;
+
+       if (cppc_state == AMD_PSTATE_ACTIVE)
+               amd_pstate_epp_offline(policy);
+
+       return 0;
+}
+
+static int amd_pstate_epp_verify_policy(struct cpufreq_policy_data *policy)
+{
+       cpufreq_verify_within_cpu_limits(policy);
+       pr_debug("policy_max =%d, policy_min=%d\n", policy->max, policy->min);
+       return 0;
+}
+
+static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+       int ret;
+
+       /* avoid suspending when EPP is not enabled */
+       if (cppc_state != AMD_PSTATE_ACTIVE)
+               return 0;
+
+       /* set this flag to avoid setting core offline*/
+       cpudata->suspended = true;
+
+       /* disable CPPC in lowlevel firmware */
+       ret = amd_pstate_enable(false);
+       if (ret)
+               pr_err("failed to suspend, return %d\n", ret);
+
+       return 0;
+}
+
+static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
+{
+       struct amd_cpudata *cpudata = policy->driver_data;
+
+       if (cpudata->suspended) {
+               mutex_lock(&amd_pstate_limits_lock);
+
+               /* enable amd pstate from suspend state*/
+               amd_pstate_epp_reenable(cpudata);
+
+               mutex_unlock(&amd_pstate_limits_lock);
+
+               cpudata->suspended = false;
+       }
+
+       return 0;
+}
+
 static struct cpufreq_driver amd_pstate_driver = {
        .flags          = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS,
        .verify         = amd_pstate_verify,
@@ -616,6 +1237,20 @@ static struct cpufreq_driver amd_pstate_driver = {
        .attr           = amd_pstate_attr,
 };
 
+static struct cpufreq_driver amd_pstate_epp_driver = {
+       .flags          = CPUFREQ_CONST_LOOPS,
+       .verify         = amd_pstate_epp_verify_policy,
+       .setpolicy      = amd_pstate_epp_set_policy,
+       .init           = amd_pstate_epp_cpu_init,
+       .exit           = amd_pstate_epp_cpu_exit,
+       .offline        = amd_pstate_epp_cpu_offline,
+       .online         = amd_pstate_epp_cpu_online,
+       .suspend        = amd_pstate_epp_suspend,
+       .resume         = amd_pstate_epp_resume,
+       .name           = "amd_pstate_epp",
+       .attr           = amd_pstate_epp_attr,
+};
+
 static int __init amd_pstate_init(void)
 {
        int ret;
@@ -625,10 +1260,10 @@ static int __init amd_pstate_init(void)
        /*
         * by default the pstate driver is disabled to load
         * enable the amd_pstate passive mode driver explicitly
-        * with amd_pstate=passive in kernel command line
+        * with amd_pstate=passive or other modes in kernel command line
         */
-       if (!cppc_load) {
-               pr_debug("driver load is disabled, boot with amd_pstate=passive to enable this\n");
+       if (cppc_state == AMD_PSTATE_DISABLE) {
+               pr_debug("driver load is disabled, boot with specific mode to enable this\n");
                return -ENODEV;
        }
 
@@ -644,7 +1279,8 @@ static int __init amd_pstate_init(void)
        /* capability check */
        if (boot_cpu_has(X86_FEATURE_CPPC)) {
                pr_debug("AMD CPPC MSR based functionality is supported\n");
-               amd_pstate_driver.adjust_perf = amd_pstate_adjust_perf;
+               if (cppc_state == AMD_PSTATE_PASSIVE)
+                       current_pstate_driver->adjust_perf = amd_pstate_adjust_perf;
        } else {
                pr_debug("AMD CPPC shared memory based functionality is supported\n");
                static_call_update(amd_pstate_enable, cppc_enable);
@@ -655,31 +1291,63 @@ static int __init amd_pstate_init(void)
        /* enable amd pstate feature */
        ret = amd_pstate_enable(true);
        if (ret) {
-               pr_err("failed to enable amd-pstate with return %d\n", ret);
+               pr_err("failed to enable with return %d\n", ret);
                return ret;
        }
 
-       ret = cpufreq_register_driver(&amd_pstate_driver);
+       ret = cpufreq_register_driver(current_pstate_driver);
        if (ret)
-               pr_err("failed to register amd_pstate_driver with return %d\n",
-                      ret);
+               pr_err("failed to register with return %d\n", ret);
+
+       amd_pstate_kobj = kobject_create_and_add("amd_pstate", &cpu_subsys.dev_root->kobj);
+       if (!amd_pstate_kobj) {
+               ret = -EINVAL;
+               pr_err("global sysfs registration failed.\n");
+               goto kobject_free;
+       }
+
+       ret = sysfs_create_group(amd_pstate_kobj, &amd_pstate_global_attr_group);
+       if (ret) {
+               pr_err("sysfs attribute export failed with error %d.\n", ret);
+               goto global_attr_free;
+       }
 
        return ret;
+
+global_attr_free:
+       kobject_put(amd_pstate_kobj);
+kobject_free:
+       cpufreq_unregister_driver(current_pstate_driver);
+       return ret;
 }
 device_initcall(amd_pstate_init);
 
 static int __init amd_pstate_param(char *str)
 {
+       size_t size;
+       int mode_idx;
+
        if (!str)
                return -EINVAL;
 
-       if (!strcmp(str, "disable")) {
-               cppc_load = 0;
-               pr_info("driver is explicitly disabled\n");
-       } else if (!strcmp(str, "passive"))
-               cppc_load = 1;
+       size = strlen(str);
+       mode_idx = get_mode_idx_from_str(str, size);
 
-       return 0;
+       if (mode_idx >= AMD_PSTATE_DISABLE && mode_idx < AMD_PSTATE_MAX) {
+               cppc_state = mode_idx;
+               if (cppc_state == AMD_PSTATE_DISABLE)
+                       pr_info("driver is explicitly disabled\n");
+
+               if (cppc_state == AMD_PSTATE_ACTIVE)
+                       current_pstate_driver = &amd_pstate_epp_driver;
+
+               if (cppc_state == AMD_PSTATE_PASSIVE)
+                       current_pstate_driver = &amd_pstate_driver;
+
+               return 0;
+       }
+
+       return -EINVAL;
 }
 early_param("amd_pstate", amd_pstate_param);
 
index d180128..c11d22f 100644 (file)
@@ -280,6 +280,7 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy)
        policy->cpuinfo.transition_latency = transition_latency;
        policy->dvfs_possible_from_any_cpu = true;
        policy->fast_switch_possible = true;
+       policy->suspend_freq = freq_table[0].frequency;
 
        if (policy_has_boost_freq(policy)) {
                ret = cpufreq_enable_boost_support();
@@ -321,7 +322,6 @@ static struct cpufreq_driver apple_soc_cpufreq_driver = {
        .flags          = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
                          CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_IS_COOLING_DEV,
        .verify         = cpufreq_generic_frequency_table_verify,
-       .attr           = cpufreq_generic_attr,
        .get            = apple_soc_cpufreq_get_rate,
        .init           = apple_soc_cpufreq_init,
        .exit           = apple_soc_cpufreq_exit,
@@ -329,6 +329,7 @@ static struct cpufreq_driver apple_soc_cpufreq_driver = {
        .fast_switch    = apple_soc_cpufreq_fast_switch,
        .register_em    = cpufreq_register_em_with_opp,
        .attr           = apple_soc_cpufreq_hw_attr,
+       .suspend        = cpufreq_generic_suspend,
 };
 
 static int __init apple_soc_cpufreq_module_init(void)
index c10fc33..b74289a 100644 (file)
@@ -445,7 +445,7 @@ static int __init armada37xx_cpufreq_driver_init(void)
                return -ENODEV;
        }
 
-       clk = clk_get(cpu_dev, 0);
+       clk = clk_get(cpu_dev, NULL);
        if (IS_ERR(clk)) {
                dev_err(cpu_dev, "Cannot get clock for CPU0\n");
                return PTR_ERR(clk);
index 4153150..ffea640 100644 (file)
@@ -751,10 +751,7 @@ static int brcm_avs_cpufreq_probe(struct platform_device *pdev)
 
 static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
 {
-       int ret;
-
-       ret = cpufreq_unregister_driver(&brcm_avs_driver);
-       WARN_ON(ret);
+       cpufreq_unregister_driver(&brcm_avs_driver);
 
        brcm_avs_prepare_uninit(pdev);
 
index 432dfb4..022e355 100644 (file)
@@ -487,7 +487,8 @@ static unsigned int get_perf_level_count(struct cpufreq_policy *policy)
        cpu_data = policy->driver_data;
        perf_caps = &cpu_data->perf_caps;
        max_cap = arch_scale_cpu_capacity(cpu);
-       min_cap = div_u64(max_cap * perf_caps->lowest_perf, perf_caps->highest_perf);
+       min_cap = div_u64((u64)max_cap * perf_caps->lowest_perf,
+                         perf_caps->highest_perf);
        if ((min_cap == 0) || (max_cap < min_cap))
                return 0;
        return 1 + max_cap / CPPC_EM_CAP_STEP - min_cap / CPPC_EM_CAP_STEP;
@@ -519,10 +520,10 @@ static int cppc_get_cpu_power(struct device *cpu_dev,
        cpu_data = policy->driver_data;
        perf_caps = &cpu_data->perf_caps;
        max_cap = arch_scale_cpu_capacity(cpu_dev->id);
-       min_cap = div_u64(max_cap * perf_caps->lowest_perf,
-                       perf_caps->highest_perf);
-
-       perf_step = CPPC_EM_CAP_STEP * perf_caps->highest_perf / max_cap;
+       min_cap = div_u64((u64)max_cap * perf_caps->lowest_perf,
+                         perf_caps->highest_perf);
+       perf_step = div_u64((u64)CPPC_EM_CAP_STEP * perf_caps->highest_perf,
+                           max_cap);
        min_step = min_cap / CPPC_EM_CAP_STEP;
        max_step = max_cap / CPPC_EM_CAP_STEP;
 
index 8ab6728..e857036 100644 (file)
@@ -137,6 +137,7 @@ static const struct of_device_id blocklist[] __initconst = {
        { .compatible = "nvidia,tegra30", },
        { .compatible = "nvidia,tegra124", },
        { .compatible = "nvidia,tegra210", },
+       { .compatible = "nvidia,tegra234", },
 
        { .compatible = "qcom,apq8096", },
        { .compatible = "qcom,msm8996", },
@@ -150,6 +151,7 @@ static const struct of_device_id blocklist[] __initconst = {
        { .compatible = "qcom,sdm845", },
        { .compatible = "qcom,sm6115", },
        { .compatible = "qcom,sm6350", },
+       { .compatible = "qcom,sm6375", },
        { .compatible = "qcom,sm8150", },
        { .compatible = "qcom,sm8250", },
        { .compatible = "qcom,sm8350", },
index 7e56a42..6d8fd3b 100644 (file)
@@ -993,7 +993,7 @@ static const struct sysfs_ops sysfs_ops = {
        .store  = store,
 };
 
-static struct kobj_type ktype_cpufreq = {
+static const struct kobj_type ktype_cpufreq = {
        .sysfs_ops      = &sysfs_ops,
        .default_groups = cpufreq_groups,
        .release        = cpufreq_sysfs_release,
@@ -2904,12 +2904,12 @@ EXPORT_SYMBOL_GPL(cpufreq_register_driver);
  * Returns zero if successful, and -EINVAL if the cpufreq_driver is
  * currently not initialised.
  */
-int cpufreq_unregister_driver(struct cpufreq_driver *driver)
+void cpufreq_unregister_driver(struct cpufreq_driver *driver)
 {
        unsigned long flags;
 
-       if (!cpufreq_driver || (driver != cpufreq_driver))
-               return -EINVAL;
+       if (WARN_ON(!cpufreq_driver || (driver != cpufreq_driver)))
+               return;
 
        pr_debug("unregistering driver %s\n", driver->name);
 
@@ -2926,8 +2926,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
 
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
        cpus_read_unlock();
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
 
index 9e97f60..ebb3a81 100644 (file)
@@ -133,12 +133,14 @@ static int __init davinci_cpufreq_probe(struct platform_device *pdev)
 
 static int __exit davinci_cpufreq_remove(struct platform_device *pdev)
 {
+       cpufreq_unregister_driver(&davinci_driver);
+
        clk_put(cpufreq.armclk);
 
        if (cpufreq.asyncclk)
                clk_put(cpufreq.asyncclk);
 
-       return cpufreq_unregister_driver(&davinci_driver);
+       return 0;
 }
 
 static struct platform_driver davinci_cpufreq_driver = {
diff --git a/drivers/cpufreq/loongson1-cpufreq.c b/drivers/cpufreq/loongson1-cpufreq.c
deleted file mode 100644 (file)
index fb72d70..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * CPU Frequency Scaling for Loongson 1 SoC
- *
- * Copyright (C) 2014-2016 Zhang, Keguang <keguang.zhang@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/cpu.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <cpufreq.h>
-#include <loongson1.h>
-
-struct ls1x_cpufreq {
-       struct device *dev;
-       struct clk *clk;        /* CPU clk */
-       struct clk *mux_clk;    /* MUX of CPU clk */
-       struct clk *pll_clk;    /* PLL clk */
-       struct clk *osc_clk;    /* OSC clk */
-       unsigned int max_freq;
-       unsigned int min_freq;
-};
-
-static struct ls1x_cpufreq *cpufreq;
-
-static int ls1x_cpufreq_notifier(struct notifier_block *nb,
-                                unsigned long val, void *data)
-{
-       if (val == CPUFREQ_POSTCHANGE)
-               current_cpu_data.udelay_val = loops_per_jiffy;
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block ls1x_cpufreq_notifier_block = {
-       .notifier_call = ls1x_cpufreq_notifier
-};
-
-static int ls1x_cpufreq_target(struct cpufreq_policy *policy,
-                              unsigned int index)
-{
-       struct device *cpu_dev = get_cpu_device(policy->cpu);
-       unsigned int old_freq, new_freq;
-
-       old_freq = policy->cur;
-       new_freq = policy->freq_table[index].frequency;
-
-       /*
-        * The procedure of reconfiguring CPU clk is as below.
-        *
-        *  - Reparent CPU clk to OSC clk
-        *  - Reset CPU clock (very important)
-        *  - Reconfigure CPU DIV
-        *  - Reparent CPU clk back to CPU DIV clk
-        */
-
-       clk_set_parent(policy->clk, cpufreq->osc_clk);
-       __raw_writel(__raw_readl(LS1X_CLK_PLL_DIV) | RST_CPU_EN | RST_CPU,
-                    LS1X_CLK_PLL_DIV);
-       __raw_writel(__raw_readl(LS1X_CLK_PLL_DIV) & ~(RST_CPU_EN | RST_CPU),
-                    LS1X_CLK_PLL_DIV);
-       clk_set_rate(cpufreq->mux_clk, new_freq * 1000);
-       clk_set_parent(policy->clk, cpufreq->mux_clk);
-       dev_dbg(cpu_dev, "%u KHz --> %u KHz\n", old_freq, new_freq);
-
-       return 0;
-}
-
-static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
-{
-       struct device *cpu_dev = get_cpu_device(policy->cpu);
-       struct cpufreq_frequency_table *freq_tbl;
-       unsigned int pll_freq, freq;
-       int steps, i;
-
-       pll_freq = clk_get_rate(cpufreq->pll_clk) / 1000;
-
-       steps = 1 << DIV_CPU_WIDTH;
-       freq_tbl = kcalloc(steps, sizeof(*freq_tbl), GFP_KERNEL);
-       if (!freq_tbl)
-               return -ENOMEM;
-
-       for (i = 0; i < (steps - 1); i++) {
-               freq = pll_freq / (i + 1);
-               if ((freq < cpufreq->min_freq) || (freq > cpufreq->max_freq))
-                       freq_tbl[i].frequency = CPUFREQ_ENTRY_INVALID;
-               else
-                       freq_tbl[i].frequency = freq;
-               dev_dbg(cpu_dev,
-                       "cpufreq table: index %d: frequency %d\n", i,
-                       freq_tbl[i].frequency);
-       }
-       freq_tbl[i].frequency = CPUFREQ_TABLE_END;
-
-       policy->clk = cpufreq->clk;
-       cpufreq_generic_init(policy, freq_tbl, 0);
-
-       return 0;
-}
-
-static int ls1x_cpufreq_exit(struct cpufreq_policy *policy)
-{
-       kfree(policy->freq_table);
-       return 0;
-}
-
-static struct cpufreq_driver ls1x_cpufreq_driver = {
-       .name           = "cpufreq-ls1x",
-       .flags          = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
-       .verify         = cpufreq_generic_frequency_table_verify,
-       .target_index   = ls1x_cpufreq_target,
-       .get            = cpufreq_generic_get,
-       .init           = ls1x_cpufreq_init,
-       .exit           = ls1x_cpufreq_exit,
-       .attr           = cpufreq_generic_attr,
-};
-
-static int ls1x_cpufreq_remove(struct platform_device *pdev)
-{
-       cpufreq_unregister_notifier(&ls1x_cpufreq_notifier_block,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-       cpufreq_unregister_driver(&ls1x_cpufreq_driver);
-
-       return 0;
-}
-
-static int ls1x_cpufreq_probe(struct platform_device *pdev)
-{
-       struct plat_ls1x_cpufreq *pdata = dev_get_platdata(&pdev->dev);
-       struct clk *clk;
-       int ret;
-
-       if (!pdata || !pdata->clk_name || !pdata->osc_clk_name) {
-               dev_err(&pdev->dev, "platform data missing\n");
-               return -EINVAL;
-       }
-
-       cpufreq =
-           devm_kzalloc(&pdev->dev, sizeof(struct ls1x_cpufreq), GFP_KERNEL);
-       if (!cpufreq)
-               return -ENOMEM;
-
-       cpufreq->dev = &pdev->dev;
-
-       clk = devm_clk_get(&pdev->dev, pdata->clk_name);
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "unable to get %s clock\n",
-                       pdata->clk_name);
-               return PTR_ERR(clk);
-       }
-       cpufreq->clk = clk;
-
-       clk = clk_get_parent(clk);
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "unable to get parent of %s clock\n",
-                       __clk_get_name(cpufreq->clk));
-               return PTR_ERR(clk);
-       }
-       cpufreq->mux_clk = clk;
-
-       clk = clk_get_parent(clk);
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "unable to get parent of %s clock\n",
-                       __clk_get_name(cpufreq->mux_clk));
-               return PTR_ERR(clk);
-       }
-       cpufreq->pll_clk = clk;
-
-       clk = devm_clk_get(&pdev->dev, pdata->osc_clk_name);
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "unable to get %s clock\n",
-                       pdata->osc_clk_name);
-               return PTR_ERR(clk);
-       }
-       cpufreq->osc_clk = clk;
-
-       cpufreq->max_freq = pdata->max_freq;
-       cpufreq->min_freq = pdata->min_freq;
-
-       ret = cpufreq_register_driver(&ls1x_cpufreq_driver);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "failed to register CPUFreq driver: %d\n", ret);
-               return ret;
-       }
-
-       ret = cpufreq_register_notifier(&ls1x_cpufreq_notifier_block,
-                                       CPUFREQ_TRANSITION_NOTIFIER);
-
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "failed to register CPUFreq notifier: %d\n",ret);
-               cpufreq_unregister_driver(&ls1x_cpufreq_driver);
-       }
-
-       return ret;
-}
-
-static struct platform_driver ls1x_cpufreq_platdrv = {
-       .probe  = ls1x_cpufreq_probe,
-       .remove = ls1x_cpufreq_remove,
-       .driver = {
-               .name   = "ls1x-cpufreq",
-       },
-};
-
-module_platform_driver(ls1x_cpufreq_platdrv);
-
-MODULE_ALIAS("platform:ls1x-cpufreq");
-MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
-MODULE_DESCRIPTION("Loongson1 CPUFreq driver");
-MODULE_LICENSE("GPL");
index f803397..b22f5cc 100644 (file)
@@ -317,13 +317,16 @@ static int mtk_cpufreq_hw_driver_probe(struct platform_device *pdev)
 
 static int mtk_cpufreq_hw_driver_remove(struct platform_device *pdev)
 {
-       return cpufreq_unregister_driver(&cpufreq_mtk_hw_driver);
+       cpufreq_unregister_driver(&cpufreq_mtk_hw_driver);
+
+       return 0;
 }
 
 static const struct of_device_id mtk_cpufreq_hw_match[] = {
        { .compatible = "mediatek,cpufreq-hw", .data = &cpufreq_mtk_offsets },
        {}
 };
+MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match);
 
 static struct platform_driver mtk_cpufreq_hw_driver = {
        .probe = mtk_cpufreq_hw_driver_probe,
index 1b50df0..81649a1 100644 (file)
@@ -184,7 +184,9 @@ static int omap_cpufreq_probe(struct platform_device *pdev)
 
 static int omap_cpufreq_remove(struct platform_device *pdev)
 {
-       return cpufreq_unregister_driver(&omap_driver);
+       cpufreq_unregister_driver(&omap_driver);
+
+       return 0;
 }
 
 static struct platform_driver omap_cpufreq_platdrv = {
index 340fed3..2f581d2 100644 (file)
@@ -143,40 +143,42 @@ static unsigned long qcom_lmh_get_throttle_freq(struct qcom_cpufreq_data *data)
        return lval * xo_rate;
 }
 
-/* Get the current frequency of the CPU (after throttling) */
-static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
+/* Get the frequency requested by the cpufreq core for the CPU */
+static unsigned int qcom_cpufreq_get_freq(unsigned int cpu)
 {
        struct qcom_cpufreq_data *data;
+       const struct qcom_cpufreq_soc_data *soc_data;
        struct cpufreq_policy *policy;
+       unsigned int index;
 
        policy = cpufreq_cpu_get_raw(cpu);
        if (!policy)
                return 0;
 
        data = policy->driver_data;
+       soc_data = qcom_cpufreq.soc_data;
+
+       index = readl_relaxed(data->base + soc_data->reg_perf_state);
+       index = min(index, LUT_MAX_ENTRIES - 1);
 
-       return qcom_lmh_get_throttle_freq(data) / HZ_PER_KHZ;
+       return policy->freq_table[index].frequency;
 }
 
-/* Get the frequency requested by the cpufreq core for the CPU */
-static unsigned int qcom_cpufreq_get_freq(unsigned int cpu)
+static unsigned int qcom_cpufreq_hw_get(unsigned int cpu)
 {
        struct qcom_cpufreq_data *data;
-       const struct qcom_cpufreq_soc_data *soc_data;
        struct cpufreq_policy *policy;
-       unsigned int index;
 
        policy = cpufreq_cpu_get_raw(cpu);
        if (!policy)
                return 0;
 
        data = policy->driver_data;
-       soc_data = qcom_cpufreq.soc_data;
 
-       index = readl_relaxed(data->base + soc_data->reg_perf_state);
-       index = min(index, LUT_MAX_ENTRIES - 1);
+       if (data->throttle_irq >= 0)
+               return qcom_lmh_get_throttle_freq(data) / HZ_PER_KHZ;
 
-       return policy->freq_table[index].frequency;
+       return qcom_cpufreq_get_freq(cpu);
 }
 
 static unsigned int qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy,
@@ -649,9 +651,10 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
 {
        struct clk_hw_onecell_data *clk_data;
        struct device *dev = &pdev->dev;
+       struct device_node *soc_node;
        struct device *cpu_dev;
        struct clk *clk;
-       int ret, i, num_domains;
+       int ret, i, num_domains, reg_sz;
 
        clk = clk_get(dev, "xo");
        if (IS_ERR(clk))
@@ -679,7 +682,21 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
                return ret;
 
        /* Allocate qcom_cpufreq_data based on the available frequency domains in DT */
-       num_domains = of_property_count_elems_of_size(dev->of_node, "reg", sizeof(u32) * 4);
+       soc_node = of_get_parent(dev->of_node);
+       if (!soc_node)
+               return -EINVAL;
+
+       ret = of_property_read_u32(soc_node, "#address-cells", &reg_sz);
+       if (ret)
+               goto of_exit;
+
+       ret = of_property_read_u32(soc_node, "#size-cells", &i);
+       if (ret)
+               goto of_exit;
+
+       reg_sz += i;
+
+       num_domains = of_property_count_elems_of_size(dev->of_node, "reg", sizeof(u32) * reg_sz);
        if (num_domains <= 0)
                return num_domains;
 
@@ -689,6 +706,8 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        qcom_cpufreq.soc_data = of_device_get_match_data(dev);
+       if (!qcom_cpufreq.soc_data)
+               return -ENODEV;
 
        clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_domains), GFP_KERNEL);
        if (!clk_data)
@@ -743,12 +762,17 @@ static int qcom_cpufreq_hw_driver_probe(struct platform_device *pdev)
        else
                dev_dbg(dev, "QCOM CPUFreq HW driver initialized\n");
 
+of_exit:
+       of_node_put(soc_node);
+
        return ret;
 }
 
 static int qcom_cpufreq_hw_driver_remove(struct platform_device *pdev)
 {
-       return cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
+       cpufreq_unregister_driver(&cpufreq_qcom_hw_driver);
+
+       return 0;
 }
 
 static struct platform_driver qcom_cpufreq_hw_driver = {
index 4596c3e..5890e25 100644 (file)
@@ -411,7 +411,8 @@ static int tegra194_cpufreq_set_target(struct cpufreq_policy *policy,
 
 static struct cpufreq_driver tegra194_cpufreq_driver = {
        .name = "tegra194",
-       .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+       .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
+                CPUFREQ_IS_COOLING_DEV,
        .verify = cpufreq_generic_frequency_table_verify,
        .target_index = tegra194_cpufreq_set_target,
        .get = tegra194_get_speed,
index 53100fb..12205e2 100644 (file)
@@ -3,7 +3,7 @@
  * Microchip / Atmel ECC (I2C) driver.
  *
  * Copyright (c) 2017, Microchip Technology Inc.
- * Author: Tudor Ambarus <tudor.ambarus@microchip.com>
+ * Author: Tudor Ambarus
  */
 
 #include <linux/delay.h>
@@ -411,6 +411,6 @@ static void __exit atmel_ecc_exit(void)
 module_init(atmel_ecc_init);
 module_exit(atmel_ecc_exit);
 
-MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>");
+MODULE_AUTHOR("Tudor Ambarus");
 MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
 MODULE_LICENSE("GPL v2");
index 81ce09b..55bff1e 100644 (file)
@@ -3,7 +3,7 @@
  * Microchip / Atmel ECC (I2C) driver.
  *
  * Copyright (c) 2017, Microchip Technology Inc.
- * Author: Tudor Ambarus <tudor.ambarus@microchip.com>
+ * Author: Tudor Ambarus
  */
 
 #include <linux/bitrev.h>
@@ -390,6 +390,6 @@ static void __exit atmel_i2c_exit(void)
 module_init(atmel_i2c_init);
 module_exit(atmel_i2c_exit);
 
-MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>");
+MODULE_AUTHOR("Tudor Ambarus");
 MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
 MODULE_LICENSE("GPL v2");
index 48929ef..35f7857 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (c) 2017, Microchip Technology Inc.
- * Author: Tudor Ambarus <tudor.ambarus@microchip.com>
+ * Author: Tudor Ambarus
  */
 
 #ifndef __ATMEL_I2C_H__
index ad0849a..13cde44 100644 (file)
@@ -736,4 +736,3 @@ module_exit(cxl_acpi_exit);
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS(CXL);
 MODULE_IMPORT_NS(ACPI);
-MODULE_SOFTDEP("pre: cxl_pmem");
index f3d2169..c2e4b10 100644 (file)
@@ -227,34 +227,16 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_nvdimm_bridge *cxl_nvb,
        return cxl_nvd;
 }
 
-static void cxl_nvd_unregister(void *_cxl_nvd)
+static void cxlmd_release_nvdimm(void *_cxlmd)
 {
-       struct cxl_nvdimm *cxl_nvd = _cxl_nvd;
-       struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
+       struct cxl_memdev *cxlmd = _cxlmd;
+       struct cxl_nvdimm *cxl_nvd = cxlmd->cxl_nvd;
        struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;
 
-       /*
-        * Either the bridge is in ->remove() context under the device_lock(),
-        * or cxlmd_release_nvdimm() is cancelling the bridge's release action
-        * for @cxl_nvd and doing it itself (while manually holding the bridge
-        * lock).
-        */
-       device_lock_assert(&cxl_nvb->dev);
        cxl_nvd->cxlmd = NULL;
        cxlmd->cxl_nvd = NULL;
+       cxlmd->cxl_nvb = NULL;
        device_unregister(&cxl_nvd->dev);
-}
-
-static void cxlmd_release_nvdimm(void *_cxlmd)
-{
-       struct cxl_memdev *cxlmd = _cxlmd;
-       struct cxl_nvdimm_bridge *cxl_nvb = cxlmd->cxl_nvb;
-
-       device_lock(&cxl_nvb->dev);
-       if (cxlmd->cxl_nvd)
-               devm_release_action(&cxl_nvb->dev, cxl_nvd_unregister,
-                                   cxlmd->cxl_nvd);
-       device_unlock(&cxl_nvb->dev);
        put_device(&cxl_nvb->dev);
 }
 
@@ -293,22 +275,6 @@ int devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd)
 
        dev_dbg(&cxlmd->dev, "register %s\n", dev_name(dev));
 
-       /*
-        * The two actions below arrange for @cxl_nvd to be deleted when either
-        * the top-level PMEM bridge goes down, or the endpoint device goes
-        * through ->remove().
-        */
-       device_lock(&cxl_nvb->dev);
-       if (cxl_nvb->dev.driver)
-               rc = devm_add_action_or_reset(&cxl_nvb->dev, cxl_nvd_unregister,
-                                             cxl_nvd);
-       else
-               rc = -ENXIO;
-       device_unlock(&cxl_nvb->dev);
-
-       if (rc)
-               goto err_alloc;
-
        /* @cxlmd carries a reference on @cxl_nvb until cxlmd_release_nvdimm */
        return devm_add_action_or_reset(&cxlmd->dev, cxlmd_release_nvdimm, cxlmd);
 
index 02f28da..940f805 100644 (file)
@@ -131,7 +131,7 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
                struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
                struct cxl_port *iter = cxled_to_port(cxled);
                struct cxl_ep *ep;
-               int rc;
+               int rc = 0;
 
                while (!is_cxl_root(to_cxl_port(iter->dev.parent)))
                        iter = to_cxl_port(iter->dev.parent);
@@ -143,7 +143,8 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
 
                        cxl_rr = cxl_rr_load(iter, cxlr);
                        cxld = cxl_rr->decoder;
-                       rc = cxld->reset(cxld);
+                       if (cxld->reset)
+                               rc = cxld->reset(cxld);
                        if (rc)
                                return rc;
                }
@@ -186,7 +187,8 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
                             iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) {
                                cxl_rr = cxl_rr_load(iter, cxlr);
                                cxld = cxl_rr->decoder;
-                               cxld->reset(cxld);
+                               if (cxld->reset)
+                                       cxld->reset(cxld);
                        }
 
                        cxled->cxld.reset(&cxled->cxld);
@@ -991,10 +993,10 @@ static int cxl_port_setup_targets(struct cxl_port *port,
                int i, distance;
 
                /*
-                * Passthrough ports impose no distance requirements between
+                * Passthrough decoders impose no distance requirements between
                 * peers
                 */
-               if (port->nr_dports == 1)
+               if (cxl_rr->nr_targets == 1)
                        distance = 0;
                else
                        distance = p->nr_targets / cxl_rr->nr_targets;
index 33083a5..258004f 100644 (file)
@@ -554,8 +554,11 @@ static bool cxl_report_and_clear(struct cxl_dev_state *cxlds)
 
        /* If multiple errors, log header points to first error from ctrl reg */
        if (hweight32(status) > 1) {
-               addr = cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
-               fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, readl(addr)));
+               void __iomem *rcc_addr =
+                       cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
+
+               fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
+                                  readl(rcc_addr)));
        } else {
                fe = status;
        }
index eedefeb..08bbbac 100644 (file)
@@ -225,11 +225,35 @@ static int cxl_pmem_ctl(struct nvdimm_bus_descriptor *nd_desc,
        return cxl_pmem_nvdimm_ctl(nvdimm, cmd, buf, buf_len);
 }
 
+static int detach_nvdimm(struct device *dev, void *data)
+{
+       struct cxl_nvdimm *cxl_nvd;
+       bool release = false;
+
+       if (!is_cxl_nvdimm(dev))
+               return 0;
+
+       device_lock(dev);
+       if (!dev->driver)
+               goto out;
+
+       cxl_nvd = to_cxl_nvdimm(dev);
+       if (cxl_nvd->cxlmd && cxl_nvd->cxlmd->cxl_nvb == data)
+               release = true;
+out:
+       device_unlock(dev);
+       if (release)
+               device_release_driver(dev);
+       return 0;
+}
+
 static void unregister_nvdimm_bus(void *_cxl_nvb)
 {
        struct cxl_nvdimm_bridge *cxl_nvb = _cxl_nvb;
        struct nvdimm_bus *nvdimm_bus = cxl_nvb->nvdimm_bus;
 
+       bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb, detach_nvdimm);
+
        cxl_nvb->nvdimm_bus = NULL;
        nvdimm_bus_unregister(nvdimm_bus);
 }
index da4438f..c4c4728 100644 (file)
@@ -475,7 +475,7 @@ EXPORT_SYMBOL_GPL(put_dax);
 /**
  * dax_holder() - obtain the holder of a dax device
  * @dax_dev: a dax_device instance
-
+ *
  * Return: the holder's data which represents the holder if registered,
  * otherwize NULL.
  */
index 406b4e2..0de0482 100644 (file)
@@ -167,7 +167,7 @@ struct dma_fence *dma_fence_allocate_private_stub(void)
                       0, 0);
 
        set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
-               &dma_fence_stub.flags);
+               &fence->flags);
 
        dma_fence_signal(fence);
 
index c741b64..8a6e6b6 100644 (file)
@@ -451,7 +451,8 @@ static int dma_chan_get(struct dma_chan *chan)
        /* The channel is already in use, update client count */
        if (chan->client_count) {
                __module_get(owner);
-               goto out;
+               chan->client_count++;
+               return 0;
        }
 
        if (!try_module_get(owner))
@@ -470,11 +471,11 @@ static int dma_chan_get(struct dma_chan *chan)
                        goto err_out;
        }
 
+       chan->client_count++;
+
        if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask))
                balance_ref_count(chan);
 
-out:
-       chan->client_count++;
        return 0;
 
 err_out:
index a183d93..bf85aa0 100644 (file)
@@ -1018,6 +1018,11 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
 
        /* The bad descriptor currently is in the head of vc list */
        vd = vchan_next_desc(&chan->vc);
+       if (!vd) {
+               dev_err(chan2dev(chan), "BUG: %s, IRQ with no descriptors\n",
+                       axi_chan_name(chan));
+               goto out;
+       }
        /* Remove the completed descriptor from issued list */
        list_del(&vd->node);
 
@@ -1032,6 +1037,7 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
        /* Try to restart the controller */
        axi_chan_start_first_queued(chan);
 
+out:
        spin_unlock_irqrestore(&chan->vc.lock, flags);
 }
 
index 06f5d37..29dbb0f 100644 (file)
@@ -1172,8 +1172,19 @@ static void idxd_flush_pending_descs(struct idxd_irq_entry *ie)
        spin_unlock(&ie->list_lock);
 
        list_for_each_entry_safe(desc, itr, &flist, list) {
+               struct dma_async_tx_descriptor *tx;
+
                list_del(&desc->list);
                ctype = desc->completion->status ? IDXD_COMPLETE_NORMAL : IDXD_COMPLETE_ABORT;
+               /*
+                * wq is being disabled. Any remaining descriptors are
+                * likely to be stuck and can be dropped. callback could
+                * point to code that is no longer accessible, for example
+                * if dmatest module has been unloaded.
+                */
+               tx = &desc->txd;
+               tx->callback = NULL;
+               tx->callback_result = NULL;
                idxd_dma_complete_txd(desc, ctype, true);
        }
 }
@@ -1390,8 +1401,7 @@ err_res_alloc:
 err_irq:
        idxd_wq_unmap_portal(wq);
 err_map_portal:
-       rc = idxd_wq_disable(wq, false);
-       if (rc < 0)
+       if (idxd_wq_disable(wq, false))
                dev_dbg(dev, "wq %s disable failed\n", dev_name(wq_confdev(wq)));
 err:
        return rc;
@@ -1408,11 +1418,11 @@ void drv_disable_wq(struct idxd_wq *wq)
                dev_warn(dev, "Clients has claim on wq %d: %d\n",
                         wq->id, idxd_wq_refcount(wq));
 
-       idxd_wq_free_resources(wq);
        idxd_wq_unmap_portal(wq);
        idxd_wq_drain(wq);
        idxd_wq_free_irq(wq);
        idxd_wq_reset(wq);
+       idxd_wq_free_resources(wq);
        percpu_ref_exit(&wq->wq_active);
        wq->type = IDXD_WQT_NONE;
        wq->client_count = 0;
index fbea5f6..b926abe 100644 (file)
@@ -1521,10 +1521,12 @@ static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
                sdma_config_ownership(sdmac, false, true, false);
 
        if (sdma_load_context(sdmac))
-               goto err_desc_out;
+               goto err_bd_out;
 
        return desc;
 
+err_bd_out:
+       sdma_free_bd(desc);
 err_desc_out:
        kfree(desc);
 err_out:
index 9b9184f..1709d15 100644 (file)
@@ -914,7 +914,7 @@ static void ldma_dev_init(struct ldma_dev *d)
        }
 }
 
-static int ldma_cfg_init(struct ldma_dev *d)
+static int ldma_parse_dt(struct ldma_dev *d)
 {
        struct fwnode_handle *fwnode = dev_fwnode(d->dev);
        struct ldma_port *p;
@@ -1661,10 +1661,6 @@ static int intel_ldma_probe(struct platform_device *pdev)
                p->ldev = d;
        }
 
-       ret = ldma_cfg_init(d);
-       if (ret)
-               return ret;
-
        dma_dev->dev = &pdev->dev;
 
        ch_mask = (unsigned long)d->channels_mask;
@@ -1675,6 +1671,10 @@ static int intel_ldma_probe(struct platform_device *pdev)
                        ldma_dma_init_v3X(j, d);
        }
 
+       ret = ldma_parse_dt(d);
+       if (ret)
+               return ret;
+
        dma_dev->device_alloc_chan_resources = ldma_alloc_chan_resources;
        dma_dev->device_free_chan_resources = ldma_free_chan_resources;
        dma_dev->device_terminate_all = ldma_terminate_all;
index 377da23..a2bf13f 100644 (file)
@@ -71,12 +71,13 @@ static int pt_core_execute_cmd(struct ptdma_desc *desc, struct pt_cmd_queue *cmd
        bool soc = FIELD_GET(DWORD0_SOC, desc->dw0);
        u8 *q_desc = (u8 *)&cmd_q->qbase[cmd_q->qidx];
        u32 tail;
+       unsigned long flags;
 
        if (soc) {
                desc->dw0 |= FIELD_PREP(DWORD0_IOC, desc->dw0);
                desc->dw0 &= ~DWORD0_SOC;
        }
-       mutex_lock(&cmd_q->q_mutex);
+       spin_lock_irqsave(&cmd_q->q_lock, flags);
 
        /* Copy 32-byte command descriptor to hw queue. */
        memcpy(q_desc, desc, 32);
@@ -91,7 +92,7 @@ static int pt_core_execute_cmd(struct ptdma_desc *desc, struct pt_cmd_queue *cmd
 
        /* Turn the queue back on using our cached control register */
        pt_start_queue(cmd_q);
-       mutex_unlock(&cmd_q->q_mutex);
+       spin_unlock_irqrestore(&cmd_q->q_lock, flags);
 
        return 0;
 }
@@ -199,7 +200,7 @@ int pt_core_init(struct pt_device *pt)
 
        cmd_q->pt = pt;
        cmd_q->dma_pool = dma_pool;
-       mutex_init(&cmd_q->q_mutex);
+       spin_lock_init(&cmd_q->q_lock);
 
        /* Page alignment satisfies our needs for N <= 128 */
        cmd_q->qsize = Q_SIZE(Q_DESC_SIZE);
index d093c43..21b4bf8 100644 (file)
@@ -196,7 +196,7 @@ struct pt_cmd_queue {
        struct ptdma_desc *qbase;
 
        /* Aligned queue start address (per requirement) */
-       struct mutex q_mutex ____cacheline_aligned;
+       spinlock_t q_lock ____cacheline_aligned;
        unsigned int qidx;
 
        unsigned int qsize;
index 061add8..59a36cb 100644 (file)
@@ -1756,6 +1756,7 @@ static int gpi_create_spi_tre(struct gchan *chan, struct gpi_desc *desc,
                tre->dword[3] = u32_encode_bits(TRE_TYPE_GO, TRE_FLAGS_TYPE);
                if (spi->cmd == SPI_RX) {
                        tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_IEOB);
+                       tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_LINK);
                } else if (spi->cmd == SPI_TX) {
                        tre->dword[3] |= u32_encode_bits(1, TRE_FLAGS_CHAIN);
                } else { /* SPI_DUPLEX */
index 1d1180d..8f67f45 100644 (file)
@@ -711,6 +711,7 @@ static int tegra_dma_terminate_all(struct dma_chan *dc)
                        return err;
                }
 
+               vchan_terminate_vdesc(&tdc->dma_desc->vd);
                tegra_dma_disable(tdc);
                tdc->dma_desc = NULL;
        }
index ae39b52..79da93c 100644 (file)
@@ -221,7 +221,7 @@ static int tegra_adma_init(struct tegra_adma *tdma)
        int ret;
 
        /* Clear any interrupts */
-       tdma_write(tdma, tdma->cdata->global_int_clear, 0x1);
+       tdma_write(tdma, tdma->cdata->ch_base_offset + tdma->cdata->global_int_clear, 0x1);
 
        /* Assert soft reset */
        tdma_write(tdma, ADMA_GLOBAL_SOFT_RESET, 0x1);
index ce8b80b..4c62274 100644 (file)
@@ -762,11 +762,12 @@ static void udma_decrement_byte_counters(struct udma_chan *uc, u32 val)
        if (uc->desc->dir == DMA_DEV_TO_MEM) {
                udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val);
                udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val);
-               udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
+               if (uc->config.ep_type != PSIL_EP_NATIVE)
+                       udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
        } else {
                udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val);
                udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val);
-               if (!uc->bchan)
+               if (!uc->bchan && uc->config.ep_type != PSIL_EP_NATIVE)
                        udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
        }
 }
index a8d23cd..ac09f0e 100644 (file)
@@ -3143,8 +3143,10 @@ static int xilinx_dma_probe(struct platform_device *pdev)
        /* Initialize the channels */
        for_each_child_of_node(node, child) {
                err = xilinx_dma_child_probe(xdev, child);
-               if (err < 0)
+               if (err < 0) {
+                       of_node_put(child);
                        goto error;
+               }
        }
 
        if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
index 19522c5..0689e15 100644 (file)
@@ -34,6 +34,9 @@
 static DEFINE_MUTEX(device_ctls_mutex);
 static LIST_HEAD(edac_device_list);
 
+/* Default workqueue processing interval on this instance, in msecs */
+#define DEFAULT_POLL_INTERVAL 1000
+
 #ifdef CONFIG_EDAC_DEBUG
 static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
 {
@@ -336,7 +339,7 @@ static void edac_device_workq_function(struct work_struct *work_req)
         * whole one second to save timers firing all over the period
         * between integral seconds
         */
-       if (edac_dev->poll_msec == 1000)
+       if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL)
                edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
        else
                edac_queue_work(&edac_dev->work, edac_dev->delay);
@@ -366,7 +369,7 @@ static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
         * timers firing on sub-second basis, while they are happy
         * to fire together on the 1 second exactly
         */
-       if (edac_dev->poll_msec == 1000)
+       if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL)
                edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
        else
                edac_queue_work(&edac_dev->work, edac_dev->delay);
@@ -394,17 +397,16 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
  *     Then restart the workq on the new delay
  */
 void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
-                                       unsigned long value)
+                                   unsigned long msec)
 {
-       unsigned long jiffs = msecs_to_jiffies(value);
-
-       if (value == 1000)
-               jiffs = round_jiffies_relative(value);
-
-       edac_dev->poll_msec = value;
-       edac_dev->delay     = jiffs;
+       edac_dev->poll_msec = msec;
+       edac_dev->delay     = msecs_to_jiffies(msec);
 
-       edac_mod_work(&edac_dev->work, jiffs);
+       /* See comment in edac_device_workq_setup() above */
+       if (edac_dev->poll_msec == DEFAULT_POLL_INTERVAL)
+               edac_mod_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
+       else
+               edac_mod_work(&edac_dev->work, edac_dev->delay);
 }
 
 int edac_device_alloc_index(void)
@@ -443,11 +445,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
                /* This instance is NOW RUNNING */
                edac_dev->op_state = OP_RUNNING_POLL;
 
-               /*
-                * enable workq processing on this instance,
-                * default = 1000 msec
-                */
-               edac_device_workq_setup(edac_dev, 1000);
+               edac_device_workq_setup(edac_dev, edac_dev->poll_msec ?: DEFAULT_POLL_INTERVAL);
        } else {
                edac_dev->op_state = OP_RUNNING_INTERRUPT;
        }
index 763c076..47593af 100644 (file)
@@ -53,7 +53,7 @@ bool edac_stop_work(struct delayed_work *work);
 bool edac_mod_work(struct delayed_work *work, unsigned long delay);
 
 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
-                                          *edac_dev, unsigned long value);
+                                          *edac_dev, unsigned long msec);
 extern void edac_mc_reset_delay_period(unsigned long value);
 
 /*
index 61b76ec..19fba25 100644 (file)
@@ -174,8 +174,10 @@ static int highbank_mc_probe(struct platform_device *pdev)
        drvdata = mci->pvt_info;
        platform_set_drvdata(pdev, mci);
 
-       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
-               return -ENOMEM;
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+               res = -ENOMEM;
+               goto free;
+       }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -243,6 +245,7 @@ err2:
        edac_mc_del_mc(&pdev->dev);
 err:
        devres_release_group(&pdev->dev, NULL);
+free:
        edac_mc_free(mci);
        return res;
 }
index 97a27e4..c45519f 100644 (file)
@@ -252,7 +252,7 @@ clear:
 static int
 dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
 {
-       struct llcc_drv_data *drv = edev_ctl->pvt_info;
+       struct llcc_drv_data *drv = edev_ctl->dev->platform_data;
        int ret;
 
        ret = dump_syn_reg_values(drv, bank, err_type);
@@ -289,7 +289,7 @@ static irqreturn_t
 llcc_ecc_irq_handler(int irq, void *edev_ctl)
 {
        struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
-       struct llcc_drv_data *drv = edac_dev_ctl->pvt_info;
+       struct llcc_drv_data *drv = edac_dev_ctl->dev->platform_data;
        irqreturn_t irq_rc = IRQ_NONE;
        u32 drp_error, trp_error, i;
        int ret;
@@ -358,7 +358,6 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
        edev_ctl->dev_name = dev_name(dev);
        edev_ctl->ctl_name = "llcc";
        edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
-       edev_ctl->pvt_info = llcc_driv_data;
 
        rc = edac_device_add_device(edev_ctl);
        if (rc)
index 9c89f7d..958aa46 100644 (file)
@@ -819,8 +819,10 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
 
        r = container_of(resource, struct inbound_transaction_resource,
                         resource);
-       if (is_fcp_request(r->request))
+       if (is_fcp_request(r->request)) {
+               kfree(r->data);
                goto out;
+       }
 
        if (a->length != fw_get_response_length(r->request)) {
                ret = -EINVAL;
index f818d00..ffdad59 100644 (file)
@@ -910,6 +910,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
                              xfer->hdr.protocol_id, xfer->hdr.seq,
                              xfer->hdr.poll_completion);
 
+       /* Clear any stale status */
+       xfer->hdr.status = SCMI_SUCCESS;
        xfer->state = SCMI_XFER_SENT_OK;
        /*
         * Even though spinlocking is not needed here since no race is possible
index 1dfe534..87b4f4d 100644 (file)
@@ -81,10 +81,11 @@ u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem)
 void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
                          struct scmi_xfer *xfer)
 {
+       size_t len = ioread32(&shmem->length);
+
        xfer->hdr.status = ioread32(shmem->msg_payload);
        /* Skip the length of header and status in shmem area i.e 8 bytes */
-       xfer->rx.len = min_t(size_t, xfer->rx.len,
-                            ioread32(&shmem->length) - 8);
+       xfer->rx.len = min_t(size_t, xfer->rx.len, len > 8 ? len - 8 : 0);
 
        /* Take a copy to the rx buffer.. */
        memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len);
@@ -93,8 +94,10 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem,
 void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
                              size_t max_len, struct scmi_xfer *xfer)
 {
+       size_t len = ioread32(&shmem->length);
+
        /* Skip only the length of header in shmem area i.e 4 bytes */
-       xfer->rx.len = min_t(size_t, max_len, ioread32(&shmem->length) - 4);
+       xfer->rx.len = min_t(size_t, max_len, len > 4 ? len - 4 : 0);
 
        /* Take a copy to the rx buffer.. */
        memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len);
index 33c9b81..1db975c 100644 (file)
@@ -160,7 +160,6 @@ static void scmi_vio_channel_cleanup_sync(struct scmi_vio_channel *vioch)
        }
 
        vioch->shutdown_done = &vioch_shutdown_done;
-       virtio_break_device(vioch->vqueue->vdev);
        if (!vioch->is_rx && vioch->deferred_tx_wq)
                /* Cannot be kicked anymore after this...*/
                vioch->deferred_tx_wq = NULL;
@@ -482,6 +481,12 @@ static int virtio_chan_free(int id, void *p, void *data)
        struct scmi_chan_info *cinfo = p;
        struct scmi_vio_channel *vioch = cinfo->transport_info;
 
+       /*
+        * Break device to inhibit further traffic flowing while shutting down
+        * the channels: doing it later holding vioch->lock creates unsafe
+        * locking dependency chains as reported by LOCKDEP.
+        */
+       virtio_break_device(vioch->vqueue->vdev);
        scmi_vio_channel_cleanup_sync(vioch);
 
        scmi_free_channel(cinfo, data, id);
index 09716ee..1e0b016 100644 (file)
@@ -394,8 +394,8 @@ static int __init efisubsys_init(void)
        efi_kobj = kobject_create_and_add("efi", firmware_kobj);
        if (!efi_kobj) {
                pr_err("efi: Firmware registration failed.\n");
-               destroy_workqueue(efi_rts_wq);
-               return -ENOMEM;
+               error = -ENOMEM;
+               goto err_destroy_wq;
        }
 
        if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
@@ -443,7 +443,10 @@ err_unregister:
 err_put:
        kobject_put(efi_kobj);
        efi_kobj = NULL;
-       destroy_workqueue(efi_rts_wq);
+err_destroy_wq:
+       if (efi_rts_wq)
+               destroy_workqueue(efi_rts_wq);
+
        return error;
 }
 
@@ -1004,6 +1007,8 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
        /* first try to find a slot in an existing linked list entry */
        for (prsv = efi_memreserve_root->next; prsv; ) {
                rsv = memremap(prsv, sizeof(*rsv), MEMREMAP_WB);
+               if (!rsv)
+                       return -ENOMEM;
                index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
                if (index < rsv->size) {
                        rsv->entry[index].base = addr;
index ff2d18c..4501652 100644 (file)
@@ -19,10 +19,13 @@ static bool system_needs_vamap(void)
        const u8 *type1_family = efi_get_smbios_string(1, family);
 
        /*
-        * Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()
-        * has not been called prior.
+        * Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
+        * SetVirtualAddressMap() has not been called prior.
         */
-       if (!type1_family || strcmp(type1_family, "Altra"))
+       if (!type1_family || (
+           strcmp(type1_family, "eMAG") &&
+           strcmp(type1_family, "Altra") &&
+           strcmp(type1_family, "Altra Max")))
                return false;
 
        efi_warn("Working around broken SetVirtualAddressMap()\n");
index 0a9aba5..f178b29 100644 (file)
@@ -33,7 +33,7 @@ int __init efi_memattr_init(void)
                return -ENOMEM;
        }
 
-       if (tbl->version > 1) {
+       if (tbl->version > 2) {
                pr_warn("Unexpected EFI Memory Attributes table version %d\n",
                        tbl->version);
                goto unmap;
index 7feee3d..1fba4e0 100644 (file)
@@ -62,6 +62,7 @@ struct efi_runtime_work efi_rts_work;
                                                                        \
        if (!efi_enabled(EFI_RUNTIME_SERVICES)) {                       \
                pr_warn_once("EFI Runtime Services are disabled!\n");   \
+               efi_rts_work.status = EFI_DEVICE_ERROR;                 \
                goto exit;                                              \
        }                                                               \
                                                                        \
index 2652c39..33ae947 100644 (file)
@@ -93,14 +93,19 @@ static int coreboot_table_populate(struct device *dev, void *ptr)
        for (i = 0; i < header->table_entries; i++) {
                entry = ptr_entry;
 
-               device = kzalloc(sizeof(struct device) + entry->size, GFP_KERNEL);
+               if (entry->size < sizeof(*entry)) {
+                       dev_warn(dev, "coreboot table entry too small!\n");
+                       return -EINVAL;
+               }
+
+               device = kzalloc(sizeof(device->dev) + entry->size, GFP_KERNEL);
                if (!device)
                        return -ENOMEM;
 
                device->dev.parent = dev;
                device->dev.bus = &coreboot_bus_type;
                device->dev.release = coreboot_device_release;
-               memcpy(&device->entry, ptr_entry, entry->size);
+               memcpy(device->raw, ptr_entry, entry->size);
 
                switch (device->entry.tag) {
                case LB_TAG_CBMEM_ENTRY:
index 37f4d33..d814dca 100644 (file)
@@ -79,6 +79,7 @@ struct coreboot_device {
                struct lb_cbmem_ref cbmem_ref;
                struct lb_cbmem_entry cbmem_entry;
                struct lb_framebuffer framebuffer;
+               DECLARE_FLEX_ARRAY(u8, raw);
        };
 };
 
index 4e2575d..871bedf 100644 (file)
@@ -361,9 +361,10 @@ static efi_status_t gsmi_get_variable(efi_char16_t *name,
                memcpy(data, gsmi_dev.data_buf->start, *data_size);
 
                /* All variables are have the following attributes */
-               *attr = EFI_VARIABLE_NON_VOLATILE |
-                       EFI_VARIABLE_BOOTSERVICE_ACCESS |
-                       EFI_VARIABLE_RUNTIME_ACCESS;
+               if (attr)
+                       *attr = EFI_VARIABLE_NON_VOLATILE |
+                               EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                               EFI_VARIABLE_RUNTIME_ACCESS;
        }
 
        spin_unlock_irqrestore(&gsmi_dev.lock, flags);
index e7bcfca..447ee4e 100644 (file)
@@ -440,6 +440,9 @@ static const struct file_operations psci_debugfs_ops = {
 
 static int __init psci_debugfs_init(void)
 {
+       if (!invoke_psci_fn || !psci_ops.get_version)
+               return 0;
+
        return PTR_ERR_OR_ZERO(debugfs_create_file("psci", 0444, NULL, NULL,
                                                   &psci_debugfs_ops));
 }
index 79d4885..03f1bd8 100644 (file)
@@ -574,20 +574,27 @@ static int m10bmc_sec_probe(struct platform_device *pdev)
        len = scnprintf(buf, SEC_UPDATE_LEN_MAX, "secure-update%d",
                        sec->fw_name_id);
        sec->fw_name = kmemdup_nul(buf, len, GFP_KERNEL);
-       if (!sec->fw_name)
-               return -ENOMEM;
+       if (!sec->fw_name) {
+               ret = -ENOMEM;
+               goto fw_name_fail;
+       }
 
        fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name,
                                       &m10bmc_ops, sec);
        if (IS_ERR(fwl)) {
                dev_err(sec->dev, "Firmware Upload driver failed to start\n");
-               kfree(sec->fw_name);
-               xa_erase(&fw_upload_xa, sec->fw_name_id);
-               return PTR_ERR(fwl);
+               ret = PTR_ERR(fwl);
+               goto fw_uploader_fail;
        }
 
        sec->fwl = fwl;
        return 0;
+
+fw_uploader_fail:
+       kfree(sec->fw_name);
+fw_name_fail:
+       xa_erase(&fw_upload_xa, sec->fw_name_id);
+       return ret;
 }
 
 static int m10bmc_sec_remove(struct platform_device *pdev)
index 357cea5..f7f0198 100644 (file)
@@ -213,9 +213,9 @@ static int s10_ops_write_init(struct fpga_manager *mgr,
        /* Allocate buffers from the service layer's pool. */
        for (i = 0; i < NUM_SVC_BUFS; i++) {
                kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE);
-               if (!kbuf) {
+               if (IS_ERR(kbuf)) {
                        s10_free_buffers(mgr);
-                       ret = -ENOMEM;
+                       ret = PTR_ERR(kbuf);
                        goto init_done;
                }
 
index 2e17797..6cedf46 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/gpio/driver.h>
 #include <linux/bitops.h>
+#include <linux/seq_file.h>
 
 #define EP93XX_GPIO_F_INT_STATUS 0x5c
 #define EP93XX_GPIO_A_INT_STATUS 0xa0
@@ -40,7 +41,6 @@
 #define EP93XX_GPIO_F_IRQ_BASE 80
 
 struct ep93xx_gpio_irq_chip {
-       struct irq_chip ic;
        u8 irq_offset;
        u8 int_unmasked;
        u8 int_enabled;
@@ -148,7 +148,7 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
         */
        struct irq_chip *irqchip = irq_desc_get_chip(desc);
        unsigned int irq = irq_desc_get_irq(desc);
-       int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
+       int port_f_idx = (irq & 7) ^ 4; /* {20..23,48..51} -> {0..7} */
        int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx;
 
        chained_irq_enter(irqchip, desc);
@@ -185,6 +185,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
        ep93xx_gpio_update_int_params(epg, eic);
 
        writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET);
+       gpiochip_disable_irq(gc, irqd_to_hwirq(d));
 }
 
 static void ep93xx_gpio_irq_mask(struct irq_data *d)
@@ -195,6 +196,7 @@ static void ep93xx_gpio_irq_mask(struct irq_data *d)
 
        eic->int_unmasked &= ~BIT(d->irq & 7);
        ep93xx_gpio_update_int_params(epg, eic);
+       gpiochip_disable_irq(gc, irqd_to_hwirq(d));
 }
 
 static void ep93xx_gpio_irq_unmask(struct irq_data *d)
@@ -203,6 +205,7 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d)
        struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
        struct ep93xx_gpio *epg = gpiochip_get_data(gc);
 
+       gpiochip_enable_irq(gc, irqd_to_hwirq(d));
        eic->int_unmasked |= BIT(d->irq & 7);
        ep93xx_gpio_update_int_params(epg, eic);
 }
@@ -320,15 +323,25 @@ static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
        return 0;
 }
 
-static void ep93xx_init_irq_chip(struct device *dev, struct irq_chip *ic)
+static void ep93xx_irq_print_chip(struct irq_data *data, struct seq_file *p)
 {
-       ic->irq_ack = ep93xx_gpio_irq_ack;
-       ic->irq_mask_ack = ep93xx_gpio_irq_mask_ack;
-       ic->irq_mask = ep93xx_gpio_irq_mask;
-       ic->irq_unmask = ep93xx_gpio_irq_unmask;
-       ic->irq_set_type = ep93xx_gpio_irq_type;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+
+       seq_printf(p, dev_name(gc->parent));
 }
 
+static const struct irq_chip gpio_eic_irq_chip = {
+       .name                   = "ep93xx-gpio-eic",
+       .irq_ack                = ep93xx_gpio_irq_ack,
+       .irq_mask               = ep93xx_gpio_irq_mask,
+       .irq_unmask             = ep93xx_gpio_irq_unmask,
+       .irq_mask_ack   = ep93xx_gpio_irq_mask_ack,
+       .irq_set_type   = ep93xx_gpio_irq_type,
+       .irq_print_chip = ep93xx_irq_print_chip,
+       .flags                  = IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
 static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
                                struct platform_device *pdev,
                                struct ep93xx_gpio *epg,
@@ -350,8 +363,6 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
 
        girq = &gc->irq;
        if (bank->has_irq || bank->has_hierarchical_irq) {
-               struct irq_chip *ic;
-
                gc->set_config = ep93xx_gpio_set_config;
                egc->eic = devm_kcalloc(dev, 1,
                                        sizeof(*egc->eic),
@@ -359,12 +370,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
                if (!egc->eic)
                        return -ENOMEM;
                egc->eic->irq_offset = bank->irq;
-               ic = &egc->eic->ic;
-               ic->name = devm_kasprintf(dev, GFP_KERNEL, "gpio-irq-%s", bank->label);
-               if (!ic->name)
-                       return -ENOMEM;
-               ep93xx_init_irq_chip(dev, ic);
-               girq->chip = ic;
+               gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip);
        }
 
        if (bank->has_irq) {
index d5626c5..9d0cec4 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/syscore_ops.h>
 #include <linux/gpio/driver.h>
 #include <linux/of.h>
@@ -159,6 +160,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mxc_gpio_port *port = gc->private;
+       unsigned long flags;
        u32 bit, val;
        u32 gpio_idx = d->hwirq;
        int edge;
@@ -197,6 +199,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
                return -EINVAL;
        }
 
+       raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+
        if (GPIO_EDGE_SEL >= 0) {
                val = readl(port->base + GPIO_EDGE_SEL);
                if (edge == GPIO_INT_BOTH_EDGES)
@@ -217,15 +221,20 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
        writel(1 << gpio_idx, port->base + GPIO_ISR);
        port->pad_type[gpio_idx] = type;
 
-       return 0;
+       raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+
+       return port->gc.direction_input(&port->gc, gpio_idx);
 }
 
 static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
 {
        void __iomem *reg = port->base;
+       unsigned long flags;
        u32 bit, val;
        int edge;
 
+       raw_spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+
        reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
        bit = gpio & 0xf;
        val = readl(reg);
@@ -240,9 +249,12 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio)
        } else {
                pr_err("mxc: invalid configuration for GPIO %d: %x\n",
                       gpio, edge);
-               return;
+               goto unlock;
        }
        writel(val | (edge << (bit << 1)), reg);
+
+unlock:
+       raw_spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
 }
 
 /* handle 32 interrupts in one status register */
index bed0380..17c53f4 100644 (file)
@@ -385,7 +385,7 @@ err:
 }
 
 static bool acpi_gpio_irq_is_wake(struct device *parent,
-                                 struct acpi_resource_gpio *agpio)
+                                 const struct acpi_resource_gpio *agpio)
 {
        unsigned int pin = agpio->pin_table[0];
 
@@ -778,7 +778,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
                lookup->info.pin_config = agpio->pin_config;
                lookup->info.debounce = agpio->debounce_timeout;
                lookup->info.gpioint = gpioint;
-               lookup->info.wake_capable = agpio->wake_capable == ACPI_WAKE_CAPABLE;
+               lookup->info.wake_capable = acpi_gpio_irq_is_wake(&lookup->info.adev->dev, agpio);
 
                /*
                 * Polarity and triggering are only specified for GpioInt
@@ -1104,7 +1104,8 @@ int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, in
                                dev_dbg(&adev->dev, "IRQ %d already in use\n", irq);
                        }
 
-                       if (wake_capable)
+                       /* avoid suspend issues with GPIOs when systems are using S3 */
+                       if (wake_capable && acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
                                *wake_capable = info.wake_capable;
 
                        return irq;
@@ -1623,6 +1624,19 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
                        .ignore_interrupt = "AMDI0030:00@18",
                },
        },
+       {
+               /*
+                * Spurious wakeups from TP_ATTN# pin
+                * Found in BIOS 1.7.8
+                * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
+                */
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
+               },
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .ignore_wake = "ELAN0415:00@9",
+               },
+       },
        {} /* Terminating entry */
 };
 
index e3e2e6e..d148a1b 100644 (file)
@@ -243,6 +243,7 @@ extern int amdgpu_num_kcq;
 
 #define AMDGPU_VCNFW_LOG_SIZE (32 * 1024)
 extern int amdgpu_vcnfw_log;
+extern int amdgpu_sg_display;
 
 #define AMDGPU_VM_MAX_NUM_CTX                  4096
 #define AMDGPU_SG_THRESHOLD                    (256*1024*1024)
index b15091d..3b5c537 100644 (file)
@@ -2099,7 +2099,7 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_device *adev, struct amdgpu_b
        }
 
        amdgpu_amdkfd_remove_eviction_fence(
-               bo, bo->kfd_bo->process_info->eviction_fence);
+               bo, bo->vm_bo->vm->process_info->eviction_fence);
 
        amdgpu_bo_unreserve(bo);
 
index 8516c81..7af3041 100644 (file)
@@ -61,6 +61,8 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p,
                amdgpu_ctx_put(p->ctx);
                return -ECANCELED;
        }
+
+       amdgpu_sync_create(&p->sync);
        return 0;
 }
 
@@ -452,18 +454,6 @@ static int amdgpu_syncobj_lookup_and_add(struct amdgpu_cs_parser *p,
        }
 
        r = amdgpu_sync_fence(&p->sync, fence);
-       if (r)
-               goto error;
-
-       /*
-        * When we have an explicit dependency it might be necessary to insert a
-        * pipeline sync to make sure that all caches etc are flushed and the
-        * next job actually sees the results from the previous one.
-        */
-       if (fence->context == p->gang_leader->base.entity->fence_context)
-               r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence);
-
-error:
        dma_fence_put(fence);
        return r;
 }
@@ -1188,10 +1178,19 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
 static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
 {
        struct amdgpu_fpriv *fpriv = p->filp->driver_priv;
+       struct drm_gpu_scheduler *sched;
        struct amdgpu_bo_list_entry *e;
+       struct dma_fence *fence;
        unsigned int i;
        int r;
 
+       r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_leader_idx]);
+       if (r) {
+               if (r != -ERESTARTSYS)
+                       DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n");
+               return r;
+       }
+
        list_for_each_entry(e, &p->validated, tv.head) {
                struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
                struct dma_resv *resv = bo->tbo.base.resv;
@@ -1211,10 +1210,27 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p)
                        return r;
        }
 
-       r = amdgpu_ctx_wait_prev_fence(p->ctx, p->entities[p->gang_leader_idx]);
-       if (r && r != -ERESTARTSYS)
-               DRM_ERROR("amdgpu_ctx_wait_prev_fence failed.\n");
-       return r;
+       sched = p->gang_leader->base.entity->rq->sched;
+       while ((fence = amdgpu_sync_get_fence(&p->sync))) {
+               struct drm_sched_fence *s_fence = to_drm_sched_fence(fence);
+
+               /*
+                * When we have an dependency it might be necessary to insert a
+                * pipeline sync to make sure that all caches etc are flushed and the
+                * next job actually sees the results from the previous one
+                * before we start executing on the same scheduler ring.
+                */
+               if (!s_fence || s_fence->sched != sched) {
+                       dma_fence_put(fence);
+                       continue;
+               }
+
+               r = amdgpu_sync_fence(&p->gang_leader->explicit_sync, fence);
+               dma_fence_put(fence);
+               if (r)
+                       return r;
+       }
+       return 0;
 }
 
 static void amdgpu_cs_post_dependencies(struct amdgpu_cs_parser *p)
@@ -1254,9 +1270,12 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
                        continue;
 
                fence = &p->jobs[i]->base.s_fence->scheduled;
+               dma_fence_get(fence);
                r = drm_sched_job_add_dependency(&leader->base, fence);
-               if (r)
+               if (r) {
+                       dma_fence_put(fence);
                        goto error_cleanup;
+               }
        }
 
        if (p->gang_size > 1) {
@@ -1344,6 +1363,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser)
 {
        unsigned i;
 
+       amdgpu_sync_free(&parser->sync);
        for (i = 0; i < parser->num_post_deps; i++) {
                drm_syncobj_put(parser->post_deps[i].syncobj);
                kfree(parser->post_deps[i].chain);
index afe6af9..2f28a8c 100644 (file)
@@ -36,6 +36,7 @@
 #include <generated/utsrelease.h>
 #include <linux/pci-p2pdma.h>
 
+#include <drm/drm_aperture.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_probe_helper.h>
@@ -90,6 +91,8 @@ MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
 #define AMDGPU_MAX_RETRY_LIMIT         2
 #define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL)
 
+static const struct drm_driver amdgpu_kms_driver;
+
 const char *amdgpu_asic_name[] = {
        "TAHITI",
        "PITCAIRN",
@@ -3687,6 +3690,11 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        if (r)
                return r;
 
+       /* Get rid of things like offb */
+       r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver);
+       if (r)
+               return r;
+
        /* Enable TMZ based on IP_VERSION */
        amdgpu_gmc_tmz_set(adev);
 
index 1353ffd..3fe277b 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include <drm/amdgpu_drm.h>
-#include <drm/drm_aperture.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fbdev_generic.h>
 #include <drm/drm_gem.h>
@@ -187,6 +186,7 @@ int amdgpu_num_kcq = -1;
 int amdgpu_smartshift_bias;
 int amdgpu_use_xgmi_p2p = 1;
 int amdgpu_vcnfw_log;
+int amdgpu_sg_display = -1; /* auto */
 
 static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
 
@@ -932,6 +932,16 @@ module_param_named(num_kcq, amdgpu_num_kcq, int, 0444);
 MODULE_PARM_DESC(vcnfw_log, "Enable vcnfw log(0 = disable (default value), 1 = enable)");
 module_param_named(vcnfw_log, amdgpu_vcnfw_log, int, 0444);
 
+/**
+ * DOC: sg_display (int)
+ * Disable S/G (scatter/gather) display (i.e., display from system memory).
+ * This option is only relevant on APUs.  Set this option to 0 to disable
+ * S/G display if you experience flickering or other issues under memory
+ * pressure and report the issue.
+ */
+MODULE_PARM_DESC(sg_display, "S/G Display (-1 = auto (default), 0 = disable)");
+module_param_named(sg_display, amdgpu_sg_display, int, 0444);
+
 /**
  * DOC: smu_pptable_id (int)
  * Used to override pptable id. id = 0 use VBIOS pptable.
@@ -2122,11 +2132,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
        }
 #endif
 
-       /* Get rid of things like offb */
-       ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver);
-       if (ret)
-               return ret;
-
        adev = devm_drm_dev_alloc(&pdev->dev, &amdgpu_kms_driver, typeof(*adev), ddev);
        if (IS_ERR(adev))
                return PTR_ERR(adev);
index 0044420..faff4a3 100644 (file)
@@ -618,7 +618,13 @@ void amdgpu_fence_driver_sw_fini(struct amdgpu_device *adev)
                if (!ring || !ring->fence_drv.initialized)
                        continue;
 
-               if (!ring->no_scheduler)
+               /*
+                * Notice we check for sched.ops since there's some
+                * override on the meaning of sched.ready by amdgpu.
+                * The natural check would be sched.ready, which is
+                * set as drm_sched_init() finishes...
+                */
+               if (ring->sched.ops)
                        drm_sched_fini(&ring->sched);
 
                for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
index 23692e5..3380daf 100644 (file)
@@ -156,6 +156,9 @@ static bool amdgpu_gfx_is_compute_multipipe_capable(struct amdgpu_device *adev)
                return amdgpu_compute_multipipe == 1;
        }
 
+       if (adev->ip_versions[GC_HWIP][0] > IP_VERSION(9, 0, 0))
+               return true;
+
        /* FIXME: spreading the queues across pipes causes perf regressions
         * on POLARIS11 compute workloads */
        if (adev->asic_type == CHIP_POLARIS11)
index fcb711a..3f07b1a 100644 (file)
@@ -497,6 +497,7 @@ void amdgpu_vmid_free_reserved(struct amdgpu_device *adev,
            !--id_mgr->reserved_use_count) {
                /* give the reserved ID back to normal round robin */
                list_add(&id_mgr->reserved->list, &id_mgr->ids_lru);
+               id_mgr->reserved = NULL;
        }
        vm->reserved_vmid[vmhub] = false;
        mutex_unlock(&id_mgr->lock);
index 9e54992..c3d9d75 100644 (file)
@@ -161,8 +161,14 @@ void amdgpu_job_free_resources(struct amdgpu_job *job)
        struct dma_fence *f;
        unsigned i;
 
-       /* use sched fence if available */
-       f = job->base.s_fence ? &job->base.s_fence->finished :  &job->hw_fence;
+       /* Check if any fences where initialized */
+       if (job->base.s_fence && job->base.s_fence->finished.ops)
+               f = &job->base.s_fence->finished;
+       else if (job->hw_fence.ops)
+               f = &job->hw_fence;
+       else
+               f = NULL;
+
        for (i = 0; i < job->num_ibs; ++i)
                amdgpu_ib_free(ring->adev, &job->ibs[i], f);
 }
index 4e684c2..25a68d8 100644 (file)
@@ -470,8 +470,9 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
        return true;
 
 fail:
-       DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
-                 man->size);
+       if (man)
+               DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
+                         man->size);
        return false;
 }
 
index f752c7a..3989e75 100644 (file)
@@ -295,7 +295,7 @@ struct amdgpu_ring {
 #define amdgpu_ring_parse_cs(r, p, job, ib) ((r)->funcs->parse_cs((p), (job), (ib)))
 #define amdgpu_ring_patch_cs_in_place(r, p, job, ib) ((r)->funcs->patch_cs_in_place((p), (job), (ib)))
 #define amdgpu_ring_test_ring(r) (r)->funcs->test_ring((r))
-#define amdgpu_ring_test_ib(r, t) (r)->funcs->test_ib((r), (t))
+#define amdgpu_ring_test_ib(r, t) ((r)->funcs->test_ib ? (r)->funcs->test_ib((r), (t)) : 0)
 #define amdgpu_ring_get_rptr(r) (r)->funcs->get_rptr((r))
 #define amdgpu_ring_get_wptr(r) (r)->funcs->get_wptr((r))
 #define amdgpu_ring_set_wptr(r) (r)->funcs->set_wptr((r))
index bac7976..dcd8c06 100644 (file)
@@ -391,8 +391,10 @@ int amdgpu_sync_push_to_job(struct amdgpu_sync *sync, struct amdgpu_job *job)
 
                dma_fence_get(f);
                r = drm_sched_job_add_dependency(&job->base, f);
-               if (r)
+               if (r) {
+                       dma_fence_put(f);
                        return r;
+               }
        }
        return 0;
 }
index b5f3bba..01e42bd 100644 (file)
@@ -974,7 +974,7 @@ int amdgpu_vm_ptes_update(struct amdgpu_vm_update_params *params,
                        trace_amdgpu_vm_update_ptes(params, frag_start, upd_end,
                                                    min(nptes, 32u), dst, incr,
                                                    upd_flags,
-                                                   vm->task_info.pid,
+                                                   vm->task_info.tgid,
                                                    vm->immediate.fence_context);
                        amdgpu_vm_pte_update_flags(params, to_amdgpu_bo_vm(pt),
                                                   cursor.level, pe_start, dst,
index faa1214..9fa1d81 100644 (file)
@@ -882,7 +882,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
                kfree(rsv);
 
        list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
-               drm_buddy_free_list(&mgr->mm, &rsv->blocks);
+               drm_buddy_free_list(&mgr->mm, &rsv->allocated);
                kfree(rsv);
        }
        drm_buddy_fini(&mgr->mm);
index a56c6e1..66eb102 100644 (file)
@@ -790,8 +790,8 @@ static void gfx_v11_0_read_wave_data(struct amdgpu_device *adev, uint32_t simd,
         * zero here */
        WARN_ON(simd != 0);
 
-       /* type 2 wave data */
-       dst[(*no_fields)++] = 2;
+       /* type 3 wave data */
+       dst[(*no_fields)++] = 3;
        dst[(*no_fields)++] = wave_read_ind(adev, wave, ixSQ_WAVE_STATUS);
        dst[(*no_fields)++] = wave_read_ind(adev, wave, ixSQ_WAVE_PC_LO);
        dst[(*no_fields)++] = wave_read_ind(adev, wave, ixSQ_WAVE_PC_HI);
@@ -1287,10 +1287,8 @@ static int gfx_v11_0_sw_init(void *handle)
 
        switch (adev->ip_versions[GC_HWIP][0]) {
        case IP_VERSION(11, 0, 0):
-       case IP_VERSION(11, 0, 1):
        case IP_VERSION(11, 0, 2):
        case IP_VERSION(11, 0, 3):
-       case IP_VERSION(11, 0, 4):
                adev->gfx.me.num_me = 1;
                adev->gfx.me.num_pipe_per_me = 1;
                adev->gfx.me.num_queue_per_pipe = 1;
@@ -1298,6 +1296,15 @@ static int gfx_v11_0_sw_init(void *handle)
                adev->gfx.mec.num_pipe_per_mec = 4;
                adev->gfx.mec.num_queue_per_pipe = 4;
                break;
+       case IP_VERSION(11, 0, 1):
+       case IP_VERSION(11, 0, 4):
+               adev->gfx.me.num_me = 1;
+               adev->gfx.me.num_pipe_per_me = 1;
+               adev->gfx.me.num_queue_per_pipe = 1;
+               adev->gfx.mec.num_mec = 1;
+               adev->gfx.mec.num_pipe_per_mec = 4;
+               adev->gfx.mec.num_queue_per_pipe = 4;
+               break;
        default:
                adev->gfx.me.num_me = 1;
                adev->gfx.me.num_pipe_per_me = 1;
index f202b45..5dde6f8 100644 (file)
@@ -6877,7 +6877,6 @@ static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_gfx = {
        .emit_gds_switch = gfx_v9_0_ring_emit_gds_switch,
        .emit_hdp_flush = gfx_v9_0_ring_emit_hdp_flush,
        .test_ring = gfx_v9_0_ring_test_ring,
-       .test_ib = gfx_v9_0_ring_test_ib,
        .insert_nop = amdgpu_ring_insert_nop,
        .pad_ib = amdgpu_ring_generic_pad_ib,
        .emit_switch_buffer = gfx_v9_ring_emit_sb,
index 95548c5..077c53c 100644 (file)
@@ -35,6 +35,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_0_imu.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_1_imu.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_2_imu.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_3_imu.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_imu.bin");
 
 static int imu_v11_0_init_microcode(struct amdgpu_device *adev)
 {
index 970b066..5dff79e 100644 (file)
@@ -40,6 +40,8 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_2_mes1.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes.bin");
 MODULE_FIRMWARE("amdgpu/gc_11_0_3_mes1.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes.bin");
+MODULE_FIRMWARE("amdgpu/gc_11_0_4_mes1.bin");
 
 static int mes_v11_0_hw_fini(void *handle);
 static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev);
@@ -196,7 +198,6 @@ static int mes_v11_0_add_hw_queue(struct amdgpu_mes *mes,
        mes_add_queue_pkt.trap_handler_addr = input->tba_addr;
        mes_add_queue_pkt.tma_addr = input->tma_addr;
        mes_add_queue_pkt.is_kfd_process = input->is_kfd_process;
-       mes_add_queue_pkt.trap_en = 1;
 
        /* For KFD, gds_size is re-used for queue size (needed in MES for AQL queues) */
        mes_add_queue_pkt.is_aql_queue = input->is_aql_queue;
index 15eb365..09fdcd2 100644 (file)
@@ -337,7 +337,13 @@ const struct nbio_hdp_flush_reg nbio_v4_3_hdp_flush_reg = {
 
 static void nbio_v4_3_init_registers(struct amdgpu_device *adev)
 {
-       return;
+       if (adev->ip_versions[NBIO_HWIP][0] == IP_VERSION(4, 3, 0)) {
+               uint32_t data;
+
+               data = RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF2_STRAP2);
+               data &= ~RCC_DEV0_EPF2_STRAP2__STRAP_NO_SOFT_RESET_DEV0_F2_MASK;
+               WREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF2_STRAP2, data);
+       }
 }
 
 static u32 nbio_v4_3_get_rom_offset(struct amdgpu_device *adev)
index 5562670..7050238 100644 (file)
@@ -640,7 +640,10 @@ static int soc21_common_early_init(void *handle)
                        AMD_CG_SUPPORT_GFX_CGCG |
                        AMD_CG_SUPPORT_GFX_CGLS |
                        AMD_CG_SUPPORT_REPEATER_FGCG |
-                       AMD_CG_SUPPORT_GFX_MGCG;
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_HDP_SD |
+                       AMD_CG_SUPPORT_ATHUB_MGCG |
+                       AMD_CG_SUPPORT_ATHUB_LS;
                adev->pg_flags = AMD_PG_SUPPORT_VCN |
                        AMD_PG_SUPPORT_VCN_DPG |
                        AMD_PG_SUPPORT_JPEG;
index ecb4c3a..c06ada0 100644 (file)
@@ -200,7 +200,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
        queue_input.wptr_addr = (uint64_t)q->properties.write_ptr;
 
        if (q->wptr_bo) {
-               wptr_addr_off = (uint64_t)q->properties.write_ptr - (uint64_t)q->wptr_bo->kfd_bo->va;
+               wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1);
                queue_input.wptr_mc_addr = ((uint64_t)q->wptr_bo->tbo.resource->start << PAGE_SHIFT) + wptr_addr_off;
        }
 
index 814f998..b94d2c1 100644 (file)
@@ -570,6 +570,15 @@ svm_range_vram_node_new(struct amdgpu_device *adev, struct svm_range *prange,
                goto reserve_bo_failed;
        }
 
+       if (clear) {
+               r = amdgpu_bo_sync_wait(bo, AMDGPU_FENCE_OWNER_KFD, false);
+               if (r) {
+                       pr_debug("failed %d to sync bo\n", r);
+                       amdgpu_bo_unreserve(bo);
+                       goto reserve_bo_failed;
+               }
+       }
+
        r = dma_resv_reserve_fences(bo->tbo.base.resv, 1);
        if (r) {
                pr_debug("failed %d to reserve bo\n", r);
index 1b7f20a..93dee3d 100644 (file)
@@ -1184,24 +1184,38 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
 
        memset(pa_config, 0, sizeof(*pa_config));
 
-       logical_addr_low  = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18;
-       pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
-
-       if (adev->apu_flags & AMD_APU_IS_RAVEN2)
-               /*
-                * Raven2 has a HW issue that it is unable to use the vram which
-                * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the
-                * workaround that increase system aperture high address (add 1)
-                * to get rid of the VM fault and hardware hang.
-                */
-               logical_addr_high = max((adev->gmc.fb_end >> 18) + 0x1, adev->gmc.agp_end >> 18);
-       else
-               logical_addr_high = max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18;
-
        agp_base = 0;
        agp_bot = adev->gmc.agp_start >> 24;
        agp_top = adev->gmc.agp_end >> 24;
 
+       /* AGP aperture is disabled */
+       if (agp_bot == agp_top) {
+               logical_addr_low  = adev->gmc.vram_start >> 18;
+               if (adev->apu_flags & AMD_APU_IS_RAVEN2)
+                       /*
+                        * Raven2 has a HW issue that it is unable to use the vram which
+                        * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the
+                        * workaround that increase system aperture high address (add 1)
+                        * to get rid of the VM fault and hardware hang.
+                        */
+                       logical_addr_high = (adev->gmc.fb_end >> 18) + 0x1;
+               else
+                       logical_addr_high = adev->gmc.vram_end >> 18;
+       } else {
+               logical_addr_low  = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18;
+               if (adev->apu_flags & AMD_APU_IS_RAVEN2)
+                       /*
+                        * Raven2 has a HW issue that it is unable to use the vram which
+                        * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the
+                        * workaround that increase system aperture high address (add 1)
+                        * to get rid of the VM fault and hardware hang.
+                        */
+                       logical_addr_high = max((adev->gmc.fb_end >> 18) + 0x1, adev->gmc.agp_end >> 18);
+               else
+                       logical_addr_high = max(adev->gmc.fb_end, adev->gmc.agp_end) >> 18;
+       }
+
+       pt_base = amdgpu_gmc_pd_addr(adev->gart.bo);
 
        page_table_start.high_part = (u32)(adev->gmc.gart_start >> 44) & 0xF;
        page_table_start.low_part = (u32)(adev->gmc.gart_start >> 12);
@@ -1513,6 +1527,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
                }
                break;
        }
+       if (init_data.flags.gpu_vm_support &&
+           (amdgpu_sg_display == 0))
+               init_data.flags.gpu_vm_support = false;
 
        if (init_data.flags.gpu_vm_support)
                adev->mode_info.gpu_vm_support = true;
@@ -1730,10 +1747,6 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
                adev->dm.vblank_control_workqueue = NULL;
        }
 
-       for (i = 0; i < adev->dm.display_indexes_num; i++) {
-               drm_encoder_cleanup(&adev->dm.mst_encoders[i].base);
-       }
-
        amdgpu_dm_destroy_drm_device(&adev->dm);
 
 #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
@@ -4507,6 +4520,17 @@ DEVICE_ATTR_WO(s3_debug);
 static int dm_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       struct amdgpu_mode_info *mode_info = &adev->mode_info;
+       struct atom_context *ctx = mode_info->atom_context;
+       int index = GetIndexIntoMasterTable(DATA, Object_Header);
+       u16 data_offset;
+
+       /* if there is no object header, skip DM */
+       if (!amdgpu_atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
+               adev->harvest_ip_mask |= AMD_HARVEST_IP_DMU_MASK;
+               dev_info(adev->dev, "No object header, skipping DM\n");
+               return -ENOENT;
+       }
 
        switch (adev->asic_type) {
 #if defined(CONFIG_DRM_AMD_DC_SI)
@@ -5311,8 +5335,6 @@ static void fill_stream_properties_from_drm_display_mode(
 
        timing_out->aspect_ratio = get_aspect_ratio(mode_in);
 
-       stream->output_color_space = get_output_color_space(timing_out);
-
        stream->out_transfer_func->type = TF_TYPE_PREDEFINED;
        stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
        if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
@@ -5323,6 +5345,8 @@ static void fill_stream_properties_from_drm_display_mode(
                        adjust_colour_depth_from_display_info(timing_out, info);
                }
        }
+
+       stream->output_color_space = get_output_color_space(timing_out);
 }
 
 static void fill_audio_info(struct audio_info *audio_info,
@@ -8887,6 +8911,13 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
                if (!dm_old_crtc_state->stream)
                        goto skip_modeset;
 
+               /* Unset freesync video if it was active before */
+               if (dm_old_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED) {
+                       dm_new_crtc_state->freesync_config.state = VRR_STATE_INACTIVE;
+                       dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = 0;
+               }
+
+               /* Now check if we should set freesync video mode */
                if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
                    is_timing_unchanged_for_freesync(new_crtc_state,
                                                     old_crtc_state)) {
@@ -9503,6 +9534,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
        bool lock_and_validation_needed = false;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
+       struct drm_dp_mst_topology_mgr *mgr;
+       struct drm_dp_mst_topology_state *mst_state;
        struct dsc_mst_fairness_vars vars[MAX_PIPES];
 #endif
 
@@ -9530,8 +9563,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                        goto fail;
                }
 
-               if (dm_old_con_state->abm_level !=
-                   dm_new_con_state->abm_level)
+               if (dm_old_con_state->abm_level != dm_new_con_state->abm_level ||
+                   dm_old_con_state->scaling != dm_new_con_state->scaling)
                        new_crtc_state->connectors_changed = true;
        }
 
@@ -9751,6 +9784,28 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                lock_and_validation_needed = true;
        }
 
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       /* set the slot info for each mst_state based on the link encoding format */
+       for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) {
+               struct amdgpu_dm_connector *aconnector;
+               struct drm_connector *connector;
+               struct drm_connector_list_iter iter;
+               u8 link_coding_cap;
+
+               drm_connector_list_iter_begin(dev, &iter);
+               drm_for_each_connector_iter(connector, &iter) {
+                       if (connector->index == mst_state->mgr->conn_base_id) {
+                               aconnector = to_amdgpu_dm_connector(connector);
+                               link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(aconnector->dc_link);
+                               drm_dp_mst_update_slots(mst_state, link_coding_cap);
+
+                               break;
+                       }
+               }
+               drm_connector_list_iter_end(&iter);
+       }
+#endif
+
        /**
         * Streams and planes are reset when there are changes that affect
         * bandwidth. Anything that affects bandwidth needs to go through
index 6994c9a..5cff56b 100644 (file)
@@ -120,23 +120,50 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
 }
 
 static void
-fill_dc_mst_payload_table_from_drm(struct drm_dp_mst_topology_state *mst_state,
-                                  struct amdgpu_dm_connector *aconnector,
+fill_dc_mst_payload_table_from_drm(struct dc_link *link,
+                                  bool enable,
+                                  struct drm_dp_mst_atomic_payload *target_payload,
                                   struct dc_dp_mst_stream_allocation_table *table)
 {
        struct dc_dp_mst_stream_allocation_table new_table = { 0 };
        struct dc_dp_mst_stream_allocation *sa;
-       struct drm_dp_mst_atomic_payload *payload;
+       struct link_mst_stream_allocation_table copy_of_link_table =
+                                                                               link->mst_stream_alloc_table;
+
+       int i;
+       int current_hw_table_stream_cnt = copy_of_link_table.stream_count;
+       struct link_mst_stream_allocation *dc_alloc;
+
+       /* TODO: refactor to set link->mst_stream_alloc_table directly if possible.*/
+       if (enable) {
+               dc_alloc =
+               &copy_of_link_table.stream_allocations[current_hw_table_stream_cnt];
+               dc_alloc->vcp_id = target_payload->vcpi;
+               dc_alloc->slot_count = target_payload->time_slots;
+       } else {
+               for (i = 0; i < copy_of_link_table.stream_count; i++) {
+                       dc_alloc =
+                       &copy_of_link_table.stream_allocations[i];
+
+                       if (dc_alloc->vcp_id == target_payload->vcpi) {
+                               dc_alloc->vcp_id = 0;
+                               dc_alloc->slot_count = 0;
+                               break;
+                       }
+               }
+               ASSERT(i != copy_of_link_table.stream_count);
+       }
 
        /* Fill payload info*/
-       list_for_each_entry(payload, &mst_state->payloads, next) {
-               if (payload->delete)
-                       continue;
-
-               sa = &new_table.stream_allocations[new_table.stream_count];
-               sa->slot_count = payload->time_slots;
-               sa->vcp_id = payload->vcpi;
-               new_table.stream_count++;
+       for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
+               dc_alloc =
+                       &copy_of_link_table.stream_allocations[i];
+               if (dc_alloc->vcp_id > 0 && dc_alloc->slot_count > 0) {
+                       sa = &new_table.stream_allocations[new_table.stream_count];
+                       sa->slot_count = dc_alloc->slot_count;
+                       sa->vcp_id = dc_alloc->vcp_id;
+                       new_table.stream_count++;
+               }
        }
 
        /* Overwrite the old table */
@@ -185,7 +212,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table(
         * AUX message. The sequence is slot 1-63 allocated sequence for each
         * stream. AMD ASIC stream slot allocation should follow the same
         * sequence. copy DRM MST allocation to dc */
-       fill_dc_mst_payload_table_from_drm(mst_state, aconnector, proposed_table);
+       fill_dc_mst_payload_table_from_drm(stream->link, enable, payload, proposed_table);
 
        return true;
 }
index 1edf738..abdbd43 100644 (file)
@@ -468,7 +468,6 @@ static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs
 static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
 {
        drm_encoder_cleanup(encoder);
-       kfree(encoder);
 }
 
 static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
@@ -904,11 +903,6 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
        if (IS_ERR(mst_state))
                return PTR_ERR(mst_state);
 
-       mst_state->pbn_div = dm_mst_get_pbn_divider(dc_link);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       drm_dp_mst_update_slots(mst_state, dc_link_dp_mst_decide_link_encoding_format(dc_link));
-#endif
-
        /* Set up params */
        for (i = 0; i < dc_state->stream_count; i++) {
                struct dc_dsc_policy dsc_policy = {0};
index 471078f..652270a 100644 (file)
@@ -90,8 +90,8 @@ static const struct out_csc_color_matrix_type output_csc_matrix[] = {
                { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
                                0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
        { COLOR_SPACE_YCBCR2020_TYPE,
-               { 0x1000, 0xF149, 0xFEB7, 0x0000, 0x0868, 0x15B2,
-                               0x01E6, 0x0000, 0xFB88, 0xF478, 0x1000, 0x0000} },
+               { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
+                               0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
        { COLOR_SPACE_YCBCR709_BLACK_TYPE,
                { 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x0000,
                                0x0000, 0x0200, 0x0000, 0x0000, 0x0000, 0x1000} },
index 342e906..c88f044 100644 (file)
@@ -3995,10 +3995,13 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
        struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
        int i;
        bool mst_mode = (link->type == dc_connection_mst_branch);
+       /* adjust for drm changes*/
+       bool update_drm_mst_state = true;
        const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
        const struct dc_link_settings empty_link_settings = {0};
        DC_LOGGER_INIT(link->ctx->logger);
 
+
        /* deallocate_mst_payload is called before disable link. When mode or
         * disable/enable monitor, new stream is created which is not in link
         * stream[] yet. For this, payload is not allocated yet, so de-alloc
@@ -4014,7 +4017,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                                &empty_link_settings,
                                avg_time_slots_per_mtp);
 
-       if (mst_mode) {
+       if (mst_mode || update_drm_mst_state) {
                /* when link is in mst mode, reply on mst manager to remove
                 * payload
                 */
@@ -4077,11 +4080,18 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
                        stream->ctx,
                        stream);
 
+               if (!update_drm_mst_state)
+                       dm_helpers_dp_mst_send_payload_allocation(
+                               stream->ctx,
+                               stream,
+                               false);
+       }
+
+       if (update_drm_mst_state)
                dm_helpers_dp_mst_send_payload_allocation(
                        stream->ctx,
                        stream,
                        false);
-       }
 
        return DC_OK;
 }
index fe2023f..8f894c1 100644 (file)
@@ -3626,7 +3626,7 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
                                                (int)hubp->curs_attr.width || pos_cpy.x
                                                <= (int)hubp->curs_attr.width +
                                                pipe_ctx->plane_state->src_rect.x) {
-                                               pos_cpy.x = temp_x + viewport_width;
+                                               pos_cpy.x = 2 * viewport_width - temp_x;
                                        }
                                }
                        } else {
index f9ea1e8..79850a6 100644 (file)
@@ -874,8 +874,9 @@ static const struct dc_plane_cap plane_cap = {
        },
 
        // 6:1 downscaling ratio: 1000/6 = 166.666
+       // 4:1 downscaling ratio for ARGB888 to prevent underflow during P010 playback: 1000/4 = 250
        .max_downscale_factor = {
-                       .argb8888 = 167,
+                       .argb8888 = 250,
                        .nv12 = 167,
                        .fp16 = 167
        },
@@ -1763,7 +1764,7 @@ static bool dcn314_resource_construct(
        pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;
        pool->base.pipe_count = pool->base.res_cap->num_timing_generator;
        pool->base.mpcc_count = pool->base.res_cap->num_timing_generator;
-       dc->caps.max_downscale_ratio = 600;
+       dc->caps.max_downscale_ratio = 400;
        dc->caps.i2c_speed_in_khz = 100;
        dc->caps.i2c_speed_in_khz_hdcp = 100;
        dc->caps.max_cursor_size = 256;
index dc46494..a4e9fd5 100644 (file)
@@ -94,7 +94,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
        .apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations,
-       .does_plane_fit_in_mall = dcn30_does_plane_fit_in_mall,
+       .does_plane_fit_in_mall = NULL,
        .set_backlight_level = dcn21_set_backlight_level,
        .set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
        .hardware_release = dcn30_hardware_release,
index 950669f..cb7c0c8 100644 (file)
@@ -3183,7 +3183,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
                } else {
                        v->MIN_DST_Y_NEXT_START[k] = v->VTotal[k] - v->VFrontPorch[k] + v->VTotal[k] - v->VActive[k] - v->VStartup[k];
                }
-               v->MIN_DST_Y_NEXT_START[k] += dml_floor(4.0 * v->TSetup[k] / (double)v->HTotal[k] / v->PixelClock[k], 1.0) / 4.0;
+               v->MIN_DST_Y_NEXT_START[k] += dml_floor(4.0 * v->TSetup[k] / ((double)v->HTotal[k] / v->PixelClock[k]), 1.0) / 4.0;
                if (((v->VUpdateOffsetPix[k] + v->VUpdateWidthPix[k] + v->VReadyOffsetPix[k]) / v->HTotal[k])
                                <= (isInterlaceTiming ?
                                                dml_floor((v->VTotal[k] - v->VActive[k] - v->VFrontPorch[k] - v->VStartup[k]) / 2.0, 1.0) :
index 4a12292..92c18bf 100644 (file)
@@ -532,6 +532,9 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
        if (dmub->hw_funcs.reset)
                dmub->hw_funcs.reset(dmub);
 
+       /* reset the cache of the last wptr as well now that hw is reset */
+       dmub->inbox1_last_wptr = 0;
+
        cw0.offset.quad_part = inst_fb->gpu_addr;
        cw0.region.base = DMUB_CW0_BASE;
        cw0.region.top = cw0.region.base + inst_fb->size - 1;
@@ -649,6 +652,15 @@ enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
        if (dmub->hw_funcs.reset)
                dmub->hw_funcs.reset(dmub);
 
+       /* mailboxes have been reset in hw, so reset the sw state as well */
+       dmub->inbox1_last_wptr = 0;
+       dmub->inbox1_rb.wrpt = 0;
+       dmub->inbox1_rb.rptr = 0;
+       dmub->outbox0_rb.wrpt = 0;
+       dmub->outbox0_rb.rptr = 0;
+       dmub->outbox1_rb.wrpt = 0;
+       dmub->outbox1_rb.rptr = 0;
+
        dmub->hw_init = false;
 
        return DMUB_STATUS_OK;
index 236657e..2f3e239 100644 (file)
@@ -1991,6 +1991,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
                case IP_VERSION(9, 4, 2):
                case IP_VERSION(10, 3, 0):
                case IP_VERSION(11, 0, 0):
+               case IP_VERSION(11, 0, 1):
+               case IP_VERSION(11, 0, 2):
                        *states = ATTR_STATE_SUPPORTED;
                        break;
                default:
@@ -2007,14 +2009,16 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
                      gc_ver == IP_VERSION(10, 3, 0) ||
                      gc_ver == IP_VERSION(10, 1, 2) ||
                      gc_ver == IP_VERSION(11, 0, 0) ||
-                     gc_ver == IP_VERSION(11, 0, 2)))
+                     gc_ver == IP_VERSION(11, 0, 2) ||
+                     gc_ver == IP_VERSION(11, 0, 3)))
                        *states = ATTR_STATE_UNSUPPORTED;
        } else if (DEVICE_ATTR_IS(pp_dpm_dclk)) {
                if (!(gc_ver == IP_VERSION(10, 3, 1) ||
                      gc_ver == IP_VERSION(10, 3, 0) ||
                      gc_ver == IP_VERSION(10, 1, 2) ||
                      gc_ver == IP_VERSION(11, 0, 0) ||
-                     gc_ver == IP_VERSION(11, 0, 2)))
+                     gc_ver == IP_VERSION(11, 0, 2) ||
+                     gc_ver == IP_VERSION(11, 0, 3)))
                        *states = ATTR_STATE_UNSUPPORTED;
        } else if (DEVICE_ATTR_IS(pp_power_profile_mode)) {
                if (amdgpu_dpm_get_power_profile_mode(adev, NULL) == -EOPNOTSUPP)
index ca3beb5..6ab1550 100644 (file)
@@ -1499,6 +1499,20 @@ static int smu_disable_dpms(struct smu_context *smu)
                }
        }
 
+       /*
+        * For SMU 13.0.4/11, PMFW will handle the features disablement properly
+        * for gpu reset case. Driver involvement is unnecessary.
+        */
+       if (amdgpu_in_reset(adev)) {
+               switch (adev->ip_versions[MP1_HWIP][0]) {
+               case IP_VERSION(13, 0, 4):
+               case IP_VERSION(13, 0, 11):
+                       return 0;
+               default:
+                       break;
+               }
+       }
+
        /*
         * For gpu reset, runpm and hibernation through BACO,
         * BACO feature has to be kept enabled.
index d6b964c..4bc7aee 100644 (file)
                                                                        (1 << FEATURE_DS_FCLK_BIT) | \
                                                                        (1 << FEATURE_DS_LCLK_BIT) | \
                                                                        (1 << FEATURE_DS_DCFCLK_BIT) | \
-                                                                       (1 << FEATURE_DS_UCLK_BIT))
+                                                                       (1 << FEATURE_DS_UCLK_BIT) | \
+                                                                       (1ULL << FEATURE_DS_VCN_BIT))
 
 //For use with feature control messages
 typedef enum {
@@ -522,9 +523,9 @@ typedef enum  {
   TEMP_HOTSPOT_M,
   TEMP_MEM,
   TEMP_VR_GFX,
-  TEMP_VR_SOC,
   TEMP_VR_MEM0,
   TEMP_VR_MEM1,
+  TEMP_VR_SOC,
   TEMP_VR_U,
   TEMP_LIQUID0,
   TEMP_LIQUID1,
index d6b1393..48a3a39 100644 (file)
 #define NUM_FEATURES                          64
 
 #define ALLOWED_FEATURE_CTRL_DEFAULT 0xFFFFFFFFFFFFFFFFULL
-#define ALLOWED_FEATURE_CTRL_SCPM        (1 << FEATURE_DPM_GFXCLK_BIT) | \
-                                         (1 << FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT) | \
-                                         (1 << FEATURE_DPM_UCLK_BIT) | \
-                                         (1 << FEATURE_DPM_FCLK_BIT) | \
-                                         (1 << FEATURE_DPM_SOCCLK_BIT) | \
-                                         (1 << FEATURE_DPM_MP0CLK_BIT) | \
-                                         (1 << FEATURE_DPM_LINK_BIT) | \
-                                         (1 << FEATURE_DPM_DCN_BIT) | \
-                                         (1 << FEATURE_DS_GFXCLK_BIT) | \
-                                         (1 << FEATURE_DS_SOCCLK_BIT) | \
-                                         (1 << FEATURE_DS_FCLK_BIT) | \
-                                         (1 << FEATURE_DS_LCLK_BIT) | \
-                                         (1 << FEATURE_DS_DCFCLK_BIT) | \
-                                         (1 << FEATURE_DS_UCLK_BIT)
+#define ALLOWED_FEATURE_CTRL_SCPM      ((1 << FEATURE_DPM_GFXCLK_BIT) | \
+                                       (1 << FEATURE_DPM_GFX_POWER_OPTIMIZER_BIT) | \
+                                       (1 << FEATURE_DPM_UCLK_BIT) | \
+                                       (1 << FEATURE_DPM_FCLK_BIT) | \
+                                       (1 << FEATURE_DPM_SOCCLK_BIT) | \
+                                       (1 << FEATURE_DPM_MP0CLK_BIT) | \
+                                       (1 << FEATURE_DPM_LINK_BIT) | \
+                                       (1 << FEATURE_DPM_DCN_BIT) | \
+                                       (1 << FEATURE_DS_GFXCLK_BIT) | \
+                                       (1 << FEATURE_DS_SOCCLK_BIT) | \
+                                       (1 << FEATURE_DS_FCLK_BIT) | \
+                                       (1 << FEATURE_DS_LCLK_BIT) | \
+                                       (1 << FEATURE_DS_DCFCLK_BIT) | \
+                                       (1 << FEATURE_DS_UCLK_BIT) | \
+                                       (1ULL << FEATURE_DS_VCN_BIT))
 
 //For use with feature control messages
 typedef enum {
index e8c6feb..992163e 100644 (file)
 #define SMU13_DRIVER_IF_VERSION_INV 0xFFFFFFFF
 #define SMU13_DRIVER_IF_VERSION_YELLOW_CARP 0x04
 #define SMU13_DRIVER_IF_VERSION_ALDE 0x08
-#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_0 0x34
+#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_0 0x37
 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_4 0x07
 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_5 0x04
 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_0_10 0x32
-#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x35
+#define SMU13_DRIVER_IF_VERSION_SMU_V13_0_7 0x37
 #define SMU13_DRIVER_IF_VERSION_SMU_V13_0_10 0x1D
 
 #define SMU13_MODE1_RESET_WAIT_TIME_IN_MS 500  //500ms
index 85e2221..5cdc071 100644 (file)
@@ -1171,6 +1171,7 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu,
        int ret = 0;
        uint32_t apu_percent = 0;
        uint32_t dgpu_percent = 0;
+       struct amdgpu_device *adev = smu->adev;
 
 
        ret = smu_cmn_get_metrics_table(smu,
@@ -1196,7 +1197,11 @@ static int renoir_get_smu_metrics_data(struct smu_context *smu,
                *value = metrics->AverageUvdActivity / 100;
                break;
        case METRICS_AVERAGE_SOCKETPOWER:
-               *value = (metrics->CurrentSocketPower << 8) / 1000;
+               if (((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1)) && (adev->pm.fw_version >= 0x40000f)) ||
+               ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 0)) && (adev->pm.fw_version >= 0x373200)))
+                       *value = metrics->CurrentSocketPower << 8;
+               else
+                       *value = (metrics->CurrentSocketPower << 8) / 1000;
                break;
        case METRICS_TEMPERATURE_EDGE:
                *value = (metrics->GfxTemperature / 100) *
index e54b760..b4373b6 100644 (file)
@@ -1261,7 +1261,8 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
                                uint32_t speed)
 {
        struct amdgpu_device *adev = smu->adev;
-       uint32_t tach_period, crystal_clock_freq;
+       uint32_t crystal_clock_freq = 2500;
+       uint32_t tach_period;
        int ret;
 
        if (!speed)
@@ -1271,7 +1272,6 @@ int smu_v13_0_set_fan_speed_rpm(struct smu_context *smu,
        if (ret)
                return ret;
 
-       crystal_clock_freq = amdgpu_asic_get_xclk(adev);
        tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
        WREG32_SOC15(THM, 0, regCG_TACH_CTRL,
                     REG_SET_FIELD(RREG32_SOC15(THM, 0, regCG_TACH_CTRL),
@@ -2298,6 +2298,10 @@ bool smu_v13_0_baco_is_support(struct smu_context *smu)
            !smu_baco->platform_support)
                return false;
 
+       /* return true if ASIC is in BACO state already */
+       if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER)
+               return true;
+
        if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) &&
            !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT))
                return false;
index 9643b21..508e392 100644 (file)
@@ -145,6 +145,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
        MSG_MAP(SetBadMemoryPagesRetiredFlagsPerChannel,
                            PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel,   0),
        MSG_MAP(AllowGpo,                       PPSMC_MSG_SetGpoAllow,           0),
+       MSG_MAP(AllowIHHostInterrupt,           PPSMC_MSG_AllowIHHostInterrupt,       0),
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
@@ -213,6 +214,7 @@ static struct cmn2asic_mapping smu_v13_0_0_feature_mask_map[SMU_FEATURE_COUNT] =
        FEA_MAP(SOC_PCC),
        [SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
        [SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
+       [SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT},
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
@@ -405,6 +407,9 @@ static int smu_v13_0_0_setup_pptable(struct smu_context *smu)
        struct amdgpu_device *adev = smu->adev;
        int ret = 0;
 
+       if (amdgpu_sriov_vf(smu->adev))
+               return 0;
+
        ret = smu_v13_0_0_get_pptable_from_pmfw(smu,
                                                &smu_table->power_play_table,
                                                &smu_table->power_play_table_size);
@@ -1255,6 +1260,9 @@ static int smu_v13_0_0_get_thermal_temperature_range(struct smu_context *smu,
                table_context->power_play_table;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
 
+       if (amdgpu_sriov_vf(smu->adev))
+               return 0;
+
        if (!range)
                return -EINVAL;
 
index 5c6c6ad..9e1967d 100644 (file)
@@ -124,6 +124,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] =
        MSG_MAP(DFCstateControl,                PPSMC_MSG_SetExternalClientDfCstateAllow, 0),
        MSG_MAP(ArmD3,                          PPSMC_MSG_ArmD3,                       0),
        MSG_MAP(AllowGpo,                       PPSMC_MSG_SetGpoAllow,           0),
+       MSG_MAP(GetPptLimit,                    PPSMC_MSG_GetPptLimit,                 0),
 };
 
 static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = {
@@ -192,6 +193,7 @@ static struct cmn2asic_mapping smu_v13_0_7_feature_mask_map[SMU_FEATURE_COUNT] =
        FEA_MAP(SOC_PCC),
        [SMU_FEATURE_DPM_VCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
        [SMU_FEATURE_DPM_DCLK_BIT] = {1, FEATURE_MM_DPM_BIT},
+       [SMU_FEATURE_PPT_BIT] = {1, FEATURE_THROTTLERS_BIT},
 };
 
 static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = {
index a2f0860..d751820 100644 (file)
@@ -193,6 +193,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev)
        struct hdmi_codec_pdata pdata;
        struct platform_device *platform;
 
+       memset(&pdata, 0, sizeof(pdata));
        pdata.ops               = &dw_hdmi_i2s_ops;
        pdata.i2s               = 1;
        pdata.max_i2s_channels  = 8;
index 51a4668..4ca3726 100644 (file)
@@ -3372,6 +3372,9 @@ void drm_dp_remove_payload(struct drm_dp_mst_topology_mgr *mgr,
 
        mgr->payload_count--;
        mgr->next_start_slot -= payload->time_slots;
+
+       if (payload->delete)
+               drm_dp_mst_put_port_malloc(payload->port);
 }
 EXPORT_SYMBOL(drm_dp_remove_payload);
 
@@ -4327,7 +4330,6 @@ int drm_dp_atomic_release_time_slots(struct drm_atomic_state *state,
 
        drm_dbg_atomic(mgr->dev, "[MST PORT:%p] TU %d -> 0\n", port, payload->time_slots);
        if (!payload->delete) {
-               drm_dp_mst_put_port_malloc(port);
                payload->pbn = 0;
                payload->delete = true;
                topology_state->payload_mask &= ~BIT(payload->vcpi - 1);
index 11bb593..3d1f50f 100644 (file)
@@ -38,6 +38,25 @@ static void drm_block_free(struct drm_buddy *mm,
        kmem_cache_free(slab_blocks, block);
 }
 
+static void list_insert_sorted(struct drm_buddy *mm,
+                              struct drm_buddy_block *block)
+{
+       struct drm_buddy_block *node;
+       struct list_head *head;
+
+       head = &mm->free_list[drm_buddy_block_order(block)];
+       if (list_empty(head)) {
+               list_add(&block->link, head);
+               return;
+       }
+
+       list_for_each_entry(node, head, link)
+               if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node))
+                       break;
+
+       __list_add(&block->link, node->link.prev, &node->link);
+}
+
 static void mark_allocated(struct drm_buddy_block *block)
 {
        block->header &= ~DRM_BUDDY_HEADER_STATE;
@@ -52,8 +71,7 @@ static void mark_free(struct drm_buddy *mm,
        block->header &= ~DRM_BUDDY_HEADER_STATE;
        block->header |= DRM_BUDDY_FREE;
 
-       list_add(&block->link,
-                &mm->free_list[drm_buddy_block_order(block)]);
+       list_insert_sorted(mm, block);
 }
 
 static void mark_split(struct drm_buddy_block *block)
@@ -387,20 +405,26 @@ err_undo:
 }
 
 static struct drm_buddy_block *
-get_maxblock(struct list_head *head)
+get_maxblock(struct drm_buddy *mm, unsigned int order)
 {
        struct drm_buddy_block *max_block = NULL, *node;
+       unsigned int i;
 
-       max_block = list_first_entry_or_null(head,
-                                            struct drm_buddy_block,
-                                            link);
-       if (!max_block)
-               return NULL;
+       for (i = order; i <= mm->max_order; ++i) {
+               if (!list_empty(&mm->free_list[i])) {
+                       node = list_last_entry(&mm->free_list[i],
+                                              struct drm_buddy_block,
+                                              link);
+                       if (!max_block) {
+                               max_block = node;
+                               continue;
+                       }
 
-       list_for_each_entry(node, head, link) {
-               if (drm_buddy_block_offset(node) >
-                   drm_buddy_block_offset(max_block))
-                       max_block = node;
+                       if (drm_buddy_block_offset(node) >
+                           drm_buddy_block_offset(max_block)) {
+                               max_block = node;
+                       }
+               }
        }
 
        return max_block;
@@ -412,20 +436,23 @@ alloc_from_freelist(struct drm_buddy *mm,
                    unsigned long flags)
 {
        struct drm_buddy_block *block = NULL;
-       unsigned int i;
+       unsigned int tmp;
        int err;
 
-       for (i = order; i <= mm->max_order; ++i) {
-               if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
-                       block = get_maxblock(&mm->free_list[i]);
-                       if (block)
-                               break;
-               } else {
-                       block = list_first_entry_or_null(&mm->free_list[i],
-                                                        struct drm_buddy_block,
-                                                        link);
-                       if (block)
-                               break;
+       if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
+               block = get_maxblock(mm, order);
+               if (block)
+                       /* Store the obtained block order */
+                       tmp = drm_buddy_block_order(block);
+       } else {
+               for (tmp = order; tmp <= mm->max_order; ++tmp) {
+                       if (!list_empty(&mm->free_list[tmp])) {
+                               block = list_last_entry(&mm->free_list[tmp],
+                                                       struct drm_buddy_block,
+                                                       link);
+                               if (block)
+                                       break;
+                       }
                }
        }
 
@@ -434,18 +461,18 @@ alloc_from_freelist(struct drm_buddy *mm,
 
        BUG_ON(!drm_buddy_block_is_free(block));
 
-       while (i != order) {
+       while (tmp != order) {
                err = split_block(mm, block);
                if (unlikely(err))
                        goto err_undo;
 
                block = block->right;
-               i--;
+               tmp--;
        }
        return block;
 
 err_undo:
-       if (i != order)
+       if (tmp != order)
                __drm_buddy_free(mm, block);
        return ERR_PTR(err);
 }
index fd67efe..056ab9d 100644 (file)
@@ -233,21 +233,17 @@ void drm_client_dev_restore(struct drm_device *dev)
 
 static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
 {
-       struct drm_device *dev = buffer->client->dev;
-
        if (buffer->gem) {
                drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
                drm_gem_object_put(buffer->gem);
        }
 
-       if (buffer->handle)
-               drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
-
        kfree(buffer);
 }
 
 static struct drm_client_buffer *
-drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
+drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
+                        u32 format, u32 *handle)
 {
        const struct drm_format_info *info = drm_format_info(format);
        struct drm_mode_create_dumb dumb_args = { };
@@ -269,16 +265,15 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u
        if (ret)
                goto err_delete;
 
-       buffer->handle = dumb_args.handle;
-       buffer->pitch = dumb_args.pitch;
-
        obj = drm_gem_object_lookup(client->file, dumb_args.handle);
        if (!obj)  {
                ret = -ENOENT;
                goto err_delete;
        }
 
+       buffer->pitch = dumb_args.pitch;
        buffer->gem = obj;
+       *handle = dumb_args.handle;
 
        return buffer;
 
@@ -365,7 +360,8 @@ static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
 }
 
 static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
-                                  u32 width, u32 height, u32 format)
+                                  u32 width, u32 height, u32 format,
+                                  u32 handle)
 {
        struct drm_client_dev *client = buffer->client;
        struct drm_mode_fb_cmd fb_req = { };
@@ -377,7 +373,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
        fb_req.depth = info->depth;
        fb_req.width = width;
        fb_req.height = height;
-       fb_req.handle = buffer->handle;
+       fb_req.handle = handle;
        fb_req.pitch = buffer->pitch;
 
        ret = drm_mode_addfb(client->dev, &fb_req, client->file);
@@ -414,13 +410,24 @@ struct drm_client_buffer *
 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
 {
        struct drm_client_buffer *buffer;
+       u32 handle;
        int ret;
 
-       buffer = drm_client_buffer_create(client, width, height, format);
+       buffer = drm_client_buffer_create(client, width, height, format,
+                                         &handle);
        if (IS_ERR(buffer))
                return buffer;
 
-       ret = drm_client_buffer_addfb(buffer, width, height, format);
+       ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
+
+       /*
+        * The handle is only needed for creating the framebuffer, destroy it
+        * again to solve a circular dependency should anybody export the GEM
+        * object as DMA-buf. The framebuffer and our buffer structure are still
+        * holding references to the GEM object to prevent its destruction.
+        */
+       drm_mode_destroy_dumb(client->dev, handle, client->file);
+
        if (ret) {
                drm_client_buffer_delete(buffer);
                return ERR_PTR(ret);
index b3a731b..0d0c26e 100644 (file)
@@ -30,7 +30,9 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/console.h>
+#include <linux/pci.h>
 #include <linux/sysrq.h>
+#include <linux/vga_switcheroo.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_drv.h>
@@ -1909,6 +1911,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
                return ret;
 
        strcpy(fb_helper->fb->comm, "[fbcon]");
+
+       /* Set the fb info for vgaswitcheroo clients. Does nothing otherwise. */
+       if (dev_is_pci(dev->dev))
+               vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), fb_helper->info);
+
        return 0;
 }
 
index ab86956..593aa32 100644 (file)
@@ -171,11 +171,6 @@ static const struct fb_ops drm_fbdev_fb_ops = {
        .fb_imageblit   = drm_fbdev_fb_imageblit,
 };
 
-static struct fb_deferred_io drm_fbdev_defio = {
-       .delay          = HZ / 20,
-       .deferred_io    = drm_fb_helper_deferred_io,
-};
-
 /*
  * This function uses the client API to create a framebuffer backed by a dumb buffer.
  */
@@ -222,8 +217,14 @@ static int drm_fbdev_fb_probe(struct drm_fb_helper *fb_helper,
                        return -ENOMEM;
                fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
 
-               fbi->fbdefio = &drm_fbdev_defio;
-               fb_deferred_io_init(fbi);
+               /* Set a default deferred I/O handler */
+               fb_helper->fbdefio.delay = HZ / 20;
+               fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io;
+
+               fbi->fbdefio = &fb_helper->fbdefio;
+               ret = fb_deferred_io_init(fbi);
+               if (ret)
+                       return ret;
        } else {
                /* buffer is mapped for HW framebuffer */
                ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
index 52d8800..3659f04 100644 (file)
@@ -304,6 +304,12 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM"),
                },
                .driver_data = (void *)&lcd1200x1920_rightside_up,
+       }, {    /* Lenovo Ideapad D330-10IGL (HD) */
+               .matches = {
+                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL"),
+               },
+               .driver_data = (void *)&lcd800x1280_rightside_up,
        }, {    /* Lenovo Yoga Book X90F / X91F / X91L */
                .matches = {
                  /* Non exact match to match all versions */
index 7de37f8..83229a0 100644 (file)
@@ -240,27 +240,8 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
 }
 EXPORT_SYMBOL(drm_vma_offset_remove);
 
-/**
- * drm_vma_node_allow - Add open-file to list of allowed users
- * @node: Node to modify
- * @tag: Tag of file to remove
- *
- * Add @tag to the list of allowed open-files for this node. If @tag is
- * already on this list, the ref-count is incremented.
- *
- * The list of allowed-users is preserved across drm_vma_offset_add() and
- * drm_vma_offset_remove() calls. You may even call it if the node is currently
- * not added to any offset-manager.
- *
- * You must remove all open-files the same number of times as you added them
- * before destroying the node. Otherwise, you will leak memory.
- *
- * This is locked against concurrent access internally.
- *
- * RETURNS:
- * 0 on success, negative error code on internal failure (out-of-mem)
- */
-int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag)
+static int vma_node_allow(struct drm_vma_offset_node *node,
+                         struct drm_file *tag, bool ref_counted)
 {
        struct rb_node **iter;
        struct rb_node *parent = NULL;
@@ -282,7 +263,8 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag)
                entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb);
 
                if (tag == entry->vm_tag) {
-                       entry->vm_count++;
+                       if (ref_counted)
+                               entry->vm_count++;
                        goto unlock;
                } else if (tag > entry->vm_tag) {
                        iter = &(*iter)->rb_right;
@@ -307,8 +289,58 @@ unlock:
        kfree(new);
        return ret;
 }
+
+/**
+ * drm_vma_node_allow - Add open-file to list of allowed users
+ * @node: Node to modify
+ * @tag: Tag of file to remove
+ *
+ * Add @tag to the list of allowed open-files for this node. If @tag is
+ * already on this list, the ref-count is incremented.
+ *
+ * The list of allowed-users is preserved across drm_vma_offset_add() and
+ * drm_vma_offset_remove() calls. You may even call it if the node is currently
+ * not added to any offset-manager.
+ *
+ * You must remove all open-files the same number of times as you added them
+ * before destroying the node. Otherwise, you will leak memory.
+ *
+ * This is locked against concurrent access internally.
+ *
+ * RETURNS:
+ * 0 on success, negative error code on internal failure (out-of-mem)
+ */
+int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag)
+{
+       return vma_node_allow(node, tag, true);
+}
 EXPORT_SYMBOL(drm_vma_node_allow);
 
+/**
+ * drm_vma_node_allow_once - Add open-file to list of allowed users
+ * @node: Node to modify
+ * @tag: Tag of file to remove
+ *
+ * Add @tag to the list of allowed open-files for this node.
+ *
+ * The list of allowed-users is preserved across drm_vma_offset_add() and
+ * drm_vma_offset_remove() calls. You may even call it if the node is currently
+ * not added to any offset-manager.
+ *
+ * This is not ref-counted unlike drm_vma_node_allow() hence drm_vma_node_revoke()
+ * should only be called once after this.
+ *
+ * This is locked against concurrent access internally.
+ *
+ * RETURNS:
+ * 0 on success, negative error code on internal failure (out-of-mem)
+ */
+int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag)
+{
+       return vma_node_allow(node, tag, false);
+}
+EXPORT_SYMBOL(drm_vma_node_allow_once);
+
 /**
  * drm_vma_node_revoke - Remove open-file from list of allowed users
  * @node: Node to modify
index 572a4e3..a491e6c 100644 (file)
@@ -2466,6 +2466,22 @@ static enum port dvo_port_to_port(struct drm_i915_private *i915,
                                          dvo_port);
 }
 
+static enum port
+dsi_dvo_port_to_port(struct drm_i915_private *i915, u8 dvo_port)
+{
+       switch (dvo_port) {
+       case DVO_PORT_MIPIA:
+               return PORT_A;
+       case DVO_PORT_MIPIC:
+               if (DISPLAY_VER(i915) >= 11)
+                       return PORT_B;
+               else
+                       return PORT_C;
+       default:
+               return PORT_NONE;
+       }
+}
+
 static int parse_bdb_230_dp_max_link_rate(const int vbt_max_link_rate)
 {
        switch (vbt_max_link_rate) {
@@ -3414,19 +3430,16 @@ bool intel_bios_is_dsi_present(struct drm_i915_private *i915,
 
                dvo_port = child->dvo_port;
 
-               if (dvo_port == DVO_PORT_MIPIA ||
-                   (dvo_port == DVO_PORT_MIPIB && DISPLAY_VER(i915) >= 11) ||
-                   (dvo_port == DVO_PORT_MIPIC && DISPLAY_VER(i915) < 11)) {
-                       if (port)
-                               *port = dvo_port - DVO_PORT_MIPIA;
-                       return true;
-               } else if (dvo_port == DVO_PORT_MIPIB ||
-                          dvo_port == DVO_PORT_MIPIC ||
-                          dvo_port == DVO_PORT_MIPID) {
+               if (dsi_dvo_port_to_port(i915, dvo_port) == PORT_NONE) {
                        drm_dbg_kms(&i915->drm,
                                    "VBT has unsupported DSI port %c\n",
                                    port_name(dvo_port - DVO_PORT_MIPIA));
+                       continue;
                }
+
+               if (port)
+                       *port = dsi_dvo_port_to_port(i915, dvo_port);
+               return true;
        }
 
        return false;
@@ -3511,7 +3524,7 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder,
                if (!(child->device_type & DEVICE_TYPE_MIPI_OUTPUT))
                        continue;
 
-               if (child->dvo_port - DVO_PORT_MIPIA == encoder->port) {
+               if (dsi_dvo_port_to_port(i915, child->dvo_port) == encoder->port) {
                        if (!devdata->dsc)
                                return false;
 
index b74e36d..407a477 100644 (file)
@@ -1319,7 +1319,7 @@ static const struct intel_cdclk_vals adlp_cdclk_table[] = {
        { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 },
        { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
        { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
-       { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 },
+       { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 },
 
        { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 },
        { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 },
index 5575d7a..f76c06b 100644 (file)
@@ -328,8 +328,20 @@ out_unlock:
        return ret;
 }
 
+static int intelfb_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip)
+{
+       if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2))
+               return 0;
+
+       if (helper->fb->funcs->dirty)
+               return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1);
+
+       return 0;
+}
+
 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
        .fb_probe = intelfb_create,
+       .fb_dirty = intelfb_dirty,
 };
 
 static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
index 76490cc..7d07fa3 100644 (file)
@@ -1627,7 +1627,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
        u32 offset;
        int ret;
 
-       if (w > max_width || w < min_width || h > max_height) {
+       if (w > max_width || w < min_width || h > max_height || h < 1) {
                drm_dbg_kms(&dev_priv->drm,
                            "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
                            w, h, min_width, max_width, max_height);
index e0766d1..1155464 100644 (file)
@@ -1587,7 +1587,8 @@ skl_crtc_allocate_plane_ddb(struct intel_atomic_state *state,
                                skl_check_wm_level(&wm->wm[level], ddb);
 
                        if (icl_need_wm1_wa(i915, plane_id) &&
-                           level == 1 && wm->wm[0].enable) {
+                           level == 1 && !wm->wm[level].enable &&
+                           wm->wm[0].enable) {
                                wm->wm[level].blocks = wm->wm[0].blocks;
                                wm->wm[level].lines = wm->wm[0].lines;
                                wm->wm[level].ignore_lines = wm->wm[0].ignore_lines;
index 7f2831e..e4b78ab 100644 (file)
@@ -1688,6 +1688,10 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
        init_contexts(&i915->gem.contexts);
 }
 
+/*
+ * Note that this implicitly consumes the ctx reference, by placing
+ * the ctx in the context_xa.
+ */
 static void gem_context_register(struct i915_gem_context *ctx,
                                 struct drm_i915_file_private *fpriv,
                                 u32 id)
@@ -1703,10 +1707,6 @@ static void gem_context_register(struct i915_gem_context *ctx,
        snprintf(ctx->name, sizeof(ctx->name), "%s[%d]",
                 current->comm, pid_nr(ctx->pid));
 
-       /* And finally expose ourselves to userspace via the idr */
-       old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
-       WARN_ON(old);
-
        spin_lock(&ctx->client->ctx_lock);
        list_add_tail_rcu(&ctx->client_link, &ctx->client->ctx_list);
        spin_unlock(&ctx->client->ctx_lock);
@@ -1714,6 +1714,10 @@ static void gem_context_register(struct i915_gem_context *ctx,
        spin_lock(&i915->gem.contexts.lock);
        list_add_tail(&ctx->link, &i915->gem.contexts.list);
        spin_unlock(&i915->gem.contexts.lock);
+
+       /* And finally expose ourselves to userspace via the idr */
+       old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
+       WARN_ON(old);
 }
 
 int i915_gem_context_open(struct drm_i915_private *i915,
@@ -1857,11 +1861,19 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
        vm = ctx->vm;
        GEM_BUG_ON(!vm);
 
+       /*
+        * Get a reference for the allocated handle.  Once the handle is
+        * visible in the vm_xa table, userspace could try to close it
+        * from under our feet, so we need to hold the extra reference
+        * first.
+        */
+       i915_vm_get(vm);
+
        err = xa_alloc(&file_priv->vm_xa, &id, vm, xa_limit_32b, GFP_KERNEL);
-       if (err)
+       if (err) {
+               i915_vm_put(vm);
                return err;
-
-       i915_vm_get(vm);
+       }
 
        GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
        args->value = id;
@@ -2199,14 +2211,22 @@ finalize_create_context_locked(struct drm_i915_file_private *file_priv,
        if (IS_ERR(ctx))
                return ctx;
 
+       /*
+        * One for the xarray and one for the caller.  We need to grab
+        * the reference *prior* to making the ctx visble to userspace
+        * in gem_context_register(), as at any point after that
+        * userspace can try to race us with another thread destroying
+        * the context under our feet.
+        */
+       i915_gem_context_get(ctx);
+
        gem_context_register(ctx, file_priv, id);
 
        old = xa_erase(&file_priv->proto_context_xa, id);
        GEM_BUG_ON(old != pc);
        proto_context_close(file_priv->dev_priv, pc);
 
-       /* One for the xarray and one for the caller */
-       return i915_gem_context_get(ctx);
+       return ctx;
 }
 
 struct i915_gem_context *
index f266b68..0f2e056 100644 (file)
@@ -3483,6 +3483,13 @@ err_request:
                                   eb.composite_fence :
                                   &eb.requests[0]->fence);
 
+       if (unlikely(eb.gem_context->syncobj)) {
+               drm_syncobj_replace_fence(eb.gem_context->syncobj,
+                                         eb.composite_fence ?
+                                         eb.composite_fence :
+                                         &eb.requests[0]->fence);
+       }
+
        if (out_fence) {
                if (err == 0) {
                        fd_install(out_fence_fd, out_fence->file);
@@ -3494,13 +3501,6 @@ err_request:
                }
        }
 
-       if (unlikely(eb.gem_context->syncobj)) {
-               drm_syncobj_replace_fence(eb.gem_context->syncobj,
-                                         eb.composite_fence ?
-                                         eb.composite_fence :
-                                         &eb.requests[0]->fence);
-       }
-
        if (!out_fence && eb.composite_fence)
                dma_fence_put(eb.composite_fence);
 
index 0ad44f3..c7c252d 100644 (file)
@@ -697,7 +697,7 @@ insert:
        GEM_BUG_ON(lookup_mmo(obj, mmap_type) != mmo);
 out:
        if (file)
-               drm_vma_node_allow(&mmo->vma_node, file);
+               drm_vma_node_allow_once(&mmo->vma_node, file);
        return mmo;
 
 err:
index 9c759df..9377288 100644 (file)
@@ -579,7 +579,7 @@ static int shmem_object_init(struct intel_memory_region *mem,
        mapping_set_gfp_mask(mapping, mask);
        GEM_BUG_ON(!(mapping_gfp_mask(mapping) & __GFP_RECLAIM));
 
-       i915_gem_object_init(obj, &i915_gem_shmem_ops, &lock_class, 0);
+       i915_gem_object_init(obj, &i915_gem_shmem_ops, &lock_class, flags);
        obj->mem_flags |= I915_BO_FLAG_STRUCT_PAGE;
        obj->write_domain = I915_GEM_DOMAIN_CPU;
        obj->read_domains = I915_GEM_DOMAIN_CPU;
index fd42b89..bc21b1c 100644 (file)
@@ -305,10 +305,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
        spin_unlock(&obj->vma.lock);
 
        obj->tiling_and_stride = tiling | stride;
-       i915_gem_object_unlock(obj);
-
-       /* Force the fence to be reacquired for GTT access */
-       i915_gem_object_release_mmap_gtt(obj);
 
        /* Try to preallocate memory required to save swizzling on put-pages */
        if (i915_gem_object_needs_bit17_swizzle(obj)) {
@@ -321,6 +317,11 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
                obj->bit_17 = NULL;
        }
 
+       i915_gem_object_unlock(obj);
+
+       /* Force the fence to be reacquired for GTT access */
+       i915_gem_object_release_mmap_gtt(obj);
+
        return 0;
 }
 
index beaf27e..977dead 100644 (file)
@@ -1847,7 +1847,7 @@ static int igt_shrink_thp(void *arg)
                        I915_SHRINK_ACTIVE);
        i915_vma_unpin(vma);
        if (err)
-               goto out_put;
+               goto out_wf;
 
        /*
         * Now that the pages are *unpinned* shrinking should invoke
@@ -1863,19 +1863,19 @@ static int igt_shrink_thp(void *arg)
                pr_err("unexpected pages mismatch, should_swap=%s\n",
                       str_yes_no(should_swap));
                err = -EINVAL;
-               goto out_put;
+               goto out_wf;
        }
 
        if (should_swap == (obj->mm.page_sizes.sg || obj->mm.page_sizes.phys)) {
                pr_err("unexpected residual page-size bits, should_swap=%s\n",
                       str_yes_no(should_swap));
                err = -EINVAL;
-               goto out_put;
+               goto out_wf;
        }
 
        err = i915_vma_pin(vma, 0, 0, flags);
        if (err)
-               goto out_put;
+               goto out_wf;
 
        while (n--) {
                err = cpu_check(obj, n, 0xdeadbeaf);
index e94365b..2aa63ec 100644 (file)
@@ -528,7 +528,7 @@ retry:
        return rq;
 }
 
-struct i915_request *intel_context_find_active_request(struct intel_context *ce)
+struct i915_request *intel_context_get_active_request(struct intel_context *ce)
 {
        struct intel_context *parent = intel_context_to_parent(ce);
        struct i915_request *rq, *active = NULL;
@@ -552,6 +552,8 @@ struct i915_request *intel_context_find_active_request(struct intel_context *ce)
 
                active = rq;
        }
+       if (active)
+               active = i915_request_get_rcu(active);
        spin_unlock_irqrestore(&parent->guc_state.lock, flags);
 
        return active;
index fb62b7b..0a8d553 100644 (file)
@@ -268,8 +268,7 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
 
 struct i915_request *intel_context_create_request(struct intel_context *ce);
 
-struct i915_request *
-intel_context_find_active_request(struct intel_context *ce);
+struct i915_request *intel_context_get_active_request(struct intel_context *ce);
 
 static inline bool intel_context_is_barrier(const struct intel_context *ce)
 {
index cbc8b85..7a4504e 100644 (file)
@@ -248,8 +248,8 @@ void intel_engine_dump_active_requests(struct list_head *requests,
 ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine,
                                   ktime_t *now);
 
-struct i915_request *
-intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine);
+void intel_engine_get_hung_entity(struct intel_engine_cs *engine,
+                                 struct intel_context **ce, struct i915_request **rq);
 
 u32 intel_engine_context_size(struct intel_gt *gt, u8 class);
 struct intel_context *
index c33e0d7..d37931e 100644 (file)
@@ -2094,17 +2094,6 @@ static void print_request_ring(struct drm_printer *m, struct i915_request *rq)
        }
 }
 
-static unsigned long list_count(struct list_head *list)
-{
-       struct list_head *pos;
-       unsigned long count = 0;
-
-       list_for_each(pos, list)
-               count++;
-
-       return count;
-}
-
 static unsigned long read_ul(void *p, size_t x)
 {
        return *(unsigned long *)(p + x);
@@ -2196,11 +2185,11 @@ void intel_engine_dump_active_requests(struct list_head *requests,
        }
 }
 
-static void engine_dump_active_requests(struct intel_engine_cs *engine, struct drm_printer *m)
+static void engine_dump_active_requests(struct intel_engine_cs *engine,
+                                       struct drm_printer *m)
 {
+       struct intel_context *hung_ce = NULL;
        struct i915_request *hung_rq = NULL;
-       struct intel_context *ce;
-       bool guc;
 
        /*
         * No need for an engine->irq_seqno_barrier() before the seqno reads.
@@ -2209,27 +2198,22 @@ static void engine_dump_active_requests(struct intel_engine_cs *engine, struct d
         * But the intention here is just to report an instantaneous snapshot
         * so that's fine.
         */
-       lockdep_assert_held(&engine->sched_engine->lock);
+       intel_engine_get_hung_entity(engine, &hung_ce, &hung_rq);
 
        drm_printf(m, "\tRequests:\n");
 
-       guc = intel_uc_uses_guc_submission(&engine->gt->uc);
-       if (guc) {
-               ce = intel_engine_get_hung_context(engine);
-               if (ce)
-                       hung_rq = intel_context_find_active_request(ce);
-       } else {
-               hung_rq = intel_engine_execlist_find_hung_request(engine);
-       }
-
        if (hung_rq)
                engine_dump_request(hung_rq, m, "\t\thung");
+       else if (hung_ce)
+               drm_printf(m, "\t\tGot hung ce but no hung rq!\n");
 
-       if (guc)
+       if (intel_uc_uses_guc_submission(&engine->gt->uc))
                intel_guc_dump_active_requests(engine, hung_rq, m);
        else
-               intel_engine_dump_active_requests(&engine->sched_engine->requests,
-                                                 hung_rq, m);
+               intel_execlists_dump_active_requests(engine, hung_rq, m);
+
+       if (hung_rq)
+               i915_request_put(hung_rq);
 }
 
 void intel_engine_dump(struct intel_engine_cs *engine,
@@ -2239,7 +2223,6 @@ void intel_engine_dump(struct intel_engine_cs *engine,
        struct i915_gpu_error * const error = &engine->i915->gpu_error;
        struct i915_request *rq;
        intel_wakeref_t wakeref;
-       unsigned long flags;
        ktime_t dummy;
 
        if (header) {
@@ -2276,13 +2259,8 @@ void intel_engine_dump(struct intel_engine_cs *engine,
                   i915_reset_count(error));
        print_properties(engine, m);
 
-       spin_lock_irqsave(&engine->sched_engine->lock, flags);
        engine_dump_active_requests(engine, m);
 
-       drm_printf(m, "\tOn hold?: %lu\n",
-                  list_count(&engine->sched_engine->hold));
-       spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
-
        drm_printf(m, "\tMMIO base:  0x%08x\n", engine->mmio_base);
        wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm);
        if (wakeref) {
@@ -2328,8 +2306,7 @@ intel_engine_create_virtual(struct intel_engine_cs **siblings,
        return siblings[0]->cops->create_virtual(siblings, count, flags);
 }
 
-struct i915_request *
-intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine)
+static struct i915_request *engine_execlist_find_hung_request(struct intel_engine_cs *engine)
 {
        struct i915_request *request, *active = NULL;
 
@@ -2381,6 +2358,33 @@ intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine)
        return active;
 }
 
+void intel_engine_get_hung_entity(struct intel_engine_cs *engine,
+                                 struct intel_context **ce, struct i915_request **rq)
+{
+       unsigned long flags;
+
+       *ce = intel_engine_get_hung_context(engine);
+       if (*ce) {
+               intel_engine_clear_hung_context(engine);
+
+               *rq = intel_context_get_active_request(*ce);
+               return;
+       }
+
+       /*
+        * Getting here with GuC enabled means it is a forced error capture
+        * with no actual hang. So, no need to attempt the execlist search.
+        */
+       if (intel_uc_uses_guc_submission(&engine->gt->uc))
+               return;
+
+       spin_lock_irqsave(&engine->sched_engine->lock, flags);
+       *rq = engine_execlist_find_hung_request(engine);
+       if (*rq)
+               *rq = i915_request_get_rcu(*rq);
+       spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
+}
+
 void xehp_enable_ccs_engines(struct intel_engine_cs *engine)
 {
        /*
index 2daffa7..21cb5b6 100644 (file)
@@ -4148,6 +4148,33 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
        spin_unlock_irqrestore(&sched_engine->lock, flags);
 }
 
+static unsigned long list_count(struct list_head *list)
+{
+       struct list_head *pos;
+       unsigned long count = 0;
+
+       list_for_each(pos, list)
+               count++;
+
+       return count;
+}
+
+void intel_execlists_dump_active_requests(struct intel_engine_cs *engine,
+                                         struct i915_request *hung_rq,
+                                         struct drm_printer *m)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&engine->sched_engine->lock, flags);
+
+       intel_engine_dump_active_requests(&engine->sched_engine->requests, hung_rq, m);
+
+       drm_printf(m, "\tOn hold?: %lu\n",
+                  list_count(&engine->sched_engine->hold));
+
+       spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
+}
+
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftest_execlists.c"
 #endif
index a1aa92c..d2c7d45 100644 (file)
@@ -32,6 +32,10 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
                                                        int indent),
                                   unsigned int max);
 
+void intel_execlists_dump_active_requests(struct intel_engine_cs *engine,
+                                         struct i915_request *hung_rq,
+                                         struct drm_printer *m);
+
 bool
 intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine);
 
index c3cd926..a5454af 100644 (file)
 #define GEN9_WM_CHICKEN3                       _MMIO(0x5588)
 #define   GEN9_FACTOR_IN_CLR_VAL_HIZ           (1 << 9)
 
-#define CHICKEN_RASTER_1                       _MMIO(0x6204)
+#define CHICKEN_RASTER_1                       MCR_REG(0x6204)
 #define   DIS_SF_ROUND_NEAREST_EVEN            REG_BIT(8)
 
-#define CHICKEN_RASTER_2                       _MMIO(0x6208)
+#define CHICKEN_RASTER_2                       MCR_REG(0x6208)
 #define   TBIMR_FAST_CLIP                      REG_BIT(5)
 
 #define VFLSKPD                                        MCR_REG(0x62a8)
 #define   RC_OP_FLUSH_ENABLE                   (1 << 0)
 #define   HIZ_RAW_STALL_OPT_DISABLE            (1 << 2)
 #define CACHE_MODE_1                           _MMIO(0x7004) /* IVB+ */
-#define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE    (1 << 6)
-#define   GEN8_4x4_STC_OPTIMIZATION_DISABLE    (1 << 6)
-#define   GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE   (1 << 1)
+#define   MSAA_OPTIMIZATION_REDUC_DISABLE      REG_BIT(11)
+#define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE    REG_BIT(6)
+#define   GEN8_4x4_STC_OPTIMIZATION_DISABLE    REG_BIT(6)
+#define   GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE   REG_BIT(1)
 
 #define GEN7_GT_MODE                           _MMIO(0x7008)
 #define   GEN9_IZ_HASHING_MASK(slice)          (0x3 << ((slice) * 2))
 #define GEN8_L3CNTLREG                         _MMIO(0x7034)
 #define   GEN8_ERRDETBCTRL                     (1 << 9)
 
+#define PSS_MODE2                              _MMIO(0x703c)
+#define   SCOREBOARD_STALL_FLUSH_CONTROL       REG_BIT(5)
+
 #define GEN7_SC_INSTDONE                       _MMIO(0x7100)
 #define GEN12_SC_INSTDONE_EXTRA                        _MMIO(0x7104)
 #define GEN12_SC_INSTDONE_EXTRA2               _MMIO(0x7108)
index 7771a19..bbeeb6d 100644 (file)
@@ -288,39 +288,6 @@ static const u8 dg2_xcs_offsets[] = {
        END
 };
 
-static const u8 mtl_xcs_offsets[] = {
-       NOP(1),
-       LRI(13, POSTED),
-       REG16(0x244),
-       REG(0x034),
-       REG(0x030),
-       REG(0x038),
-       REG(0x03c),
-       REG(0x168),
-       REG(0x140),
-       REG(0x110),
-       REG(0x1c0),
-       REG(0x1c4),
-       REG(0x1c8),
-       REG(0x180),
-       REG16(0x2b4),
-       NOP(4),
-
-       NOP(1),
-       LRI(9, POSTED),
-       REG16(0x3a8),
-       REG16(0x28c),
-       REG16(0x288),
-       REG16(0x284),
-       REG16(0x280),
-       REG16(0x27c),
-       REG16(0x278),
-       REG16(0x274),
-       REG16(0x270),
-
-       END
-};
-
 static const u8 gen8_rcs_offsets[] = {
        NOP(1),
        LRI(14, POSTED),
@@ -739,9 +706,7 @@ static const u8 *reg_offsets(const struct intel_engine_cs *engine)
                else
                        return gen8_rcs_offsets;
        } else {
-               if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 70))
-                       return mtl_xcs_offsets;
-               else if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55))
+               if (GRAPHICS_VER_FULL(engine->i915) >= IP_VER(12, 55))
                        return dg2_xcs_offsets;
                else if (GRAPHICS_VER(engine->i915) >= 12)
                        return gen12_xcs_offsets;
index 24736eb..78dc5e4 100644 (file)
@@ -278,6 +278,7 @@ out:
 static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
 {
        struct intel_uncore *uncore = gt->uncore;
+       int loops = 2;
        int err;
 
        /*
@@ -285,18 +286,39 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
         * for fifo space for the write or forcewake the chip for
         * the read
         */
-       intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
+       do {
+               intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
 
-       /* Wait for the device to ack the reset requests */
-       err = __intel_wait_for_register_fw(uncore,
-                                          GEN6_GDRST, hw_domain_mask, 0,
-                                          500, 0,
-                                          NULL);
+               /*
+                * Wait for the device to ack the reset requests.
+                *
+                * On some platforms, e.g. Jasperlake, we see that the
+                * engine register state is not cleared until shortly after
+                * GDRST reports completion, causing a failure as we try
+                * to immediately resume while the internal state is still
+                * in flux. If we immediately repeat the reset, the second
+                * reset appears to serialise with the first, and since
+                * it is a no-op, the registers should retain their reset
+                * value. However, there is still a concern that upon
+                * leaving the second reset, the internal engine state
+                * is still in flux and not ready for resuming.
+                */
+               err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,
+                                                  hw_domain_mask, 0,
+                                                  2000, 0,
+                                                  NULL);
+       } while (err == 0 && --loops);
        if (err)
                GT_TRACE(gt,
                         "Wait for 0x%08x engines reset failed\n",
                         hw_domain_mask);
 
+       /*
+        * As we have observed that the engine state is still volatile
+        * after GDRST is acked, impose a small delay to let everything settle.
+        */
+       udelay(50);
+
        return err;
 }
 
index 2afb4f8..949c193 100644 (file)
@@ -645,7 +645,7 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
 static void dg2_ctx_gt_tuning_init(struct intel_engine_cs *engine,
                                   struct i915_wa_list *wal)
 {
-       wa_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP);
+       wa_mcr_masked_en(wal, CHICKEN_RASTER_2, TBIMR_FAST_CLIP);
        wa_mcr_write_clr_set(wal, XEHP_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK,
                             REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f));
        wa_mcr_add(wal,
@@ -771,11 +771,19 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine,
 
        /* Wa_14014947963:dg2 */
        if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_B0, STEP_FOREVER) ||
-               IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915))
+           IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915))
                wa_masked_field_set(wal, VF_PREEMPTION, PREEMPTION_VERTEX_COUNT, 0x4000);
 
+       /* Wa_18018764978:dg2 */
+       if (IS_DG2_GRAPHICS_STEP(engine->i915, G10, STEP_C0, STEP_FOREVER) ||
+           IS_DG2_G11(engine->i915) || IS_DG2_G12(engine->i915))
+               wa_masked_en(wal, PSS_MODE2, SCOREBOARD_STALL_FLUSH_CONTROL);
+
        /* Wa_15010599737:dg2 */
-       wa_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN);
+       wa_mcr_masked_en(wal, CHICKEN_RASTER_1, DIS_SF_ROUND_NEAREST_EVEN);
+
+       /* Wa_18019271663:dg2 */
+       wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE);
 }
 
 static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine,
index 0a42f18..c10977c 100644 (file)
@@ -1702,7 +1702,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st
                        goto next_context;
 
                guilty = false;
-               rq = intel_context_find_active_request(ce);
+               rq = intel_context_get_active_request(ce);
                if (!rq) {
                        head = ce->ring->tail;
                        goto out_replay;
@@ -1715,6 +1715,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st
                head = intel_ring_wrap(ce->ring, rq->head);
 
                __i915_request_reset(rq, guilty);
+               i915_request_put(rq);
 out_replay:
                guc_reset_state(ce, head, guilty);
 next_context:
@@ -4817,6 +4818,8 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine)
 
        xa_lock_irqsave(&guc->context_lookup, flags);
        xa_for_each(&guc->context_lookup, index, ce) {
+               bool found;
+
                if (!kref_get_unless_zero(&ce->ref))
                        continue;
 
@@ -4833,10 +4836,18 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine)
                                goto next;
                }
 
+               found = false;
+               spin_lock(&ce->guc_state.lock);
                list_for_each_entry(rq, &ce->guc_state.requests, sched.link) {
                        if (i915_test_request_state(rq) != I915_REQUEST_ACTIVE)
                                continue;
 
+                       found = true;
+                       break;
+               }
+               spin_unlock(&ce->guc_state.lock);
+
+               if (found) {
                        intel_engine_set_hung_context(engine, ce);
 
                        /* Can only cope with one hang at a time... */
@@ -4844,6 +4855,7 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine)
                        xa_lock(&guc->context_lookup);
                        goto done;
                }
+
 next:
                intel_context_put(ce);
                xa_lock(&guc->context_lookup);
index 69103ae..61c38fc 100644 (file)
@@ -1069,12 +1069,9 @@ static int i915_driver_open(struct drm_device *dev, struct drm_file *file)
  */
 static void i915_driver_lastclose(struct drm_device *dev)
 {
-       struct drm_i915_private *i915 = to_i915(dev);
-
        intel_fbdev_restore_mode(dev);
 
-       if (HAS_DISPLAY(i915))
-               vga_switcheroo_process_delayed_switch();
+       vga_switcheroo_process_delayed_switch();
 }
 
 static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
index 9d5d5a3..b20bd63 100644 (file)
@@ -1596,43 +1596,20 @@ capture_engine(struct intel_engine_cs *engine,
 {
        struct intel_engine_capture_vma *capture = NULL;
        struct intel_engine_coredump *ee;
-       struct intel_context *ce;
+       struct intel_context *ce = NULL;
        struct i915_request *rq = NULL;
-       unsigned long flags;
 
        ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL, dump_flags);
        if (!ee)
                return NULL;
 
-       ce = intel_engine_get_hung_context(engine);
-       if (ce) {
-               intel_engine_clear_hung_context(engine);
-               rq = intel_context_find_active_request(ce);
-               if (!rq || !i915_request_started(rq))
-                       goto no_request_capture;
-       } else {
-               /*
-                * Getting here with GuC enabled means it is a forced error capture
-                * with no actual hang. So, no need to attempt the execlist search.
-                */
-               if (!intel_uc_uses_guc_submission(&engine->gt->uc)) {
-                       spin_lock_irqsave(&engine->sched_engine->lock, flags);
-                       rq = intel_engine_execlist_find_hung_request(engine);
-                       spin_unlock_irqrestore(&engine->sched_engine->lock,
-                                              flags);
-               }
-       }
-       if (rq)
-               rq = i915_request_get_rcu(rq);
-
-       if (!rq)
+       intel_engine_get_hung_entity(engine, &ce, &rq);
+       if (!rq || !i915_request_started(rq))
                goto no_request_capture;
 
        capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL);
-       if (!capture) {
-               i915_request_put(rq);
+       if (!capture)
                goto no_request_capture;
-       }
        if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)
                intel_guc_capture_get_matching_node(engine->gt, ee, ce);
 
@@ -1642,6 +1619,8 @@ capture_engine(struct intel_engine_cs *engine,
        return ee;
 
 no_request_capture:
+       if (rq)
+               i915_request_put(rq);
        kfree(ee);
        return NULL;
 }
index ccd1f86..4fada7e 100644 (file)
@@ -423,7 +423,8 @@ static const struct intel_device_info ilk_m_info = {
        .has_coherent_ggtt = true, \
        .has_llc = 1, \
        .has_rc6 = 1, \
-       .has_rc6p = 1, \
+       /* snb does support rc6p, but enabling it causes various issues */ \
+       .has_rc6p = 0, \
        .has_rps = true, \
        .dma_mask_size = 40, \
        .__runtime.ppgtt_type = INTEL_PPGTT_ALIASING, \
index 23777d5..f45bd6b 100644 (file)
@@ -19,6 +19,10 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev,
                dev_err(&pdev->dev, "DRM not initialized, aborting switch.\n");
                return;
        }
+       if (!HAS_DISPLAY(i915)) {
+               dev_err(&pdev->dev, "Device state not initialized, aborting switch.\n");
+               return;
+       }
 
        if (state == VGA_SWITCHEROO_ON) {
                drm_info(&i915->drm, "switched on\n");
@@ -44,7 +48,7 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
         * locking inversion with the driver load path. And the access here is
         * completely racy anyway. So don't bother with locking for now.
         */
-       return i915 && atomic_read(&i915->drm.open_count) == 0;
+       return i915 && HAS_DISPLAY(i915) && atomic_read(&i915->drm.open_count) == 0;
 }
 
 static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
index 3a33be5..135390d 100644 (file)
@@ -2116,7 +2116,7 @@ int i915_vma_unbind_async(struct i915_vma *vma, bool trylock_vm)
        if (!obj->mm.rsgt)
                return -EBUSY;
 
-       err = dma_resv_reserve_fences(obj->base.resv, 1);
+       err = dma_resv_reserve_fences(obj->base.resv, 2);
        if (err)
                return -EBUSY;
 
index 310fb83..2990dd4 100644 (file)
@@ -28,8 +28,7 @@ struct intel_engine_cs *intel_selftest_find_any_engine(struct intel_gt *gt)
 
 int intel_selftest_modify_policy(struct intel_engine_cs *engine,
                                 struct intel_selftest_saved_policy *saved,
-                                u32 modify_type)
-
+                                enum selftest_scheduler_modify modify_type)
 {
        int err;
 
index 6484b97..f3c9600 100644 (file)
@@ -876,7 +876,8 @@ static void a6xx_gmu_rpmh_off(struct a6xx_gmu *gmu)
 #define GBIF_CLIENT_HALT_MASK             BIT(0)
 #define GBIF_ARB_HALT_MASK                BIT(1)
 
-static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu)
+static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu,
+               bool gx_off)
 {
        struct msm_gpu *gpu = &adreno_gpu->base;
 
@@ -889,9 +890,11 @@ static void a6xx_bus_clear_pending_transactions(struct adreno_gpu *adreno_gpu)
                return;
        }
 
-       /* Halt the gx side of GBIF */
-       gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1);
-       spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1);
+       if (gx_off) {
+               /* Halt the gx side of GBIF */
+               gpu_write(gpu, REG_A6XX_RBBM_GBIF_HALT, 1);
+               spin_until(gpu_read(gpu, REG_A6XX_RBBM_GBIF_HALT_ACK) & 1);
+       }
 
        /* Halt new client requests on GBIF */
        gpu_write(gpu, REG_A6XX_GBIF_HALT, GBIF_CLIENT_HALT_MASK);
@@ -929,7 +932,7 @@ static void a6xx_gmu_force_off(struct a6xx_gmu *gmu)
        /* Halt the gmu cm3 core */
        gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 1);
 
-       a6xx_bus_clear_pending_transactions(adreno_gpu);
+       a6xx_bus_clear_pending_transactions(adreno_gpu, true);
 
        /* Reset GPU core blocks */
        gpu_write(gpu, REG_A6XX_RBBM_SW_RESET_CMD, 1);
@@ -1083,7 +1086,7 @@ static void a6xx_gmu_shutdown(struct a6xx_gmu *gmu)
                        return;
                }
 
-               a6xx_bus_clear_pending_transactions(adreno_gpu);
+               a6xx_bus_clear_pending_transactions(adreno_gpu, a6xx_gpu->hung);
 
                /* tell the GMU we want to slumber */
                ret = a6xx_gmu_notify_slumber(gmu);
index 36c8fb6..3be0f29 100644 (file)
@@ -1270,6 +1270,12 @@ static void a6xx_recover(struct msm_gpu *gpu)
        if (hang_debug)
                a6xx_dump(gpu);
 
+       /*
+        * To handle recovery specific sequences during the rpm suspend we are
+        * about to trigger
+        */
+       a6xx_gpu->hung = true;
+
        /* Halt SQE first */
        gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3);
 
@@ -1312,6 +1318,7 @@ static void a6xx_recover(struct msm_gpu *gpu)
        mutex_unlock(&gpu->active_lock);
 
        msm_gpu_hw_init(gpu);
+       a6xx_gpu->hung = false;
 }
 
 static const char *a6xx_uche_fault_block(struct msm_gpu *gpu, u32 mid)
index ab853f6..eea2e60 100644 (file)
@@ -32,6 +32,7 @@ struct a6xx_gpu {
        void *llc_slice;
        void *htw_llc_slice;
        bool have_mmu500;
+       bool hung;
 };
 
 #define to_a6xx_gpu(x) container_of(x, struct a6xx_gpu, base)
index 6288064..36f062c 100644 (file)
@@ -551,13 +551,14 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
        return 0;
 }
 
+static int adreno_system_suspend(struct device *dev);
 static void adreno_unbind(struct device *dev, struct device *master,
                void *data)
 {
        struct msm_drm_private *priv = dev_get_drvdata(master);
        struct msm_gpu *gpu = dev_to_gpu(dev);
 
-       pm_runtime_force_suspend(dev);
+       WARN_ON_ONCE(adreno_system_suspend(dev));
        gpu->funcs->destroy(gpu);
 
        priv->gpu_pdev = NULL;
@@ -609,7 +610,7 @@ static int adreno_remove(struct platform_device *pdev)
 
 static void adreno_shutdown(struct platform_device *pdev)
 {
-       pm_runtime_force_suspend(&pdev->dev);
+       WARN_ON_ONCE(adreno_system_suspend(&pdev->dev));
 }
 
 static const struct of_device_id dt_match[] = {
index 57586c7..3605f09 100644 (file)
@@ -352,6 +352,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
                /* Ensure string is null terminated: */
                str[len] = '\0';
 
+               mutex_lock(&gpu->lock);
+
                if (param == MSM_PARAM_COMM) {
                        paramp = &ctx->comm;
                } else {
@@ -361,6 +363,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
                kfree(*paramp);
                *paramp = str;
 
+               mutex_unlock(&gpu->lock);
+
                return 0;
        }
        case MSM_PARAM_SYSPROF:
index 5d4b1c9..b4f9b13 100644 (file)
@@ -29,11 +29,9 @@ enum {
        ADRENO_FW_MAX,
 };
 
-enum adreno_quirks {
-       ADRENO_QUIRK_TWO_PASS_USE_WFI = 1,
-       ADRENO_QUIRK_FAULT_DETECT_MASK = 2,
-       ADRENO_QUIRK_LMLOADKILL_DISABLE = 3,
-};
+#define ADRENO_QUIRK_TWO_PASS_USE_WFI          BIT(0)
+#define ADRENO_QUIRK_FAULT_DETECT_MASK         BIT(1)
+#define ADRENO_QUIRK_LMLOADKILL_DISABLE                BIT(2)
 
 struct adreno_rev {
        uint8_t  core;
@@ -65,7 +63,7 @@ struct adreno_info {
        const char *name;
        const char *fw[ADRENO_FW_MAX];
        uint32_t gmem;
-       enum adreno_quirks quirks;
+       u64 quirks;
        struct msm_gpu *(*init)(struct drm_device *dev);
        const char *zapfw;
        u32 inactive_period;
index 7cbcef6..62f6ff6 100644 (file)
@@ -132,7 +132,6 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
  * dpu_encoder_phys_wb_setup_fb - setup output framebuffer
  * @phys_enc:  Pointer to physical encoder
  * @fb:                Pointer to output framebuffer
- * @wb_roi:    Pointer to output region of interest
  */
 static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
                struct drm_framebuffer *fb)
@@ -692,7 +691,7 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
 
 /**
  * dpu_encoder_phys_wb_init - initialize writeback encoder
- * @init:      Pointer to init info structure with initialization params
+ * @p: Pointer to init info structure with initialization params
  */
 struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
                struct dpu_enc_phys_init_params *p)
index d030a93..cc3efed 100644 (file)
@@ -423,6 +423,10 @@ void dp_aux_isr(struct drm_dp_aux *dp_aux)
 
        isr = dp_catalog_aux_get_irq(aux->catalog);
 
+       /* no interrupts pending, return immediately */
+       if (!isr)
+               return;
+
        if (!aux->cmd_busy)
                return;
 
index 4d3fdc8..97372bb 100644 (file)
@@ -532,11 +532,19 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
 
        ret = devm_pm_runtime_enable(&pdev->dev);
        if (ret)
-               return ret;
+               goto err_put_phy;
 
        platform_set_drvdata(pdev, hdmi);
 
-       return component_add(&pdev->dev, &msm_hdmi_ops);
+       ret = component_add(&pdev->dev, &msm_hdmi_ops);
+       if (ret)
+               goto err_put_phy;
+
+       return 0;
+
+err_put_phy:
+       msm_hdmi_put_phy(hdmi);
+       return ret;
 }
 
 static int msm_hdmi_dev_remove(struct platform_device *pdev)
index 8b0b0ac..45e81eb 100644 (file)
@@ -1278,7 +1278,7 @@ void msm_drv_shutdown(struct platform_device *pdev)
         * msm_drm_init, drm_dev->registered is used as an indicator that the
         * shutdown will be successful.
         */
-       if (drm && drm->registered)
+       if (drm && drm->registered && priv->kms)
                drm_atomic_helper_shutdown(drm);
 }
 
index 30ed45a..3802495 100644 (file)
@@ -335,6 +335,8 @@ static void get_comm_cmdline(struct msm_gem_submit *submit, char **comm, char **
        struct msm_file_private *ctx = submit->queue->ctx;
        struct task_struct *task;
 
+       WARN_ON(!mutex_is_locked(&submit->gpu->lock));
+
        /* Note that kstrdup will return NULL if argument is NULL: */
        *comm = kstrdup(ctx->comm, GFP_KERNEL);
        *cmd  = kstrdup(ctx->cmdline, GFP_KERNEL);
index 651786b..732295e 100644 (file)
@@ -376,10 +376,18 @@ struct msm_file_private {
         */
        int sysprof;
 
-       /** comm: Overridden task comm, see MSM_PARAM_COMM */
+       /**
+        * comm: Overridden task comm, see MSM_PARAM_COMM
+        *
+        * Accessed under msm_gpu::lock
+        */
        char *comm;
 
-       /** cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE */
+       /**
+        * cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE
+        *
+        * Accessed under msm_gpu::lock
+        */
        char *cmdline;
 
        /**
index 86b28ad..2527afe 100644 (file)
@@ -47,15 +47,17 @@ struct msm_mdss {
 static int msm_mdss_parse_data_bus_icc_path(struct device *dev,
                                            struct msm_mdss *msm_mdss)
 {
-       struct icc_path *path0 = of_icc_get(dev, "mdp0-mem");
-       struct icc_path *path1 = of_icc_get(dev, "mdp1-mem");
+       struct icc_path *path0;
+       struct icc_path *path1;
 
+       path0 = of_icc_get(dev, "mdp0-mem");
        if (IS_ERR_OR_NULL(path0))
                return PTR_ERR_OR_ZERO(path0);
 
        msm_mdss->path[0] = path0;
        msm_mdss->num_paths = 1;
 
+       path1 = of_icc_get(dev, "mdp1-mem");
        if (!IS_ERR_OR_NULL(path1)) {
                msm_mdss->path[1] = path1;
                msm_mdss->num_paths++;
index 4076837..c5a4f49 100644 (file)
@@ -97,6 +97,7 @@ int gp100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct n
 int gp102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
 int gp10b_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
 int gv100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
+int tu102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
 int ga100_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
 int ga102_fb_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_fb **);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
deleted file mode 100644 (file)
index e87de79..0000000
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * Copyright © 2007 David Airlie
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *     David Airlie
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/sysrq.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/screen_info.h>
-#include <linux/vga_switcheroo.h>
-#include <linux/console.h>
-
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_probe_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_fourcc.h>
-#include <drm/drm_atomic.h>
-
-#include "nouveau_drv.h"
-#include "nouveau_gem.h"
-#include "nouveau_bo.h"
-#include "nouveau_fbcon.h"
-#include "nouveau_chan.h"
-#include "nouveau_vmm.h"
-
-#include "nouveau_crtc.h"
-
-MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
-int nouveau_nofbaccel = 0;
-module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
-
-MODULE_PARM_DESC(fbcon_bpp, "fbcon bits-per-pixel (default: auto)");
-static int nouveau_fbcon_bpp;
-module_param_named(fbcon_bpp, nouveau_fbcon_bpp, int, 0400);
-
-static void
-nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-       struct nvif_device *device = &drm->client.device;
-       int ret;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return;
-
-       ret = -ENODEV;
-       if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-           mutex_trylock(&drm->client.mutex)) {
-               if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
-                       ret = nv04_fbcon_fillrect(info, rect);
-               else
-               if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
-                       ret = nv50_fbcon_fillrect(info, rect);
-               else
-                       ret = nvc0_fbcon_fillrect(info, rect);
-               mutex_unlock(&drm->client.mutex);
-       }
-
-       if (ret == 0)
-               return;
-
-       if (ret != -ENODEV)
-               nouveau_fbcon_gpu_lockup(info);
-       drm_fb_helper_cfb_fillrect(info, rect);
-}
-
-static void
-nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-       struct nvif_device *device = &drm->client.device;
-       int ret;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return;
-
-       ret = -ENODEV;
-       if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-           mutex_trylock(&drm->client.mutex)) {
-               if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
-                       ret = nv04_fbcon_copyarea(info, image);
-               else
-               if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
-                       ret = nv50_fbcon_copyarea(info, image);
-               else
-                       ret = nvc0_fbcon_copyarea(info, image);
-               mutex_unlock(&drm->client.mutex);
-       }
-
-       if (ret == 0)
-               return;
-
-       if (ret != -ENODEV)
-               nouveau_fbcon_gpu_lockup(info);
-       drm_fb_helper_cfb_copyarea(info, image);
-}
-
-static void
-nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-       struct nvif_device *device = &drm->client.device;
-       int ret;
-
-       if (info->state != FBINFO_STATE_RUNNING)
-               return;
-
-       ret = -ENODEV;
-       if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
-           mutex_trylock(&drm->client.mutex)) {
-               if (device->info.family < NV_DEVICE_INFO_V0_TESLA)
-                       ret = nv04_fbcon_imageblit(info, image);
-               else
-               if (device->info.family < NV_DEVICE_INFO_V0_FERMI)
-                       ret = nv50_fbcon_imageblit(info, image);
-               else
-                       ret = nvc0_fbcon_imageblit(info, image);
-               mutex_unlock(&drm->client.mutex);
-       }
-
-       if (ret == 0)
-               return;
-
-       if (ret != -ENODEV)
-               nouveau_fbcon_gpu_lockup(info);
-       drm_fb_helper_cfb_imageblit(info, image);
-}
-
-static int
-nouveau_fbcon_sync(struct fb_info *info)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-       struct nouveau_channel *chan = drm->channel;
-       int ret;
-
-       if (!chan || !chan->accel_done || in_interrupt() ||
-           info->state != FBINFO_STATE_RUNNING ||
-           info->flags & FBINFO_HWACCEL_DISABLED)
-               return 0;
-
-       if (!mutex_trylock(&drm->client.mutex))
-               return 0;
-
-       ret = nouveau_channel_idle(chan);
-       mutex_unlock(&drm->client.mutex);
-       if (ret) {
-               nouveau_fbcon_gpu_lockup(info);
-               return 0;
-       }
-
-       chan->accel_done = false;
-       return 0;
-}
-
-static int
-nouveau_fbcon_open(struct fb_info *info, int user)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-       int ret = pm_runtime_get_sync(drm->dev->dev);
-       if (ret < 0 && ret != -EACCES) {
-               pm_runtime_put(drm->dev->dev);
-               return ret;
-       }
-       return 0;
-}
-
-static int
-nouveau_fbcon_release(struct fb_info *info, int user)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-       pm_runtime_put(drm->dev->dev);
-       return 0;
-}
-
-static const struct fb_ops nouveau_fbcon_ops = {
-       .owner = THIS_MODULE,
-       DRM_FB_HELPER_DEFAULT_OPS,
-       .fb_open = nouveau_fbcon_open,
-       .fb_release = nouveau_fbcon_release,
-       .fb_fillrect = nouveau_fbcon_fillrect,
-       .fb_copyarea = nouveau_fbcon_copyarea,
-       .fb_imageblit = nouveau_fbcon_imageblit,
-       .fb_sync = nouveau_fbcon_sync,
-};
-
-static const struct fb_ops nouveau_fbcon_sw_ops = {
-       .owner = THIS_MODULE,
-       DRM_FB_HELPER_DEFAULT_OPS,
-       .fb_open = nouveau_fbcon_open,
-       .fb_release = nouveau_fbcon_release,
-       .fb_fillrect = drm_fb_helper_cfb_fillrect,
-       .fb_copyarea = drm_fb_helper_cfb_copyarea,
-       .fb_imageblit = drm_fb_helper_cfb_imageblit,
-};
-
-void
-nouveau_fbcon_accel_save_disable(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       if (drm->fbcon && drm->fbcon->helper.info) {
-               drm->fbcon->saved_flags = drm->fbcon->helper.info->flags;
-               drm->fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED;
-       }
-}
-
-void
-nouveau_fbcon_accel_restore(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       if (drm->fbcon && drm->fbcon->helper.info)
-               drm->fbcon->helper.info->flags = drm->fbcon->saved_flags;
-}
-
-static void
-nouveau_fbcon_accel_fini(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_fbdev *fbcon = drm->fbcon;
-       if (fbcon && drm->channel) {
-               console_lock();
-               if (fbcon->helper.info)
-                       fbcon->helper.info->flags |= FBINFO_HWACCEL_DISABLED;
-               console_unlock();
-               nouveau_channel_idle(drm->channel);
-               nvif_object_dtor(&fbcon->twod);
-               nvif_object_dtor(&fbcon->blit);
-               nvif_object_dtor(&fbcon->gdi);
-               nvif_object_dtor(&fbcon->patt);
-               nvif_object_dtor(&fbcon->rop);
-               nvif_object_dtor(&fbcon->clip);
-               nvif_object_dtor(&fbcon->surf2d);
-       }
-}
-
-static void
-nouveau_fbcon_accel_init(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_fbdev *fbcon = drm->fbcon;
-       struct fb_info *info = fbcon->helper.info;
-       int ret;
-
-       if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA)
-               ret = nv04_fbcon_accel_init(info);
-       else
-       if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
-               ret = nv50_fbcon_accel_init(info);
-       else
-               ret = nvc0_fbcon_accel_init(info);
-
-       if (ret == 0)
-               info->fbops = &nouveau_fbcon_ops;
-}
-
-static void
-nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *fbcon)
-{
-       struct fb_info *info = fbcon->helper.info;
-       struct fb_fillrect rect;
-
-       /* Clear the entire fbcon.  The drm will program every connector
-        * with it's preferred mode.  If the sizes differ, one display will
-        * quite likely have garbage around the console.
-        */
-       rect.dx = rect.dy = 0;
-       rect.width = info->var.xres_virtual;
-       rect.height = info->var.yres_virtual;
-       rect.color = 0;
-       rect.rop = ROP_COPY;
-       info->fbops->fb_fillrect(info, &rect);
-}
-
-static int
-nouveau_fbcon_create(struct drm_fb_helper *helper,
-                    struct drm_fb_helper_surface_size *sizes)
-{
-       struct nouveau_fbdev *fbcon =
-               container_of(helper, struct nouveau_fbdev, helper);
-       struct drm_device *dev = fbcon->helper.dev;
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nvif_device *device = &drm->client.device;
-       struct fb_info *info;
-       struct drm_framebuffer *fb;
-       struct nouveau_channel *chan;
-       struct nouveau_bo *nvbo;
-       struct drm_mode_fb_cmd2 mode_cmd = {};
-       int ret;
-
-       mode_cmd.width = sizes->surface_width;
-       mode_cmd.height = sizes->surface_height;
-
-       mode_cmd.pitches[0] = mode_cmd.width * (sizes->surface_bpp >> 3);
-       mode_cmd.pitches[0] = roundup(mode_cmd.pitches[0], 256);
-
-       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
-                                                         sizes->surface_depth);
-
-       ret = nouveau_gem_new(&drm->client, mode_cmd.pitches[0] *
-                             mode_cmd.height, 0, NOUVEAU_GEM_DOMAIN_VRAM,
-                             0, 0x0000, &nvbo);
-       if (ret) {
-               NV_ERROR(drm, "failed to allocate framebuffer\n");
-               goto out;
-       }
-
-       ret = nouveau_framebuffer_new(dev, &mode_cmd, &nvbo->bo.base, &fb);
-       if (ret)
-               goto out_unref;
-
-       ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
-       if (ret) {
-               NV_ERROR(drm, "failed to pin fb: %d\n", ret);
-               goto out_unref;
-       }
-
-       ret = nouveau_bo_map(nvbo);
-       if (ret) {
-               NV_ERROR(drm, "failed to map fb: %d\n", ret);
-               goto out_unpin;
-       }
-
-       chan = nouveau_nofbaccel ? NULL : drm->channel;
-       if (chan && device->info.family >= NV_DEVICE_INFO_V0_TESLA) {
-               ret = nouveau_vma_new(nvbo, chan->vmm, &fbcon->vma);
-               if (ret) {
-                       NV_ERROR(drm, "failed to map fb into chan: %d\n", ret);
-                       chan = NULL;
-               }
-       }
-
-       info = drm_fb_helper_alloc_info(helper);
-       if (IS_ERR(info)) {
-               ret = PTR_ERR(info);
-               goto out_unlock;
-       }
-
-       /* setup helper */
-       fbcon->helper.fb = fb;
-
-       if (!chan)
-               info->flags = FBINFO_HWACCEL_DISABLED;
-       else
-               info->flags = FBINFO_HWACCEL_COPYAREA |
-                             FBINFO_HWACCEL_FILLRECT |
-                             FBINFO_HWACCEL_IMAGEBLIT;
-       info->fbops = &nouveau_fbcon_sw_ops;
-       info->fix.smem_start = nvbo->bo.resource->bus.offset;
-       info->fix.smem_len = nvbo->bo.base.size;
-
-       info->screen_base = nvbo_kmap_obj_iovirtual(nvbo);
-       info->screen_size = nvbo->bo.base.size;
-
-       drm_fb_helper_fill_info(info, &fbcon->helper, sizes);
-
-       /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
-
-       if (chan)
-               nouveau_fbcon_accel_init(dev);
-       nouveau_fbcon_zfill(dev, fbcon);
-
-       /* To allow resizeing without swapping buffers */
-       NV_INFO(drm, "allocated %dx%d fb: 0x%llx, bo %p\n",
-               fb->width, fb->height, nvbo->offset, nvbo);
-
-       if (dev_is_pci(dev->dev))
-               vga_switcheroo_client_fb_set(to_pci_dev(dev->dev), info);
-
-       return 0;
-
-out_unlock:
-       if (chan)
-               nouveau_vma_del(&fbcon->vma);
-       nouveau_bo_unmap(nvbo);
-out_unpin:
-       nouveau_bo_unpin(nvbo);
-out_unref:
-       nouveau_bo_ref(NULL, &nvbo);
-out:
-       return ret;
-}
-
-static int
-nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
-{
-       struct drm_framebuffer *fb = fbcon->helper.fb;
-       struct nouveau_bo *nvbo;
-
-       drm_fb_helper_unregister_info(&fbcon->helper);
-       drm_fb_helper_fini(&fbcon->helper);
-
-       if (fb && fb->obj[0]) {
-               nvbo = nouveau_gem_object(fb->obj[0]);
-               nouveau_vma_del(&fbcon->vma);
-               nouveau_bo_unmap(nvbo);
-               nouveau_bo_unpin(nvbo);
-               drm_framebuffer_put(fb);
-       }
-
-       return 0;
-}
-
-void nouveau_fbcon_gpu_lockup(struct fb_info *info)
-{
-       struct nouveau_fbdev *fbcon = info->par;
-       struct nouveau_drm *drm = nouveau_drm(fbcon->helper.dev);
-
-       NV_ERROR(drm, "GPU lockup - switching to software fbcon\n");
-       info->flags |= FBINFO_HWACCEL_DISABLED;
-}
-
-static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
-       .fb_probe = nouveau_fbcon_create,
-};
-
-static void
-nouveau_fbcon_set_suspend_work(struct work_struct *work)
-{
-       struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work);
-       int state = READ_ONCE(drm->fbcon_new_state);
-
-       if (state == FBINFO_STATE_RUNNING)
-               pm_runtime_get_sync(drm->dev->dev);
-
-       console_lock();
-       if (state == FBINFO_STATE_RUNNING)
-               nouveau_fbcon_accel_restore(drm->dev);
-       drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
-       if (state != FBINFO_STATE_RUNNING)
-               nouveau_fbcon_accel_save_disable(drm->dev);
-       console_unlock();
-
-       if (state == FBINFO_STATE_RUNNING) {
-               nouveau_fbcon_hotplug_resume(drm->fbcon);
-               pm_runtime_mark_last_busy(drm->dev->dev);
-               pm_runtime_put_autosuspend(drm->dev->dev);
-       }
-}
-
-void
-nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       if (!drm->fbcon)
-               return;
-
-       drm->fbcon_new_state = state;
-       /* Since runtime resume can happen as a result of a sysfs operation,
-        * it's possible we already have the console locked. So handle fbcon
-        * init/deinit from a seperate work thread
-        */
-       schedule_work(&drm->fbcon_work);
-}
-
-void
-nouveau_fbcon_output_poll_changed(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_fbdev *fbcon = drm->fbcon;
-       int ret;
-
-       if (!fbcon)
-               return;
-
-       mutex_lock(&fbcon->hotplug_lock);
-
-       ret = pm_runtime_get(dev->dev);
-       if (ret == 1 || ret == -EACCES) {
-               drm_fb_helper_hotplug_event(&fbcon->helper);
-
-               pm_runtime_mark_last_busy(dev->dev);
-               pm_runtime_put_autosuspend(dev->dev);
-       } else if (ret == 0) {
-               /* If the GPU was already in the process of suspending before
-                * this event happened, then we can't block here as we'll
-                * deadlock the runtime pmops since they wait for us to
-                * finish. So, just defer this event for when we runtime
-                * resume again. It will be handled by fbcon_work.
-                */
-               NV_DEBUG(drm, "fbcon HPD event deferred until runtime resume\n");
-               fbcon->hotplug_waiting = true;
-               pm_runtime_put_noidle(drm->dev->dev);
-       } else {
-               DRM_WARN("fbcon HPD event lost due to RPM failure: %d\n",
-                        ret);
-       }
-
-       mutex_unlock(&fbcon->hotplug_lock);
-}
-
-void
-nouveau_fbcon_hotplug_resume(struct nouveau_fbdev *fbcon)
-{
-       struct nouveau_drm *drm;
-
-       if (!fbcon)
-               return;
-       drm = nouveau_drm(fbcon->helper.dev);
-
-       mutex_lock(&fbcon->hotplug_lock);
-       if (fbcon->hotplug_waiting) {
-               fbcon->hotplug_waiting = false;
-
-               NV_DEBUG(drm, "Handling deferred fbcon HPD events\n");
-               drm_fb_helper_hotplug_event(&fbcon->helper);
-       }
-       mutex_unlock(&fbcon->hotplug_lock);
-}
-
-int
-nouveau_fbcon_init(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_fbdev *fbcon;
-       int preferred_bpp = nouveau_fbcon_bpp;
-       int ret;
-
-       if (!dev->mode_config.num_crtc ||
-           (to_pci_dev(dev->dev)->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-               return 0;
-
-       fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
-       if (!fbcon)
-               return -ENOMEM;
-
-       drm->fbcon = fbcon;
-       INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work);
-       mutex_init(&fbcon->hotplug_lock);
-
-       drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs);
-
-       ret = drm_fb_helper_init(dev, &fbcon->helper);
-       if (ret)
-               goto free;
-
-       if (preferred_bpp != 8 && preferred_bpp != 16 && preferred_bpp != 32) {
-               if (drm->client.device.info.ram_size <= 32 * 1024 * 1024)
-                       preferred_bpp = 8;
-               else
-               if (drm->client.device.info.ram_size <= 64 * 1024 * 1024)
-                       preferred_bpp = 16;
-               else
-                       preferred_bpp = 32;
-       }
-
-       /* disable all the possible outputs/crtcs before entering KMS mode */
-       if (!drm_drv_uses_atomic_modeset(dev))
-               drm_helper_disable_unused_functions(dev);
-
-       ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
-       if (ret)
-               goto fini;
-
-       if (fbcon->helper.info)
-               fbcon->helper.info->pixmap.buf_align = 4;
-       return 0;
-
-fini:
-       drm_fb_helper_fini(&fbcon->helper);
-free:
-       kfree(fbcon);
-       drm->fbcon = NULL;
-       return ret;
-}
-
-void
-nouveau_fbcon_fini(struct drm_device *dev)
-{
-       struct nouveau_drm *drm = nouveau_drm(dev);
-
-       if (!drm->fbcon)
-               return;
-
-       drm_kms_helper_poll_fini(dev);
-       nouveau_fbcon_accel_fini(dev);
-       nouveau_fbcon_destroy(dev, drm->fbcon);
-       kfree(drm->fbcon);
-       drm->fbcon = NULL;
-}
index fcf2a00..91fb494 100644 (file)
@@ -151,6 +151,9 @@ nvkm_firmware_mem_page(struct nvkm_memory *memory)
 static enum nvkm_memory_target
 nvkm_firmware_mem_target(struct nvkm_memory *memory)
 {
+       if (nvkm_firmware_mem(memory)->device->func->tegra)
+               return NVKM_MEM_TARGET_NCOH;
+
        return NVKM_MEM_TARGET_HOST;
 }
 
index 364fea3..1c81e5b 100644 (file)
@@ -2405,7 +2405,7 @@ nv162_chipset = {
        .bus      = { 0x00000001, gf100_bus_new },
        .devinit  = { 0x00000001, tu102_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
-       .fb       = { 0x00000001, gv100_fb_new },
+       .fb       = { 0x00000001, tu102_fb_new },
        .fuse     = { 0x00000001, gm107_fuse_new },
        .gpio     = { 0x00000001, gk104_gpio_new },
        .gsp      = { 0x00000001, gv100_gsp_new },
@@ -2440,7 +2440,7 @@ nv164_chipset = {
        .bus      = { 0x00000001, gf100_bus_new },
        .devinit  = { 0x00000001, tu102_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
-       .fb       = { 0x00000001, gv100_fb_new },
+       .fb       = { 0x00000001, tu102_fb_new },
        .fuse     = { 0x00000001, gm107_fuse_new },
        .gpio     = { 0x00000001, gk104_gpio_new },
        .gsp      = { 0x00000001, gv100_gsp_new },
@@ -2475,7 +2475,7 @@ nv166_chipset = {
        .bus      = { 0x00000001, gf100_bus_new },
        .devinit  = { 0x00000001, tu102_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
-       .fb       = { 0x00000001, gv100_fb_new },
+       .fb       = { 0x00000001, tu102_fb_new },
        .fuse     = { 0x00000001, gm107_fuse_new },
        .gpio     = { 0x00000001, gk104_gpio_new },
        .gsp      = { 0x00000001, gv100_gsp_new },
@@ -2510,7 +2510,7 @@ nv167_chipset = {
        .bus      = { 0x00000001, gf100_bus_new },
        .devinit  = { 0x00000001, tu102_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
-       .fb       = { 0x00000001, gv100_fb_new },
+       .fb       = { 0x00000001, tu102_fb_new },
        .fuse     = { 0x00000001, gm107_fuse_new },
        .gpio     = { 0x00000001, gk104_gpio_new },
        .gsp      = { 0x00000001, gv100_gsp_new },
@@ -2545,7 +2545,7 @@ nv168_chipset = {
        .bus      = { 0x00000001, gf100_bus_new },
        .devinit  = { 0x00000001, tu102_devinit_new },
        .fault    = { 0x00000001, tu102_fault_new },
-       .fb       = { 0x00000001, gv100_fb_new },
+       .fb       = { 0x00000001, tu102_fb_new },
        .fuse     = { 0x00000001, gm107_fuse_new },
        .gpio     = { 0x00000001, gk104_gpio_new },
        .gsp      = { 0x00000001, gv100_gsp_new },
index 393ade9..b7da3ab 100644 (file)
@@ -48,6 +48,16 @@ gm200_flcn_pio_dmem_rd(struct nvkm_falcon *falcon, u8 port, const u8 *img, int l
                img += 4;
                len -= 4;
        }
+
+       /* Sigh.  Tegra PMU FW's init message... */
+       if (len) {
+               u32 data = nvkm_falcon_rd32(falcon, 0x1c4 + (port * 8));
+
+               while (len--) {
+                       *(u8 *)img++ = data & 0xff;
+                       data >>= 8;
+               }
+       }
 }
 
 static void
@@ -64,6 +74,8 @@ gm200_flcn_pio_dmem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int l
                img += 4;
                len -= 4;
        }
+
+       WARN_ON(len);
 }
 
 static void
@@ -74,7 +86,7 @@ gm200_flcn_pio_dmem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 d
 
 const struct nvkm_falcon_func_pio
 gm200_flcn_dmem_pio = {
-       .min = 4,
+       .min = 1,
        .max = 0x100,
        .wr_init = gm200_flcn_pio_dmem_wr_init,
        .wr = gm200_flcn_pio_dmem_wr,
index 634f64f..81a1ad2 100644 (file)
@@ -65,10 +65,33 @@ tu102_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
        return ret;
 }
 
+static int
+tu102_devinit_wait(struct nvkm_device *device)
+{
+       unsigned timeout = 50 + 2000;
+
+       do {
+               if (nvkm_rd32(device, 0x118128) & 0x00000001) {
+                       if ((nvkm_rd32(device, 0x118234) & 0x000000ff) == 0xff)
+                               return 0;
+               }
+
+               usleep_range(1000, 2000);
+       } while (timeout--);
+
+       return -ETIMEDOUT;
+}
+
 int
 tu102_devinit_post(struct nvkm_devinit *base, bool post)
 {
        struct nv50_devinit *init = nv50_devinit(base);
+       int ret;
+
+       ret = tu102_devinit_wait(init->base.subdev.device);
+       if (ret)
+               return ret;
+
        gm200_devinit_preos(init, post);
        return 0;
 }
index 5d0bab8..6ba5120 100644 (file)
@@ -32,6 +32,7 @@ nvkm-y += nvkm/subdev/fb/gp100.o
 nvkm-y += nvkm/subdev/fb/gp102.o
 nvkm-y += nvkm/subdev/fb/gp10b.o
 nvkm-y += nvkm/subdev/fb/gv100.o
+nvkm-y += nvkm/subdev/fb/tu102.o
 nvkm-y += nvkm/subdev/fb/ga100.o
 nvkm-y += nvkm/subdev/fb/ga102.o
 
index 8b7c8ea..5a21b0a 100644 (file)
@@ -40,12 +40,6 @@ ga102_fb_vpr_scrub(struct nvkm_fb *fb)
        return ret;
 }
 
-static bool
-ga102_fb_vpr_scrub_required(struct nvkm_fb *fb)
-{
-       return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0;
-}
-
 static const struct nvkm_fb_func
 ga102_fb = {
        .dtor = gf100_fb_dtor,
@@ -56,7 +50,7 @@ ga102_fb = {
        .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
        .ram_new = ga102_ram_new,
        .default_bigpage = 16,
-       .vpr.scrub_required = ga102_fb_vpr_scrub_required,
+       .vpr.scrub_required = tu102_fb_vpr_scrub_required,
        .vpr.scrub = ga102_fb_vpr_scrub,
 };
 
index 1f01264..0e3c0a8 100644 (file)
@@ -49,8 +49,3 @@ gv100_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, s
 }
 
 MODULE_FIRMWARE("nvidia/gv100/nvdec/scrubber.bin");
-MODULE_FIRMWARE("nvidia/tu102/nvdec/scrubber.bin");
-MODULE_FIRMWARE("nvidia/tu104/nvdec/scrubber.bin");
-MODULE_FIRMWARE("nvidia/tu106/nvdec/scrubber.bin");
-MODULE_FIRMWARE("nvidia/tu116/nvdec/scrubber.bin");
-MODULE_FIRMWARE("nvidia/tu117/nvdec/scrubber.bin");
index ac03eac..f517751 100644 (file)
@@ -89,4 +89,6 @@ bool gp102_fb_vpr_scrub_required(struct nvkm_fb *);
 int gp102_fb_vpr_scrub(struct nvkm_fb *);
 
 int gv100_fb_init_page(struct nvkm_fb *);
+
+bool tu102_fb_vpr_scrub_required(struct nvkm_fb *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/tu102.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/tu102.c
new file mode 100644 (file)
index 0000000..be82af0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "gf100.h"
+#include "ram.h"
+
+bool
+tu102_fb_vpr_scrub_required(struct nvkm_fb *fb)
+{
+       return (nvkm_rd32(fb->subdev.device, 0x1fa80c) & 0x00000010) != 0;
+}
+
+static const struct nvkm_fb_func
+tu102_fb = {
+       .dtor = gf100_fb_dtor,
+       .oneinit = gf100_fb_oneinit,
+       .init = gm200_fb_init,
+       .init_page = gv100_fb_init_page,
+       .init_unkn = gp100_fb_init_unkn,
+       .sysmem.flush_page_init = gf100_fb_sysmem_flush_page_init,
+       .vpr.scrub_required = tu102_fb_vpr_scrub_required,
+       .vpr.scrub = gp102_fb_vpr_scrub,
+       .ram_new = gp100_ram_new,
+       .default_bigpage = 16,
+};
+
+int
+tu102_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
+{
+       return gp102_fb_new_(&tu102_fb, device, type, inst, pfb);
+}
+
+MODULE_FIRMWARE("nvidia/tu102/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/tu104/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/tu106/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/tu116/nvdec/scrubber.bin");
+MODULE_FIRMWARE("nvidia/tu117/nvdec/scrubber.bin");
index a724037..2ed04da 100644 (file)
@@ -225,7 +225,7 @@ gm20b_pmu_init(struct nvkm_pmu *pmu)
 
        pmu->initmsg_received = false;
 
-       nvkm_falcon_load_dmem(falcon, &args, addr_args, sizeof(args), 0);
+       nvkm_falcon_pio_wr(falcon, (u8 *)&args, 0, 0, DMEM, addr_args, sizeof(args), 0, false);
        nvkm_falcon_start(falcon);
        return 0;
 }
index 857a2f0..c924f11 100644 (file)
@@ -1193,14 +1193,11 @@ static int boe_panel_enter_sleep_mode(struct boe_panel *boe)
        return 0;
 }
 
-static int boe_panel_unprepare(struct drm_panel *panel)
+static int boe_panel_disable(struct drm_panel *panel)
 {
        struct boe_panel *boe = to_boe_panel(panel);
        int ret;
 
-       if (!boe->prepared)
-               return 0;
-
        ret = boe_panel_enter_sleep_mode(boe);
        if (ret < 0) {
                dev_err(panel->dev, "failed to set panel off: %d\n", ret);
@@ -1209,6 +1206,16 @@ static int boe_panel_unprepare(struct drm_panel *panel)
 
        msleep(150);
 
+       return 0;
+}
+
+static int boe_panel_unprepare(struct drm_panel *panel)
+{
+       struct boe_panel *boe = to_boe_panel(panel);
+
+       if (!boe->prepared)
+               return 0;
+
        if (boe->desc->discharge_on_disable) {
                regulator_disable(boe->avee);
                regulator_disable(boe->avdd);
@@ -1528,6 +1535,7 @@ static enum drm_panel_orientation boe_panel_get_orientation(struct drm_panel *pa
 }
 
 static const struct drm_panel_funcs boe_panel_funcs = {
+       .disable = boe_panel_disable,
        .unprepare = boe_panel_unprepare,
        .prepare = boe_panel_prepare,
        .enable = boe_panel_enable,
index 0796003..e6403a9 100644 (file)
@@ -3,7 +3,8 @@
 config DRM_PANFROST
        tristate "Panfrost (DRM support for ARM Mali Midgard/Bifrost GPUs)"
        depends on DRM
-       depends on ARM || ARM64 || (COMPILE_TEST && !GENERIC_ATOMIC64)
+       depends on ARM || ARM64 || COMPILE_TEST
+       depends on !GENERIC_ATOMIC64    # for IOMMU_IO_PGTABLE_LPAE
        depends on MMU
        select DRM_SCHED
        select IOMMU_SUPPORT
index 53464af..91f69e6 100644 (file)
@@ -656,18 +656,8 @@ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs = {
        .atomic_check = drm_crtc_helper_atomic_check,
 };
 
-static void ssd130x_crtc_reset(struct drm_crtc *crtc)
-{
-       struct drm_device *drm = crtc->dev;
-       struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
-
-       ssd130x_init(ssd130x);
-
-       drm_atomic_helper_crtc_reset(crtc);
-}
-
 static const struct drm_crtc_funcs ssd130x_crtc_funcs = {
-       .reset = ssd130x_crtc_reset,
+       .reset = drm_atomic_helper_crtc_reset,
        .destroy = drm_crtc_cleanup,
        .set_config = drm_atomic_helper_set_config,
        .page_flip = drm_atomic_helper_page_flip,
@@ -686,6 +676,12 @@ static void ssd130x_encoder_helper_atomic_enable(struct drm_encoder *encoder,
        if (ret)
                return;
 
+       ret = ssd130x_init(ssd130x);
+       if (ret) {
+               ssd130x_power_off(ssd130x);
+               return;
+       }
+
        ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON);
 
        backlight_enable(ssd130x->bl_dev);
index ba3aa0a..da5493f 100644 (file)
@@ -173,7 +173,7 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
 
        clear = src_iter->ops->maps_tt && (!ttm || !ttm_tt_is_populated(ttm));
        if (!(clear && ttm && !(ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC)))
-               ttm_move_memcpy(clear, ttm->num_pages, dst_iter, src_iter);
+               ttm_move_memcpy(clear, PFN_UP(dst_mem->size), dst_iter, src_iter);
 
        if (!src_iter->ops->maps_tt)
                ttm_kmap_iter_linear_io_fini(&_src_iter.io, bdev, src_mem);
index 43d9b3a..c5947ed 100644 (file)
@@ -179,6 +179,7 @@ static void vc4_bo_destroy(struct vc4_bo *bo)
                bo->validated_shader = NULL;
        }
 
+       mutex_destroy(&bo->madv_lock);
        drm_gem_dma_free(&bo->base);
 }
 
@@ -394,7 +395,6 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
 {
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct vc4_bo *bo;
-       int ret;
 
        if (WARN_ON_ONCE(vc4->is_vc5))
                return ERR_PTR(-ENODEV);
@@ -406,9 +406,7 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
        bo->madv = VC4_MADV_WILLNEED;
        refcount_set(&bo->usecnt, 0);
 
-       ret = drmm_mutex_init(dev, &bo->madv_lock);
-       if (ret)
-               return ERR_PTR(ret);
+       mutex_init(&bo->madv_lock);
 
        mutex_lock(&vc4->bo_lock);
        bo->label = VC4_BO_TYPE_KERNEL;
index 12a00d6..5574421 100644 (file)
@@ -3018,7 +3018,8 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
        }
 
        vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
-                                                 vc4_hdmi, "vc4",
+                                                 vc4_hdmi,
+                                                 vc4_hdmi->variant->card_name,
                                                  CEC_CAP_DEFAULTS |
                                                  CEC_CAP_CONNECTOR_INFO, 1);
        ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap);
index 5d05093..da45215 100644 (file)
@@ -126,7 +126,6 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
        void __user *user_bo_handles = NULL;
        struct virtio_gpu_object_array *buflist = NULL;
        struct sync_file *sync_file;
-       int in_fence_fd = exbuf->fence_fd;
        int out_fence_fd = -1;
        void *buf;
        uint64_t fence_ctx;
@@ -152,13 +151,11 @@ static int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
                ring_idx = exbuf->ring_idx;
        }
 
-       exbuf->fence_fd = -1;
-
        virtio_gpu_create_context(dev, file);
        if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) {
                struct dma_fence *in_fence;
 
-               in_fence = sync_file_get_fence(in_fence_fd);
+               in_fence = sync_file_get_fence(exbuf->fence_fd);
 
                if (!in_fence)
                        return -EINVAL;
@@ -358,10 +355,18 @@ static int virtio_gpu_resource_create_ioctl(struct drm_device *dev, void *data,
                drm_gem_object_release(obj);
                return ret;
        }
-       drm_gem_object_put(obj);
 
        rc->res_handle = qobj->hw_res_handle; /* similiar to a VM address */
        rc->bo_handle = handle;
+
+       /*
+        * The handle owns the reference now.  But we must drop our
+        * remaining reference *after* we no longer need to dereference
+        * the obj.  Otherwise userspace could guess the handle and
+        * race closing it from another thread.
+        */
+       drm_gem_object_put(obj);
+
        return 0;
 }
 
@@ -723,11 +728,18 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
                drm_gem_object_release(obj);
                return ret;
        }
-       drm_gem_object_put(obj);
 
        rc_blob->res_handle = bo->hw_res_handle;
        rc_blob->bo_handle = handle;
 
+       /*
+        * The handle owns the reference now.  But we must drop our
+        * remaining reference *after* we no longer need to dereference
+        * the obj.  Otherwise userspace could guess the handle and
+        * race closing it from another thread.
+        */
+       drm_gem_object_put(obj);
+
        return 0;
 }
 
index 932b125..ddf8373 100644 (file)
@@ -254,40 +254,6 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
        kref_put(&base->refcount, ttm_release_base);
 }
 
-/**
- * ttm_base_object_noref_lookup - look up a base object without reference
- * @tfile: The struct ttm_object_file the object is registered with.
- * @key: The object handle.
- *
- * This function looks up a ttm base object and returns a pointer to it
- * without refcounting the pointer. The returned pointer is only valid
- * until ttm_base_object_noref_release() is called, and the object
- * pointed to by the returned pointer may be doomed. Any persistent usage
- * of the object requires a refcount to be taken using kref_get_unless_zero().
- * Iff this function returns successfully it needs to be paired with
- * ttm_base_object_noref_release() and no sleeping- or scheduling functions
- * may be called inbetween these function callse.
- *
- * Return: A pointer to the object if successful or NULL otherwise.
- */
-struct ttm_base_object *
-ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key)
-{
-       struct vmwgfx_hash_item *hash;
-       int ret;
-
-       rcu_read_lock();
-       ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
-       if (ret) {
-               rcu_read_unlock();
-               return NULL;
-       }
-
-       __release(RCU);
-       return hlist_entry(hash, struct ttm_ref_object, hash)->obj;
-}
-EXPORT_SYMBOL(ttm_base_object_noref_lookup);
-
 struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
                                               uint64_t key)
 {
@@ -295,15 +261,16 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
        struct vmwgfx_hash_item *hash;
        int ret;
 
-       rcu_read_lock();
-       ret = ttm_tfile_find_ref_rcu(tfile, key, &hash);
+       spin_lock(&tfile->lock);
+       ret = ttm_tfile_find_ref(tfile, key, &hash);
 
        if (likely(ret == 0)) {
                base = hlist_entry(hash, struct ttm_ref_object, hash)->obj;
                if (!kref_get_unless_zero(&base->refcount))
                        base = NULL;
        }
-       rcu_read_unlock();
+       spin_unlock(&tfile->lock);
+
 
        return base;
 }
index f0ebbe3..8098a38 100644 (file)
@@ -307,18 +307,4 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
 #define ttm_prime_object_kfree(__obj, __prime)         \
        kfree_rcu(__obj, __prime.base.rhead)
 
-struct ttm_base_object *
-ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint64_t key);
-
-/**
- * ttm_base_object_noref_release - release a base object pointer looked up
- * without reference
- *
- * Releases a base object pointer looked up with ttm_base_object_noref_lookup().
- */
-static inline void ttm_base_object_noref_release(void)
-{
-       __acquire(RCU);
-       rcu_read_unlock();
-}
 #endif
index 321c551..aa1cd51 100644 (file)
@@ -715,44 +715,6 @@ int vmw_user_bo_lookup(struct drm_file *filp,
        return 0;
 }
 
-/**
- * vmw_user_bo_noref_lookup - Look up a vmw user buffer object without reference
- * @filp: The TTM object file the handle is registered with.
- * @handle: The user buffer object handle.
- *
- * This function looks up a struct vmw_bo and returns a pointer to the
- * struct vmw_buffer_object it derives from without refcounting the pointer.
- * The returned pointer is only valid until vmw_user_bo_noref_release() is
- * called, and the object pointed to by the returned pointer may be doomed.
- * Any persistent usage of the object requires a refcount to be taken using
- * ttm_bo_reference_unless_doomed(). Iff this function returns successfully it
- * needs to be paired with vmw_user_bo_noref_release() and no sleeping-
- * or scheduling functions may be called in between these function calls.
- *
- * Return: A struct vmw_buffer_object pointer if successful or negative
- * error pointer on failure.
- */
-struct vmw_buffer_object *
-vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle)
-{
-       struct vmw_buffer_object *vmw_bo;
-       struct ttm_buffer_object *bo;
-       struct drm_gem_object *gobj = drm_gem_object_lookup(filp, handle);
-
-       if (!gobj) {
-               DRM_ERROR("Invalid buffer object handle 0x%08lx.\n",
-                         (unsigned long)handle);
-               return ERR_PTR(-ESRCH);
-       }
-       vmw_bo = gem_to_vmw_bo(gobj);
-       bo = ttm_bo_get_unless_zero(&vmw_bo->base);
-       vmw_bo = vmw_buffer_object(bo);
-       drm_gem_object_put(gobj);
-
-       return vmw_bo;
-}
-
-
 /**
  * vmw_bo_fence_single - Utility function to fence a single TTM buffer
  *                       object without unreserving it.
index b062b02..5acbf58 100644 (file)
@@ -830,12 +830,7 @@ extern int vmw_user_resource_lookup_handle(
        uint32_t handle,
        const struct vmw_user_resource_conv *converter,
        struct vmw_resource **p_res);
-extern struct vmw_resource *
-vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
-                                     struct ttm_object_file *tfile,
-                                     uint32_t handle,
-                                     const struct vmw_user_resource_conv *
-                                     converter);
+
 extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv);
 extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -874,15 +869,6 @@ static inline bool vmw_resource_mob_attached(const struct vmw_resource *res)
        return !RB_EMPTY_NODE(&res->mob_node);
 }
 
-/**
- * vmw_user_resource_noref_release - release a user resource pointer looked up
- * without reference
- */
-static inline void vmw_user_resource_noref_release(void)
-{
-       ttm_base_object_noref_release();
-}
-
 /**
  * Buffer object helper functions - vmwgfx_bo.c
  */
@@ -934,8 +920,6 @@ extern void vmw_bo_unmap(struct vmw_buffer_object *vbo);
 extern void vmw_bo_move_notify(struct ttm_buffer_object *bo,
                               struct ttm_resource *mem);
 extern void vmw_bo_swap_notify(struct ttm_buffer_object *bo);
-extern struct vmw_buffer_object *
-vmw_user_bo_noref_lookup(struct drm_file *filp, u32 handle);
 
 /**
  * vmw_bo_adjust_prio - Adjust the buffer object eviction priority
index a5379f6..a44d53e 100644 (file)
@@ -290,20 +290,26 @@ static void vmw_execbuf_rcache_update(struct vmw_res_cache_entry *rcache,
        rcache->valid_handle = 0;
 }
 
+enum vmw_val_add_flags {
+       vmw_val_add_flag_none  =      0,
+       vmw_val_add_flag_noctx = 1 << 0,
+};
+
 /**
- * vmw_execbuf_res_noref_val_add - Add a resource described by an unreferenced
- * rcu-protected pointer to the validation list.
+ * vmw_execbuf_res_val_add - Add a resource to the validation list.
  *
  * @sw_context: Pointer to the software context.
  * @res: Unreferenced rcu-protected pointer to the resource.
  * @dirty: Whether to change dirty status.
+ * @flags: specifies whether to use the context or not
  *
  * Returns: 0 on success. Negative error code on failure. Typical error codes
  * are %-EINVAL on inconsistency and %-ESRCH if the resource was doomed.
  */
-static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
-                                        struct vmw_resource *res,
-                                        u32 dirty)
+static int vmw_execbuf_res_val_add(struct vmw_sw_context *sw_context,
+                                  struct vmw_resource *res,
+                                  u32 dirty,
+                                  u32 flags)
 {
        struct vmw_private *dev_priv = res->dev_priv;
        int ret;
@@ -318,24 +324,30 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
                if (dirty)
                        vmw_validation_res_set_dirty(sw_context->ctx,
                                                     rcache->private, dirty);
-               vmw_user_resource_noref_release();
                return 0;
        }
 
-       priv_size = vmw_execbuf_res_size(dev_priv, res_type);
-       ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
-                                         dirty, (void **)&ctx_info,
-                                         &first_usage);
-       vmw_user_resource_noref_release();
-       if (ret)
-               return ret;
+       if ((flags & vmw_val_add_flag_noctx) != 0) {
+               ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
+                                                 (void **)&ctx_info, NULL);
+               if (ret)
+                       return ret;
 
-       if (priv_size && first_usage) {
-               ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
-                                             ctx_info);
-               if (ret) {
-                       VMW_DEBUG_USER("Failed first usage context setup.\n");
+       } else {
+               priv_size = vmw_execbuf_res_size(dev_priv, res_type);
+               ret = vmw_validation_add_resource(sw_context->ctx, res, priv_size,
+                                                 dirty, (void **)&ctx_info,
+                                                 &first_usage);
+               if (ret)
                        return ret;
+
+               if (priv_size && first_usage) {
+                       ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, res,
+                                                     ctx_info);
+                       if (ret) {
+                               VMW_DEBUG_USER("Failed first usage context setup.\n");
+                               return ret;
+                       }
                }
        }
 
@@ -343,43 +355,6 @@ static int vmw_execbuf_res_noref_val_add(struct vmw_sw_context *sw_context,
        return 0;
 }
 
-/**
- * vmw_execbuf_res_noctx_val_add - Add a non-context resource to the resource
- * validation list if it's not already on it
- *
- * @sw_context: Pointer to the software context.
- * @res: Pointer to the resource.
- * @dirty: Whether to change dirty status.
- *
- * Returns: Zero on success. Negative error code on failure.
- */
-static int vmw_execbuf_res_noctx_val_add(struct vmw_sw_context *sw_context,
-                                        struct vmw_resource *res,
-                                        u32 dirty)
-{
-       struct vmw_res_cache_entry *rcache;
-       enum vmw_res_type res_type = vmw_res_type(res);
-       void *ptr;
-       int ret;
-
-       rcache = &sw_context->res_cache[res_type];
-       if (likely(rcache->valid && rcache->res == res)) {
-               if (dirty)
-                       vmw_validation_res_set_dirty(sw_context->ctx,
-                                                    rcache->private, dirty);
-               return 0;
-       }
-
-       ret = vmw_validation_add_resource(sw_context->ctx, res, 0, dirty,
-                                         &ptr, NULL);
-       if (ret)
-               return ret;
-
-       vmw_execbuf_rcache_update(rcache, res, ptr);
-
-       return 0;
-}
-
 /**
  * vmw_view_res_val_add - Add a view and the surface it's pointing to to the
  * validation list
@@ -398,13 +373,13 @@ static int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
         * First add the resource the view is pointing to, otherwise it may be
         * swapped out when the view is validated.
         */
-       ret = vmw_execbuf_res_noctx_val_add(sw_context, vmw_view_srf(view),
-                                           vmw_view_dirtying(view));
+       ret = vmw_execbuf_res_val_add(sw_context, vmw_view_srf(view),
+                                     vmw_view_dirtying(view), vmw_val_add_flag_noctx);
        if (ret)
                return ret;
 
-       return vmw_execbuf_res_noctx_val_add(sw_context, view,
-                                            VMW_RES_DIRTY_NONE);
+       return vmw_execbuf_res_val_add(sw_context, view, VMW_RES_DIRTY_NONE,
+                                      vmw_val_add_flag_noctx);
 }
 
 /**
@@ -475,8 +450,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
                        if (IS_ERR(res))
                                continue;
 
-                       ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
-                                                           VMW_RES_DIRTY_SET);
+                       ret = vmw_execbuf_res_val_add(sw_context, res,
+                                                     VMW_RES_DIRTY_SET,
+                                                     vmw_val_add_flag_noctx);
                        if (unlikely(ret != 0))
                                return ret;
                }
@@ -490,9 +466,9 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
                if (vmw_res_type(entry->res) == vmw_res_view)
                        ret = vmw_view_res_val_add(sw_context, entry->res);
                else
-                       ret = vmw_execbuf_res_noctx_val_add
-                               (sw_context, entry->res,
-                                vmw_binding_dirtying(entry->bt));
+                       ret = vmw_execbuf_res_val_add(sw_context, entry->res,
+                                                     vmw_binding_dirtying(entry->bt),
+                                                     vmw_val_add_flag_noctx);
                if (unlikely(ret != 0))
                        break;
        }
@@ -658,7 +634,8 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
 {
        struct vmw_res_cache_entry *rcache = &sw_context->res_cache[res_type];
        struct vmw_resource *res;
-       int ret;
+       int ret = 0;
+       bool needs_unref = false;
 
        if (p_res)
                *p_res = NULL;
@@ -683,17 +660,18 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
                if (ret)
                        return ret;
 
-               res = vmw_user_resource_noref_lookup_handle
-                       (dev_priv, sw_context->fp->tfile, *id_loc, converter);
-               if (IS_ERR(res)) {
+               ret = vmw_user_resource_lookup_handle
+                       (dev_priv, sw_context->fp->tfile, *id_loc, converter, &res);
+               if (ret != 0) {
                        VMW_DEBUG_USER("Could not find/use resource 0x%08x.\n",
                                       (unsigned int) *id_loc);
-                       return PTR_ERR(res);
+                       return ret;
                }
+               needs_unref = true;
 
-               ret = vmw_execbuf_res_noref_val_add(sw_context, res, dirty);
+               ret = vmw_execbuf_res_val_add(sw_context, res, dirty, vmw_val_add_flag_none);
                if (unlikely(ret != 0))
-                       return ret;
+                       goto res_check_done;
 
                if (rcache->valid && rcache->res == res) {
                        rcache->valid_handle = true;
@@ -708,7 +686,11 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
        if (p_res)
                *p_res = res;
 
-       return 0;
+res_check_done:
+       if (needs_unref)
+               vmw_resource_unreference(&res);
+
+       return ret;
 }
 
 /**
@@ -1171,9 +1153,9 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
        int ret;
 
        vmw_validation_preload_bo(sw_context->ctx);
-       vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
-       if (IS_ERR(vmw_bo)) {
-               VMW_DEBUG_USER("Could not find or use MOB buffer.\n");
+       ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
+       if (ret != 0) {
+               drm_dbg(&dev_priv->drm, "Could not find or use MOB buffer.\n");
                return PTR_ERR(vmw_bo);
        }
        ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, true, false);
@@ -1225,9 +1207,9 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        int ret;
 
        vmw_validation_preload_bo(sw_context->ctx);
-       vmw_bo = vmw_user_bo_noref_lookup(sw_context->filp, handle);
-       if (IS_ERR(vmw_bo)) {
-               VMW_DEBUG_USER("Could not find or use GMR region.\n");
+       ret = vmw_user_bo_lookup(sw_context->filp, handle, &vmw_bo);
+       if (ret != 0) {
+               drm_dbg(&dev_priv->drm, "Could not find or use GMR region.\n");
                return PTR_ERR(vmw_bo);
        }
        ret = vmw_validation_add_bo(sw_context->ctx, vmw_bo, false, false);
@@ -2025,8 +2007,9 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
                res = vmw_shader_lookup(vmw_context_res_man(ctx),
                                        cmd->body.shid, cmd->body.type);
                if (!IS_ERR(res)) {
-                       ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
-                                                           VMW_RES_DIRTY_NONE);
+                       ret = vmw_execbuf_res_val_add(sw_context, res,
+                                                     VMW_RES_DIRTY_NONE,
+                                                     vmw_val_add_flag_noctx);
                        if (unlikely(ret != 0))
                                return ret;
 
@@ -2273,8 +2256,9 @@ static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
                        return PTR_ERR(res);
                }
 
-               ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
-                                                   VMW_RES_DIRTY_NONE);
+               ret = vmw_execbuf_res_val_add(sw_context, res,
+                                             VMW_RES_DIRTY_NONE,
+                                             vmw_val_add_flag_noctx);
                if (ret)
                        return ret;
        }
@@ -2777,8 +2761,8 @@ static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
                return PTR_ERR(res);
        }
 
-       ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
-                                           VMW_RES_DIRTY_NONE);
+       ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
+                                     vmw_val_add_flag_noctx);
        if (ret) {
                VMW_DEBUG_USER("Error creating resource validation node.\n");
                return ret;
@@ -3098,8 +3082,8 @@ static int vmw_cmd_dx_bind_streamoutput(struct vmw_private *dev_priv,
 
        vmw_dx_streamoutput_set_size(res, cmd->body.sizeInBytes);
 
-       ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
-                                           VMW_RES_DIRTY_NONE);
+       ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
+                                     vmw_val_add_flag_noctx);
        if (ret) {
                DRM_ERROR("Error creating resource validation node.\n");
                return ret;
@@ -3148,8 +3132,8 @@ static int vmw_cmd_dx_set_streamoutput(struct vmw_private *dev_priv,
                return 0;
        }
 
-       ret = vmw_execbuf_res_noctx_val_add(sw_context, res,
-                                           VMW_RES_DIRTY_NONE);
+       ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_NONE,
+                                     vmw_val_add_flag_noctx);
        if (ret) {
                DRM_ERROR("Error creating resource validation node.\n");
                return ret;
@@ -4066,22 +4050,26 @@ static int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
        if (ret)
                return ret;
 
-       res = vmw_user_resource_noref_lookup_handle
+       ret = vmw_user_resource_lookup_handle
                (dev_priv, sw_context->fp->tfile, handle,
-                user_context_converter);
-       if (IS_ERR(res)) {
+                user_context_converter, &res);
+       if (ret != 0) {
                VMW_DEBUG_USER("Could not find or user DX context 0x%08x.\n",
                               (unsigned int) handle);
-               return PTR_ERR(res);
+               return ret;
        }
 
-       ret = vmw_execbuf_res_noref_val_add(sw_context, res, VMW_RES_DIRTY_SET);
-       if (unlikely(ret != 0))
+       ret = vmw_execbuf_res_val_add(sw_context, res, VMW_RES_DIRTY_SET,
+                                     vmw_val_add_flag_none);
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&res);
                return ret;
+       }
 
        sw_context->dx_ctx_node = vmw_execbuf_info_from_res(sw_context, res);
        sw_context->man = vmw_context_res_man(res);
 
+       vmw_resource_unreference(&res);
        return 0;
 }
 
old mode 100755 (executable)
new mode 100644 (file)
index f66caa5..c7d645e 100644 (file)
@@ -281,39 +281,6 @@ out_bad_resource:
        return ret;
 }
 
-/**
- * vmw_user_resource_noref_lookup_handle - lookup a struct resource from a
- * TTM user-space handle and perform basic type checks
- *
- * @dev_priv:     Pointer to a device private struct
- * @tfile:        Pointer to a struct ttm_object_file identifying the caller
- * @handle:       The TTM user-space handle
- * @converter:    Pointer to an object describing the resource type
- *
- * If the handle can't be found or is associated with an incorrect resource
- * type, -EINVAL will be returned.
- */
-struct vmw_resource *
-vmw_user_resource_noref_lookup_handle(struct vmw_private *dev_priv,
-                                     struct ttm_object_file *tfile,
-                                     uint32_t handle,
-                                     const struct vmw_user_resource_conv
-                                     *converter)
-{
-       struct ttm_base_object *base;
-
-       base = ttm_base_object_noref_lookup(tfile, handle);
-       if (!base)
-               return ERR_PTR(-ESRCH);
-
-       if (unlikely(ttm_base_object_type(base) != converter->object_type)) {
-               ttm_base_object_noref_release();
-               return ERR_PTR(-EINVAL);
-       }
-
-       return converter->base_obj_to_res(base);
-}
-
 /*
  * Helper function that looks either a surface or bo.
  *
index 0d8e6bd..90996c1 100644 (file)
@@ -717,7 +717,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
        return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
 
-static int xen_drv_remove(struct xenbus_device *dev)
+static void xen_drv_remove(struct xenbus_device *dev)
 {
        struct xen_drm_front_info *front_info = dev_get_drvdata(&dev->dev);
        int to = 100;
@@ -751,7 +751,6 @@ static int xen_drv_remove(struct xenbus_device *dev)
 
        xen_drm_drv_fini(front_info);
        xenbus_frontend_closed(dev);
-       return 0;
 }
 
 static const struct xenbus_device_id xen_driver_ids[] = {
index ab125f7..c751d12 100644 (file)
@@ -227,6 +227,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
        cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
        if (cl_data->num_hid_devices == 0)
                return -ENODEV;
+       cl_data->is_any_sensor_enabled = false;
 
        INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
        INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
@@ -282,11 +283,12 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
                }
                rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);
                if (rc)
-                       return rc;
+                       goto cleanup;
                mp2_ops->start(privdata, info);
                status = amd_sfh_wait_for_response
                                (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED);
                if (status == SENSOR_ENABLED) {
+                       cl_data->is_any_sensor_enabled = true;
                        cl_data->sensor_sts[i] = SENSOR_ENABLED;
                        rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
                        if (rc) {
@@ -301,19 +303,26 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
                                        cl_data->sensor_sts[i]);
                                goto cleanup;
                        }
+               } else {
+                       cl_data->sensor_sts[i] = SENSOR_DISABLED;
+                       dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
+                               cl_data->sensor_idx[i],
+                               get_sensor_name(cl_data->sensor_idx[i]),
+                               cl_data->sensor_sts[i]);
                }
                dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
                        cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
                        cl_data->sensor_sts[i]);
        }
-       if (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0) {
+       if (!cl_data->is_any_sensor_enabled ||
+          (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0)) {
                amd_sfh_hid_client_deinit(privdata);
                for (i = 0; i < cl_data->num_hid_devices; i++) {
                        devm_kfree(dev, cl_data->feature_report[i]);
                        devm_kfree(dev, in_data->input_report[i]);
                        devm_kfree(dev, cl_data->report_descr[i]);
                }
-               dev_warn(dev, "Failed to discover, sensors not enabled\n");
+               dev_warn(dev, "Failed to discover, sensors not enabled is %d\n", cl_data->is_any_sensor_enabled);
                return -EOPNOTSUPP;
        }
        schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
index 3754fb4..5280368 100644 (file)
@@ -32,6 +32,7 @@ struct amd_input_data {
 struct amdtp_cl_data {
        u8 init_done;
        u32 cur_hid_dev;
+       bool is_any_sensor_enabled;
        u32 hid_dev_count;
        u32 num_hid_devices;
        struct device_info *hid_devices;
index 4da2f9f..a1d6e08 100644 (file)
@@ -160,7 +160,7 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
                }
                rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);
                if (rc)
-                       return rc;
+                       goto cleanup;
 
                writel(0, privdata->mmio + AMD_P2C_MSG(0));
                mp2_ops->start(privdata, info);
index 467d789..25ed7b9 100644 (file)
@@ -60,7 +60,6 @@ static int betopff_init(struct hid_device *hid)
        struct list_head *report_list =
                        &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct input_dev *dev;
-       int field_count = 0;
        int error;
        int i, j;
 
@@ -86,19 +85,21 @@ static int betopff_init(struct hid_device *hid)
         * -----------------------------------------
         * Do init them with default value.
         */
+       if (report->maxfield < 4) {
+               hid_err(hid, "not enough fields in the report: %d\n",
+                               report->maxfield);
+               return -ENODEV;
+       }
        for (i = 0; i < report->maxfield; i++) {
+               if (report->field[i]->report_count < 1) {
+                       hid_err(hid, "no values in the field\n");
+                       return -ENODEV;
+               }
                for (j = 0; j < report->field[i]->report_count; j++) {
                        report->field[i]->value[j] = 0x00;
-                       field_count++;
                }
        }
 
-       if (field_count < 4) {
-               hid_err(hid, "not enough fields in the report: %d\n",
-                               field_count);
-               return -ENODEV;
-       }
-
        betopff = kzalloc(sizeof(*betopff), GFP_KERNEL);
        if (!betopff)
                return -ENOMEM;
index e8c5e3a..e8b1666 100644 (file)
@@ -344,6 +344,11 @@ static int bigben_probe(struct hid_device *hid,
        }
 
        report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       if (list_empty(report_list)) {
+               hid_err(hid, "no output report found\n");
+               error = -ENODEV;
+               goto error_hw_stop;
+       }
        bigben->report = list_entry(report_list->next,
                struct hid_report, list);
 
index bd47628..5c72aef 100644 (file)
@@ -993,8 +993,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
                 * Validating on id 0 means we should examine the first
                 * report in the list.
                 */
-               report = list_entry(
-                               hid->report_enum[type].report_list.next,
+               report = list_first_entry_or_null(
+                               &hid->report_enum[type].report_list,
                                struct hid_report, list);
        } else {
                report = hid->report_enum[type].report_id_hash[id];
@@ -1202,6 +1202,7 @@ int hid_open_report(struct hid_device *device)
        __u8 *end;
        __u8 *next;
        int ret;
+       int i;
        static int (*dispatch_type[])(struct hid_parser *parser,
                                      struct hid_item *item) = {
                hid_parser_main,
@@ -1252,6 +1253,8 @@ int hid_open_report(struct hid_device *device)
                goto err;
        }
        device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+       for (i = 0; i < HID_DEFAULT_NUM_COLLECTIONS; i++)
+               device->collection[i].parent_idx = -1;
 
        ret = -EINVAL;
        while ((next = fetch_item(start, end, &item)) != NULL) {
index e59e991..4fa45ee 100644 (file)
@@ -12,6 +12,7 @@
  *  Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org>
  *  Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com>
  *  Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red>
+ *  Copyright (c) 2022 Takahiro Fujii <fujii@xaxxi.net>
  */
 
 /*
@@ -89,7 +90,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        case USB_DEVICE_ID_ELECOM_M_DT1URBK:
        case USB_DEVICE_ID_ELECOM_M_DT1DRBK:
        case USB_DEVICE_ID_ELECOM_M_HT1URBK:
-       case USB_DEVICE_ID_ELECOM_M_HT1DRBK:
+       case USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D:
                /*
                 * Report descriptor format:
                 * 12: button bit count
@@ -99,6 +100,16 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                 */
                mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8);
                break;
+       case USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C:
+               /*
+                * Report descriptor format:
+                * 22: button bit count
+                * 30: padding bit count
+                * 24: button report size
+                * 16: button usage maximum
+                */
+               mouse_button_fixup(hdev, rdesc, *rsize, 22, 30, 24, 16, 8);
+               break;
        }
        return rdesc;
 }
@@ -112,7 +123,8 @@ static const struct hid_device_id elecom_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, elecom_devices);
index 82713ef..9e36b4c 100644 (file)
 #define USB_DEVICE_ID_CH_AXIS_295      0x001c
 
 #define USB_VENDOR_ID_CHERRY           0x046a
-#define USB_DEVICE_ID_CHERRY_MOUSE_000C        0x000c
 #define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
 #define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR    0x0027
 
 #define I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100   0x29CF
 #define I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV    0x2CF9
 #define I2C_DEVICE_ID_HP_SPECTRE_X360_15       0x2817
+#define I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG  0x29DF
+#define I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN 0x2BC8
 #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544
 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN   0x2706
 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN   0x261A
 #define USB_DEVICE_ID_ELECOM_M_DT1URBK 0x00fe
 #define USB_DEVICE_ID_ELECOM_M_DT1DRBK 0x00ff
 #define USB_DEVICE_ID_ELECOM_M_HT1URBK 0x010c
-#define USB_DEVICE_ID_ELECOM_M_HT1DRBK 0x010d
+#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D    0x010d
+#define USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C    0x011c
 
 #define USB_VENDOR_ID_DREAM_CHEEKY     0x1d34
 #define USB_DEVICE_ID_DREAM_CHEEKY_WN  0x0004
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540   0x0075
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640   0x0094
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
+#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2      0x0905
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S     0x0909
 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
index 9b59e43..77c8c49 100644 (file)
@@ -370,6 +370,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
                USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),
          HID_BATTERY_QUIRK_IGNORE },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN),
+         HID_BATTERY_QUIRK_IGNORE },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),
          HID_BATTERY_QUIRK_IGNORE },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
@@ -384,6 +386,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
          HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
          HID_BATTERY_QUIRK_IGNORE },
+       { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG),
+         HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
          HID_BATTERY_QUIRK_IGNORE },
        { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN),
index abf2c95..9c1ee8e 100644 (file)
@@ -3978,7 +3978,8 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
        }
 
        hidpp_initialize_battery(hidpp);
-       hidpp_initialize_hires_scroll(hidpp);
+       if (!hid_is_usb(hidpp->hid_dev))
+               hidpp_initialize_hires_scroll(hidpp);
 
        /* forward current battery state */
        if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
index f399bf0..27c4089 100644 (file)
@@ -944,6 +944,7 @@ ATTRIBUTE_GROUPS(ps_device);
 
 static int dualsense_get_calibration_data(struct dualsense *ds)
 {
+       struct hid_device *hdev = ds->base.hdev;
        short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus;
        short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus;
        short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus;
@@ -954,6 +955,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
        int speed_2x;
        int range_2g;
        int ret = 0;
+       int i;
        uint8_t *buf;
 
        buf = kzalloc(DS_FEATURE_REPORT_CALIBRATION_SIZE, GFP_KERNEL);
@@ -1005,6 +1007,21 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
        ds->gyro_calib_data[2].sens_numer = speed_2x*DS_GYRO_RES_PER_DEG_S;
        ds->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus;
 
+       /*
+        * Sanity check gyro calibration data. This is needed to prevent crashes
+        * during report handling of virtual, clone or broken devices not implementing
+        * calibration data properly.
+        */
+       for (i = 0; i < ARRAY_SIZE(ds->gyro_calib_data); i++) {
+               if (ds->gyro_calib_data[i].sens_denom == 0) {
+                       hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.",
+                                       ds->gyro_calib_data[i].abs_code);
+                       ds->gyro_calib_data[i].bias = 0;
+                       ds->gyro_calib_data[i].sens_numer = DS_GYRO_RANGE;
+                       ds->gyro_calib_data[i].sens_denom = S16_MAX;
+               }
+       }
+
        /*
         * Set accelerometer calibration and normalization parameters.
         * Data values will be normalized to 1/DS_ACC_RES_PER_G g.
@@ -1027,6 +1044,21 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
        ds->accel_calib_data[2].sens_numer = 2*DS_ACC_RES_PER_G;
        ds->accel_calib_data[2].sens_denom = range_2g;
 
+       /*
+        * Sanity check accelerometer calibration data. This is needed to prevent crashes
+        * during report handling of virtual, clone or broken devices not implementing calibration
+        * data properly.
+        */
+       for (i = 0; i < ARRAY_SIZE(ds->accel_calib_data); i++) {
+               if (ds->accel_calib_data[i].sens_denom == 0) {
+                       hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.",
+                                       ds->accel_calib_data[i].abs_code);
+                       ds->accel_calib_data[i].bias = 0;
+                       ds->accel_calib_data[i].sens_numer = DS_ACC_RANGE;
+                       ds->accel_calib_data[i].sens_denom = S16_MAX;
+               }
+       }
+
 err_free:
        kfree(buf);
        return ret;
@@ -1737,6 +1769,7 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
        int speed_2x;
        int range_2g;
        int ret = 0;
+       int i;
        uint8_t *buf;
 
        if (ds4->base.hdev->bus == BUS_USB) {
@@ -1830,6 +1863,21 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
        ds4->gyro_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S;
        ds4->gyro_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus;
 
+       /*
+        * Sanity check gyro calibration data. This is needed to prevent crashes
+        * during report handling of virtual, clone or broken devices not implementing
+        * calibration data properly.
+        */
+       for (i = 0; i < ARRAY_SIZE(ds4->gyro_calib_data); i++) {
+               if (ds4->gyro_calib_data[i].sens_denom == 0) {
+                       hid_warn(hdev, "Invalid gyro calibration data for axis (%d), disabling calibration.",
+                                       ds4->gyro_calib_data[i].abs_code);
+                       ds4->gyro_calib_data[i].bias = 0;
+                       ds4->gyro_calib_data[i].sens_numer = DS4_GYRO_RANGE;
+                       ds4->gyro_calib_data[i].sens_denom = S16_MAX;
+               }
+       }
+
        /*
         * Set accelerometer calibration and normalization parameters.
         * Data values will be normalized to 1/DS4_ACC_RES_PER_G g.
@@ -1852,6 +1900,21 @@ static int dualshock4_get_calibration_data(struct dualshock4 *ds4)
        ds4->accel_calib_data[2].sens_numer = 2*DS4_ACC_RES_PER_G;
        ds4->accel_calib_data[2].sens_denom = range_2g;
 
+       /*
+        * Sanity check accelerometer calibration data. This is needed to prevent crashes
+        * during report handling of virtual, clone or broken devices not implementing calibration
+        * data properly.
+        */
+       for (i = 0; i < ARRAY_SIZE(ds4->accel_calib_data); i++) {
+               if (ds4->accel_calib_data[i].sens_denom == 0) {
+                       hid_warn(hdev, "Invalid accelerometer calibration data for axis (%d), disabling calibration.",
+                                       ds4->accel_calib_data[i].abs_code);
+                       ds4->accel_calib_data[i].bias = 0;
+                       ds4->accel_calib_data[i].sens_numer = DS4_ACC_RANGE;
+                       ds4->accel_calib_data[i].sens_denom = S16_MAX;
+               }
+       }
+
 err_free:
        kfree(buf);
        return ret;
index 0e9702c..5bc91f6 100644 (file)
@@ -54,7 +54,6 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS), HID_QUIRK_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE), HID_QUIRK_NOGET },
-       { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_MOUSE_000C), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB), HID_QUIRK_NO_INIT_REPORTS },
        { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB), HID_QUIRK_NO_INIT_REPORTS },
@@ -394,7 +393,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_010D) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK_011C) },
 #endif
 #if IS_ENABLED(CONFIG_HID_ELO)
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
index 7fa6fe0..cfbbc39 100644 (file)
@@ -525,6 +525,8 @@ static const struct hid_device_id uclogic_devices[] = {
                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
+                               USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
index cd1233d..3c5eea3 100644 (file)
@@ -1655,6 +1655,8 @@ int uclogic_params_init(struct uclogic_params *params,
                break;
        case VID_PID(USB_VENDOR_ID_UGEE,
                     USB_DEVICE_ID_UGEE_PARBLO_A610_PRO):
+       case VID_PID(USB_VENDOR_ID_UGEE,
+                    USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01_V2):
        case VID_PID(USB_VENDOR_ID_UGEE,
                     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
        case VID_PID(USB_VENDOR_ID_UGEE,
index 40554c8..00046cb 100644 (file)
@@ -104,6 +104,11 @@ void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev,
        int required_slots = (size / DMA_SLOT_SIZE)
                + 1 * (size % DMA_SLOT_SIZE != 0);
 
+       if (!dev->ishtp_dma_tx_map) {
+               dev_err(dev->devc, "Fail to allocate Tx map\n");
+               return NULL;
+       }
+
        spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags);
        for (i = 0; i <= (dev->ishtp_dma_num_slots - required_slots); i++) {
                free = 1;
@@ -150,6 +155,11 @@ void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev,
                return;
        }
 
+       if (!dev->ishtp_dma_tx_map) {
+               dev_err(dev->devc, "Fail to allocate Tx map\n");
+               return;
+       }
+
        i = (msg_addr - dev->ishtp_host_dma_tx_buf) / DMA_SLOT_SIZE;
        spin_lock_irqsave(&dev->ishtp_dma_tx_lock, flags);
        for (j = 0; j < acked_slots; j++) {
index cbe43e2..64ac5bd 100644 (file)
@@ -1963,7 +1963,7 @@ static void  hv_balloon_debugfs_init(struct hv_dynmem_device *b)
 
 static void  hv_balloon_debugfs_exit(struct hv_dynmem_device *b)
 {
-       debugfs_remove(debugfs_lookup("hv-balloon", NULL));
+       debugfs_lookup_and_remove("hv-balloon", NULL);
 }
 
 #else
index bdf3b50..c1c74ce 100644 (file)
 #define SDA_HOLD_TIME          0x90
 
 /**
- * axxia_i2c_dev - I2C device context
+ * struct axxia_i2c_dev - I2C device context
  * @base: pointer to register struct
  * @msg: pointer to current message
  * @msg_r: pointer to current read message (sequence transfer)
index a3240ec..581e02c 100644 (file)
@@ -351,7 +351,8 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
                 *
                 * If your hardware is free from tHD;STA issue, try this one.
                 */
-               return DIV_ROUND_CLOSEST(ic_clk * tSYMBOL, MICRO) - 8 + offset;
+               return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) -
+                      8 + offset;
        else
                /*
                 * Conditional expression:
@@ -367,7 +368,8 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
                 * The reason why we need to take into account "tf" here,
                 * is the same as described in i2c_dw_scl_lcnt().
                 */
-               return DIV_ROUND_CLOSEST(ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset;
+               return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) -
+                      3 + offset;
 }
 
 u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
@@ -383,7 +385,8 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
         * account the fall time of SCL signal (tf).  Default tf value
         * should be 0.3 us, for safety.
         */
-       return DIV_ROUND_CLOSEST(ic_clk * (tLOW + tf), MICRO) - 1 + offset;
+       return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) -
+              1 + offset;
 }
 
 int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
index e499f96..782fe1e 100644 (file)
@@ -396,6 +396,8 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
        { PCI_VDEVICE(ATI,  0x73a4), navi_amd },
        { PCI_VDEVICE(ATI,  0x73e4), navi_amd },
        { PCI_VDEVICE(ATI,  0x73c4), navi_amd },
+       { PCI_VDEVICE(ATI,  0x7444), navi_amd },
+       { PCI_VDEVICE(ATI,  0x7464), navi_amd },
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
index ba043b5..74182db 100644 (file)
@@ -351,13 +351,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
 
        if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
                dev_pm_set_driver_flags(&pdev->dev,
-                                       DPM_FLAG_SMART_PREPARE |
-                                       DPM_FLAG_MAY_SKIP_RESUME);
+                                       DPM_FLAG_SMART_PREPARE);
        } else {
                dev_pm_set_driver_flags(&pdev->dev,
                                        DPM_FLAG_SMART_PREPARE |
-                                       DPM_FLAG_SMART_SUSPEND |
-                                       DPM_FLAG_MAY_SKIP_RESUME);
+                                       DPM_FLAG_SMART_SUSPEND);
        }
 
        device_enable_async_suspend(&pdev->dev);
@@ -419,21 +417,8 @@ static int dw_i2c_plat_prepare(struct device *dev)
         */
        return !has_acpi_companion(dev);
 }
-
-static void dw_i2c_plat_complete(struct device *dev)
-{
-       /*
-        * The device can only be in runtime suspend at this point if it has not
-        * been resumed throughout the ending system suspend/resume cycle, so if
-        * the platform firmware might mess up with it, request the runtime PM
-        * framework to resume it.
-        */
-       if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
-               pm_request_resume(dev);
-}
 #else
 #define dw_i2c_plat_prepare    NULL
-#define dw_i2c_plat_complete   NULL
 #endif
 
 #ifdef CONFIG_PM
@@ -483,7 +468,6 @@ static int __maybe_unused dw_i2c_plat_resume(struct device *dev)
 
 static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
        .prepare = dw_i2c_plat_prepare,
-       .complete = dw_i2c_plat_complete,
        SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
        SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL)
 };
index 5af5cff..d113bed 100644 (file)
@@ -826,8 +826,8 @@ static int mxs_i2c_probe(struct platform_device *pdev)
        /* Setup the DMA */
        i2c->dmach = dma_request_chan(dev, "rx-tx");
        if (IS_ERR(i2c->dmach)) {
-               dev_err(dev, "Failed to request dma\n");
-               return PTR_ERR(i2c->dmach);
+               return dev_err_probe(dev, PTR_ERR(i2c->dmach),
+                                    "Failed to request dma\n");
        }
 
        platform_set_drvdata(pdev, i2c);
index d1658ed..b31cf4f 100644 (file)
@@ -80,7 +80,7 @@ enum {
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 /**
- * struct i2c_spec_values:
+ * struct i2c_spec_values - I2C specification values for various modes
  * @min_hold_start_ns: min hold time (repeated) START condition
  * @min_low_ns: min LOW period of the SCL clock
  * @min_high_ns: min HIGH period of the SCL cloc
@@ -136,7 +136,7 @@ static const struct i2c_spec_values fast_mode_plus_spec = {
 };
 
 /**
- * struct rk3x_i2c_calced_timings:
+ * struct rk3x_i2c_calced_timings - calculated V1 timings
  * @div_low: Divider output for low
  * @div_high: Divider output for high
  * @tuning: Used to adjust setup/hold data time,
@@ -159,7 +159,7 @@ enum rk3x_i2c_state {
 };
 
 /**
- * struct rk3x_i2c_soc_data:
+ * struct rk3x_i2c_soc_data - SOC-specific data
  * @grf_offset: offset inside the grf regmap for setting the i2c type
  * @calc_timings: Callback function for i2c timing information calculated
  */
@@ -239,7 +239,8 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
 }
 
 /**
- * Generate a START condition, which triggers a REG_INT_START interrupt.
+ * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt.
+ * @i2c: target controller data
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
@@ -258,8 +259,8 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 }
 
 /**
- * Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
- *
+ * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
+ * @i2c: target controller data
  * @error: Error code to return in rk3x_i2c_xfer
  */
 static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
@@ -298,7 +299,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
 }
 
 /**
- * Setup a read according to i2c->msg
+ * rk3x_i2c_prepare_read - Setup a read according to i2c->msg
+ * @i2c: target controller data
  */
 static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
 {
@@ -329,7 +331,8 @@ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
 }
 
 /**
- * Fill the transmit buffer with data from i2c->msg
+ * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg
+ * @i2c: target controller data
  */
 static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
 {
@@ -532,11 +535,10 @@ out:
 }
 
 /**
- * Get timing values of I2C specification
- *
+ * rk3x_i2c_get_spec - Get timing values of I2C specification
  * @speed: Desired SCL frequency
  *
- * Returns: Matched i2c spec values.
+ * Return: Matched i2c_spec_values.
  */
 static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 {
@@ -549,13 +551,12 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 }
 
 /**
- * Calculate divider values for desired SCL frequency
- *
+ * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency
  * @clk_rate: I2C input clock rate
  * @t: Known I2C timing information
  * @t_calc: Caculated rk3x private timings that would be written into regs
  *
- * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
@@ -710,13 +711,12 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
 }
 
 /**
- * Calculate timing values for desired SCL frequency
- *
+ * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency
  * @clk_rate: I2C input clock rate
  * @t: Known I2C timing information
  * @t_calc: Caculated rk3x private timings that would be written into regs
  *
- * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  * The following formulas are v1's method to calculate timings.
@@ -960,14 +960,14 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 }
 
 /**
- * Setup I2C registers for an I2C operation specified by msgs, num.
- *
- * Must be called with i2c->lock held.
- *
+ * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num.
+ * @i2c: target controller data
  * @msgs: I2C msgs to process
  * @num: Number of msgs
  *
- * returns: Number of I2C msgs processed or negative in case of error
+ * Must be called with i2c->lock held.
+ *
+ * Return: Number of I2C msgs processed or negative in case of error
  */
 static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
 {
index a2def6f..5eac7ea 100644 (file)
@@ -280,6 +280,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
                        hid_sensor_convert_timestamp(
                                        &accel_state->common_attributes,
                                        *(int64_t *)raw_data);
+               ret = 0;
        break;
        default:
                break;
index 3d2e8b4..a4e7c7e 100644 (file)
@@ -298,8 +298,10 @@ static int berlin2_adc_probe(struct platform_device *pdev)
        int ret;
 
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
-       if (!indio_dev)
+       if (!indio_dev) {
+               of_node_put(parent_np);
                return -ENOMEM;
+       }
 
        priv = iio_priv(indio_dev);
 
index 36777b8..f5a0fc9 100644 (file)
@@ -86,6 +86,8 @@
 
 #define IMX8QXP_ADC_TIMEOUT            msecs_to_jiffies(100)
 
+#define IMX8QXP_ADC_MAX_FIFO_SIZE              16
+
 struct imx8qxp_adc {
        struct device *dev;
        void __iomem *regs;
@@ -95,6 +97,7 @@ struct imx8qxp_adc {
        /* Serialise ADC channel reads */
        struct mutex lock;
        struct completion completion;
+       u32 fifo[IMX8QXP_ADC_MAX_FIFO_SIZE];
 };
 
 #define IMX8QXP_ADC_CHAN(_idx) {                               \
@@ -238,8 +241,7 @@ static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,
                        return ret;
                }
 
-               *val = FIELD_GET(IMX8QXP_ADC_RESFIFO_VAL_MASK,
-                                readl(adc->regs + IMX8QXP_ADR_ADC_RESFIFO));
+               *val = adc->fifo[0];
 
                mutex_unlock(&adc->lock);
                return IIO_VAL_INT;
@@ -265,10 +267,15 @@ static irqreturn_t imx8qxp_adc_isr(int irq, void *dev_id)
 {
        struct imx8qxp_adc *adc = dev_id;
        u32 fifo_count;
+       int i;
 
        fifo_count = FIELD_GET(IMX8QXP_ADC_FCTRL_FCOUNT_MASK,
                               readl(adc->regs + IMX8QXP_ADR_ADC_FCTRL));
 
+       for (i = 0; i < fifo_count; i++)
+               adc->fifo[i] = FIELD_GET(IMX8QXP_ADC_RESFIFO_VAL_MASK,
+                               readl_relaxed(adc->regs + IMX8QXP_ADR_ADC_RESFIFO));
+
        if (fifo_count)
                complete(&adc->completion);
 
index 6d21ea8..a428bdb 100644 (file)
@@ -1520,6 +1520,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match);
 
 static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
 {
index f53e855..32873fb 100644 (file)
 #define TWL6030_GPADCS                         BIT(1)
 #define TWL6030_GPADCR                         BIT(0)
 
+#define USB_VBUS_CTRL_SET                      0x04
+#define USB_ID_CTRL_SET                                0x06
+
+#define TWL6030_MISC1                          0xE4
+#define VBUS_MEAS                              0x01
+#define ID_MEAS                                        0x01
+
+#define VAC_MEAS                0x04
+#define VBAT_MEAS               0x02
+#define BB_MEAS                 0x01
+
+
 /**
  * struct twl6030_chnl_calib - channel calibration
  * @gain:              slope coefficient for ideal curve
@@ -927,6 +939,26 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = twl_i2c_write_u8(TWL_MODULE_USB, VBUS_MEAS, USB_VBUS_CTRL_SET);
+       if (ret < 0) {
+               dev_err(dev, "failed to wire up inputs\n");
+               return ret;
+       }
+
+       ret = twl_i2c_write_u8(TWL_MODULE_USB, ID_MEAS, USB_ID_CTRL_SET);
+       if (ret < 0) {
+               dev_err(dev, "failed to wire up inputs\n");
+               return ret;
+       }
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID0,
+                               VBAT_MEAS | BB_MEAS | VAC_MEAS,
+                               TWL6030_MISC1);
+       if (ret < 0) {
+               dev_err(dev, "failed to wire up inputs\n");
+               return ret;
+       }
+
        indio_dev->name = DRIVER_NAME;
        indio_dev->info = &twl6030_gpadc_iio_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
index 5b4bdf3..a507d2e 100644 (file)
@@ -1329,7 +1329,7 @@ static int ams_parse_firmware(struct iio_dev *indio_dev)
 
        dev_channels = devm_krealloc(dev, ams_channels, dev_size, GFP_KERNEL);
        if (!dev_channels)
-               ret = -ENOMEM;
+               return -ENOMEM;
 
        indio_dev->channels = dev_channels;
        indio_dev->num_channels = num_channels;
index 8f0ad02..698c50d 100644 (file)
@@ -231,6 +231,7 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
                gyro_state->timestamp =
                        hid_sensor_convert_timestamp(&gyro_state->common_attributes,
                                                     *(s64 *)raw_data);
+               ret = 0;
        break;
        default:
                break;
index 423cfe5..6d189c4 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/regmap.h>
 #include <linux/acpi.h>
 #include <linux/bitops.h>
+#include <linux/bitfield.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #define FXOS8700_NVM_DATA_BNK0      0xa7
 
 /* Bit definitions for FXOS8700_CTRL_REG1 */
-#define FXOS8700_CTRL_ODR_MSK       0x38
 #define FXOS8700_CTRL_ODR_MAX       0x00
-#define FXOS8700_CTRL_ODR_MIN       GENMASK(4, 3)
+#define FXOS8700_CTRL_ODR_MSK       GENMASK(5, 3)
 
 /* Bit definitions for FXOS8700_M_CTRL_REG1 */
 #define FXOS8700_HMS_MASK           GENMASK(1, 0)
@@ -320,7 +320,7 @@ static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
        switch (iio_type) {
        case IIO_ACCEL:
                return FXOS8700_ACCEL;
-       case IIO_ANGL_VEL:
+       case IIO_MAGN:
                return FXOS8700_MAGN;
        default:
                return -EINVAL;
@@ -345,15 +345,35 @@ static int fxos8700_set_active_mode(struct fxos8700_data *data,
 static int fxos8700_set_scale(struct fxos8700_data *data,
                              enum fxos8700_sensor t, int uscale)
 {
-       int i;
+       int i, ret, val;
+       bool active_mode;
        static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
        struct device *dev = regmap_get_device(data->regmap);
 
        if (t == FXOS8700_MAGN) {
-               dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
+               dev_err(dev, "Magnetometer scale is locked at 0.001Gs\n");
                return -EINVAL;
        }
 
+       /*
+        * When device is in active mode, it failed to set an ACCEL
+        * full-scale range(2g/4g/8g) in FXOS8700_XYZ_DATA_CFG.
+        * This is not align with the datasheet, but it is a fxos8700
+        * chip behavier. Set the device in standby mode before setting
+        * an ACCEL full-scale range.
+        */
+       ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
+       if (ret)
+               return ret;
+
+       active_mode = val & FXOS8700_ACTIVE;
+       if (active_mode) {
+               ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
+                                  val & ~FXOS8700_ACTIVE);
+               if (ret)
+                       return ret;
+       }
+
        for (i = 0; i < scale_num; i++)
                if (fxos8700_accel_scale[i].uscale == uscale)
                        break;
@@ -361,8 +381,12 @@ static int fxos8700_set_scale(struct fxos8700_data *data,
        if (i == scale_num)
                return -EINVAL;
 
-       return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
+       ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
                            fxos8700_accel_scale[i].bits);
+       if (ret)
+               return ret;
+       return regmap_write(data->regmap, FXOS8700_CTRL_REG1,
+                                 active_mode);
 }
 
 static int fxos8700_get_scale(struct fxos8700_data *data,
@@ -372,7 +396,7 @@ static int fxos8700_get_scale(struct fxos8700_data *data,
        static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
 
        if (t == FXOS8700_MAGN) {
-               *uscale = 1200; /* Magnetometer is locked at 1200uT */
+               *uscale = 1000; /* Magnetometer is locked at 0.001Gs */
                return 0;
        }
 
@@ -394,22 +418,61 @@ static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
                             int axis, int *val)
 {
        u8 base, reg;
+       s16 tmp;
        int ret;
-       enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
 
-       base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
+       /*
+        * Different register base addresses varies with channel types.
+        * This bug hasn't been noticed before because using an enum is
+        * really hard to read. Use an a switch statement to take over that.
+        */
+       switch (chan_type) {
+       case IIO_ACCEL:
+               base = FXOS8700_OUT_X_MSB;
+               break;
+       case IIO_MAGN:
+               base = FXOS8700_M_OUT_X_MSB;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        /* Block read 6 bytes of device output registers to avoid data loss */
        ret = regmap_bulk_read(data->regmap, base, data->buf,
-                              FXOS8700_DATA_BUF_SIZE);
+                              sizeof(data->buf));
        if (ret)
                return ret;
 
        /* Convert axis to buffer index */
        reg = axis - IIO_MOD_X;
 
+       /*
+        * Convert to native endianness. The accel data and magn data
+        * are signed, so a forced type conversion is needed.
+        */
+       tmp = be16_to_cpu(data->buf[reg]);
+
+       /*
+        * ACCEL output data registers contain the X-axis, Y-axis, and Z-axis
+        * 14-bit left-justified sample data and MAGN output data registers
+        * contain the X-axis, Y-axis, and Z-axis 16-bit sample data. Apply
+        * a signed 2 bits right shift to the readback raw data from ACCEL
+        * output data register and keep that from MAGN sensor as the origin.
+        * Value should be extended to 32 bit.
+        */
+       switch (chan_type) {
+       case IIO_ACCEL:
+               tmp = tmp >> 2;
+               break;
+       case IIO_MAGN:
+               /* Nothing to do */
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* Convert to native endianness */
-       *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
+       *val = sign_extend32(tmp, 15);
 
        return 0;
 }
@@ -445,10 +508,9 @@ static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
        if (i >= odr_num)
                return -EINVAL;
 
-       return regmap_update_bits(data->regmap,
-                                 FXOS8700_CTRL_REG1,
-                                 FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
-                                 fxos8700_odr[i].bits << 3 | active_mode);
+       val &= ~FXOS8700_CTRL_ODR_MSK;
+       val |= FIELD_PREP(FXOS8700_CTRL_ODR_MSK, fxos8700_odr[i].bits) | FXOS8700_ACTIVE;
+       return regmap_write(data->regmap, FXOS8700_CTRL_REG1, val);
 }
 
 static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
@@ -461,7 +523,7 @@ static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
        if (ret)
                return ret;
 
-       val &= FXOS8700_CTRL_ODR_MSK;
+       val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val);
 
        for (i = 0; i < odr_num; i++)
                if (val == fxos8700_odr[i].bits)
@@ -526,7 +588,7 @@ static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
 static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
                      "1.5625 6.25 12.5 50 100 200 400 800");
 static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
-static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
+static IIO_CONST_ATTR(in_magn_scale_available, "0.001000");
 
 static struct attribute *fxos8700_attrs[] = {
        &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
@@ -592,14 +654,19 @@ static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
        if (ret)
                return ret;
 
-       /* Max ODR (800Hz individual or 400Hz hybrid), active mode */
-       ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
-                          FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
+       /*
+        * Set max full-scale range (+/-8G) for ACCEL sensor in chip
+        * initialization then activate the device.
+        */
+       ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
        if (ret)
                return ret;
 
-       /* Set for max full-scale range (+/-8G) */
-       return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
+       /* Max ODR (800Hz individual or 400Hz hybrid), active mode */
+       return regmap_update_bits(data->regmap, FXOS8700_CTRL_REG1,
+                               FXOS8700_CTRL_ODR_MSK | FXOS8700_ACTIVE,
+                               FIELD_PREP(FXOS8700_CTRL_ODR_MSK, FXOS8700_CTRL_ODR_MAX) |
+                               FXOS8700_ACTIVE);
 }
 
 static void fxos8700_chip_uninit(void *data)
index f666084..8c16cda 100644 (file)
@@ -4,6 +4,7 @@ config IIO_ST_LSM6DSX
        tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors"
        depends on (I2C || SPI || I3C)
        select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        select IIO_KFIFO_BUF
        select IIO_ST_LSM6DSX_I2C if (I2C)
        select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
index 001055d..b1674a5 100644 (file)
@@ -440,6 +440,8 @@ static int cm32181_probe(struct i2c_client *client)
        if (!indio_dev)
                return -ENOMEM;
 
+       i2c_set_clientdata(client, indio_dev);
+
        /*
         * Some ACPI systems list 2 I2C resources for the CM3218 sensor, the
         * SMBus Alert Response Address (ARA, 0x0c) and the actual I2C address.
@@ -460,8 +462,6 @@ static int cm32181_probe(struct i2c_client *client)
                        return PTR_ERR(client);
        }
 
-       i2c_set_clientdata(client, indio_dev);
-
        cm32181 = iio_priv(indio_dev);
        cm32181->client = client;
        cm32181->dev = dev;
@@ -490,7 +490,8 @@ static int cm32181_probe(struct i2c_client *client)
 
 static int cm32181_suspend(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
+       struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev));
+       struct i2c_client *client = cm32181->client;
 
        return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
                                         CM32181_CMD_ALS_DISABLE);
@@ -498,8 +499,8 @@ static int cm32181_suspend(struct device *dev)
 
 static int cm32181_resume(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
        struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev));
+       struct i2c_client *client = cm32181->client;
 
        return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
                                         cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
index 43b26bc..39357dc 100644 (file)
@@ -26,8 +26,8 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf)
        if (umem_dmabuf->sgt)
                goto wait_fence;
 
-       sgt = dma_buf_map_attachment_unlocked(umem_dmabuf->attach,
-                                             DMA_BIDIRECTIONAL);
+       sgt = dma_buf_map_attachment(umem_dmabuf->attach,
+                                    DMA_BIDIRECTIONAL);
        if (IS_ERR(sgt))
                return PTR_ERR(sgt);
 
@@ -103,8 +103,8 @@ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf)
                umem_dmabuf->last_sg_trim = 0;
        }
 
-       dma_buf_unmap_attachment_unlocked(umem_dmabuf->attach, umem_dmabuf->sgt,
-                                         DMA_BIDIRECTIONAL);
+       dma_buf_unmap_attachment(umem_dmabuf->attach, umem_dmabuf->sgt,
+                                DMA_BIDIRECTIONAL);
 
        umem_dmabuf->sgt = NULL;
 }
index 26b021f..11b1c16 100644 (file)
@@ -2957,15 +2957,18 @@ EXPORT_SYMBOL(__rdma_block_iter_start);
 bool __rdma_block_iter_next(struct ib_block_iter *biter)
 {
        unsigned int block_offset;
+       unsigned int sg_delta;
 
        if (!biter->__sg_nents || !biter->__sg)
                return false;
 
        biter->__dma_addr = sg_dma_address(biter->__sg) + biter->__sg_advance;
        block_offset = biter->__dma_addr & (BIT_ULL(biter->__pg_bit) - 1);
-       biter->__sg_advance += BIT_ULL(biter->__pg_bit) - block_offset;
+       sg_delta = BIT_ULL(biter->__pg_bit) - block_offset;
 
-       if (biter->__sg_advance >= sg_dma_len(biter->__sg)) {
+       if (sg_dma_len(biter->__sg) - biter->__sg_advance > sg_delta) {
+               biter->__sg_advance += sg_delta;
+       } else {
                biter->__sg_advance = 0;
                biter->__sg = sg_next(biter->__sg);
                biter->__sg_nents--;
index f5f9269..7c5d487 100644 (file)
@@ -1318,12 +1318,15 @@ static int user_exp_rcv_setup(struct hfi1_filedata *fd, unsigned long arg,
                addr = arg + offsetof(struct hfi1_tid_info, tidcnt);
                if (copy_to_user((void __user *)addr, &tinfo.tidcnt,
                                 sizeof(tinfo.tidcnt)))
-                       return -EFAULT;
+                       ret = -EFAULT;
 
                addr = arg + offsetof(struct hfi1_tid_info, length);
-               if (copy_to_user((void __user *)addr, &tinfo.length,
+               if (!ret && copy_to_user((void __user *)addr, &tinfo.length,
                                 sizeof(tinfo.length)))
                        ret = -EFAULT;
+
+               if (ret)
+                       hfi1_user_exp_rcv_invalid(fd, &tinfo);
        }
 
        return ret;
index 186d302..350884d 100644 (file)
@@ -23,18 +23,25 @@ static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata,
 static bool tid_rb_invalidate(struct mmu_interval_notifier *mni,
                              const struct mmu_notifier_range *range,
                              unsigned long cur_seq);
+static bool tid_cover_invalidate(struct mmu_interval_notifier *mni,
+                                const struct mmu_notifier_range *range,
+                                unsigned long cur_seq);
 static int program_rcvarray(struct hfi1_filedata *fd, struct tid_user_buf *,
                            struct tid_group *grp,
                            unsigned int start, u16 count,
                            u32 *tidlist, unsigned int *tididx,
                            unsigned int *pmapped);
-static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
-                             struct tid_group **grp);
+static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo);
+static void __clear_tid_node(struct hfi1_filedata *fd,
+                            struct tid_rb_node *node);
 static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node);
 
 static const struct mmu_interval_notifier_ops tid_mn_ops = {
        .invalidate = tid_rb_invalidate,
 };
+static const struct mmu_interval_notifier_ops tid_cover_ops = {
+       .invalidate = tid_cover_invalidate,
+};
 
 /*
  * Initialize context and file private data needed for Expected
@@ -153,16 +160,11 @@ static void unpin_rcv_pages(struct hfi1_filedata *fd,
 static int pin_rcv_pages(struct hfi1_filedata *fd, struct tid_user_buf *tidbuf)
 {
        int pinned;
-       unsigned int npages;
+       unsigned int npages = tidbuf->npages;
        unsigned long vaddr = tidbuf->vaddr;
        struct page **pages = NULL;
        struct hfi1_devdata *dd = fd->uctxt->dd;
 
-       /* Get the number of pages the user buffer spans */
-       npages = num_user_pages(vaddr, tidbuf->length);
-       if (!npages)
-               return -EINVAL;
-
        if (npages > fd->uctxt->expected_count) {
                dd_dev_err(dd, "Expected buffer too big\n");
                return -EINVAL;
@@ -189,7 +191,6 @@ static int pin_rcv_pages(struct hfi1_filedata *fd, struct tid_user_buf *tidbuf)
                return pinned;
        }
        tidbuf->pages = pages;
-       tidbuf->npages = npages;
        fd->tid_n_pinned += pinned;
        return pinned;
 }
@@ -253,53 +254,66 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
                tididx = 0, mapped, mapped_pages = 0;
        u32 *tidlist = NULL;
        struct tid_user_buf *tidbuf;
+       unsigned long mmu_seq = 0;
 
        if (!PAGE_ALIGNED(tinfo->vaddr))
                return -EINVAL;
+       if (tinfo->length == 0)
+               return -EINVAL;
 
        tidbuf = kzalloc(sizeof(*tidbuf), GFP_KERNEL);
        if (!tidbuf)
                return -ENOMEM;
 
+       mutex_init(&tidbuf->cover_mutex);
        tidbuf->vaddr = tinfo->vaddr;
        tidbuf->length = tinfo->length;
+       tidbuf->npages = num_user_pages(tidbuf->vaddr, tidbuf->length);
        tidbuf->psets = kcalloc(uctxt->expected_count, sizeof(*tidbuf->psets),
                                GFP_KERNEL);
        if (!tidbuf->psets) {
-               kfree(tidbuf);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto fail_release_mem;
+       }
+
+       if (fd->use_mn) {
+               ret = mmu_interval_notifier_insert(
+                       &tidbuf->notifier, current->mm,
+                       tidbuf->vaddr, tidbuf->npages * PAGE_SIZE,
+                       &tid_cover_ops);
+               if (ret)
+                       goto fail_release_mem;
+               mmu_seq = mmu_interval_read_begin(&tidbuf->notifier);
        }
 
        pinned = pin_rcv_pages(fd, tidbuf);
        if (pinned <= 0) {
-               kfree(tidbuf->psets);
-               kfree(tidbuf);
-               return pinned;
+               ret = (pinned < 0) ? pinned : -ENOSPC;
+               goto fail_unpin;
        }
 
        /* Find sets of physically contiguous pages */
        tidbuf->n_psets = find_phys_blocks(tidbuf, pinned);
 
-       /*
-        * We don't need to access this under a lock since tid_used is per
-        * process and the same process cannot be in hfi1_user_exp_rcv_clear()
-        * and hfi1_user_exp_rcv_setup() at the same time.
-        */
+       /* Reserve the number of expected tids to be used. */
        spin_lock(&fd->tid_lock);
        if (fd->tid_used + tidbuf->n_psets > fd->tid_limit)
                pageset_count = fd->tid_limit - fd->tid_used;
        else
                pageset_count = tidbuf->n_psets;
+       fd->tid_used += pageset_count;
        spin_unlock(&fd->tid_lock);
 
-       if (!pageset_count)
-               goto bail;
+       if (!pageset_count) {
+               ret = -ENOSPC;
+               goto fail_unreserve;
+       }
 
        ngroups = pageset_count / dd->rcv_entries.group_size;
        tidlist = kcalloc(pageset_count, sizeof(*tidlist), GFP_KERNEL);
        if (!tidlist) {
                ret = -ENOMEM;
-               goto nomem;
+               goto fail_unreserve;
        }
 
        tididx = 0;
@@ -395,43 +409,78 @@ int hfi1_user_exp_rcv_setup(struct hfi1_filedata *fd,
        }
 unlock:
        mutex_unlock(&uctxt->exp_mutex);
-nomem:
        hfi1_cdbg(TID, "total mapped: tidpairs:%u pages:%u (%d)", tididx,
                  mapped_pages, ret);
-       if (tididx) {
-               spin_lock(&fd->tid_lock);
-               fd->tid_used += tididx;
-               spin_unlock(&fd->tid_lock);
-               tinfo->tidcnt = tididx;
-               tinfo->length = mapped_pages * PAGE_SIZE;
-
-               if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
-                                tidlist, sizeof(tidlist[0]) * tididx)) {
-                       /*
-                        * On failure to copy to the user level, we need to undo
-                        * everything done so far so we don't leak resources.
-                        */
-                       tinfo->tidlist = (unsigned long)&tidlist;
-                       hfi1_user_exp_rcv_clear(fd, tinfo);
-                       tinfo->tidlist = 0;
-                       ret = -EFAULT;
-                       goto bail;
+
+       /* fail if nothing was programmed, set error if none provided */
+       if (tididx == 0) {
+               if (ret >= 0)
+                       ret = -ENOSPC;
+               goto fail_unreserve;
+       }
+
+       /* adjust reserved tid_used to actual count */
+       spin_lock(&fd->tid_lock);
+       fd->tid_used -= pageset_count - tididx;
+       spin_unlock(&fd->tid_lock);
+
+       /* unpin all pages not covered by a TID */
+       unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages, pinned - mapped_pages,
+                       false);
+
+       if (fd->use_mn) {
+               /* check for an invalidate during setup */
+               bool fail = false;
+
+               mutex_lock(&tidbuf->cover_mutex);
+               fail = mmu_interval_read_retry(&tidbuf->notifier, mmu_seq);
+               mutex_unlock(&tidbuf->cover_mutex);
+
+               if (fail) {
+                       ret = -EBUSY;
+                       goto fail_unprogram;
                }
        }
 
-       /*
-        * If not everything was mapped (due to insufficient RcvArray entries,
-        * for example), unpin all unmapped pages so we can pin them nex time.
-        */
-       if (mapped_pages != pinned)
-               unpin_rcv_pages(fd, tidbuf, NULL, mapped_pages,
-                               (pinned - mapped_pages), false);
-bail:
+       tinfo->tidcnt = tididx;
+       tinfo->length = mapped_pages * PAGE_SIZE;
+
+       if (copy_to_user(u64_to_user_ptr(tinfo->tidlist),
+                        tidlist, sizeof(tidlist[0]) * tididx)) {
+               ret = -EFAULT;
+               goto fail_unprogram;
+       }
+
+       if (fd->use_mn)
+               mmu_interval_notifier_remove(&tidbuf->notifier);
+       kfree(tidbuf->pages);
        kfree(tidbuf->psets);
+       kfree(tidbuf);
        kfree(tidlist);
+       return 0;
+
+fail_unprogram:
+       /* unprogram, unmap, and unpin all allocated TIDs */
+       tinfo->tidlist = (unsigned long)tidlist;
+       hfi1_user_exp_rcv_clear(fd, tinfo);
+       tinfo->tidlist = 0;
+       pinned = 0;             /* nothing left to unpin */
+       pageset_count = 0;      /* nothing left reserved */
+fail_unreserve:
+       spin_lock(&fd->tid_lock);
+       fd->tid_used -= pageset_count;
+       spin_unlock(&fd->tid_lock);
+fail_unpin:
+       if (fd->use_mn)
+               mmu_interval_notifier_remove(&tidbuf->notifier);
+       if (pinned > 0)
+               unpin_rcv_pages(fd, tidbuf, NULL, 0, pinned, false);
+fail_release_mem:
        kfree(tidbuf->pages);
+       kfree(tidbuf->psets);
        kfree(tidbuf);
-       return ret > 0 ? 0 : ret;
+       kfree(tidlist);
+       return ret;
 }
 
 int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,
@@ -452,7 +501,7 @@ int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,
 
        mutex_lock(&uctxt->exp_mutex);
        for (tididx = 0; tididx < tinfo->tidcnt; tididx++) {
-               ret = unprogram_rcvarray(fd, tidinfo[tididx], NULL);
+               ret = unprogram_rcvarray(fd, tidinfo[tididx]);
                if (ret) {
                        hfi1_cdbg(TID, "Failed to unprogram rcv array %d",
                                  ret);
@@ -706,6 +755,7 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd,
        }
 
        node->fdata = fd;
+       mutex_init(&node->invalidate_mutex);
        node->phys = page_to_phys(pages[0]);
        node->npages = npages;
        node->rcventry = rcventry;
@@ -721,11 +771,6 @@ static int set_rcvarray_entry(struct hfi1_filedata *fd,
                        &tid_mn_ops);
                if (ret)
                        goto out_unmap;
-               /*
-                * FIXME: This is in the wrong order, the notifier should be
-                * established before the pages are pinned by pin_rcv_pages.
-                */
-               mmu_interval_read_begin(&node->notifier);
        }
        fd->entry_to_rb[node->rcventry - uctxt->expected_base] = node;
 
@@ -745,8 +790,7 @@ out_unmap:
        return -EFAULT;
 }
 
-static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
-                             struct tid_group **grp)
+static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo)
 {
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
        struct hfi1_devdata *dd = uctxt->dd;
@@ -769,9 +813,6 @@ static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
        if (!node || node->rcventry != (uctxt->expected_base + rcventry))
                return -EBADF;
 
-       if (grp)
-               *grp = node->grp;
-
        if (fd->use_mn)
                mmu_interval_notifier_remove(&node->notifier);
        cacheless_tid_rb_remove(fd, node);
@@ -779,23 +820,34 @@ static int unprogram_rcvarray(struct hfi1_filedata *fd, u32 tidinfo,
        return 0;
 }
 
-static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
+static void __clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
 {
        struct hfi1_ctxtdata *uctxt = fd->uctxt;
        struct hfi1_devdata *dd = uctxt->dd;
 
+       mutex_lock(&node->invalidate_mutex);
+       if (node->freed)
+               goto done;
+       node->freed = true;
+
        trace_hfi1_exp_tid_unreg(uctxt->ctxt, fd->subctxt, node->rcventry,
                                 node->npages,
                                 node->notifier.interval_tree.start, node->phys,
                                 node->dma_addr);
 
-       /*
-        * Make sure device has seen the write before we unpin the
-        * pages.
-        */
+       /* Make sure device has seen the write before pages are unpinned */
        hfi1_put_tid(dd, node->rcventry, PT_INVALID_FLUSH, 0, 0);
 
        unpin_rcv_pages(fd, NULL, node, 0, node->npages, true);
+done:
+       mutex_unlock(&node->invalidate_mutex);
+}
+
+static void clear_tid_node(struct hfi1_filedata *fd, struct tid_rb_node *node)
+{
+       struct hfi1_ctxtdata *uctxt = fd->uctxt;
+
+       __clear_tid_node(fd, node);
 
        node->grp->used--;
        node->grp->map &= ~(1 << (node->rcventry - node->grp->base));
@@ -854,10 +906,16 @@ static bool tid_rb_invalidate(struct mmu_interval_notifier *mni,
        if (node->freed)
                return true;
 
+       /* take action only if unmapping */
+       if (range->event != MMU_NOTIFY_UNMAP)
+               return true;
+
        trace_hfi1_exp_tid_inval(uctxt->ctxt, fdata->subctxt,
                                 node->notifier.interval_tree.start,
                                 node->rcventry, node->npages, node->dma_addr);
-       node->freed = true;
+
+       /* clear the hardware rcvarray entry */
+       __clear_tid_node(fdata, node);
 
        spin_lock(&fdata->invalid_lock);
        if (fdata->invalid_tid_idx < uctxt->expected_count) {
@@ -887,6 +945,23 @@ static bool tid_rb_invalidate(struct mmu_interval_notifier *mni,
        return true;
 }
 
+static bool tid_cover_invalidate(struct mmu_interval_notifier *mni,
+                                const struct mmu_notifier_range *range,
+                                unsigned long cur_seq)
+{
+       struct tid_user_buf *tidbuf =
+               container_of(mni, struct tid_user_buf, notifier);
+
+       /* take action only if unmapping */
+       if (range->event == MMU_NOTIFY_UNMAP) {
+               mutex_lock(&tidbuf->cover_mutex);
+               mmu_interval_set_seq(mni, cur_seq);
+               mutex_unlock(&tidbuf->cover_mutex);
+       }
+
+       return true;
+}
+
 static void cacheless_tid_rb_remove(struct hfi1_filedata *fdata,
                                    struct tid_rb_node *tnode)
 {
index 8c53e41..f8ee997 100644 (file)
@@ -16,6 +16,8 @@ struct tid_pageset {
 };
 
 struct tid_user_buf {
+       struct mmu_interval_notifier notifier;
+       struct mutex cover_mutex;
        unsigned long vaddr;
        unsigned long length;
        unsigned int npages;
@@ -27,6 +29,7 @@ struct tid_user_buf {
 struct tid_rb_node {
        struct mmu_interval_notifier notifier;
        struct hfi1_filedata *fdata;
+       struct mutex invalidate_mutex; /* covers hw removal */
        unsigned long phys;
        struct tid_group *grp;
        u32 rcventry;
index 7b086fe..195aa9e 100644 (file)
@@ -1722,6 +1722,9 @@ static int irdma_add_mqh_4(struct irdma_device *iwdev,
                        continue;
 
                idev = in_dev_get(ip_dev);
+               if (!idev)
+                       continue;
+
                in_dev_for_each_ifa_rtnl(ifa, idev) {
                        ibdev_dbg(&iwdev->ibdev,
                                  "CM: Allocating child CM Listener forIP=%pI4, vlan_id=%d, MAC=%pM\n",
index ea15ec7..54b6193 100644 (file)
@@ -289,7 +289,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
 
        /* IB ports start with 1, MANA Ethernet ports start with 0 */
        port = ucmd.port;
-       if (ucmd.port > mc->num_ports)
+       if (port < 1 || port > mc->num_ports)
                return -EINVAL;
 
        if (attr->cap.max_send_wr > MAX_SEND_BUFFERS_PER_QUEUE) {
index c301b3b..a2857ac 100644 (file)
@@ -276,8 +276,8 @@ iter_chunk:
                                size = pa_end - pa_start + PAGE_SIZE;
                                usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x",
                                        va_start, &pa_start, size, flags);
-                               err = iommu_map(pd->domain, va_start, pa_start,
-                                                       size, flags);
+                               err = iommu_map_atomic(pd->domain, va_start,
+                                                      pa_start, size, flags);
                                if (err) {
                                        usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
                                                va_start, &pa_start, size, err);
@@ -293,8 +293,8 @@ iter_chunk:
                                size = pa - pa_start + PAGE_SIZE;
                                usnic_dbg("va 0x%lx pa %pa size 0x%zx flags 0x%x\n",
                                        va_start, &pa_start, size, flags);
-                               err = iommu_map(pd->domain, va_start, pa_start,
-                                               size, flags);
+                               err = iommu_map_atomic(pd->domain, va_start,
+                                                      pa_start, size, flags);
                                if (err) {
                                        usnic_err("Failed to map va 0x%lx pa %pa size 0x%zx with err %d\n",
                                                va_start, &pa_start, size, err);
index a754fc9..7b41d79 100644 (file)
@@ -98,11 +98,11 @@ enum rxe_device_param {
        RXE_MAX_SRQ                     = DEFAULT_MAX_VALUE - RXE_MIN_SRQ_INDEX,
 
        RXE_MIN_MR_INDEX                = 0x00000001,
-       RXE_MAX_MR_INDEX                = DEFAULT_MAX_VALUE,
-       RXE_MAX_MR                      = DEFAULT_MAX_VALUE - RXE_MIN_MR_INDEX,
-       RXE_MIN_MW_INDEX                = 0x00010001,
-       RXE_MAX_MW_INDEX                = 0x00020000,
-       RXE_MAX_MW                      = 0x00001000,
+       RXE_MAX_MR_INDEX                = DEFAULT_MAX_VALUE >> 1,
+       RXE_MAX_MR                      = RXE_MAX_MR_INDEX - RXE_MIN_MR_INDEX,
+       RXE_MIN_MW_INDEX                = RXE_MAX_MR_INDEX + 1,
+       RXE_MAX_MW_INDEX                = DEFAULT_MAX_VALUE,
+       RXE_MAX_MW                      = RXE_MAX_MW_INDEX - RXE_MIN_MW_INDEX,
 
        RXE_MAX_PKT_PER_ACK             = 64,
 
index f50620f..1151c0b 100644 (file)
@@ -23,16 +23,16 @@ static const struct rxe_type_info {
                .size           = sizeof(struct rxe_ucontext),
                .elem_offset    = offsetof(struct rxe_ucontext, elem),
                .min_index      = 1,
-               .max_index      = UINT_MAX,
-               .max_elem       = UINT_MAX,
+               .max_index      = RXE_MAX_UCONTEXT,
+               .max_elem       = RXE_MAX_UCONTEXT,
        },
        [RXE_TYPE_PD] = {
                .name           = "pd",
                .size           = sizeof(struct rxe_pd),
                .elem_offset    = offsetof(struct rxe_pd, elem),
                .min_index      = 1,
-               .max_index      = UINT_MAX,
-               .max_elem       = UINT_MAX,
+               .max_index      = RXE_MAX_PD,
+               .max_elem       = RXE_MAX_PD,
        },
        [RXE_TYPE_AH] = {
                .name           = "ah",
@@ -40,7 +40,7 @@ static const struct rxe_type_info {
                .elem_offset    = offsetof(struct rxe_ah, elem),
                .min_index      = RXE_MIN_AH_INDEX,
                .max_index      = RXE_MAX_AH_INDEX,
-               .max_elem       = RXE_MAX_AH_INDEX - RXE_MIN_AH_INDEX + 1,
+               .max_elem       = RXE_MAX_AH,
        },
        [RXE_TYPE_SRQ] = {
                .name           = "srq",
@@ -49,7 +49,7 @@ static const struct rxe_type_info {
                .cleanup        = rxe_srq_cleanup,
                .min_index      = RXE_MIN_SRQ_INDEX,
                .max_index      = RXE_MAX_SRQ_INDEX,
-               .max_elem       = RXE_MAX_SRQ_INDEX - RXE_MIN_SRQ_INDEX + 1,
+               .max_elem       = RXE_MAX_SRQ,
        },
        [RXE_TYPE_QP] = {
                .name           = "qp",
@@ -58,7 +58,7 @@ static const struct rxe_type_info {
                .cleanup        = rxe_qp_cleanup,
                .min_index      = RXE_MIN_QP_INDEX,
                .max_index      = RXE_MAX_QP_INDEX,
-               .max_elem       = RXE_MAX_QP_INDEX - RXE_MIN_QP_INDEX + 1,
+               .max_elem       = RXE_MAX_QP,
        },
        [RXE_TYPE_CQ] = {
                .name           = "cq",
@@ -66,8 +66,8 @@ static const struct rxe_type_info {
                .elem_offset    = offsetof(struct rxe_cq, elem),
                .cleanup        = rxe_cq_cleanup,
                .min_index      = 1,
-               .max_index      = UINT_MAX,
-               .max_elem       = UINT_MAX,
+               .max_index      = RXE_MAX_CQ,
+               .max_elem       = RXE_MAX_CQ,
        },
        [RXE_TYPE_MR] = {
                .name           = "mr",
@@ -76,7 +76,7 @@ static const struct rxe_type_info {
                .cleanup        = rxe_mr_cleanup,
                .min_index      = RXE_MIN_MR_INDEX,
                .max_index      = RXE_MAX_MR_INDEX,
-               .max_elem       = RXE_MAX_MR_INDEX - RXE_MIN_MR_INDEX + 1,
+               .max_elem       = RXE_MAX_MR,
        },
        [RXE_TYPE_MW] = {
                .name           = "mw",
@@ -85,7 +85,7 @@ static const struct rxe_type_info {
                .cleanup        = rxe_mw_cleanup,
                .min_index      = RXE_MIN_MW_INDEX,
                .max_index      = RXE_MAX_MW_INDEX,
-               .max_elem       = RXE_MAX_MW_INDEX - RXE_MIN_MW_INDEX + 1,
+               .max_elem       = RXE_MAX_MW,
        },
 };
 
index ac25fc8..f10d4bc 100644 (file)
@@ -2200,6 +2200,14 @@ int ipoib_intf_init(struct ib_device *hca, u32 port, const char *name,
                rn->attach_mcast = ipoib_mcast_attach;
                rn->detach_mcast = ipoib_mcast_detach;
                rn->hca = hca;
+
+               rc = netif_set_real_num_tx_queues(dev, 1);
+               if (rc)
+                       goto out;
+
+               rc = netif_set_real_num_rx_queues(dev, 1);
+               if (rc)
+                       goto out;
        }
 
        priv->rn_ops = dev->netdev_ops;
index c76ba29..5adba0f 100644 (file)
@@ -312,9 +312,8 @@ void rtrs_srv_destroy_path_files(struct rtrs_srv_path *srv_path)
 
        if (srv_path->kobj.state_in_sysfs) {
                sysfs_remove_group(&srv_path->kobj, &rtrs_srv_path_attr_group);
-               kobject_del(&srv_path->kobj);
                kobject_put(&srv_path->kobj);
+               rtrs_srv_destroy_once_sysfs_root_folders(srv_path);
        }
 
-       rtrs_srv_destroy_once_sysfs_root_folders(srv_path);
 }
index 8d8ebdc..67f1c73 100644 (file)
@@ -51,7 +51,7 @@ module_param_array(ptr_size, int, NULL, 0444);
 MODULE_PARM_DESC(ptr_size,
        "Pointing device width, height in pixels (default 800,600)");
 
-static int xenkbd_remove(struct xenbus_device *);
+static void xenkbd_remove(struct xenbus_device *);
 static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
 static void xenkbd_disconnect_backend(struct xenkbd_info *);
 
@@ -404,7 +404,7 @@ static int xenkbd_resume(struct xenbus_device *dev)
        return xenkbd_connect_backend(dev, info);
 }
 
-static int xenkbd_remove(struct xenbus_device *dev)
+static void xenkbd_remove(struct xenbus_device *dev)
 {
        struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 
@@ -417,7 +417,6 @@ static int xenkbd_remove(struct xenbus_device *dev)
                input_unregister_device(info->mtouch);
        free_page((unsigned long)info->page);
        kfree(info);
-       return 0;
 }
 
 static int xenkbd_connect_backend(struct xenbus_device *dev,
index b0f7764..fa021af 100644 (file)
@@ -192,7 +192,6 @@ static const char * const smbus_pnp_ids[] = {
        "SYN3221", /* HP 15-ay000 */
        "SYN323d", /* HP Spectre X360 13-w013dx */
        "SYN3257", /* HP Envy 13-ad105ng */
-       "SYN3286", /* HP Laptop 15-da3001TU */
        NULL
 };
 
index 46f8a69..efc6173 100644 (file)
@@ -1238,6 +1238,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
                .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
                                        SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "PCX0DX"),
+               },
+               .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+                                       SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+       },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_NAME, "X170SM"),
index ba6781f..df3196f 100644 (file)
@@ -488,7 +488,7 @@ int qnoc_probe(struct platform_device *pdev)
        }
 
 regmap_done:
-       ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
+       ret = devm_clk_bulk_get_optional(dev, qp->num_clks, qp->bus_clks);
        if (ret)
                return ret;
 
index c2903ae..25a1a32 100644 (file)
@@ -33,6 +33,13 @@ static const char * const bus_a0noc_clocks[] = {
        "aggre0_noc_mpu_cfg"
 };
 
+static const char * const bus_a2noc_clocks[] = {
+       "bus",
+       "bus_a",
+       "aggre2_ufs_axi",
+       "ufs_axi"
+};
+
 static const u16 mas_a0noc_common_links[] = {
        MSM8996_SLAVE_A0NOC_SNOC
 };
@@ -1806,7 +1813,7 @@ static const struct regmap_config msm8996_a0noc_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
        .val_bits       = 32,
-       .max_register   = 0x9000,
+       .max_register   = 0x6000,
        .fast_io        = true
 };
 
@@ -1830,7 +1837,7 @@ static const struct regmap_config msm8996_a1noc_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
        .val_bits       = 32,
-       .max_register   = 0x7000,
+       .max_register   = 0x5000,
        .fast_io        = true
 };
 
@@ -1851,7 +1858,7 @@ static const struct regmap_config msm8996_a2noc_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
        .val_bits       = 32,
-       .max_register   = 0xa000,
+       .max_register   = 0x7000,
        .fast_io        = true
 };
 
@@ -1859,6 +1866,8 @@ static const struct qcom_icc_desc msm8996_a2noc = {
        .type = QCOM_ICC_NOC,
        .nodes = a2noc_nodes,
        .num_nodes = ARRAY_SIZE(a2noc_nodes),
+       .clocks = bus_a2noc_clocks,
+       .num_clocks = ARRAY_SIZE(bus_a2noc_clocks),
        .regmap_cfg = &msm8996_a2noc_regmap_config
 };
 
@@ -1877,7 +1886,7 @@ static const struct regmap_config msm8996_bimc_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
        .val_bits       = 32,
-       .max_register   = 0x62000,
+       .max_register   = 0x5a000,
        .fast_io        = true
 };
 
@@ -1988,7 +1997,7 @@ static const struct regmap_config msm8996_mnoc_regmap_config = {
        .reg_bits       = 32,
        .reg_stride     = 4,
        .val_bits       = 32,
-       .max_register   = 0x20000,
+       .max_register   = 0x1c000,
        .fast_io        = true
 };
 
index ab16019..f2425b0 100644 (file)
@@ -3858,7 +3858,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
 
 static void arm_smmu_device_shutdown(struct platform_device *pdev)
 {
-       arm_smmu_device_remove(pdev);
+       struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+
+       arm_smmu_device_disable(smmu);
 }
 
 static const struct of_device_id arm_smmu_of_match[] = {
index 719fbca..2ff7a72 100644 (file)
@@ -1316,8 +1316,14 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
 
        switch (cap) {
        case IOMMU_CAP_CACHE_COHERENCY:
-               /* Assume that a coherent TCU implies coherent TBUs */
-               return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
+               /*
+                * It's overwhelmingly the case in practice that when the pagetable
+                * walk interface is connected to a coherent interconnect, all the
+                * translation interfaces are too. Furthermore if the device is
+                * natively coherent, then its translation interface must also be.
+                */
+               return cfg->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK ||
+                       device_get_dma_attr(dev) == DEV_DMA_COHERENT;
        case IOMMU_CAP_NOEXEC:
                return true;
        default:
@@ -2185,19 +2191,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int arm_smmu_device_remove(struct platform_device *pdev)
+static void arm_smmu_device_shutdown(struct platform_device *pdev)
 {
        struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
 
        if (!smmu)
-               return -ENODEV;
+               return;
 
        if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
                dev_notice(&pdev->dev, "disabling translation\n");
 
-       iommu_device_unregister(&smmu->iommu);
-       iommu_device_sysfs_remove(&smmu->iommu);
-
        arm_smmu_rpm_get(smmu);
        /* Turn the thing off */
        arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, ARM_SMMU_sCR0_CLIENTPD);
@@ -2209,12 +2212,21 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
                clk_bulk_disable(smmu->num_clks, smmu->clks);
 
        clk_bulk_unprepare(smmu->num_clks, smmu->clks);
-       return 0;
 }
 
-static void arm_smmu_device_shutdown(struct platform_device *pdev)
+static int arm_smmu_device_remove(struct platform_device *pdev)
 {
-       arm_smmu_device_remove(pdev);
+       struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+
+       if (!smmu)
+               return -ENODEV;
+
+       iommu_device_unregister(&smmu->iommu);
+       iommu_device_sysfs_remove(&smmu->iommu);
+
+       arm_smmu_device_shutdown(pdev);
+
+       return 0;
 }
 
 static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
index de91dd8..5f6a85a 100644 (file)
@@ -3185,14 +3185,16 @@ EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner);
  */
 int iommu_device_claim_dma_owner(struct device *dev, void *owner)
 {
-       struct iommu_group *group = iommu_group_get(dev);
+       struct iommu_group *group;
        int ret = 0;
 
-       if (!group)
-               return -ENODEV;
        if (WARN_ON(!owner))
                return -EINVAL;
 
+       group = iommu_group_get(dev);
+       if (!group)
+               return -ENODEV;
+
        mutex_lock(&group->mutex);
        if (group->owner_cnt) {
                if (group->owner != owner) {
index a44ad92..fe452ce 100644 (file)
@@ -197,7 +197,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
 
        curr = __get_cached_rbnode(iovad, limit_pfn);
        curr_iova = to_iova(curr);
-       retry_pfn = curr_iova->pfn_hi + 1;
+       retry_pfn = curr_iova->pfn_hi;
 
 retry:
        do {
@@ -211,7 +211,7 @@ retry:
        if (high_pfn < size || new_pfn < low_pfn) {
                if (low_pfn == iovad->start_pfn && retry_pfn < limit_pfn) {
                        high_pfn = limit_pfn;
-                       low_pfn = retry_pfn;
+                       low_pfn = retry_pfn + 1;
                        curr = iova_find_limit(iovad, limit_pfn);
                        curr_iova = to_iova(curr);
                        goto retry;
index 69682ee..ca581ff 100644 (file)
@@ -683,7 +683,7 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
        ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
                                     dev_name(&pdev->dev));
        if (ret)
-               return ret;
+               goto out_clk_unprepare;
 
        ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
        if (ret)
@@ -698,6 +698,8 @@ out_dev_unreg:
        iommu_device_unregister(&data->iommu);
 out_sysfs_remove:
        iommu_device_sysfs_remove(&data->iommu);
+out_clk_unprepare:
+       clk_disable_unprepare(data->bclk);
        return ret;
 }
 
index 9741358..f96034e 100644 (file)
@@ -106,7 +106,8 @@ static inline unsigned long bkey_bytes(const struct bkey *k)
        return bkey_u64s(k) * sizeof(__u64);
 }
 
-#define bkey_copy(_dest, _src) memcpy(_dest, _src, bkey_bytes(_src))
+#define bkey_copy(_dest, _src) unsafe_memcpy(_dest, _src, bkey_bytes(_src), \
+                                       /* bkey is always padded */)
 
 static inline void bkey_copy_key(struct bkey *dest, const struct bkey *src)
 {
index e5da469..c182c21 100644 (file)
@@ -149,7 +149,8 @@ add:
                                    bytes, GFP_KERNEL);
                        if (!i)
                                return -ENOMEM;
-                       memcpy(&i->j, j, bytes);
+                       unsafe_memcpy(&i->j, j, bytes,
+                               /* "bytes" was calculated by set_bytes() above */);
                        /* Add to the location after 'where' points to */
                        list_add(&i->list, where);
                        ret = 1;
index 8af6392..02b0240 100644 (file)
@@ -3644,7 +3644,7 @@ EXPORT_SYMBOL_GPL(md_rdev_init);
  */
 static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
 {
-       static struct md_rdev *claim_rdev; /* just for claiming the bdev */
+       static struct md_rdev claim_rdev; /* just for claiming the bdev */
        struct md_rdev *rdev;
        sector_t size;
        int err;
@@ -3662,7 +3662,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
 
        rdev->bdev = blkdev_get_by_dev(newdev,
                        FMODE_READ | FMODE_WRITE | FMODE_EXCL,
-                       super_format == -2 ? claim_rdev : rdev);
+                       super_format == -2 ? &claim_rdev : rdev);
        if (IS_ERR(rdev->bdev)) {
                pr_warn("md: could not open device unknown-block(%u,%u).\n",
                        MAJOR(newdev), MINOR(newdev));
index fc3758a..53e4952 100644 (file)
@@ -2149,8 +2149,6 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
        if (ret)
                return ret;
 
-       q->streaming = 1;
-
        /*
         * Tell driver to start streaming provided sufficient buffers
         * are available.
@@ -2161,12 +2159,13 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
                        goto unprepare;
        }
 
+       q->streaming = 1;
+
        dprintk(q, 3, "successful\n");
        return 0;
 
 unprepare:
        call_void_qop(q, unprepare_streaming, q);
-       q->streaming = 0;
        return ret;
 }
 EXPORT_SYMBOL_GPL(vb2_core_streamon);
index 3d3b6dc..002ea65 100644 (file)
@@ -150,8 +150,8 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
                         * then return an error.
                         */
                        if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last)
-                       ctrl->is_new = 1;
                                return -ERANGE;
+                       ctrl->is_new = 1;
                }
                return ret;
        default:
index 9c49d00..ea6e9e1 100644 (file)
@@ -47,19 +47,17 @@ static int atmel_ramc_probe(struct platform_device *pdev)
        caps = of_device_get_match_data(&pdev->dev);
 
        if (caps->has_ddrck) {
-               clk = devm_clk_get(&pdev->dev, "ddrck");
+               clk = devm_clk_get_enabled(&pdev->dev, "ddrck");
                if (IS_ERR(clk))
                        return PTR_ERR(clk);
-               clk_prepare_enable(clk);
        }
 
        if (caps->has_mpddr_clk) {
-               clk = devm_clk_get(&pdev->dev, "mpddr");
+               clk = devm_clk_get_enabled(&pdev->dev, "mpddr");
                if (IS_ERR(clk)) {
                        pr_err("AT91 RAMC: couldn't get mpddr clock\n");
                        return PTR_ERR(clk);
                }
-               clk_prepare_enable(clk);
        }
 
        return 0;
index 8450638..efc6c08 100644 (file)
@@ -280,10 +280,9 @@ static int mvebu_devbus_probe(struct platform_device *pdev)
        if (IS_ERR(devbus->base))
                return PTR_ERR(devbus->base);
 
-       clk = devm_clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get_enabled(&pdev->dev, NULL);
        if (IS_ERR(clk))
                return PTR_ERR(clk);
-       clk_prepare_enable(clk);
 
        /*
         * Obtain clock period in picoseconds,
index 57d9f91..d78f73d 100644 (file)
@@ -1918,7 +1918,8 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
                }
        }
 
-       if (p->wait_pin > gpmc_nr_waitpins) {
+       if (p->wait_pin != GPMC_WAITPIN_INVALID &&
+           p->wait_pin > gpmc_nr_waitpins) {
                pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
                return -EINVAL;
        }
index 62477e5..7bb73f0 100644 (file)
 #define MC_SID_STREAMID_SECURITY_WRITE_ACCESS_DISABLED BIT(16)
 #define MC_SID_STREAMID_SECURITY_OVERRIDE BIT(8)
 
-static void tegra186_mc_program_sid(struct tegra_mc *mc)
-{
-       unsigned int i;
-
-       for (i = 0; i < mc->soc->num_clients; i++) {
-               const struct tegra_mc_client *client = &mc->soc->clients[i];
-               u32 override, security;
-
-               override = readl(mc->regs + client->regs.sid.override);
-               security = readl(mc->regs + client->regs.sid.security);
-
-               dev_dbg(mc->dev, "client %s: override: %x security: %x\n",
-                       client->name, override, security);
-
-               dev_dbg(mc->dev, "setting SID %u for %s\n", client->sid,
-                       client->name);
-               writel(client->sid, mc->regs + client->regs.sid.override);
-
-               override = readl(mc->regs + client->regs.sid.override);
-               security = readl(mc->regs + client->regs.sid.security);
-
-               dev_dbg(mc->dev, "client %s: override: %x security: %x\n",
-                       client->name, override, security);
-       }
-}
-
 static int tegra186_mc_probe(struct tegra_mc *mc)
 {
        struct platform_device *pdev = to_platform_device(mc->dev);
@@ -85,8 +59,6 @@ populate:
        if (err < 0)
                return err;
 
-       tegra186_mc_program_sid(mc);
-
        return 0;
 }
 
@@ -95,13 +67,6 @@ static void tegra186_mc_remove(struct tegra_mc *mc)
        of_platform_depopulate(mc->dev);
 }
 
-static int tegra186_mc_resume(struct tegra_mc *mc)
-{
-       tegra186_mc_program_sid(mc);
-
-       return 0;
-}
-
 #if IS_ENABLED(CONFIG_IOMMU_API)
 static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
                                            const struct tegra_mc_client *client,
@@ -173,7 +138,6 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
 const struct tegra_mc_ops tegra186_mc_ops = {
        .probe = tegra186_mc_probe,
        .remove = tegra186_mc_remove,
-       .resume = tegra186_mc_resume,
        .probe_device = tegra186_mc_probe_device,
        .handle_irq = tegra30_mc_handle_irq,
 };
index c9902a1..5310606 100644 (file)
@@ -321,7 +321,7 @@ static void fastrpc_free_map(struct kref *ref)
                        perm.vmid = QCOM_SCM_VMID_HLOS;
                        perm.perm = QCOM_SCM_PERM_RWX;
                        err = qcom_scm_assign_mem(map->phys, map->size,
-                               &(map->fl->cctx->vmperms[0].vmid), &perm, 1);
+                               &map->fl->cctx->perms, &perm, 1);
                        if (err) {
                                dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
                                                map->phys, map->size, err);
@@ -334,6 +334,13 @@ static void fastrpc_free_map(struct kref *ref)
                dma_buf_put(map->buf);
        }
 
+       if (map->fl) {
+               spin_lock(&map->fl->lock);
+               list_del(&map->node);
+               spin_unlock(&map->fl->lock);
+               map->fl = NULL;
+       }
+
        kfree(map);
 }
 
@@ -343,38 +350,41 @@ static void fastrpc_map_put(struct fastrpc_map *map)
                kref_put(&map->refcount, fastrpc_free_map);
 }
 
-static void fastrpc_map_get(struct fastrpc_map *map)
+static int fastrpc_map_get(struct fastrpc_map *map)
 {
-       if (map)
-               kref_get(&map->refcount);
+       if (!map)
+               return -ENOENT;
+
+       return kref_get_unless_zero(&map->refcount) ? 0 : -ENOENT;
 }
 
 
 static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
-                           struct fastrpc_map **ppmap)
+                           struct fastrpc_map **ppmap, bool take_ref)
 {
+       struct fastrpc_session_ctx *sess = fl->sctx;
        struct fastrpc_map *map = NULL;
+       int ret = -ENOENT;
 
-       mutex_lock(&fl->mutex);
+       spin_lock(&fl->lock);
        list_for_each_entry(map, &fl->maps, node) {
-               if (map->fd == fd) {
-                       *ppmap = map;
-                       mutex_unlock(&fl->mutex);
-                       return 0;
-               }
-       }
-       mutex_unlock(&fl->mutex);
-
-       return -ENOENT;
-}
+               if (map->fd != fd)
+                       continue;
 
-static int fastrpc_map_find(struct fastrpc_user *fl, int fd,
-                           struct fastrpc_map **ppmap)
-{
-       int ret = fastrpc_map_lookup(fl, fd, ppmap);
+               if (take_ref) {
+                       ret = fastrpc_map_get(map);
+                       if (ret) {
+                               dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n",
+                                       __func__, fd, ret);
+                               break;
+                       }
+               }
 
-       if (!ret)
-               fastrpc_map_get(*ppmap);
+               *ppmap = map;
+               ret = 0;
+               break;
+       }
+       spin_unlock(&fl->lock);
 
        return ret;
 }
@@ -746,7 +756,7 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
        struct fastrpc_map *map = NULL;
        int err = 0;
 
-       if (!fastrpc_map_find(fl, fd, ppmap))
+       if (!fastrpc_map_lookup(fl, fd, ppmap, true))
                return 0;
 
        map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -788,10 +798,8 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
                 * If subsystem VMIDs are defined in DTSI, then do
                 * hyp_assign from HLOS to those VM(s)
                 */
-               unsigned int perms = BIT(QCOM_SCM_VMID_HLOS);
-
                map->attr = attr;
-               err = qcom_scm_assign_mem(map->phys, (u64)map->size, &perms,
+               err = qcom_scm_assign_mem(map->phys, (u64)map->size, &fl->cctx->perms,
                                fl->cctx->vmperms, fl->cctx->vmcount);
                if (err) {
                        dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
@@ -1070,7 +1078,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
        for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
                if (!fdlist[i])
                        break;
-               if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap))
+               if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
                        fastrpc_map_put(mmap);
        }
 
@@ -1258,10 +1266,9 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 
                /* Map if we have any heap VMIDs associated with this ADSP Static Process. */
                if (fl->cctx->vmcount) {
-                       unsigned int perms = BIT(QCOM_SCM_VMID_HLOS);
-
                        err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
-                                                       (u64)fl->cctx->remote_heap->size, &perms,
+                                                       (u64)fl->cctx->remote_heap->size,
+                                                       &fl->cctx->perms,
                                                        fl->cctx->vmperms, fl->cctx->vmcount);
                        if (err) {
                                dev_err(fl->sctx->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
@@ -1309,7 +1316,7 @@ err_invoke:
                perm.perm = QCOM_SCM_PERM_RWX;
                err = qcom_scm_assign_mem(fl->cctx->remote_heap->phys,
                                                (u64)fl->cctx->remote_heap->size,
-                                               &(fl->cctx->vmperms[0].vmid), &perm, 1);
+                                               &fl->cctx->perms, &perm, 1);
                if (err)
                        dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
                                fl->cctx->remote_heap->phys, fl->cctx->remote_heap->size, err);
@@ -1433,12 +1440,7 @@ err_invoke:
        fl->init_mem = NULL;
        fastrpc_buf_free(imem);
 err_alloc:
-       if (map) {
-               spin_lock(&fl->lock);
-               list_del(&map->node);
-               spin_unlock(&fl->lock);
-               fastrpc_map_put(map);
-       }
+       fastrpc_map_put(map);
 err:
        kfree(args);
 
@@ -1514,10 +1516,8 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
                fastrpc_context_put(ctx);
        }
 
-       list_for_each_entry_safe(map, m, &fl->maps, node) {
-               list_del(&map->node);
+       list_for_each_entry_safe(map, m, &fl->maps, node)
                fastrpc_map_put(map);
-       }
 
        list_for_each_entry_safe(buf, b, &fl->mmaps, node) {
                list_del(&buf->node);
@@ -1894,12 +1894,11 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
        /* Add memory to static PD pool, protection thru hypervisor */
        if (req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
                struct qcom_scm_vmperm perm;
-               int err = 0;
 
                perm.vmid = QCOM_SCM_VMID_HLOS;
                perm.perm = QCOM_SCM_PERM_RWX;
                err = qcom_scm_assign_mem(buf->phys, buf->size,
-                       &(fl->cctx->vmperms[0].vmid), &perm, 1);
+                       &fl->cctx->perms, &perm, 1);
                if (err) {
                        dev_err(fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
                                        buf->phys, buf->size, err);
index 4a08b62..a81b890 100644 (file)
@@ -702,13 +702,15 @@ void *mei_cldev_dma_map(struct mei_cl_device *cldev, u8 buffer_id, size_t size)
        if (cl->state == MEI_FILE_UNINITIALIZED) {
                ret = mei_cl_link(cl);
                if (ret)
-                       goto out;
+                       goto notlinked;
                /* update pointers */
                cl->cldev = cldev;
        }
 
        ret = mei_cl_dma_alloc_and_map(cl, NULL, buffer_id, size);
-out:
+       if (ret)
+               mei_cl_unlink(cl);
+notlinked:
        mutex_unlock(&bus->device_lock);
        if (ret)
                return ERR_PTR(ret);
@@ -758,7 +760,7 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
        if (cl->state == MEI_FILE_UNINITIALIZED) {
                ret = mei_cl_link(cl);
                if (ret)
-                       goto out;
+                       goto notlinked;
                /* update pointers */
                cl->cldev = cldev;
        }
@@ -785,6 +787,9 @@ int mei_cldev_enable(struct mei_cl_device *cldev)
        }
 
 out:
+       if (ret)
+               mei_cl_unlink(cl);
+notlinked:
        mutex_unlock(&bus->device_lock);
 
        return ret;
@@ -1277,7 +1282,6 @@ static void mei_cl_bus_dev_release(struct device *dev)
        mei_cl_flush_queues(cldev->cl, NULL);
        mei_me_cl_put(cldev->me_cl);
        mei_dev_bus_put(cldev->bus);
-       mei_cl_unlink(cldev->cl);
        kfree(cldev->cl);
        kfree(cldev);
 }
index 99966cd..bdc65d5 100644 (file)
 
 #define MEI_DEV_ID_RPL_S      0x7A68  /* Raptor Lake Point S */
 
+#define MEI_DEV_ID_MTL_M      0x7E70  /* Meteor Lake Point M */
+
 /*
  * MEI HW Section
  */
index 704cd0c..5bf0d50 100644 (file)
@@ -118,6 +118,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
 
        {MEI_PCI_DEVICE(MEI_DEV_ID_RPL_S, MEI_ME_PCH15_CFG)},
 
+       {MEI_PCI_DEVICE(MEI_DEV_ID_MTL_M, MEI_ME_PCH15_CFG)},
+
        /* required last entry */
        {0, }
 };
index aa7b05d..4f8d962 100644 (file)
@@ -56,8 +56,6 @@ struct vmci_guest_device {
 
        bool exclusive_vectors;
 
-       struct tasklet_struct datagram_tasklet;
-       struct tasklet_struct bm_tasklet;
        struct wait_queue_head inout_wq;
 
        void *data_buffer;
@@ -304,9 +302,8 @@ static int vmci_check_host_caps(struct pci_dev *pdev)
  * This function assumes that it has exclusive access to the data
  * in register(s) for the duration of the call.
  */
-static void vmci_dispatch_dgs(unsigned long data)
+static void vmci_dispatch_dgs(struct vmci_guest_device *vmci_dev)
 {
-       struct vmci_guest_device *vmci_dev = (struct vmci_guest_device *)data;
        u8 *dg_in_buffer = vmci_dev->data_buffer;
        struct vmci_datagram *dg;
        size_t dg_in_buffer_size = VMCI_MAX_DG_SIZE;
@@ -465,10 +462,8 @@ static void vmci_dispatch_dgs(unsigned long data)
  * Scans the notification bitmap for raised flags, clears them
  * and handles the notifications.
  */
-static void vmci_process_bitmap(unsigned long data)
+static void vmci_process_bitmap(struct vmci_guest_device *dev)
 {
-       struct vmci_guest_device *dev = (struct vmci_guest_device *)data;
-
        if (!dev->notification_bitmap) {
                dev_dbg(dev->dev, "No bitmap present in %s\n", __func__);
                return;
@@ -486,13 +481,13 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev)
        struct vmci_guest_device *dev = _dev;
 
        /*
-        * If we are using MSI-X with exclusive vectors then we simply schedule
-        * the datagram tasklet, since we know the interrupt was meant for us.
+        * If we are using MSI-X with exclusive vectors then we simply call
+        * vmci_dispatch_dgs(), since we know the interrupt was meant for us.
         * Otherwise we must read the ICR to determine what to do.
         */
 
        if (dev->exclusive_vectors) {
-               tasklet_schedule(&dev->datagram_tasklet);
+               vmci_dispatch_dgs(dev);
        } else {
                unsigned int icr;
 
@@ -502,12 +497,12 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev)
                        return IRQ_NONE;
 
                if (icr & VMCI_ICR_DATAGRAM) {
-                       tasklet_schedule(&dev->datagram_tasklet);
+                       vmci_dispatch_dgs(dev);
                        icr &= ~VMCI_ICR_DATAGRAM;
                }
 
                if (icr & VMCI_ICR_NOTIFICATION) {
-                       tasklet_schedule(&dev->bm_tasklet);
+                       vmci_process_bitmap(dev);
                        icr &= ~VMCI_ICR_NOTIFICATION;
                }
 
@@ -536,7 +531,7 @@ static irqreturn_t vmci_interrupt_bm(int irq, void *_dev)
        struct vmci_guest_device *dev = _dev;
 
        /* For MSI-X we can just assume it was meant for us. */
-       tasklet_schedule(&dev->bm_tasklet);
+       vmci_process_bitmap(dev);
 
        return IRQ_HANDLED;
 }
@@ -638,10 +633,6 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
        vmci_dev->iobase = iobase;
        vmci_dev->mmio_base = mmio_base;
 
-       tasklet_init(&vmci_dev->datagram_tasklet,
-                    vmci_dispatch_dgs, (unsigned long)vmci_dev);
-       tasklet_init(&vmci_dev->bm_tasklet,
-                    vmci_process_bitmap, (unsigned long)vmci_dev);
        init_waitqueue_head(&vmci_dev->inout_wq);
 
        if (mmio_base != NULL) {
@@ -808,8 +799,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
         * Request IRQ for legacy or MSI interrupts, or for first
         * MSI-X vector.
         */
-       error = request_irq(pci_irq_vector(pdev, 0), vmci_interrupt,
-                           IRQF_SHARED, KBUILD_MODNAME, vmci_dev);
+       error = request_threaded_irq(pci_irq_vector(pdev, 0), NULL,
+                                    vmci_interrupt, IRQF_SHARED,
+                                    KBUILD_MODNAME, vmci_dev);
        if (error) {
                dev_err(&pdev->dev, "Irq %u in use: %d\n",
                        pci_irq_vector(pdev, 0), error);
@@ -823,9 +815,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
         * between the vectors.
         */
        if (vmci_dev->exclusive_vectors) {
-               error = request_irq(pci_irq_vector(pdev, 1),
-                                   vmci_interrupt_bm, 0, KBUILD_MODNAME,
-                                   vmci_dev);
+               error = request_threaded_irq(pci_irq_vector(pdev, 1), NULL,
+                                            vmci_interrupt_bm, 0,
+                                            KBUILD_MODNAME, vmci_dev);
                if (error) {
                        dev_err(&pdev->dev,
                                "Failed to allocate irq %u: %d\n",
@@ -833,9 +825,11 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
                        goto err_free_irq;
                }
                if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) {
-                       error = request_irq(pci_irq_vector(pdev, 2),
-                                           vmci_interrupt_dma_datagram,
-                                           0, KBUILD_MODNAME, vmci_dev);
+                       error = request_threaded_irq(pci_irq_vector(pdev, 2),
+                                                    NULL,
+                                                   vmci_interrupt_dma_datagram,
+                                                    0, KBUILD_MODNAME,
+                                                    vmci_dev);
                        if (error) {
                                dev_err(&pdev->dev,
                                        "Failed to allocate irq %u: %d\n",
@@ -871,8 +865,6 @@ err_free_bm_irq:
 
 err_free_irq:
        free_irq(pci_irq_vector(pdev, 0), vmci_dev);
-       tasklet_kill(&vmci_dev->datagram_tasklet);
-       tasklet_kill(&vmci_dev->bm_tasklet);
 
 err_disable_msi:
        pci_free_irq_vectors(pdev);
@@ -943,9 +935,6 @@ static void vmci_guest_remove_device(struct pci_dev *pdev)
        free_irq(pci_irq_vector(pdev, 0), vmci_dev);
        pci_free_irq_vectors(pdev);
 
-       tasklet_kill(&vmci_dev->datagram_tasklet);
-       tasklet_kill(&vmci_dev->bm_tasklet);
-
        if (vmci_dev->notification_bitmap) {
                /*
                 * The device reset above cleared the bitmap state of the
index 89ef0c8..9e73c34 100644 (file)
 #define ESDHC_TUNING_START_TAP_DEFAULT 0x1
 #define ESDHC_TUNING_START_TAP_MASK    0x7f
 #define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE     (1 << 7)
+#define ESDHC_TUNING_STEP_DEFAULT      0x1
 #define ESDHC_TUNING_STEP_MASK         0x00070000
 #define ESDHC_TUNING_STEP_SHIFT                16
 
@@ -1368,7 +1369,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
        struct cqhci_host *cq_host = host->mmc->cqe_private;
-       int tmp;
+       u32 tmp;
 
        if (esdhc_is_usdhc(imx_data)) {
                /*
@@ -1423,17 +1424,24 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
 
                if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
                        tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
-                       tmp |= ESDHC_STD_TUNING_EN |
-                               ESDHC_TUNING_START_TAP_DEFAULT;
-                       if (imx_data->boarddata.tuning_start_tap) {
-                               tmp &= ~ESDHC_TUNING_START_TAP_MASK;
+                       tmp |= ESDHC_STD_TUNING_EN;
+
+                       /*
+                        * ROM code or bootloader may config the start tap
+                        * and step, unmask them first.
+                        */
+                       tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK);
+                       if (imx_data->boarddata.tuning_start_tap)
                                tmp |= imx_data->boarddata.tuning_start_tap;
-                       }
+                       else
+                               tmp |= ESDHC_TUNING_START_TAP_DEFAULT;
 
                        if (imx_data->boarddata.tuning_step) {
-                               tmp &= ~ESDHC_TUNING_STEP_MASK;
                                tmp |= imx_data->boarddata.tuning_step
                                        << ESDHC_TUNING_STEP_SHIFT;
+                       } else {
+                               tmp |= ESDHC_TUNING_STEP_DEFAULT
+                                       << ESDHC_TUNING_STEP_SHIFT;
                        }
 
                        /* Disable the CMD CRC check for tuning, if not, need to
index b16e12e..3db9f32 100644 (file)
@@ -1492,9 +1492,11 @@ static int sunxi_mmc_remove(struct platform_device *pdev)
        struct sunxi_mmc_host *host = mmc_priv(mmc);
 
        mmc_remove_host(mmc);
-       pm_runtime_force_suspend(&pdev->dev);
-       disable_irq(host->irq);
-       sunxi_mmc_disable(host);
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev)) {
+               disable_irq(host->irq);
+               sunxi_mmc_disable(host);
+       }
        dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
        mmc_free_host(mmc);
 
index 02601bb..6e5e11c 100644 (file)
@@ -50,7 +50,7 @@ static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs,
        int cnt = 0;
        int res = 0;
        int res2;
-       loff_t offs;
+       uint32_t offs;
        size_t retlen;
        struct sc_part_desc *pdesc = NULL;
        struct sc_part_desc *tmpdesc;
index f601e7b..1c689da 100644 (file)
@@ -91,7 +91,7 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
        buf = mtd_parser_tplink_safeloader_read_table(mtd);
        if (!buf) {
                err = -ENOENT;
-               goto err_out;
+               goto err_free_parts;
        }
 
        for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET;
@@ -118,6 +118,8 @@ static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
 err_free:
        for (idx -= 1; idx >= 0; idx--)
                kfree(parts[idx].name);
+err_free_parts:
+       kfree(parts);
 err_out:
        return err;
 };
index d8703d7..d67c926 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/math64.h>
index 4f9b4a1..5940945 100644 (file)
@@ -76,7 +76,7 @@ void bond_debug_reregister(struct bonding *bond)
 
        d = debugfs_rename(bonding_debug_root, bond->debug_dir,
                           bonding_debug_root, bond->dev->name);
-       if (d) {
+       if (!IS_ERR(d)) {
                bond->debug_dir = d;
        } else {
                netdev_warn(bond->dev, "failed to reregister, so just unregister old one\n");
index 3585f02..57eeb06 100644 (file)
@@ -48,6 +48,7 @@ mcp251xfd_ring_set_ringparam(struct net_device *ndev,
        priv->rx_obj_num = layout.cur_rx;
        priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
        priv->tx->obj_num = layout.cur_tx;
+       priv->tx_obj_num_coalesce_irq = layout.tx_coalesce;
 
        return 0;
 }
index c26755f..f6f3b43 100644 (file)
@@ -35,12 +35,13 @@ config NET_DSA_LANTIQ_GSWIP
          the xrx200 / VR9 SoC.
 
 config NET_DSA_MT7530
-       tristate "MediaTek MT753x and MT7621 Ethernet switch support"
+       tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
        select NET_DSA_TAG_MTK
        select MEDIATEK_GE_PHY
        help
-         This enables support for the MediaTek MT7530, MT7531, and MT7621
-         Ethernet switch chips.
+         This enables support for the MediaTek MT7530 and MT7531 Ethernet
+         switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
+         MT7621ST and MT7623AI SoCs is supported.
 
 config NET_DSA_MV88E6060
        tristate "Marvell 88E6060 ethernet switch chip support"
index 47b54ec..6178a96 100644 (file)
@@ -540,10 +540,10 @@ int ksz9477_fdb_del(struct ksz_device *dev, int port,
                ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]);
 
                /* clear forwarding port */
-               alu_table[2] &= ~BIT(port);
+               alu_table[1] &= ~BIT(port);
 
                /* if there is no port to forward, clear table */
-               if ((alu_table[2] & ALU_V_PORT_MAP) == 0) {
+               if ((alu_table[1] & ALU_V_PORT_MAP) == 0) {
                        alu_table[0] = 0;
                        alu_table[1] = 0;
                        alu_table[2] = 0;
index c1a633c..e315f66 100644 (file)
@@ -104,7 +104,7 @@ static const struct of_device_id ksz9477_dt_ids[] = {
        },
        {
                .compatible = "microchip,ksz8563",
-               .data = &ksz_switch_chips[KSZ9893]
+               .data = &ksz_switch_chips[KSZ8563]
        },
        {
                .compatible = "microchip,ksz9567",
index 908fa89..338f238 100644 (file)
@@ -1309,14 +1309,26 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)
                if (!priv->ports[port].pvid)
                        mt7530_rmw(priv, MT7530_PVC_P(port), ACC_FRM_MASK,
                                   MT7530_VLAN_ACC_TAGGED);
-       }
 
-       /* Set the port as a user port which is to be able to recognize VID
-        * from incoming packets before fetching entry within the VLAN table.
-        */
-       mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
-                  VLAN_ATTR(MT7530_VLAN_USER) |
-                  PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));
+               /* Set the port as a user port which is to be able to recognize
+                * VID from incoming packets before fetching entry within the
+                * VLAN table.
+                */
+               mt7530_rmw(priv, MT7530_PVC_P(port),
+                          VLAN_ATTR_MASK | PVC_EG_TAG_MASK,
+                          VLAN_ATTR(MT7530_VLAN_USER) |
+                          PVC_EG_TAG(MT7530_VLAN_EG_DISABLED));
+       } else {
+               /* Also set CPU ports to the "user" VLAN port attribute, to
+                * allow VLAN classification, but keep the EG_TAG attribute as
+                * "consistent" (i.o.w. don't change its value) for packets
+                * received by the switch from the CPU, so that tagged packets
+                * are forwarded to user ports as tagged, and untagged as
+                * untagged.
+                */
+               mt7530_rmw(priv, MT7530_PVC_P(port), VLAN_ATTR_MASK,
+                          VLAN_ATTR(MT7530_VLAN_USER));
+       }
 }
 
 static void
index 0805f24..c26b859 100644 (file)
@@ -356,7 +356,7 @@ static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
 
        if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) ||
            (port_priv->flags & IFF_BROADCAST && rxb->pkt_type == PACKET_BROADCAST))
-               rxb->offload_fwd_mark = 1;
+               rxb->offload_fwd_mark = port_priv->priv->forwarding;
 
        netif_rx(rxb);
 
index 3936543..4030d61 100644 (file)
@@ -524,19 +524,28 @@ static void xgbe_disable_vxlan(struct xgbe_prv_data *pdata)
        netif_dbg(pdata, drv, pdata->netdev, "VXLAN acceleration disabled\n");
 }
 
+static unsigned int xgbe_get_fc_queue_count(struct xgbe_prv_data *pdata)
+{
+       unsigned int max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
+
+       /* From MAC ver 30H the TFCR is per priority, instead of per queue */
+       if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) >= 0x30)
+               return max_q_count;
+       else
+               return min_t(unsigned int, pdata->tx_q_count, max_q_count);
+}
+
 static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
 {
-       unsigned int max_q_count, q_count;
        unsigned int reg, reg_val;
-       unsigned int i;
+       unsigned int i, q_count;
 
        /* Clear MTL flow control */
        for (i = 0; i < pdata->rx_q_count; i++)
                XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0);
 
        /* Clear MAC flow control */
-       max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
-       q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count);
+       q_count = xgbe_get_fc_queue_count(pdata);
        reg = MAC_Q0TFCR;
        for (i = 0; i < q_count; i++) {
                reg_val = XGMAC_IOREAD(pdata, reg);
@@ -553,9 +562,8 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata)
 {
        struct ieee_pfc *pfc = pdata->pfc;
        struct ieee_ets *ets = pdata->ets;
-       unsigned int max_q_count, q_count;
        unsigned int reg, reg_val;
-       unsigned int i;
+       unsigned int i, q_count;
 
        /* Set MTL flow control */
        for (i = 0; i < pdata->rx_q_count; i++) {
@@ -579,8 +587,7 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata)
        }
 
        /* Set MAC flow control */
-       max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
-       q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count);
+       q_count = xgbe_get_fc_queue_count(pdata);
        reg = MAC_Q0TFCR;
        for (i = 0; i < q_count; i++) {
                reg_val = XGMAC_IOREAD(pdata, reg);
index 0c5c1b1..43fdd11 100644 (file)
@@ -496,6 +496,7 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
        reg |= XGBE_KR_TRAINING_ENABLE;
        reg |= XGBE_KR_TRAINING_START;
        XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
+       pdata->kr_start_time = jiffies;
 
        netif_dbg(pdata, link, pdata->netdev,
                  "KR training initiated\n");
@@ -632,6 +633,8 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
 
        xgbe_switch_mode(pdata);
 
+       pdata->an_result = XGBE_AN_READY;
+
        xgbe_an_restart(pdata);
 
        return XGBE_AN_INCOMPAT_LINK;
@@ -1275,9 +1278,30 @@ static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
 static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
 {
        unsigned long link_timeout;
+       unsigned long kr_time;
+       int wait;
 
        link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
        if (time_after(jiffies, link_timeout)) {
+               if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) &&
+                   pdata->phy.autoneg == AUTONEG_ENABLE) {
+                       /* AN restart should not happen while KR training is in progress.
+                        * The while loop ensures no AN restart during KR training,
+                        * waits up to 500ms and AN restart is triggered only if KR
+                        * training is failed.
+                        */
+                       wait = XGBE_KR_TRAINING_WAIT_ITER;
+                       while (wait--) {
+                               kr_time = pdata->kr_start_time +
+                                         msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
+                               if (time_after(jiffies, kr_time))
+                                       break;
+                               /* AN restart is not required, if AN result is COMPLETE */
+                               if (pdata->an_result == XGBE_AN_COMPLETE)
+                                       return;
+                               usleep_range(10000, 11000);
+                       }
+               }
                netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
                xgbe_phy_config_aneg(pdata);
        }
index 71f24cb..7a41367 100644 (file)
 /* Auto-negotiation */
 #define XGBE_AN_MS_TIMEOUT             500
 #define XGBE_LINK_TIMEOUT              5
+#define XGBE_KR_TRAINING_WAIT_ITER     50
 
 #define XGBE_SGMII_AN_LINK_STATUS      BIT(1)
 #define XGBE_SGMII_AN_LINK_SPEED       (BIT(2) | BIT(3))
@@ -1280,6 +1281,7 @@ struct xgbe_prv_data {
        unsigned int parallel_detect;
        unsigned int fec_ability;
        unsigned long an_start;
+       unsigned long kr_start_time;
        enum xgbe_an_mode an_mode;
 
        /* I2C support */
index 16ce7a9..240a7e8 100644 (file)
@@ -993,7 +993,7 @@ static struct sk_buff *bnxt_rx_multi_page_skb(struct bnxt *bp,
                             DMA_ATTR_WEAK_ORDERING);
        skb = build_skb(page_address(page), PAGE_SIZE);
        if (!skb) {
-               __free_page(page);
+               page_pool_recycle_direct(rxr->page_pool, page);
                return NULL;
        }
        skb_mark_for_recycle(skb);
@@ -1031,7 +1031,7 @@ static struct sk_buff *bnxt_rx_page_skb(struct bnxt *bp,
 
        skb = napi_alloc_skb(&rxr->bnapi->napi, payload);
        if (!skb) {
-               __free_page(page);
+               page_pool_recycle_direct(rxr->page_pool, page);
                return NULL;
        }
 
index cbf17fc..ec57312 100644 (file)
@@ -3969,7 +3969,7 @@ void bnxt_ethtool_init(struct bnxt *bp)
                test_info->timeout = HWRM_CMD_TIMEOUT;
        for (i = 0; i < bp->num_tests; i++) {
                char *str = test_info->string[i];
-               char *fw_str = resp->test0_name + i * 32;
+               char *fw_str = resp->test_name[i];
 
                if (i == BNXT_MACLPBK_TEST_IDX) {
                        strcpy(str, "Mac loopback test (offline)");
@@ -3980,14 +3980,9 @@ void bnxt_ethtool_init(struct bnxt *bp)
                } else if (i == BNXT_IRQ_TEST_IDX) {
                        strcpy(str, "Interrupt_test (offline)");
                } else {
-                       strscpy(str, fw_str, ETH_GSTRING_LEN);
-                       strncat(str, " test", ETH_GSTRING_LEN - strlen(str));
-                       if (test_info->offline_mask & (1 << i))
-                               strncat(str, " (offline)",
-                                       ETH_GSTRING_LEN - strlen(str));
-                       else
-                               strncat(str, " (online)",
-                                       ETH_GSTRING_LEN - strlen(str));
+                       snprintf(str, ETH_GSTRING_LEN, "%s test (%s)",
+                                fw_str, test_info->offline_mask & (1 << i) ?
+                                       "offline" : "online");
                }
        }
 
index 2686a71..a540887 100644 (file)
@@ -10249,14 +10249,7 @@ struct hwrm_selftest_qlist_output {
        u8      unused_0;
        __le16  test_timeout;
        u8      unused_1[2];
-       char    test0_name[32];
-       char    test1_name[32];
-       char    test2_name[32];
-       char    test3_name[32];
-       char    test4_name[32];
-       char    test5_name[32];
-       char    test6_name[32];
-       char    test7_name[32];
+       char    test_name[8][32];
        u8      eyescope_target_BER_support;
        #define SELFTEST_QLIST_RESP_EYESCOPE_TARGET_BER_SUPPORT_BER_1E8_SUPPORTED  0x0UL
        #define SELFTEST_QLIST_RESP_EYESCOPE_TARGET_BER_SUPPORT_BER_1E9_SUPPORTED  0x1UL
index 59debdc..5874729 100644 (file)
@@ -11166,7 +11166,7 @@ static void tg3_reset_task(struct work_struct *work)
        rtnl_lock();
        tg3_full_lock(tp, 0);
 
-       if (!netif_running(tp->dev)) {
+       if (tp->pcierr_recovery || !netif_running(tp->dev)) {
                tg3_flag_clear(tp, RESET_TASK_PENDING);
                tg3_full_unlock(tp);
                rtnl_unlock();
@@ -18101,6 +18101,9 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        netdev_info(netdev, "PCI I/O error detected\n");
 
+       /* Want to make sure that the reset task doesn't run */
+       tg3_reset_task_cancel(tp);
+
        rtnl_lock();
 
        /* Could be second call or maybe we don't have netdev yet */
@@ -18117,9 +18120,6 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        tg3_timer_stop(tp);
 
-       /* Want to make sure that the reset task doesn't run */
-       tg3_reset_task_cancel(tp);
-
        netif_device_detach(netdev);
 
        /* Clean up software state, even if MMIO is blocked */
index 95667b9..6cda315 100644 (file)
@@ -2187,7 +2187,6 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
        bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb) ||
                      skb_is_nonlinear(*skb);
        int padlen = ETH_ZLEN - (*skb)->len;
-       int headroom = skb_headroom(*skb);
        int tailroom = skb_tailroom(*skb);
        struct sk_buff *nskb;
        u32 fcs;
@@ -2201,9 +2200,6 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
                /* FCS could be appeded to tailroom. */
                if (tailroom >= ETH_FCS_LEN)
                        goto add_fcs;
-               /* FCS could be appeded by moving data to headroom. */
-               else if (!cloned && headroom + tailroom >= ETH_FCS_LEN)
-                       padlen = 0;
                /* No room for FCS, need to reallocate skb. */
                else
                        padlen = ETH_FCS_LEN;
@@ -2212,10 +2208,7 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
                padlen += ETH_FCS_LEN;
        }
 
-       if (!cloned && headroom + tailroom >= padlen) {
-               (*skb)->data = memmove((*skb)->head, (*skb)->data, (*skb)->len);
-               skb_set_tail_pointer(*skb, (*skb)->len);
-       } else {
+       if (cloned || tailroom < padlen) {
                nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
                if (!nskb)
                        return -ENOMEM;
@@ -4634,25 +4627,26 @@ static int init_reset_optional(struct platform_device *pdev)
                if (ret)
                        return dev_err_probe(&pdev->dev, ret,
                                             "failed to init SGMII PHY\n");
-       }
 
-       ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG);
-       if (!ret) {
-               u32 pm_info[2];
+               ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG);
+               if (!ret) {
+                       u32 pm_info[2];
+
+                       ret = of_property_read_u32_array(pdev->dev.of_node, "power-domains",
+                                                        pm_info, ARRAY_SIZE(pm_info));
+                       if (ret) {
+                               dev_err(&pdev->dev, "Failed to read power management information\n");
+                               goto err_out_phy_exit;
+                       }
+                       ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_FIXED, 0);
+                       if (ret)
+                               goto err_out_phy_exit;
 
-               ret = of_property_read_u32_array(pdev->dev.of_node, "power-domains",
-                                                pm_info, ARRAY_SIZE(pm_info));
-               if (ret) {
-                       dev_err(&pdev->dev, "Failed to read power management information\n");
-                       goto err_out_phy_exit;
+                       ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_SGMII_MODE, 1);
+                       if (ret)
+                               goto err_out_phy_exit;
                }
-               ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_FIXED, 0);
-               if (ret)
-                       goto err_out_phy_exit;
 
-               ret = zynqmp_pm_set_gem_config(pm_info[1], GEM_CONFIG_SGMII_MODE, 1);
-               if (ret)
-                       goto err_out_phy_exit;
        }
 
        /* Fully reset controller at hardware level if mapped in device tree */
index bf0190e..00e2108 100644 (file)
@@ -450,7 +450,7 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
                /* ring full, shall not happen because queue is stopped if full
                 * below
                 */
-               netif_stop_queue(tx->adapter->netdev);
+               netif_stop_subqueue(tx->adapter->netdev, tx->queue_index);
 
                spin_unlock_irqrestore(&tx->lock, flags);
 
@@ -493,7 +493,7 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
 
        if (tsnep_tx_desc_available(tx) < (MAX_SKB_FRAGS + 1)) {
                /* ring can get full with next frame */
-               netif_stop_queue(tx->adapter->netdev);
+               netif_stop_subqueue(tx->adapter->netdev, tx->queue_index);
        }
 
        spin_unlock_irqrestore(&tx->lock, flags);
@@ -503,11 +503,14 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
 
 static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
 {
+       struct tsnep_tx_entry *entry;
+       struct netdev_queue *nq;
        unsigned long flags;
        int budget = 128;
-       struct tsnep_tx_entry *entry;
-       int count;
        int length;
+       int count;
+
+       nq = netdev_get_tx_queue(tx->adapter->netdev, tx->queue_index);
 
        spin_lock_irqsave(&tx->lock, flags);
 
@@ -564,8 +567,8 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
        } while (likely(budget));
 
        if ((tsnep_tx_desc_available(tx) >= ((MAX_SKB_FRAGS + 1) * 2)) &&
-           netif_queue_stopped(tx->adapter->netdev)) {
-               netif_wake_queue(tx->adapter->netdev);
+           netif_tx_queue_stopped(nq)) {
+               netif_tx_wake_queue(nq);
        }
 
        spin_unlock_irqrestore(&tx->lock, flags);
index 3f80329..027fff9 100644 (file)
@@ -2410,6 +2410,9 @@ static int dpaa_eth_poll(struct napi_struct *napi, int budget)
 
        cleaned = qman_p_poll_dqrr(np->p, budget);
 
+       if (np->xdp_act & XDP_REDIRECT)
+               xdp_do_flush();
+
        if (cleaned < budget) {
                napi_complete_done(napi, cleaned);
                qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
@@ -2417,9 +2420,6 @@ static int dpaa_eth_poll(struct napi_struct *napi, int budget)
                qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
        }
 
-       if (np->xdp_act & XDP_REDIRECT)
-               xdp_do_flush();
-
        return cleaned;
 }
 
index 0c35abb..2e79d18 100644 (file)
@@ -1993,10 +1993,15 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget)
                if (rx_cleaned >= budget ||
                    txconf_cleaned >= DPAA2_ETH_TXCONF_PER_NAPI) {
                        work_done = budget;
+                       if (ch->xdp.res & XDP_REDIRECT)
+                               xdp_do_flush();
                        goto out;
                }
        } while (store_cleaned);
 
+       if (ch->xdp.res & XDP_REDIRECT)
+               xdp_do_flush();
+
        /* Update NET DIM with the values for this CDAN */
        dpaa2_io_update_net_dim(ch->dpio, ch->stats.frames_per_cdan,
                                ch->stats.bytes_per_cdan);
@@ -2032,9 +2037,7 @@ out:
                txc_fq->dq_bytes = 0;
        }
 
-       if (ch->xdp.res & XDP_REDIRECT)
-               xdp_do_flush_map();
-       else if (rx_cleaned && ch->xdp.res & XDP_TX)
+       if (rx_cleaned && ch->xdp.res & XDP_TX)
                dpaa2_eth_xdp_tx_flush(priv, ch, &priv->fq[flowid]);
 
        return work_done;
index 3a79ead..e96449e 100644 (file)
@@ -2290,14 +2290,14 @@ static void enetc_tx_onestep_tstamp(struct work_struct *work)
 
        priv = container_of(work, struct enetc_ndev_priv, tx_onestep_tstamp);
 
-       netif_tx_lock(priv->ndev);
+       netif_tx_lock_bh(priv->ndev);
 
        clear_bit_unlock(ENETC_TX_ONESTEP_TSTAMP_IN_PROGRESS, &priv->flags);
        skb = skb_dequeue(&priv->tx_skbs);
        if (skb)
                enetc_start_xmit(skb, priv->ndev);
 
-       netif_tx_unlock(priv->ndev);
+       netif_tx_unlock_bh(priv->ndev);
 }
 
 static void enetc_tx_onestep_tstamp_init(struct enetc_ndev_priv *priv)
index 644f3c9..2341597 100644 (file)
@@ -3191,7 +3191,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
        for (q = 0; q < fep->num_rx_queues; q++) {
                rxq = fep->rx_queue[q];
                for (i = 0; i < rxq->bd.ring_size; i++)
-                       page_pool_release_page(rxq->page_pool, rxq->rx_skb_info[i].page);
+                       page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false);
 
                for (i = 0; i < XDP_STATS_TOTAL; i++)
                        rxq->stats[i] = 0;
index 9349f84..587ad81 100644 (file)
@@ -1055,6 +1055,9 @@ static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node,
                return ERR_PTR(-EPROBE_DEFER);
 
        pcs = lynx_pcs_create(mdiodev);
+       if (!pcs)
+               mdio_device_free(mdiodev);
+
        return pcs;
 }
 
index 081bd2c..e84e5be 100644 (file)
@@ -3130,7 +3130,7 @@ static int hclgevf_set_channels(struct hnae3_handle *handle, u32 new_tqps_num,
 
        hclgevf_update_rss_size(handle, new_tqps_num);
 
-       hclge_comm_get_rss_tc_info(cur_rss_size, hdev->hw_tc_map,
+       hclge_comm_get_rss_tc_info(kinfo->rss_size, hdev->hw_tc_map,
                                   tc_offset, tc_valid, tc_size);
        ret = hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset,
                                         tc_valid, tc_size);
index 0d1bab4..2a9f1ee 100644 (file)
@@ -249,6 +249,7 @@ struct iavf_cloud_filter {
 
 /* board specific private data structure */
 struct iavf_adapter {
+       struct workqueue_struct *wq;
        struct work_struct reset_task;
        struct work_struct adminq_task;
        struct delayed_work client_task;
@@ -459,7 +460,6 @@ struct iavf_device {
 
 /* needed by iavf_ethtool.c */
 extern char iavf_driver_name[];
-extern struct workqueue_struct *iavf_wq;
 
 static inline const char *iavf_state_str(enum iavf_state_t state)
 {
index d79ead5..6f171d1 100644 (file)
@@ -532,7 +532,7 @@ static int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
        if (changed_flags & IAVF_FLAG_LEGACY_RX) {
                if (netif_running(netdev)) {
                        adapter->flags |= IAVF_FLAG_RESET_NEEDED;
-                       queue_work(iavf_wq, &adapter->reset_task);
+                       queue_work(adapter->wq, &adapter->reset_task);
                }
        }
 
@@ -672,7 +672,7 @@ static int iavf_set_ringparam(struct net_device *netdev,
 
        if (netif_running(netdev)) {
                adapter->flags |= IAVF_FLAG_RESET_NEEDED;
-               queue_work(iavf_wq, &adapter->reset_task);
+               queue_work(adapter->wq, &adapter->reset_task);
        }
 
        return 0;
@@ -1433,7 +1433,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
        adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
        spin_unlock_bh(&adapter->fdir_fltr_lock);
 
-       mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+       mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 
 ret:
        if (err && fltr)
@@ -1474,7 +1474,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
        spin_unlock_bh(&adapter->fdir_fltr_lock);
 
        if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
-               mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+               mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 
        return err;
 }
@@ -1658,7 +1658,7 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
        spin_unlock_bh(&adapter->adv_rss_lock);
 
        if (!err)
-               mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+               mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 
        mutex_unlock(&adapter->crit_lock);
 
index c4e451e..4b09785 100644 (file)
@@ -49,7 +49,6 @@ MODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver")
 MODULE_LICENSE("GPL v2");
 
 static const struct net_device_ops iavf_netdev_ops;
-struct workqueue_struct *iavf_wq;
 
 int iavf_status_to_errno(enum iavf_status status)
 {
@@ -277,7 +276,7 @@ void iavf_schedule_reset(struct iavf_adapter *adapter)
        if (!(adapter->flags &
              (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED))) {
                adapter->flags |= IAVF_FLAG_RESET_NEEDED;
-               queue_work(iavf_wq, &adapter->reset_task);
+               queue_work(adapter->wq, &adapter->reset_task);
        }
 }
 
@@ -291,7 +290,7 @@ void iavf_schedule_reset(struct iavf_adapter *adapter)
 void iavf_schedule_request_stats(struct iavf_adapter *adapter)
 {
        adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_STATS;
-       mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+       mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 }
 
 /**
@@ -411,7 +410,7 @@ static irqreturn_t iavf_msix_aq(int irq, void *data)
 
        if (adapter->state != __IAVF_REMOVE)
                /* schedule work on the private workqueue */
-               queue_work(iavf_wq, &adapter->adminq_task);
+               queue_work(adapter->wq, &adapter->adminq_task);
 
        return IRQ_HANDLED;
 }
@@ -1034,7 +1033,7 @@ int iavf_replace_primary_mac(struct iavf_adapter *adapter,
 
        /* schedule the watchdog task to immediately process the request */
        if (f) {
-               queue_work(iavf_wq, &adapter->watchdog_task.work);
+               mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
                return 0;
        }
        return -ENOMEM;
@@ -1257,7 +1256,7 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
        adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES;
        if (CLIENT_ENABLED(adapter))
                adapter->flags |= IAVF_FLAG_CLIENT_NEEDS_OPEN;
-       mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+       mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 }
 
 /**
@@ -1414,7 +1413,7 @@ void iavf_down(struct iavf_adapter *adapter)
                adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES;
        }
 
-       mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+       mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
 }
 
 /**
@@ -2248,7 +2247,7 @@ iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
 
        if (aq_required) {
                adapter->aq_required |= aq_required;
-               mod_delayed_work(iavf_wq, &adapter->watchdog_task, 0);
+               mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
        }
 }
 
@@ -2693,6 +2692,15 @@ static void iavf_watchdog_task(struct work_struct *work)
                goto restart_watchdog;
        }
 
+       if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) &&
+           adapter->netdev_registered &&
+           !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section) &&
+           rtnl_trylock()) {
+               netdev_update_features(adapter->netdev);
+               rtnl_unlock();
+               adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES;
+       }
+
        if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
                iavf_change_state(adapter, __IAVF_COMM_FAILED);
 
@@ -2700,7 +2708,7 @@ static void iavf_watchdog_task(struct work_struct *work)
                adapter->aq_required = 0;
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
                mutex_unlock(&adapter->crit_lock);
-               queue_work(iavf_wq, &adapter->reset_task);
+               queue_work(adapter->wq, &adapter->reset_task);
                return;
        }
 
@@ -2708,31 +2716,31 @@ static void iavf_watchdog_task(struct work_struct *work)
        case __IAVF_STARTUP:
                iavf_startup(adapter);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(30));
                return;
        case __IAVF_INIT_VERSION_CHECK:
                iavf_init_version_check(adapter);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(30));
                return;
        case __IAVF_INIT_GET_RESOURCES:
                iavf_init_get_resources(adapter);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(1));
                return;
        case __IAVF_INIT_EXTENDED_CAPS:
                iavf_init_process_extended_caps(adapter);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(1));
                return;
        case __IAVF_INIT_CONFIG_ADAPTER:
                iavf_init_config_adapter(adapter);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(1));
                return;
        case __IAVF_INIT_FAILED:
@@ -2751,14 +2759,14 @@ static void iavf_watchdog_task(struct work_struct *work)
                        adapter->flags |= IAVF_FLAG_PF_COMMS_FAILED;
                        iavf_shutdown_adminq(hw);
                        mutex_unlock(&adapter->crit_lock);
-                       queue_delayed_work(iavf_wq,
+                       queue_delayed_work(adapter->wq,
                                           &adapter->watchdog_task, (5 * HZ));
                        return;
                }
                /* Try again from failed step*/
                iavf_change_state(adapter, adapter->last_state);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ);
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task, HZ);
                return;
        case __IAVF_COMM_FAILED:
                if (test_bit(__IAVF_IN_REMOVE_TASK,
@@ -2789,13 +2797,14 @@ static void iavf_watchdog_task(struct work_struct *work)
                adapter->aq_required = 0;
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq,
+               queue_delayed_work(adapter->wq,
                                   &adapter->watchdog_task,
                                   msecs_to_jiffies(10));
                return;
        case __IAVF_RESETTING:
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2);
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
+                                  HZ * 2);
                return;
        case __IAVF_DOWN:
        case __IAVF_DOWN_PENDING:
@@ -2834,9 +2843,9 @@ static void iavf_watchdog_task(struct work_struct *work)
                adapter->aq_required = 0;
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
                dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
-               queue_work(iavf_wq, &adapter->reset_task);
+               queue_work(adapter->wq, &adapter->reset_task);
                mutex_unlock(&adapter->crit_lock);
-               queue_delayed_work(iavf_wq,
+               queue_delayed_work(adapter->wq,
                                   &adapter->watchdog_task, HZ * 2);
                return;
        }
@@ -2845,12 +2854,13 @@ static void iavf_watchdog_task(struct work_struct *work)
        mutex_unlock(&adapter->crit_lock);
 restart_watchdog:
        if (adapter->state >= __IAVF_DOWN)
-               queue_work(iavf_wq, &adapter->adminq_task);
+               queue_work(adapter->wq, &adapter->adminq_task);
        if (adapter->aq_required)
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(20));
        else
-               queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2);
+               queue_delayed_work(adapter->wq, &adapter->watchdog_task,
+                                  HZ * 2);
 }
 
 /**
@@ -2952,7 +2962,7 @@ static void iavf_reset_task(struct work_struct *work)
         */
        if (!mutex_trylock(&adapter->crit_lock)) {
                if (adapter->state != __IAVF_REMOVE)
-                       queue_work(iavf_wq, &adapter->reset_task);
+                       queue_work(adapter->wq, &adapter->reset_task);
 
                goto reset_finish;
        }
@@ -3116,7 +3126,7 @@ continue_reset:
        bitmap_clear(adapter->vsi.active_cvlans, 0, VLAN_N_VID);
        bitmap_clear(adapter->vsi.active_svlans, 0, VLAN_N_VID);
 
-       mod_delayed_work(iavf_wq, &adapter->watchdog_task, 2);
+       mod_delayed_work(adapter->wq, &adapter->watchdog_task, 2);
 
        /* We were running when the reset started, so we need to restore some
         * state here.
@@ -3208,7 +3218,7 @@ static void iavf_adminq_task(struct work_struct *work)
                if (adapter->state == __IAVF_REMOVE)
                        return;
 
-               queue_work(iavf_wq, &adapter->adminq_task);
+               queue_work(adapter->wq, &adapter->adminq_task);
                goto out;
        }
 
@@ -3232,24 +3242,6 @@ static void iavf_adminq_task(struct work_struct *work)
        } while (pending);
        mutex_unlock(&adapter->crit_lock);
 
-       if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES)) {
-               if (adapter->netdev_registered ||
-                   !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) {
-                       struct net_device *netdev = adapter->netdev;
-
-                       rtnl_lock();
-                       netdev_update_features(netdev);
-                       rtnl_unlock();
-                       /* Request VLAN offload settings */
-                       if (VLAN_V2_ALLOWED(adapter))
-                               iavf_set_vlan_offload_features
-                                       (adapter, 0, netdev->features);
-
-                       iavf_set_queue_vlan_tag_loc(adapter);
-               }
-
-               adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES;
-       }
        if ((adapter->flags &
             (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
            adapter->state == __IAVF_RESETTING)
@@ -3850,7 +3842,7 @@ static int iavf_parse_cls_flower(struct iavf_adapter *adapter,
                                field_flags |= IAVF_CLOUD_FIELD_IIP;
                        } else {
                                dev_err(&adapter->pdev->dev, "Bad ip src mask 0x%08x\n",
-                                       be32_to_cpu(match.mask->dst));
+                                       be32_to_cpu(match.mask->src));
                                return -EINVAL;
                        }
                }
@@ -4349,7 +4341,7 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
 
        if (netif_running(netdev)) {
                adapter->flags |= IAVF_FLAG_RESET_NEEDED;
-               queue_work(iavf_wq, &adapter->reset_task);
+               queue_work(adapter->wq, &adapter->reset_task);
        }
 
        return 0;
@@ -4898,6 +4890,13 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        hw = &adapter->hw;
        hw->back = adapter;
 
+       adapter->wq = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM,
+                                             iavf_driver_name);
+       if (!adapter->wq) {
+               err = -ENOMEM;
+               goto err_alloc_wq;
+       }
+
        adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
        iavf_change_state(adapter, __IAVF_STARTUP);
 
@@ -4942,7 +4941,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        INIT_WORK(&adapter->adminq_task, iavf_adminq_task);
        INIT_DELAYED_WORK(&adapter->watchdog_task, iavf_watchdog_task);
        INIT_DELAYED_WORK(&adapter->client_task, iavf_client_task);
-       queue_delayed_work(iavf_wq, &adapter->watchdog_task,
+       queue_delayed_work(adapter->wq, &adapter->watchdog_task,
                           msecs_to_jiffies(5 * (pdev->devfn & 0x07)));
 
        /* Setup the wait queue for indicating transition to down status */
@@ -4954,6 +4953,8 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
 err_ioremap:
+       destroy_workqueue(adapter->wq);
+err_alloc_wq:
        free_netdev(netdev);
 err_alloc_etherdev:
        pci_disable_pcie_error_reporting(pdev);
@@ -5023,7 +5024,7 @@ static int __maybe_unused iavf_resume(struct device *dev_d)
                return err;
        }
 
-       queue_work(iavf_wq, &adapter->reset_task);
+       queue_work(adapter->wq, &adapter->reset_task);
 
        netif_device_attach(adapter->netdev);
 
@@ -5170,6 +5171,8 @@ static void iavf_remove(struct pci_dev *pdev)
        }
        spin_unlock_bh(&adapter->adv_rss_lock);
 
+       destroy_workqueue(adapter->wq);
+
        free_netdev(netdev);
 
        pci_disable_pcie_error_reporting(pdev);
@@ -5196,24 +5199,11 @@ static struct pci_driver iavf_driver = {
  **/
 static int __init iavf_init_module(void)
 {
-       int ret;
-
        pr_info("iavf: %s\n", iavf_driver_string);
 
        pr_info("%s\n", iavf_copyright);
 
-       iavf_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1,
-                                 iavf_driver_name);
-       if (!iavf_wq) {
-               pr_err("%s: Failed to create workqueue\n", iavf_driver_name);
-               return -ENOMEM;
-       }
-
-       ret = pci_register_driver(&iavf_driver);
-       if (ret)
-               destroy_workqueue(iavf_wq);
-
-       return ret;
+       return pci_register_driver(&iavf_driver);
 }
 
 module_init(iavf_init_module);
@@ -5227,7 +5217,6 @@ module_init(iavf_init_module);
 static void __exit iavf_exit_module(void)
 {
        pci_unregister_driver(&iavf_driver);
-       destroy_workqueue(iavf_wq);
 }
 
 module_exit(iavf_exit_module);
index 24a701f..365ca0c 100644 (file)
@@ -1952,7 +1952,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                        if (!(adapter->flags & IAVF_FLAG_RESET_PENDING)) {
                                adapter->flags |= IAVF_FLAG_RESET_PENDING;
                                dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
-                               queue_work(iavf_wq, &adapter->reset_task);
+                               queue_work(adapter->wq, &adapter->reset_task);
                        }
                        break;
                default:
@@ -2226,6 +2226,14 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
 
                iavf_process_config(adapter);
                adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
+
+               /* Request VLAN offload settings */
+               if (VLAN_V2_ALLOWED(adapter))
+                       iavf_set_vlan_offload_features(adapter, 0,
+                                                      netdev->features);
+
+               iavf_set_queue_vlan_tag_loc(adapter);
+
                was_mac_changed = !ether_addr_equal(netdev->dev_addr,
                                                    adapter->hw.mac.addr);
 
index 2f0b604..713069f 100644 (file)
@@ -880,7 +880,7 @@ void ice_set_ethtool_repr_ops(struct net_device *netdev);
 void ice_set_ethtool_safe_mode_ops(struct net_device *netdev);
 u16 ice_get_avail_txq_count(struct ice_pf *pf);
 u16 ice_get_avail_rxq_count(struct ice_pf *pf);
-int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx);
+int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked);
 void ice_update_vsi_stats(struct ice_vsi *vsi);
 void ice_update_pf_stats(struct ice_pf *pf);
 void
index d02b55b..3e08847 100644 (file)
@@ -5524,7 +5524,7 @@ bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw)
  * returned by the firmware is a 16 bit * value, but is indexed
  * by [fls(speed) - 1]
  */
-static const u32 ice_aq_to_link_speed[15] = {
+static const u32 ice_aq_to_link_speed[] = {
        SPEED_10,       /* BIT(0) */
        SPEED_100,
        SPEED_1000,
@@ -5536,10 +5536,6 @@ static const u32 ice_aq_to_link_speed[15] = {
        SPEED_40000,
        SPEED_50000,
        SPEED_100000,   /* BIT(10) */
-       0,
-       0,
-       0,
-       0               /* BIT(14) */
 };
 
 /**
@@ -5550,5 +5546,8 @@ static const u32 ice_aq_to_link_speed[15] = {
  */
 u32 ice_get_link_speed(u16 index)
 {
+       if (index >= ARRAY_SIZE(ice_aq_to_link_speed))
+               return 0;
+
        return ice_aq_to_link_speed[index];
 }
index 4f24d44..0a55c55 100644 (file)
@@ -441,7 +441,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked)
                goto out;
        }
 
-       ice_pf_dcb_recfg(pf);
+       ice_pf_dcb_recfg(pf, false);
 
 out:
        /* enable previously downed VSIs */
@@ -731,12 +731,13 @@ static int ice_dcb_noncontig_cfg(struct ice_pf *pf)
 /**
  * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs
  * @pf: pointer to the PF struct
+ * @locked: is adev device lock held
  *
  * Assumed caller has already disabled all VSIs before
  * calling this function. Reconfiguring DCB based on
  * local_dcbx_cfg.
  */
-void ice_pf_dcb_recfg(struct ice_pf *pf)
+void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked)
 {
        struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->qos_cfg.local_dcbx_cfg;
        struct iidc_event *event;
@@ -783,14 +784,16 @@ void ice_pf_dcb_recfg(struct ice_pf *pf)
                if (vsi->type == ICE_VSI_PF)
                        ice_dcbnl_set_all(vsi);
        }
-       /* Notify the AUX drivers that TC change is finished */
-       event = kzalloc(sizeof(*event), GFP_KERNEL);
-       if (!event)
-               return;
+       if (!locked) {
+               /* Notify the AUX drivers that TC change is finished */
+               event = kzalloc(sizeof(*event), GFP_KERNEL);
+               if (!event)
+                       return;
 
-       set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type);
-       ice_send_event_to_aux(pf, event);
-       kfree(event);
+               set_bit(IIDC_EVENT_AFTER_TC_CHANGE, event->type);
+               ice_send_event_to_aux(pf, event);
+               kfree(event);
+       }
 }
 
 /**
@@ -1044,7 +1047,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf,
        }
 
        /* changes in configuration update VSI */
-       ice_pf_dcb_recfg(pf);
+       ice_pf_dcb_recfg(pf, false);
 
        /* enable previously downed VSIs */
        ice_dcb_ena_dis_vsi(pf, true, true);
index 4c421c8..800879a 100644 (file)
@@ -23,7 +23,7 @@ u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index);
 int
 ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked);
 int ice_dcb_bwchk(struct ice_pf *pf, struct ice_dcbx_cfg *dcbcfg);
-void ice_pf_dcb_recfg(struct ice_pf *pf);
+void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked);
 void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi);
 int ice_init_pf_dcb(struct ice_pf *pf, bool locked);
 void ice_update_dcb_stats(struct ice_pf *pf);
@@ -128,7 +128,7 @@ static inline u8 ice_get_pfc_mode(struct ice_pf *pf)
        return 0;
 }
 
-static inline void ice_pf_dcb_recfg(struct ice_pf *pf) { }
+static inline void ice_pf_dcb_recfg(struct ice_pf *pf, bool locked) { }
 static inline void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) { }
 static inline void ice_update_dcb_stats(struct ice_pf *pf) { }
 static inline void
index 4191994..a359f16 100644 (file)
@@ -3641,7 +3641,9 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)
        struct ice_vsi *vsi = np->vsi;
        struct ice_pf *pf = vsi->back;
        int new_rx = 0, new_tx = 0;
+       bool locked = false;
        u32 curr_combined;
+       int ret = 0;
 
        /* do not support changing channels in Safe Mode */
        if (ice_is_safe_mode(pf)) {
@@ -3705,15 +3707,33 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)
                return -EINVAL;
        }
 
-       ice_vsi_recfg_qs(vsi, new_rx, new_tx);
+       if (pf->adev) {
+               mutex_lock(&pf->adev_mutex);
+               device_lock(&pf->adev->dev);
+               locked = true;
+               if (pf->adev->dev.driver) {
+                       netdev_err(dev, "Cannot change channels when RDMA is active\n");
+                       ret = -EBUSY;
+                       goto adev_unlock;
+               }
+       }
+
+       ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked);
 
-       if (!netif_is_rxfh_configured(dev))
-               return ice_vsi_set_dflt_rss_lut(vsi, new_rx);
+       if (!netif_is_rxfh_configured(dev)) {
+               ret = ice_vsi_set_dflt_rss_lut(vsi, new_rx);
+               goto adev_unlock;
+       }
 
        /* Update rss_size due to change in Rx queues */
        vsi->rss_size = ice_get_valid_rss_size(&pf->hw, new_rx);
 
-       return 0;
+adev_unlock:
+       if (locked) {
+               device_unlock(&pf->adev->dev);
+               mutex_unlock(&pf->adev_mutex);
+       }
+       return ret;
 }
 
 /**
index b5a7f24..43e199b 100644 (file)
@@ -363,6 +363,7 @@ ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
        /* Send the data out to a hardware port */
        write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
        if (!write_buf) {
+               kfree(cmd_buf);
                err = -ENOMEM;
                goto exit;
        }
@@ -460,6 +461,9 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
        for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
                pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]),
                                               GFP_KERNEL);
+               if (!pf->gnss_tty_port[i])
+                       goto err_out;
+
                pf->gnss_serial[i] = NULL;
 
                tty_port_init(pf->gnss_tty_port[i]);
@@ -469,21 +473,23 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf)
        err = tty_register_driver(tty_driver);
        if (err) {
                dev_err(dev, "Failed to register TTY driver err=%d\n", err);
-
-               for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) {
-                       tty_port_destroy(pf->gnss_tty_port[i]);
-                       kfree(pf->gnss_tty_port[i]);
-               }
-               kfree(ttydrv_name);
-               tty_driver_kref_put(pf->ice_gnss_tty_driver);
-
-               return NULL;
+               goto err_out;
        }
 
        for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++)
                dev_info(dev, "%s%d registered\n", ttydrv_name, i);
 
        return tty_driver;
+
+err_out:
+       while (i--) {
+               tty_port_destroy(pf->gnss_tty_port[i]);
+               kfree(pf->gnss_tty_port[i]);
+       }
+       kfree(ttydrv_name);
+       tty_driver_kref_put(pf->ice_gnss_tty_driver);
+
+       return NULL;
 }
 
 /**
index 94aa834..a596e07 100644 (file)
@@ -3235,9 +3235,6 @@ int ice_vsi_release(struct ice_vsi *vsi)
                }
        }
 
-       if (vsi->type == ICE_VSI_PF)
-               ice_devlink_destroy_pf_port(pf);
-
        if (vsi->type == ICE_VSI_VF &&
            vsi->agg_node && vsi->agg_node->valid)
                vsi->agg_node->num_vsis--;
index a9a7f8b..b288a01 100644 (file)
@@ -4195,12 +4195,13 @@ bool ice_is_wol_supported(struct ice_hw *hw)
  * @vsi: VSI being changed
  * @new_rx: new number of Rx queues
  * @new_tx: new number of Tx queues
+ * @locked: is adev device_lock held
  *
  * Only change the number of queues if new_tx, or new_rx is non-0.
  *
  * Returns 0 on success.
  */
-int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx)
+int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked)
 {
        struct ice_pf *pf = vsi->back;
        int err = 0, timeout = 50;
@@ -4229,7 +4230,7 @@ int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx)
 
        ice_vsi_close(vsi);
        ice_vsi_rebuild(vsi, false);
-       ice_pf_dcb_recfg(pf);
+       ice_pf_dcb_recfg(pf, locked);
        ice_vsi_open(vsi);
 done:
        clear_bit(ICE_CFG_BUSY, pf->state);
@@ -4590,7 +4591,7 @@ static void ice_print_wake_reason(struct ice_pf *pf)
 }
 
 /**
- * ice_register_netdev - register netdev and devlink port
+ * ice_register_netdev - register netdev
  * @pf: pointer to the PF struct
  */
 static int ice_register_netdev(struct ice_pf *pf)
@@ -4602,11 +4603,6 @@ static int ice_register_netdev(struct ice_pf *pf)
        if (!vsi || !vsi->netdev)
                return -EIO;
 
-       err = ice_devlink_create_pf_port(pf);
-       if (err)
-               goto err_devlink_create;
-
-       SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port);
        err = register_netdev(vsi->netdev);
        if (err)
                goto err_register_netdev;
@@ -4617,8 +4613,6 @@ static int ice_register_netdev(struct ice_pf *pf)
 
        return 0;
 err_register_netdev:
-       ice_devlink_destroy_pf_port(pf);
-err_devlink_create:
        free_netdev(vsi->netdev);
        vsi->netdev = NULL;
        clear_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
@@ -4636,6 +4630,7 @@ static int
 ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
 {
        struct device *dev = &pdev->dev;
+       struct ice_vsi *vsi;
        struct ice_pf *pf;
        struct ice_hw *hw;
        int i, err;
@@ -4918,6 +4913,18 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
        pcie_print_link_status(pf->pdev);
 
 probe_done:
+       err = ice_devlink_create_pf_port(pf);
+       if (err)
+               goto err_create_pf_port;
+
+       vsi = ice_get_main_vsi(pf);
+       if (!vsi || !vsi->netdev) {
+               err = -EINVAL;
+               goto err_netdev_reg;
+       }
+
+       SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port);
+
        err = ice_register_netdev(pf);
        if (err)
                goto err_netdev_reg;
@@ -4955,6 +4962,8 @@ err_init_aux_unroll:
 err_devlink_reg_param:
        ice_devlink_unregister_params(pf);
 err_netdev_reg:
+       ice_devlink_destroy_pf_port(pf);
+err_create_pf_port:
 err_send_version_unroll:
        ice_vsi_release_all(pf);
 err_alloc_sw_unroll:
@@ -5083,6 +5092,7 @@ static void ice_remove(struct pci_dev *pdev)
        ice_setup_mc_magic_wake(pf);
        ice_vsi_release_all(pf);
        mutex_destroy(&(&pf->hw)->fdir_fltr_lock);
+       ice_devlink_destroy_pf_port(pf);
        ice_set_wake(pf);
        ice_free_irq_msix_misc(pf);
        ice_for_each_vsi(pf, i) {
@@ -5531,7 +5541,7 @@ static int __init ice_module_init(void)
        pr_info("%s\n", ice_driver_string);
        pr_info("%s\n", ice_copyright);
 
-       ice_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0, KBUILD_MODNAME);
+       ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME);
        if (!ice_wq) {
                pr_err("Failed to create workqueue\n");
                return -ENOMEM;
index 9b762f7..61f844d 100644 (file)
@@ -5420,7 +5420,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
         */
        status = ice_add_special_words(rinfo, lkup_exts, ice_is_dvm_ena(hw));
        if (status)
-               goto err_free_lkup_exts;
+               goto err_unroll;
 
        /* Group match words into recipes using preferred recipe grouping
         * criteria.
index faba0f8..95f392a 100644 (file)
@@ -1681,7 +1681,7 @@ ice_tc_forward_to_queue(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr,
        struct ice_vsi *ch_vsi = NULL;
        u16 queue = act->rx_queue;
 
-       if (queue > vsi->num_rxq) {
+       if (queue >= vsi->num_rxq) {
                NL_SET_ERR_MSG_MOD(fltr->extack,
                                   "Unable to add filter because specified queue is invalid");
                return -EINVAL;
index d4a4001..f56fa94 100644 (file)
@@ -39,7 +39,7 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
        return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
 }
 
-static const u32 ice_legacy_aq_to_vc_speed[15] = {
+static const u32 ice_legacy_aq_to_vc_speed[] = {
        VIRTCHNL_LINK_SPEED_100MB,      /* BIT(0) */
        VIRTCHNL_LINK_SPEED_100MB,
        VIRTCHNL_LINK_SPEED_1GB,
@@ -51,10 +51,6 @@ static const u32 ice_legacy_aq_to_vc_speed[15] = {
        VIRTCHNL_LINK_SPEED_40GB,
        VIRTCHNL_LINK_SPEED_40GB,
        VIRTCHNL_LINK_SPEED_40GB,
-       VIRTCHNL_LINK_SPEED_UNKNOWN,
-       VIRTCHNL_LINK_SPEED_UNKNOWN,
-       VIRTCHNL_LINK_SPEED_UNKNOWN,
-       VIRTCHNL_LINK_SPEED_UNKNOWN     /* BIT(14) */
 };
 
 /**
@@ -71,21 +67,20 @@ static const u32 ice_legacy_aq_to_vc_speed[15] = {
  */
 u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed)
 {
-       u32 speed;
+       /* convert a BIT() value into an array index */
+       u32 index = fls(link_speed) - 1;
 
-       if (adv_link_support) {
-               /* convert a BIT() value into an array index */
-               speed = ice_get_link_speed(fls(link_speed) - 1);
-       } else {
+       if (adv_link_support)
+               return ice_get_link_speed(index);
+       else if (index < ARRAY_SIZE(ice_legacy_aq_to_vc_speed))
                /* Virtchnl speeds are not defined for every speed supported in
                 * the hardware. To maintain compatibility with older AVF
                 * drivers, while reporting the speed the new speed values are
                 * resolved to the closest known virtchnl speeds
                 */
-               speed = ice_legacy_aq_to_vc_speed[fls(link_speed) - 1];
-       }
+               return ice_legacy_aq_to_vc_speed[index];
 
-       return speed;
+       return VIRTCHNL_LINK_SPEED_UNKNOWN;
 }
 
 /* The mailbox overflow detection algorithm helps to check if there
index 5ecc0ee..b1ffb81 100644 (file)
@@ -44,13 +44,17 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi)
 
                /* outer VLAN ops regardless of port VLAN config */
                vlan_ops->add_vlan = ice_vsi_add_vlan;
-               vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
                vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
                vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
 
                if (ice_vf_is_port_vlan_ena(vf)) {
                        /* setup outer VLAN ops */
                        vlan_ops->set_port_vlan = ice_vsi_set_outer_port_vlan;
+                       /* all Rx traffic should be in the domain of the
+                        * assigned port VLAN, so prevent disabling Rx VLAN
+                        * filtering
+                        */
+                       vlan_ops->dis_rx_filtering = noop_vlan;
                        vlan_ops->ena_rx_filtering =
                                ice_vsi_ena_rx_vlan_filtering;
 
@@ -63,6 +67,9 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi)
                        vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
                        vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
                } else {
+                       vlan_ops->dis_rx_filtering =
+                               ice_vsi_dis_rx_vlan_filtering;
+
                        if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags))
                                vlan_ops->ena_rx_filtering = noop_vlan;
                        else
@@ -96,7 +103,14 @@ void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi)
                        vlan_ops->set_port_vlan = ice_vsi_set_inner_port_vlan;
                        vlan_ops->ena_rx_filtering =
                                ice_vsi_ena_rx_vlan_filtering;
+                       /* all Rx traffic should be in the domain of the
+                        * assigned port VLAN, so prevent disabling Rx VLAN
+                        * filtering
+                        */
+                       vlan_ops->dis_rx_filtering = noop_vlan;
                } else {
+                       vlan_ops->dis_rx_filtering =
+                               ice_vsi_dis_rx_vlan_filtering;
                        if (!test_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags))
                                vlan_ops->ena_rx_filtering = noop_vlan;
                        else
index a7b2263..e9747ec 100644 (file)
 #define IGC_TSAUXC_EN_TT0      BIT(0)  /* Enable target time 0. */
 #define IGC_TSAUXC_EN_TT1      BIT(1)  /* Enable target time 1. */
 #define IGC_TSAUXC_EN_CLK0     BIT(2)  /* Enable Configurable Frequency Clock 0. */
+#define IGC_TSAUXC_ST0         BIT(4)  /* Start Clock 0 Toggle on Target Time 0. */
 #define IGC_TSAUXC_EN_CLK1     BIT(5)  /* Enable Configurable Frequency Clock 1. */
+#define IGC_TSAUXC_ST1         BIT(7)  /* Start Clock 1 Toggle on Target Time 1. */
 #define IGC_TSAUXC_EN_TS0      BIT(8)  /* Enable hardware timestamp 0. */
 #define IGC_TSAUXC_AUTT0       BIT(9)  /* Auxiliary Timestamp Taken. */
 #define IGC_TSAUXC_EN_TS1      BIT(10) /* Enable hardware timestamp 0. */
index 44b1740..1dd2a7f 100644 (file)
@@ -2942,7 +2942,9 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
                if (tx_buffer->next_to_watch &&
                    time_after(jiffies, tx_buffer->time_stamp +
                    (adapter->tx_timeout_factor * HZ)) &&
-                   !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF)) {
+                   !(rd32(IGC_STATUS) & IGC_STATUS_TXOFF) &&
+                   (rd32(IGC_TDH(tx_ring->reg_idx)) !=
+                    readl(tx_ring->tail))) {
                        /* detected Tx unit hang */
                        netdev_err(tx_ring->netdev,
                                   "Detected Tx Unit Hang\n"
@@ -5068,6 +5070,24 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu)
        return 0;
 }
 
+/**
+ * igc_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ * @txqueue: queue number that timed out
+ **/
+static void igc_tx_timeout(struct net_device *netdev,
+                          unsigned int __always_unused txqueue)
+{
+       struct igc_adapter *adapter = netdev_priv(netdev);
+       struct igc_hw *hw = &adapter->hw;
+
+       /* Do the reset outside of interrupt context */
+       adapter->tx_timeout_count++;
+       schedule_work(&adapter->reset_task);
+       wr32(IGC_EICS,
+            (adapter->eims_enable_mask & ~adapter->eims_other));
+}
+
 /**
  * igc_get_stats64 - Get System Network Statistics
  * @netdev: network interface device structure
@@ -5495,7 +5515,7 @@ static void igc_watchdog_task(struct work_struct *work)
                        case SPEED_100:
                        case SPEED_1000:
                        case SPEED_2500:
-                               adapter->tx_timeout_factor = 7;
+                               adapter->tx_timeout_factor = 1;
                                break;
                        }
 
@@ -6320,6 +6340,7 @@ static const struct net_device_ops igc_netdev_ops = {
        .ndo_set_rx_mode        = igc_set_rx_mode,
        .ndo_set_mac_address    = igc_set_mac,
        .ndo_change_mtu         = igc_change_mtu,
+       .ndo_tx_timeout         = igc_tx_timeout,
        .ndo_get_stats64        = igc_get_stats64,
        .ndo_fix_features       = igc_fix_features,
        .ndo_set_features       = igc_set_features,
index 8dbb9f9..4e10ced 100644 (file)
@@ -322,7 +322,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
                ts = ns_to_timespec64(ns);
                if (rq->perout.index == 1) {
                        if (use_freq) {
-                               tsauxc_mask = IGC_TSAUXC_EN_CLK1;
+                               tsauxc_mask = IGC_TSAUXC_EN_CLK1 | IGC_TSAUXC_ST1;
                                tsim_mask = 0;
                        } else {
                                tsauxc_mask = IGC_TSAUXC_EN_TT1;
@@ -333,7 +333,7 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
                        freqout = IGC_FREQOUT1;
                } else {
                        if (use_freq) {
-                               tsauxc_mask = IGC_TSAUXC_EN_CLK0;
+                               tsauxc_mask = IGC_TSAUXC_EN_CLK0 | IGC_TSAUXC_ST0;
                                tsim_mask = 0;
                        } else {
                                tsauxc_mask = IGC_TSAUXC_EN_TT0;
@@ -347,10 +347,12 @@ static int igc_ptp_feature_enable_i225(struct ptp_clock_info *ptp,
                tsauxc = rd32(IGC_TSAUXC);
                tsim = rd32(IGC_TSIM);
                if (rq->perout.index == 1) {
-                       tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1);
+                       tsauxc &= ~(IGC_TSAUXC_EN_TT1 | IGC_TSAUXC_EN_CLK1 |
+                                   IGC_TSAUXC_ST1);
                        tsim &= ~IGC_TSICR_TT1;
                } else {
-                       tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0);
+                       tsauxc &= ~(IGC_TSAUXC_EN_TT0 | IGC_TSAUXC_EN_CLK0 |
+                                   IGC_TSAUXC_ST0);
                        tsim &= ~IGC_TSICR_TT0;
                }
                if (on) {
@@ -415,10 +417,12 @@ static int igc_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
  *
  * We need to convert the system time value stored in the RX/TXSTMP registers
  * into a hwtstamp which can be used by the upper level timestamping functions.
+ *
+ * Returns 0 on success.
  **/
-static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,
-                                      struct skb_shared_hwtstamps *hwtstamps,
-                                      u64 systim)
+static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,
+                                     struct skb_shared_hwtstamps *hwtstamps,
+                                     u64 systim)
 {
        switch (adapter->hw.mac.type) {
        case igc_i225:
@@ -428,8 +432,9 @@ static void igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,
                                                systim & 0xFFFFFFFF);
                break;
        default:
-               break;
+               return -EINVAL;
        }
+       return 0;
 }
 
 /**
@@ -650,7 +655,8 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
 
        regval = rd32(IGC_TXSTMPL);
        regval |= (u64)rd32(IGC_TXSTMPH) << 32;
-       igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
+       if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
+               return;
 
        switch (adapter->link_speed) {
        case SPEED_10:
index 24aa97f..123dca9 100644 (file)
@@ -855,9 +855,11 @@ static struct pci_dev *ixgbe_get_first_secondary_devfn(unsigned int devfn)
        rp_pdev = pci_get_domain_bus_and_slot(0, 0, devfn);
        if (rp_pdev && rp_pdev->subordinate) {
                bus = rp_pdev->subordinate->number;
+               pci_dev_put(rp_pdev);
                return pci_get_domain_bus_and_slot(0, bus, 0);
        }
 
+       pci_dev_put(rp_pdev);
        return NULL;
 }
 
@@ -874,6 +876,7 @@ static bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw)
        struct ixgbe_adapter *adapter = hw->back;
        struct pci_dev *pdev = adapter->pdev;
        struct pci_dev *func0_pdev;
+       bool has_mii = false;
 
        /* For the C3000 family of SoCs (x550em_a) the internal ixgbe devices
         * are always downstream of root ports @ 0000:00:16.0 & 0000:00:17.0
@@ -884,15 +887,16 @@ static bool ixgbe_x550em_a_has_mii(struct ixgbe_hw *hw)
        func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x16, 0));
        if (func0_pdev) {
                if (func0_pdev == pdev)
-                       return true;
-               else
-                       return false;
+                       has_mii = true;
+               goto out;
        }
        func0_pdev = ixgbe_get_first_secondary_devfn(PCI_DEVFN(0x17, 0));
        if (func0_pdev == pdev)
-               return true;
+               has_mii = true;
 
-       return false;
+out:
+       pci_dev_put(func0_pdev);
+       return has_mii;
 }
 
 /**
index b2b71fe..724df63 100644 (file)
@@ -774,9 +774,9 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable)
 
        cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG);
        if (enable)
-               cfg |= CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN;
+               cfg |= DATA_PKT_RX_EN | DATA_PKT_TX_EN;
        else
-               cfg &= ~(CMR_EN | DATA_PKT_RX_EN | DATA_PKT_TX_EN);
+               cfg &= ~(DATA_PKT_RX_EN | DATA_PKT_TX_EN);
        cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg);
        return 0;
 }
index fb2d376..5a20d93 100644 (file)
@@ -26,7 +26,6 @@
 #define CMR_P2X_SEL_SHIFT              59ULL
 #define CMR_P2X_SEL_NIX0               1ULL
 #define CMR_P2X_SEL_NIX1               2ULL
-#define CMR_EN                         BIT_ULL(55)
 #define DATA_PKT_TX_EN                 BIT_ULL(53)
 #define DATA_PKT_RX_EN                 BIT_ULL(54)
 #define CGX_LMAC_TYPE_SHIFT            40
index bda1a6f..e4407f0 100644 (file)
@@ -1500,6 +1500,9 @@ static const struct devlink_param rvu_af_dl_params[] = {
                             BIT(DEVLINK_PARAM_CMODE_RUNTIME),
                             rvu_af_dl_dwrr_mtu_get, rvu_af_dl_dwrr_mtu_set,
                             rvu_af_dl_dwrr_mtu_validate),
+};
+
+static const struct devlink_param rvu_af_dl_param_exact_match[] = {
        DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
                             "npc_exact_feature_disable", DEVLINK_PARAM_TYPE_STRING,
                             BIT(DEVLINK_PARAM_CMODE_RUNTIME),
@@ -1556,7 +1559,6 @@ int rvu_register_dl(struct rvu *rvu)
 {
        struct rvu_devlink *rvu_dl;
        struct devlink *dl;
-       size_t size;
        int err;
 
        dl = devlink_alloc(&rvu_devlink_ops, sizeof(struct rvu_devlink),
@@ -1578,21 +1580,32 @@ int rvu_register_dl(struct rvu *rvu)
                goto err_dl_health;
        }
 
+       err = devlink_params_register(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
+       if (err) {
+               dev_err(rvu->dev,
+                       "devlink params register failed with error %d", err);
+               goto err_dl_health;
+       }
+
        /* Register exact match devlink only for CN10K-B */
-       size = ARRAY_SIZE(rvu_af_dl_params);
        if (!rvu_npc_exact_has_match_table(rvu))
-               size -= 1;
+               goto done;
 
-       err = devlink_params_register(dl, rvu_af_dl_params, size);
+       err = devlink_params_register(dl, rvu_af_dl_param_exact_match,
+                                     ARRAY_SIZE(rvu_af_dl_param_exact_match));
        if (err) {
                dev_err(rvu->dev,
-                       "devlink params register failed with error %d", err);
-               goto err_dl_health;
+                       "devlink exact match params register failed with error %d", err);
+               goto err_dl_exact_match;
        }
 
+done:
        devlink_register(dl);
        return 0;
 
+err_dl_exact_match:
+       devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
+
 err_dl_health:
        rvu_health_reporters_destroy(rvu);
        devlink_free(dl);
@@ -1605,8 +1618,14 @@ void rvu_unregister_dl(struct rvu *rvu)
        struct devlink *dl = rvu_dl->dl;
 
        devlink_unregister(dl);
-       devlink_params_unregister(dl, rvu_af_dl_params,
-                                 ARRAY_SIZE(rvu_af_dl_params));
+
+       devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
+
+       /* Unregister exact match devlink only for CN10K-B */
+       if (rvu_npc_exact_has_match_table(rvu))
+               devlink_params_unregister(dl, rvu_af_dl_param_exact_match,
+                                         ARRAY_SIZE(rvu_af_dl_param_exact_match));
+
        rvu_health_reporters_destroy(rvu);
        devlink_free(dl);
 }
index 88f8772..8a41ad8 100644 (file)
@@ -1012,7 +1012,6 @@ static void otx2_pool_refill_task(struct work_struct *work)
        rbpool = cq->rbpool;
        free_ptrs = cq->pool_ptrs;
 
-       get_cpu();
        while (cq->pool_ptrs) {
                if (otx2_alloc_rbuf(pfvf, rbpool, &bufptr)) {
                        /* Schedule a WQ if we fails to free atleast half of the
@@ -1032,7 +1031,6 @@ static void otx2_pool_refill_task(struct work_struct *work)
                pfvf->hw_ops->aura_freeptr(pfvf, qidx, bufptr + OTX2_HEAD_ROOM);
                cq->pool_ptrs--;
        }
-       put_cpu();
        cq->refill_task_sched = false;
 }
 
@@ -1370,7 +1368,6 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf)
        if (err)
                goto fail;
 
-       get_cpu();
        /* Allocate pointers and free them to aura/pool */
        for (qidx = 0; qidx < hw->tot_tx_queues; qidx++) {
                pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, qidx);
@@ -1394,7 +1391,6 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf)
        }
 
 err_mem:
-       put_cpu();
        return err ? -ENOMEM : 0;
 
 fail:
@@ -1435,21 +1431,18 @@ int otx2_rq_aura_pool_init(struct otx2_nic *pfvf)
        if (err)
                goto fail;
 
-       get_cpu();
        /* Allocate pointers and free them to aura/pool */
        for (pool_id = 0; pool_id < hw->rqpool_cnt; pool_id++) {
                pool = &pfvf->qset.pool[pool_id];
                for (ptr = 0; ptr < num_ptrs; ptr++) {
                        err = otx2_alloc_rbuf(pfvf, pool, &bufptr);
                        if (err)
-                               goto err_mem;
+                               return -ENOMEM;
                        pfvf->hw_ops->aura_freeptr(pfvf, pool_id,
                                                   bufptr + OTX2_HEAD_ROOM);
                }
        }
-err_mem:
-       put_cpu();
-       return err ? -ENOMEM : 0;
+       return 0;
 fail:
        otx2_mbox_reset(&pfvf->mbox.mbox, 0);
        otx2_aura_pool_free(pfvf);
index 5bee3c3..3d22cc6 100644 (file)
@@ -736,8 +736,10 @@ static inline void cn10k_aura_freeptr(void *dev, int aura, u64 buf)
        u64 ptrs[2];
 
        ptrs[1] = buf;
+       get_cpu();
        /* Free only one buffer at time during init and teardown */
        __cn10k_aura_freeptr(pfvf, aura, ptrs, 2);
+       put_cpu();
 }
 
 /* Alloc pointer from pool/aura */
index 86653bb..7f8ffbf 100644 (file)
@@ -758,6 +758,8 @@ static void otx2vf_remove(struct pci_dev *pdev)
        if (vf->otx2_wq)
                destroy_workqueue(vf->otx2_wq);
        otx2_ptp_destroy(vf);
+       otx2_mcam_flow_del(vf);
+       otx2_shutdown_tc(vf);
        otx2vf_disable_mbox_intr(vf);
        otx2_detach_resources(&vf->mbox);
        if (test_bit(CN10K_LMTST, &vf->hw.cap_flag))
index e3de9a5..e312372 100644 (file)
@@ -1570,8 +1570,8 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
        if (IS_ERR(pp))
                return pp;
 
-       err = __xdp_rxq_info_reg(xdp_q, &eth->dummy_dev, eth->rx_napi.napi_id,
-                                id, PAGE_SIZE);
+       err = __xdp_rxq_info_reg(xdp_q, &eth->dummy_dev, id,
+                                eth->rx_napi.napi_id, PAGE_SIZE);
        if (err < 0)
                goto err_free_pp;
 
@@ -1870,7 +1870,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 
        while (done < budget) {
                unsigned int pktlen, *rxdcsum;
+               bool has_hwaccel_tag = false;
                struct net_device *netdev;
+               u16 vlan_proto, vlan_tci;
                dma_addr_t dma_addr;
                u32 hash, reason;
                int mac = 0;
@@ -2010,27 +2012,29 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 
                if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
                        if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
-                               if (trxd.rxd3 & RX_DMA_VTAG_V2)
-                                       __vlan_hwaccel_put_tag(skb,
-                                               htons(RX_DMA_VPID(trxd.rxd4)),
-                                               RX_DMA_VID(trxd.rxd4));
+                               if (trxd.rxd3 & RX_DMA_VTAG_V2) {
+                                       vlan_proto = RX_DMA_VPID(trxd.rxd4);
+                                       vlan_tci = RX_DMA_VID(trxd.rxd4);
+                                       has_hwaccel_tag = true;
+                               }
                        } else if (trxd.rxd2 & RX_DMA_VTAG) {
-                               __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)),
-                                                      RX_DMA_VID(trxd.rxd3));
+                               vlan_proto = RX_DMA_VPID(trxd.rxd3);
+                               vlan_tci = RX_DMA_VID(trxd.rxd3);
+                               has_hwaccel_tag = true;
                        }
                }
 
                /* When using VLAN untagging in combination with DSA, the
                 * hardware treats the MTK special tag as a VLAN and untags it.
                 */
-               if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) {
-                       unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0);
+               if (has_hwaccel_tag && netdev_uses_dsa(netdev)) {
+                       unsigned int port = vlan_proto & GENMASK(2, 0);
 
                        if (port < ARRAY_SIZE(eth->dsa_meta) &&
                            eth->dsa_meta[port])
                                skb_dst_set_noref(skb, &eth->dsa_meta[port]->dst);
-
-                       __vlan_hwaccel_clear_tag(skb);
+               } else if (has_hwaccel_tag) {
+                       __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci);
                }
 
                skb_record_rx_queue(skb, 0);
@@ -3111,7 +3115,7 @@ static void mtk_gdm_config(struct mtk_eth *eth, u32 config)
 
                val |= config;
 
-               if (!i && eth->netdev[0] && netdev_uses_dsa(eth->netdev[0]))
+               if (eth->netdev[i] && netdev_uses_dsa(eth->netdev[i]))
                        val |= MTK_GDMA_SPECIAL_TAG;
 
                mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
index 18a5052..2d9186d 100644 (file)
 #define SGMII_SPEED_10                 FIELD_PREP(SGMII_SPEED_MASK, 0)
 #define SGMII_SPEED_100                        FIELD_PREP(SGMII_SPEED_MASK, 1)
 #define SGMII_SPEED_1000               FIELD_PREP(SGMII_SPEED_MASK, 2)
-#define SGMII_DUPLEX_FULL              BIT(4)
+#define SGMII_DUPLEX_HALF              BIT(4)
 #define SGMII_IF_MODE_BIT5             BIT(5)
 #define SGMII_REMOTE_FAULT_DIS         BIT(8)
 #define SGMII_CODE_SYNC_SET_VAL                BIT(9)
@@ -1036,11 +1036,13 @@ struct mtk_soc_data {
  * @regmap:            The register map pointing at the range used to setup
  *                     SGMII modes
  * @ana_rgc3:          The offset refers to register ANA_RGC3 related to regmap
+ * @interface:         Currently configured interface mode
  * @pcs:               Phylink PCS structure
  */
 struct mtk_pcs {
        struct regmap   *regmap;
        u32             ana_rgc3;
+       phy_interface_t interface;
        struct phylink_pcs pcs;
 };
 
index 269208a..1ff024f 100644 (file)
@@ -615,8 +615,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
        u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP;
        int type;
 
-       flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end),
-                           GFP_ATOMIC);
+       flow_info = kzalloc(sizeof(*flow_info), GFP_ATOMIC);
        if (!flow_info)
                return;
 
index ea64fac..b5e4320 100644 (file)
@@ -279,7 +279,6 @@ struct mtk_flow_entry {
                struct {
                        struct mtk_flow_entry *base_flow;
                        struct hlist_node list;
-                       struct {} end;
                } l2_data;
        };
        struct rhash_head node;
index 5c286f2..bb00de1 100644 (file)
@@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
        int advertise, link_timer;
        bool changed, use_an;
 
-       if (interface == PHY_INTERFACE_MODE_2500BASEX)
-               rgc3 = RG_PHY_SPEED_3_125G;
-       else
-               rgc3 = 0;
-
        advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
                                                             advertising);
        if (advertise < 0)
@@ -88,9 +83,22 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
                bmcr = 0;
        }
 
-       /* Configure the underlying interface speed */
-       regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
-                          RG_PHY_SPEED_3_125G, rgc3);
+       if (mpcs->interface != interface) {
+               /* PHYA power down */
+               regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
+                                  SGMII_PHYA_PWD, SGMII_PHYA_PWD);
+
+               if (interface == PHY_INTERFACE_MODE_2500BASEX)
+                       rgc3 = RG_PHY_SPEED_3_125G;
+               else
+                       rgc3 = 0;
+
+               /* Configure the underlying interface speed */
+               regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
+                                  RG_PHY_SPEED_3_125G, rgc3);
+
+               mpcs->interface = interface;
+       }
 
        /* Update the advertisement, noting whether it has changed */
        regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE,
@@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
        regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
                           SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr);
 
-       /* Release PHYA power down state */
-       regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
-                          SGMII_PHYA_PWD, 0);
+       /* Release PHYA power down state
+        * Only removing bit SGMII_PHYA_PWD isn't enough.
+        * There are cases when the SGMII_PHYA_PWD register contains 0x9 which
+        * prevents SGMII from working. The SGMII still shows link but no traffic
+        * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was
+        * taken from a good working state of the SGMII interface.
+        * Unknown how much the QPHY needs but it is racy without a sleep.
+        * Tested on mt7622 & mt7986.
+        */
+       usleep_range(50, 100);
+       regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
 
        return changed;
 }
@@ -138,11 +154,11 @@ static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
                else
                        sgm_mode = SGMII_SPEED_1000;
 
-               if (duplex == DUPLEX_FULL)
-                       sgm_mode |= SGMII_DUPLEX_FULL;
+               if (duplex != DUPLEX_FULL)
+                       sgm_mode |= SGMII_DUPLEX_HALF;
 
                regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE,
-                                  SGMII_DUPLEX_FULL | SGMII_SPEED_MASK,
+                                  SGMII_DUPLEX_HALF | SGMII_SPEED_MASK,
                                   sgm_mode);
        }
 }
@@ -171,6 +187,8 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
                        return PTR_ERR(ss->pcs[i].regmap);
 
                ss->pcs[i].pcs.ops = &mtk_pcs_ops;
+               ss->pcs[i].pcs.poll = true;
+               ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
        }
 
        return 0;
index d3ca745..c837103 100644 (file)
@@ -2176,15 +2176,9 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
                return -EINVAL;
        }
 
-       cmd->stats = kvcalloc(MLX5_CMD_OP_MAX, sizeof(*cmd->stats), GFP_KERNEL);
-       if (!cmd->stats)
-               return -ENOMEM;
-
        cmd->pool = dma_pool_create("mlx5_cmd", mlx5_core_dma_dev(dev), size, align, 0);
-       if (!cmd->pool) {
-               err = -ENOMEM;
-               goto dma_pool_err;
-       }
+       if (!cmd->pool)
+               return -ENOMEM;
 
        err = alloc_cmd_page(dev, cmd);
        if (err)
@@ -2268,8 +2262,6 @@ err_free_page:
 
 err_free_pool:
        dma_pool_destroy(cmd->pool);
-dma_pool_err:
-       kvfree(cmd->stats);
        return err;
 }
 
@@ -2282,7 +2274,6 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev)
        destroy_msg_cache(dev);
        free_cmd_page(dev, cmd);
        dma_pool_destroy(cmd->pool);
-       kvfree(cmd->stats);
 }
 
 void mlx5_cmd_set_state(struct mlx5_core_dev *dev,
index 3e232a6..bb95b40 100644 (file)
@@ -245,8 +245,9 @@ void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev)
        pages = dev->priv.dbg.pages_debugfs;
 
        debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages);
-       debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.vfs_pages);
-       debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.host_pf_pages);
+       debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.page_counters[MLX5_VF]);
+       debugfs_create_u32("fw_pages_sfs", 0400, pages, &dev->priv.page_counters[MLX5_SF]);
+       debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.page_counters[MLX5_HOST_PF]);
        debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed);
        debugfs_create_u32("fw_pages_give_dropped", 0400, pages, &dev->priv.give_pages_dropped);
        debugfs_create_u32("fw_pages_reclaim_discard", 0400, pages,
index 2183138..5b05b88 100644 (file)
@@ -64,6 +64,7 @@ static int mlx5_query_mtrc_caps(struct mlx5_fw_tracer *tracer)
                        MLX5_GET(mtrc_cap, out, num_string_trace);
        tracer->str_db.num_string_db = MLX5_GET(mtrc_cap, out, num_string_db);
        tracer->owner = !!MLX5_GET(mtrc_cap, out, trace_owner);
+       tracer->str_db.loaded = false;
 
        for (i = 0; i < tracer->str_db.num_string_db; i++) {
                mtrc_cap_sp = MLX5_ADDR_OF(mtrc_cap, out, string_db_param[i]);
@@ -756,6 +757,7 @@ static int mlx5_fw_tracer_set_mtrc_conf(struct mlx5_fw_tracer *tracer)
        if (err)
                mlx5_core_warn(dev, "FWTracer: Failed to set tracer configurations %d\n", err);
 
+       tracer->buff.consumer_index = 0;
        return err;
 }
 
@@ -820,7 +822,6 @@ static void mlx5_fw_tracer_ownership_change(struct work_struct *work)
        mlx5_core_dbg(tracer->dev, "FWTracer: ownership changed, current=(%d)\n", tracer->owner);
        if (tracer->owner) {
                tracer->owner = false;
-               tracer->buff.consumer_index = 0;
                return;
        }
 
index 464eb3a..cdc87ec 100644 (file)
@@ -87,7 +87,7 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev)
 
        mlx5_host_pf_cleanup(dev);
 
-       err = mlx5_wait_for_pages(dev, &dev->priv.host_pf_pages);
+       err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_HOST_PF]);
        if (err)
                mlx5_core_warn(dev, "Timeout reclaiming external host PF pages err(%d)\n", err);
 }
index 6dac76f..09d441e 100644 (file)
@@ -637,7 +637,7 @@ mlx5e_htb_update_children(struct mlx5e_htb *htb, struct mlx5e_qos_node *node,
                if (child->bw_share == old_bw_share)
                        continue;
 
-               err_one = mlx5_qos_update_node(htb->mdev, child->hw_id, child->bw_share,
+               err_one = mlx5_qos_update_node(htb->mdev, child->bw_share,
                                               child->max_average_bw, child->hw_id);
                if (!err && err_one) {
                        err = err_one;
@@ -671,7 +671,7 @@ mlx5e_htb_node_modify(struct mlx5e_htb *htb, u16 classid, u64 rate, u64 ceil,
        mlx5e_htb_convert_rate(htb, rate, node->parent, &bw_share);
        mlx5e_htb_convert_ceil(htb, ceil, &max_average_bw);
 
-       err = mlx5_qos_update_node(htb->mdev, node->parent->hw_id, bw_share,
+       err = mlx5_qos_update_node(htb->mdev, bw_share,
                                   max_average_bw, node->hw_id);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack, "Firmware error when modifying a node.");
index 585bdc8..4ad19c9 100644 (file)
@@ -578,7 +578,6 @@ int mlx5e_mpwrq_validate_xsk(struct mlx5_core_dev *mdev, struct mlx5e_params *pa
 {
        enum mlx5e_mpwrq_umr_mode umr_mode = mlx5e_mpwrq_umr_mode(mdev, xsk);
        u8 page_shift = mlx5e_mpwrq_page_shift(mdev, xsk);
-       bool unaligned = xsk ? xsk->unaligned : false;
        u16 max_mtu_pkts;
 
        if (!mlx5e_check_fragmented_striding_rq_cap(mdev, page_shift, umr_mode))
@@ -591,7 +590,7 @@ int mlx5e_mpwrq_validate_xsk(struct mlx5_core_dev *mdev, struct mlx5e_params *pa
         * needed number of WQEs exceeds the maximum.
         */
        max_mtu_pkts = min_t(u8, MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE,
-                            mlx5e_mpwrq_max_log_rq_pkts(mdev, page_shift, unaligned));
+                            mlx5e_mpwrq_max_log_rq_pkts(mdev, page_shift, xsk->unaligned));
        if (params->log_rq_mtu_frames > max_mtu_pkts) {
                mlx5_core_err(mdev, "Current RQ length %d is too big for XSK with given frame size %u\n",
                              1 << params->log_rq_mtu_frames, xsk->chunk_size);
index 8099a21..ce85b48 100644 (file)
@@ -438,10 +438,6 @@ static int mlx5_esw_bridge_switchdev_event(struct notifier_block *nb,
 
        switch (event) {
        case SWITCHDEV_FDB_ADD_TO_BRIDGE:
-               /* only handle the event on native eswtich of representor */
-               if (!mlx5_esw_bridge_is_local(dev, rep, esw))
-                       break;
-
                fdb_info = container_of(info,
                                        struct switchdev_notifier_fdb_info,
                                        info);
index 512d431..c4378af 100644 (file)
@@ -34,12 +34,6 @@ static int police_act_validate(const struct flow_action_entry *act,
                return -EOPNOTSUPP;
        }
 
-       if (act->police.rate_pkt_ps) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "QoS offload not support packets per second");
-               return -EOPNOTSUPP;
-       }
-
        return 0;
 }
 
index 8d7d761..50b60fd 100644 (file)
@@ -127,6 +127,7 @@ mlx5e_post_meter_add_rule(struct mlx5e_priv *priv,
                attr->counter = act_counter;
 
        attr->flags |= MLX5_ATTR_FLAG_NO_IN_PORT;
+       attr->inner_match_level = MLX5_MATCH_NONE;
        attr->outer_match_level = MLX5_MATCH_NONE;
        attr->chain = 0;
        attr->prio = 0;
index 1cbd2eb..f2c2c75 100644 (file)
@@ -477,7 +477,6 @@ mlx5e_tc_sample_offload(struct mlx5e_tc_psample *tc_psample,
        struct mlx5e_sample_flow *sample_flow;
        struct mlx5e_sample_attr *sample_attr;
        struct mlx5_flow_attr *pre_attr;
-       u32 tunnel_id = attr->tunnel_id;
        struct mlx5_eswitch *esw;
        u32 default_tbl_id;
        u32 obj_id;
@@ -522,7 +521,7 @@ mlx5e_tc_sample_offload(struct mlx5e_tc_psample *tc_psample,
        restore_obj.sample.group_id = sample_attr->group_num;
        restore_obj.sample.rate = sample_attr->rate;
        restore_obj.sample.trunc_size = sample_attr->trunc_size;
-       restore_obj.sample.tunnel_id = tunnel_id;
+       restore_obj.sample.tunnel_id = attr->tunnel_id;
        err = mapping_add(esw->offloads.reg_c0_obj_pool, &restore_obj, &obj_id);
        if (err)
                goto err_obj_id;
@@ -548,7 +547,7 @@ mlx5e_tc_sample_offload(struct mlx5e_tc_psample *tc_psample,
        /* For decap action, do decap in the original flow table instead of the
         * default flow table.
         */
-       if (tunnel_id)
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
                pre_attr->action |= MLX5_FLOW_CONTEXT_ACTION_DECAP;
        pre_attr->modify_hdr = sample_flow->restore->modify_hdr;
        pre_attr->flags = MLX5_ATTR_FLAG_SAMPLE;
index fd07c4c..1f62c70 100644 (file)
@@ -88,6 +88,8 @@ static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
        struct udphdr *udp = (struct udphdr *)(buf);
        struct vxlanhdr *vxh;
 
+       if (tun_key->tun_flags & TUNNEL_VXLAN_OPT)
+               return -EOPNOTSUPP;
        vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
        *ip_proto = IPPROTO_UDP;
 
index a92e19c..8bed9c3 100644 (file)
@@ -122,11 +122,8 @@ struct mlx5e_ipsec_aso {
        u8 ctx[MLX5_ST_SZ_BYTES(ipsec_aso)];
        dma_addr_t dma_addr;
        struct mlx5_aso *aso;
-       /* IPsec ASO caches data on every query call,
-        * so in nested calls, we can use this boolean to save
-        * recursive calls to mlx5e_ipsec_aso_query()
-        */
-       u8 use_cache : 1;
+       /* Protect ASO WQ access, as it is global to whole IPsec */
+       spinlock_t lock;
 };
 
 struct mlx5e_ipsec {
index 8e36142..2461462 100644 (file)
@@ -320,7 +320,6 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
        if (ret)
                goto unlock;
 
-       aso->use_cache = true;
        if (attrs->esn_trigger &&
            !MLX5_GET(ipsec_aso, aso->ctx, esn_event_arm)) {
                u32 mode_param = MLX5_GET(ipsec_aso, aso->ctx, mode_parameter);
@@ -333,7 +332,6 @@ static void mlx5e_ipsec_handle_event(struct work_struct *_work)
                    !MLX5_GET(ipsec_aso, aso->ctx, hard_lft_arm) ||
                    !MLX5_GET(ipsec_aso, aso->ctx, remove_flow_enable))
                        xfrm_state_check_expire(sa_entry->x);
-       aso->use_cache = false;
 
 unlock:
        spin_unlock(&sa_entry->x->lock);
@@ -398,6 +396,7 @@ int mlx5e_ipsec_aso_init(struct mlx5e_ipsec *ipsec)
                goto err_aso_create;
        }
 
+       spin_lock_init(&aso->lock);
        ipsec->nb.notifier_call = mlx5e_ipsec_event;
        mlx5_notifier_register(mdev, &ipsec->nb);
 
@@ -456,13 +455,12 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
        struct mlx5e_hw_objs *res;
        struct mlx5_aso_wqe *wqe;
        u8 ds_cnt;
+       int ret;
 
        lockdep_assert_held(&sa_entry->x->lock);
-       if (aso->use_cache)
-               return 0;
-
        res = &mdev->mlx5e_res.hw_objs;
 
+       spin_lock_bh(&aso->lock);
        memset(aso->ctx, 0, sizeof(aso->ctx));
        wqe = mlx5_aso_get_wqe(aso->aso);
        ds_cnt = DIV_ROUND_UP(sizeof(*wqe), MLX5_SEND_WQE_DS);
@@ -477,7 +475,9 @@ int mlx5e_ipsec_aso_query(struct mlx5e_ipsec_sa_entry *sa_entry,
        mlx5e_ipsec_aso_copy(ctrl, data);
 
        mlx5_aso_post_wqe(aso->aso, false, &wqe->ctrl);
-       return mlx5_aso_poll_cq(aso->aso, false);
+       ret = mlx5_aso_poll_cq(aso->aso, false);
+       spin_unlock_bh(&aso->lock);
+       return ret;
 }
 
 void mlx5e_ipsec_aso_update_curlft(struct mlx5e_ipsec_sa_entry *sa_entry,
index 9369a58..7f6b940 100644 (file)
@@ -62,6 +62,7 @@ struct mlx5e_macsec_sa {
        u32 enc_key_id;
        u32 next_pn;
        sci_t sci;
+       ssci_t ssci;
        salt_t salt;
 
        struct rhash_head hash;
@@ -358,7 +359,6 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5_macsec_obj_attrs obj_attrs;
        union mlx5e_macsec_rule *macsec_rule;
-       struct macsec_key *key;
        int err;
 
        obj_attrs.next_pn = sa->next_pn;
@@ -368,13 +368,9 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
        obj_attrs.aso_pdn = macsec->aso.pdn;
        obj_attrs.epn_state = sa->epn_state;
 
-       key = (is_tx) ? &ctx->sa.tx_sa->key : &ctx->sa.rx_sa->key;
-
        if (sa->epn_state.epn_enabled) {
-               obj_attrs.ssci = (is_tx) ? cpu_to_be32((__force u32)ctx->sa.tx_sa->ssci) :
-                                          cpu_to_be32((__force u32)ctx->sa.rx_sa->ssci);
-
-               memcpy(&obj_attrs.salt, &key->salt, sizeof(key->salt));
+               obj_attrs.ssci = cpu_to_be32((__force u32)sa->ssci);
+               memcpy(&obj_attrs.salt, &sa->salt, sizeof(sa->salt));
        }
 
        obj_attrs.replay_window = ctx->secy->replay_window;
@@ -499,10 +495,11 @@ mlx5e_macsec_get_macsec_device_context(const struct mlx5e_macsec *macsec,
 }
 
 static void update_macsec_epn(struct mlx5e_macsec_sa *sa, const struct macsec_key *key,
-                             const pn_t *next_pn_halves)
+                             const pn_t *next_pn_halves, ssci_t ssci)
 {
        struct mlx5e_macsec_epn_state *epn_state = &sa->epn_state;
 
+       sa->ssci = ssci;
        sa->salt = key->salt;
        epn_state->epn_enabled = 1;
        epn_state->epn_msb = next_pn_halves->upper;
@@ -550,7 +547,8 @@ static int mlx5e_macsec_add_txsa(struct macsec_context *ctx)
        tx_sa->assoc_num = assoc_num;
 
        if (secy->xpn)
-               update_macsec_epn(tx_sa, &ctx_tx_sa->key, &ctx_tx_sa->next_pn_halves);
+               update_macsec_epn(tx_sa, &ctx_tx_sa->key, &ctx_tx_sa->next_pn_halves,
+                                 ctx_tx_sa->ssci);
 
        err = mlx5_create_encryption_key(mdev, ctx->sa.key, secy->key_len,
                                         MLX5_ACCEL_OBJ_MACSEC_KEY,
@@ -945,7 +943,8 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx)
        rx_sa->fs_id = rx_sc->sc_xarray_element->fs_id;
 
        if (ctx->secy->xpn)
-               update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves);
+               update_macsec_epn(rx_sa, &ctx_rx_sa->key, &ctx_rx_sa->next_pn_halves,
+                                 ctx_rx_sa->ssci);
 
        err = mlx5_create_encryption_key(mdev, ctx->sa.key, ctx->secy->key_len,
                                         MLX5_ACCEL_OBJ_MACSEC_KEY,
index 1892ccb..7cd36f4 100644 (file)
@@ -443,7 +443,7 @@ void mlx5e_enable_cvlan_filter(struct mlx5e_flow_steering *fs, bool promisc)
 
 void mlx5e_disable_cvlan_filter(struct mlx5e_flow_steering *fs, bool promisc)
 {
-       if (fs->vlan->cvlan_filter_disabled)
+       if (!fs->vlan || fs->vlan->cvlan_filter_disabled)
                return;
 
        fs->vlan->cvlan_filter_disabled = true;
index cff5f2e..6c24f33 100644 (file)
@@ -591,7 +591,8 @@ static int mlx5e_init_rxq_rq(struct mlx5e_channel *c, struct mlx5e_params *param
        rq->ix           = c->ix;
        rq->channel      = c;
        rq->mdev         = mdev;
-       rq->hw_mtu       = MLX5E_SW2HW_MTU(params, params->sw_mtu);
+       rq->hw_mtu =
+               MLX5E_SW2HW_MTU(params, params->sw_mtu) - ETH_FCS_LEN * !params->scatter_fcs_en;
        rq->xdpsq        = &c->rq_xdpsq;
        rq->stats        = &c->priv->channel_stats[c->ix]->rq;
        rq->ptp_cyc2time = mlx5_rq_ts_translator(mdev);
@@ -1014,35 +1015,6 @@ int mlx5e_flush_rq(struct mlx5e_rq *rq, int curr_state)
        return mlx5e_rq_to_ready(rq, curr_state);
 }
 
-static int mlx5e_modify_rq_scatter_fcs(struct mlx5e_rq *rq, bool enable)
-{
-       struct mlx5_core_dev *mdev = rq->mdev;
-
-       void *in;
-       void *rqc;
-       int inlen;
-       int err;
-
-       inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
-       in = kvzalloc(inlen, GFP_KERNEL);
-       if (!in)
-               return -ENOMEM;
-
-       rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
-
-       MLX5_SET(modify_rq_in, in, rq_state, MLX5_RQC_STATE_RDY);
-       MLX5_SET64(modify_rq_in, in, modify_bitmask,
-                  MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_SCATTER_FCS);
-       MLX5_SET(rqc, rqc, scatter_fcs, enable);
-       MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RDY);
-
-       err = mlx5_core_modify_rq(mdev, rq->rqn, in);
-
-       kvfree(in);
-
-       return err;
-}
-
 static int mlx5e_modify_rq_vsd(struct mlx5e_rq *rq, bool vsd)
 {
        struct mlx5_core_dev *mdev = rq->mdev;
@@ -3314,20 +3286,6 @@ static void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv)
        mlx5e_destroy_tises(priv);
 }
 
-static int mlx5e_modify_channels_scatter_fcs(struct mlx5e_channels *chs, bool enable)
-{
-       int err = 0;
-       int i;
-
-       for (i = 0; i < chs->num; i++) {
-               err = mlx5e_modify_rq_scatter_fcs(&chs->c[i]->rq, enable);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
 static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd)
 {
        int err;
@@ -3903,41 +3861,27 @@ static int mlx5e_set_rx_port_ts(struct mlx5_core_dev *mdev, bool enable)
        return mlx5_set_ports_check(mdev, in, sizeof(in));
 }
 
+static int mlx5e_set_rx_port_ts_wrap(struct mlx5e_priv *priv, void *ctx)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       bool enable = *(bool *)ctx;
+
+       return mlx5e_set_rx_port_ts(mdev, enable);
+}
+
 static int set_feature_rx_fcs(struct net_device *netdev, bool enable)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5e_channels *chs = &priv->channels;
-       struct mlx5_core_dev *mdev = priv->mdev;
+       struct mlx5e_params new_params;
        int err;
 
        mutex_lock(&priv->state_lock);
 
-       if (enable) {
-               err = mlx5e_set_rx_port_ts(mdev, false);
-               if (err)
-                       goto out;
-
-               chs->params.scatter_fcs_en = true;
-               err = mlx5e_modify_channels_scatter_fcs(chs, true);
-               if (err) {
-                       chs->params.scatter_fcs_en = false;
-                       mlx5e_set_rx_port_ts(mdev, true);
-               }
-       } else {
-               chs->params.scatter_fcs_en = false;
-               err = mlx5e_modify_channels_scatter_fcs(chs, false);
-               if (err) {
-                       chs->params.scatter_fcs_en = true;
-                       goto out;
-               }
-               err = mlx5e_set_rx_port_ts(mdev, true);
-               if (err) {
-                       mlx5_core_warn(mdev, "Failed to set RX port timestamp %d\n", err);
-                       err = 0;
-               }
-       }
-
-out:
+       new_params = chs->params;
+       new_params.scatter_fcs_en = enable;
+       err = mlx5e_safe_switch_params(priv, &new_params, mlx5e_set_rx_port_ts_wrap,
+                                      &new_params.scatter_fcs_en, true);
        mutex_unlock(&priv->state_lock);
        return err;
 }
@@ -4074,6 +4018,10 @@ static netdev_features_t mlx5e_fix_uplink_rep_features(struct net_device *netdev
        if (netdev->features & NETIF_F_GRO_HW)
                netdev_warn(netdev, "Disabling HW_GRO, not supported in switchdev mode\n");
 
+       features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+       if (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+               netdev_warn(netdev, "Disabling HW_VLAN CTAG FILTERING, not supported in switchdev mode\n");
+
        return features;
 }
 
@@ -4084,6 +4032,9 @@ static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
        struct mlx5e_vlan_table *vlan;
        struct mlx5e_params *params;
 
+       if (!netif_device_present(netdev))
+               return features;
+
        vlan = mlx5e_fs_get_vlan(priv->fs);
        mutex_lock(&priv->state_lock);
        params = &priv->channels.params;
index 75b9e15..7d90e5b 100644 (file)
@@ -191,7 +191,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport_rep)
        if (err) {
                netdev_warn(priv->netdev, "vport %d error %d reading stats\n",
                            rep->vport, err);
-               return;
+               goto out;
        }
 
        #define MLX5_GET_CTR(p, x) \
@@ -241,6 +241,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport_rep)
        rep_stats->tx_vport_rdma_multicast_bytes =
                MLX5_GET_CTR(out, received_ib_multicast.octets);
 
+out:
        kvfree(out);
 }
 
index c8820ab..3df455f 100644 (file)
@@ -2419,7 +2419,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,
 
        priv = mlx5i_epriv(netdev);
        tstamp = &priv->tstamp;
-       stats = rq->stats;
+       stats = &priv->channel_stats[rq->ix]->rq;
 
        flags_rqpn = be32_to_cpu(cqe->flags_rqpn);
        g = (flags_rqpn >> 28) & 3;
index 9af2aa2..243d5d7 100644 (file)
@@ -166,6 +166,7 @@ struct mlx5_fs_chains *mlx5e_nic_chains(struct mlx5e_tc_table *tc)
  * it's different than the ht->mutex here.
  */
 static struct lock_class_key tc_ht_lock_key;
+static struct lock_class_key tc_ht_wq_key;
 
 static void mlx5e_put_flow_tunnel_id(struct mlx5e_tc_flow *flow);
 static void free_flow_post_acts(struct mlx5e_tc_flow *flow);
@@ -1301,7 +1302,6 @@ mlx5e_tc_add_nic_flow(struct mlx5e_priv *priv,
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
                err = mlx5e_attach_mod_hdr(priv, flow, parse_attr);
-               mlx5e_mod_hdr_dealloc(&parse_attr->mod_hdr_acts);
                if (err)
                        return err;
        }
@@ -1359,8 +1359,10 @@ static void mlx5e_tc_del_nic_flow(struct mlx5e_priv *priv,
        }
        mutex_unlock(&tc->t_lock);
 
-       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) {
+               mlx5e_mod_hdr_dealloc(&attr->parse_attr->mod_hdr_acts);
                mlx5e_detach_mod_hdr(priv, flow);
+       }
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
                mlx5_fc_destroy(priv->mdev, attr->counter);
@@ -5181,6 +5183,7 @@ int mlx5e_tc_nic_init(struct mlx5e_priv *priv)
                return err;
 
        lockdep_set_class(&tc->ht.mutex, &tc_ht_lock_key);
+       lockdep_init_map(&tc->ht.run_work.lockdep_map, "tc_ht_wq_key", &tc_ht_wq_key, 0);
 
        mapping_id = mlx5_query_nic_system_image_guid(dev);
 
@@ -5287,6 +5290,7 @@ int mlx5e_tc_ht_init(struct rhashtable *tc_ht)
                return err;
 
        lockdep_set_class(&tc_ht->mutex, &tc_ht_lock_key);
+       lockdep_init_map(&tc_ht->run_work.lockdep_map, "tc_ht_wq_key", &tc_ht_wq_key, 0);
 
        return 0;
 }
index b176648..3cdcb0e 100644 (file)
@@ -1715,7 +1715,7 @@ void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16
        struct mlx5_esw_bridge *bridge;
 
        port = mlx5_esw_bridge_port_lookup(vport_num, esw_owner_vhca_id, br_offloads);
-       if (!port || port->flags & MLX5_ESW_BRIDGE_PORT_FLAG_PEER)
+       if (!port)
                return;
 
        bridge = port->bridge;
index 4f8a24d..75015d3 100644 (file)
@@ -22,15 +22,13 @@ struct mlx5_esw_rate_group {
 };
 
 static int esw_qos_tsar_config(struct mlx5_core_dev *dev, u32 *sched_ctx,
-                              u32 parent_ix, u32 tsar_ix,
-                              u32 max_rate, u32 bw_share)
+                              u32 tsar_ix, u32 max_rate, u32 bw_share)
 {
        u32 bitmask = 0;
 
        if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
                return -EOPNOTSUPP;
 
-       MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_ix);
        MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
        MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
        bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
@@ -51,7 +49,7 @@ static int esw_qos_group_config(struct mlx5_eswitch *esw, struct mlx5_esw_rate_g
        int err;
 
        err = esw_qos_tsar_config(dev, sched_ctx,
-                                 esw->qos.root_tsar_ix, group->tsar_ix,
+                                 group->tsar_ix,
                                  max_rate, bw_share);
        if (err)
                NL_SET_ERR_MSG_MOD(extack, "E-Switch modify group TSAR element failed");
@@ -67,23 +65,13 @@ static int esw_qos_vport_config(struct mlx5_eswitch *esw,
                                struct netlink_ext_ack *extack)
 {
        u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
-       struct mlx5_esw_rate_group *group = vport->qos.group;
        struct mlx5_core_dev *dev = esw->dev;
-       u32 parent_tsar_ix;
-       void *vport_elem;
        int err;
 
        if (!vport->qos.enabled)
                return -EIO;
 
-       parent_tsar_ix = group ? group->tsar_ix : esw->qos.root_tsar_ix;
-       MLX5_SET(scheduling_context, sched_ctx, element_type,
-                SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
-       vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx,
-                                 element_attributes);
-       MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
-
-       err = esw_qos_tsar_config(dev, sched_ctx, parent_tsar_ix, vport->qos.esw_tsar_ix,
+       err = esw_qos_tsar_config(dev, sched_ctx, vport->qos.esw_tsar_ix,
                                  max_rate, bw_share);
        if (err) {
                esw_warn(esw->dev,
index 0dfd574..9daf55e 100644 (file)
@@ -1464,6 +1464,7 @@ void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
        mlx5_lag_disable_change(esw->dev);
        down_write(&esw->mode_lock);
        mlx5_eswitch_disable_locked(esw);
+       esw->mode = MLX5_ESWITCH_LEGACY;
        up_write(&esw->mode_lock);
        mlx5_lag_enable_change(esw->dev);
 }
index e455b21..c981fa7 100644 (file)
@@ -143,7 +143,7 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
                if (mlx5_esw_indir_table_decap_vport(attr))
                        vport = mlx5_esw_indir_table_decap_vport(attr);
 
-               if (attr && !attr->chain && esw_attr->int_port)
+               if (!attr->chain && esw_attr && esw_attr->int_port)
                        metadata =
                                mlx5e_tc_int_port_get_metadata_for_match(esw_attr->int_port);
                else
@@ -4143,8 +4143,6 @@ int mlx5_devlink_port_fn_migratable_set(struct devlink_port *port, bool enable,
        }
 
        hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
-       memcpy(hca_caps, MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability),
-              MLX5_UN_SZ_BYTES(hca_cap_union));
        MLX5_SET(cmd_hca_cap_2, hca_caps, migratable, 1);
 
        err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport->vport,
@@ -4236,8 +4234,6 @@ int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
        }
 
        hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
-       memcpy(hca_caps, MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability),
-              MLX5_UN_SZ_BYTES(hca_cap_union));
        MLX5_SET(cmd_hca_cap, hca_caps, roce, enable);
 
        err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport_num,
index 96417c5..879555b 100644 (file)
@@ -677,6 +677,7 @@ static void mlx5_fw_fatal_reporter_err_work(struct work_struct *work)
        mutex_lock(&dev->intf_state_mutex);
        if (test_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags)) {
                mlx5_core_err(dev, "health works are not permitted at this stage\n");
+               mutex_unlock(&dev->intf_state_mutex);
                return;
        }
        mutex_unlock(&dev->intf_state_mutex);
index c247cca..e09518f 100644 (file)
@@ -90,9 +90,21 @@ static void mlx5i_get_ringparam(struct net_device *dev,
 static int mlx5i_set_channels(struct net_device *dev,
                              struct ethtool_channels *ch)
 {
-       struct mlx5e_priv *priv = mlx5i_epriv(dev);
+       struct mlx5i_priv *ipriv = netdev_priv(dev);
+       struct mlx5e_priv *epriv = mlx5i_epriv(dev);
+
+       /* rtnl lock protects from race between this ethtool op and sub
+        * interface ndo_init/uninit.
+        */
+       ASSERT_RTNL();
+       if (ipriv->num_sub_interfaces > 0) {
+               mlx5_core_warn(epriv->mdev,
+                              "can't change number of channels for interfaces with sub interfaces (%u)\n",
+                              ipriv->num_sub_interfaces);
+               return -EINVAL;
+       }
 
-       return mlx5e_ethtool_set_channels(priv, ch);
+       return mlx5e_ethtool_set_channels(epriv, ch);
 }
 
 static void mlx5i_get_channels(struct net_device *dev,
@@ -177,16 +189,16 @@ static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate)
        }
 }
 
-static int mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper)
+static u32 mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper)
 {
        int rate, width;
 
        rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper);
        if (rate < 0)
-               return -EINVAL;
+               return SPEED_UNKNOWN;
        width = mlx5_ptys_width_enum_to_int(ib_link_width_oper);
        if (width < 0)
-               return -EINVAL;
+               return SPEED_UNKNOWN;
 
        return rate * width;
 }
@@ -209,16 +221,13 @@ static int mlx5i_get_link_ksettings(struct net_device *netdev,
        ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
 
        speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper);
-       if (speed < 0)
-               return -EINVAL;
+       link_ksettings->base.speed = speed;
+       link_ksettings->base.duplex = speed == SPEED_UNKNOWN ? DUPLEX_UNKNOWN : DUPLEX_FULL;
 
-       link_ksettings->base.duplex = DUPLEX_FULL;
        link_ksettings->base.port = PORT_OTHER;
 
        link_ksettings->base.autoneg = AUTONEG_DISABLE;
 
-       link_ksettings->base.speed = speed;
-
        return 0;
 }
 
index 2c73c84..911cf4d 100644 (file)
@@ -160,6 +160,44 @@ void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
        stats->tx_dropped = sstats->tx_queue_dropped;
 }
 
+struct net_device *mlx5i_parent_get(struct net_device *netdev)
+{
+       struct mlx5e_priv *priv = mlx5i_epriv(netdev);
+       struct mlx5i_priv *ipriv, *parent_ipriv;
+       struct net_device *parent_dev;
+       int parent_ifindex;
+
+       ipriv = priv->ppriv;
+
+       parent_ifindex = netdev->netdev_ops->ndo_get_iflink(netdev);
+       parent_dev = dev_get_by_index(dev_net(netdev), parent_ifindex);
+       if (!parent_dev)
+               return NULL;
+
+       parent_ipriv = netdev_priv(parent_dev);
+
+       ASSERT_RTNL();
+       parent_ipriv->num_sub_interfaces++;
+
+       ipriv->parent_dev = parent_dev;
+
+       return parent_dev;
+}
+
+void mlx5i_parent_put(struct net_device *netdev)
+{
+       struct mlx5e_priv *priv = mlx5i_epriv(netdev);
+       struct mlx5i_priv *ipriv, *parent_ipriv;
+
+       ipriv = priv->ppriv;
+       parent_ipriv = netdev_priv(ipriv->parent_dev);
+
+       ASSERT_RTNL();
+       parent_ipriv->num_sub_interfaces--;
+
+       dev_put(ipriv->parent_dev);
+}
+
 int mlx5i_init_underlay_qp(struct mlx5e_priv *priv)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
index 99d46fd..f3f2af9 100644 (file)
@@ -54,9 +54,11 @@ struct mlx5i_priv {
        struct rdma_netdev rn; /* keep this first */
        u32 qpn;
        bool   sub_interface;
+       u32    num_sub_interfaces;
        u32    qkey;
        u16    pkey_index;
        struct mlx5i_pkey_qpn_ht *qpn_htbl;
+       struct net_device *parent_dev;
        char  *mlx5e_priv[];
 };
 
@@ -117,5 +119,9 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                   struct mlx5_av *av, u32 dqpn, u32 dqkey, bool xmit_more);
 void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
 
+/* Reference management for child to parent interfaces. */
+struct net_device *mlx5i_parent_get(struct net_device *netdev);
+void mlx5i_parent_put(struct net_device *netdev);
+
 #endif /* CONFIG_MLX5_CORE_IPOIB */
 #endif /* __MLX5E_IPOB_H__ */
index 4d9c9e4..03e6812 100644 (file)
@@ -158,21 +158,28 @@ static int mlx5i_pkey_dev_init(struct net_device *dev)
        struct mlx5e_priv *priv = mlx5i_epriv(dev);
        struct mlx5i_priv *ipriv, *parent_ipriv;
        struct net_device *parent_dev;
-       int parent_ifindex;
 
        ipriv = priv->ppriv;
 
-       /* Get QPN to netdevice hash table from parent */
-       parent_ifindex = dev->netdev_ops->ndo_get_iflink(dev);
-       parent_dev = dev_get_by_index(dev_net(dev), parent_ifindex);
+       /* Link to parent */
+       parent_dev = mlx5i_parent_get(dev);
        if (!parent_dev) {
                mlx5_core_warn(priv->mdev, "failed to get parent device\n");
                return -EINVAL;
        }
 
+       if (dev->num_rx_queues < parent_dev->real_num_rx_queues) {
+               mlx5_core_warn(priv->mdev,
+                              "failed to create child device with rx queues [%d] less than parent's [%d]\n",
+                              dev->num_rx_queues,
+                              parent_dev->real_num_rx_queues);
+               mlx5i_parent_put(dev);
+               return -EINVAL;
+       }
+
+       /* Get QPN to netdevice hash table from parent */
        parent_ipriv = netdev_priv(parent_dev);
        ipriv->qpn_htbl = parent_ipriv->qpn_htbl;
-       dev_put(parent_dev);
 
        return mlx5i_dev_init(dev);
 }
@@ -184,6 +191,7 @@ static int mlx5i_pkey_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 static void mlx5i_pkey_dev_cleanup(struct net_device *netdev)
 {
+       mlx5i_parent_put(netdev);
        return mlx5i_dev_cleanup(netdev);
 }
 
index 69cfe60..69318b1 100644 (file)
@@ -681,7 +681,7 @@ static int mlx5_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
 static const struct ptp_clock_info mlx5_ptp_clock_info = {
        .owner          = THIS_MODULE,
        .name           = "mlx5_ptp",
-       .max_adj        = 100000000,
+       .max_adj        = 50000000,
        .n_alarm        = 0,
        .n_ext_ts       = 0,
        .n_per_out      = 0,
index df134f6..4e1b575 100644 (file)
@@ -2098,7 +2098,7 @@ static void mlx5_core_verify_params(void)
        }
 }
 
-static int __init init(void)
+static int __init mlx5_init(void)
 {
        int err;
 
@@ -2110,7 +2110,7 @@ static int __init init(void)
        mlx5_core_verify_params();
        mlx5_register_debugfs();
 
-       err = pci_register_driver(&mlx5_core_driver);
+       err = mlx5e_init();
        if (err)
                goto err_debug;
 
@@ -2118,28 +2118,28 @@ static int __init init(void)
        if (err)
                goto err_sf;
 
-       err = mlx5e_init();
+       err = pci_register_driver(&mlx5_core_driver);
        if (err)
-               goto err_en;
+               goto err_pci;
 
        return 0;
 
-err_en:
+err_pci:
        mlx5_sf_driver_unregister();
 err_sf:
-       pci_unregister_driver(&mlx5_core_driver);
+       mlx5e_cleanup();
 err_debug:
        mlx5_unregister_debugfs();
        return err;
 }
 
-static void __exit cleanup(void)
+static void __exit mlx5_cleanup(void)
 {
-       mlx5e_cleanup();
-       mlx5_sf_driver_unregister();
        pci_unregister_driver(&mlx5_core_driver);
+       mlx5_sf_driver_unregister();
+       mlx5e_cleanup();
        mlx5_unregister_debugfs();
 }
 
-module_init(init);
-module_exit(cleanup);
+module_init(mlx5_init);
+module_exit(mlx5_cleanup);
index 6059635..0eb50be 100644 (file)
@@ -74,6 +74,14 @@ static u32 get_function(u16 func_id, bool ec_function)
        return (u32)func_id | (ec_function << 16);
 }
 
+static u16 func_id_to_type(struct mlx5_core_dev *dev, u16 func_id, bool ec_function)
+{
+       if (!func_id)
+               return mlx5_core_is_ecpf(dev) && !ec_function ? MLX5_HOST_PF : MLX5_PF;
+
+       return func_id <= mlx5_core_max_vfs(dev) ?  MLX5_VF : MLX5_SF;
+}
+
 static struct rb_root *page_root_per_function(struct mlx5_core_dev *dev, u32 function)
 {
        struct rb_root *root;
@@ -332,6 +340,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
        u32 out[MLX5_ST_SZ_DW(manage_pages_out)] = {0};
        int inlen = MLX5_ST_SZ_BYTES(manage_pages_in);
        int notify_fail = event;
+       u16 func_type;
        u64 addr;
        int err;
        u32 *in;
@@ -383,11 +392,9 @@ retry:
                goto out_dropped;
        }
 
+       func_type = func_id_to_type(dev, func_id, ec_function);
+       dev->priv.page_counters[func_type] += npages;
        dev->priv.fw_pages += npages;
-       if (func_id)
-               dev->priv.vfs_pages += npages;
-       else if (mlx5_core_is_ecpf(dev) && !ec_function)
-               dev->priv.host_pf_pages += npages;
 
        mlx5_core_dbg(dev, "npages %d, ec_function %d, func_id 0x%x, err %d\n",
                      npages, ec_function, func_id, err);
@@ -414,6 +421,7 @@ static void release_all_pages(struct mlx5_core_dev *dev, u16 func_id,
        struct rb_root *root;
        struct rb_node *p;
        int npages = 0;
+       u16 func_type;
 
        root = xa_load(&dev->priv.page_root_xa, function);
        if (WARN_ON_ONCE(!root))
@@ -428,11 +436,9 @@ static void release_all_pages(struct mlx5_core_dev *dev, u16 func_id,
                free_fwp(dev, fwp, fwp->free_count);
        }
 
+       func_type = func_id_to_type(dev, func_id, ec_function);
+       dev->priv.page_counters[func_type] -= npages;
        dev->priv.fw_pages -= npages;
-       if (func_id)
-               dev->priv.vfs_pages -= npages;
-       else if (mlx5_core_is_ecpf(dev) && !ec_function)
-               dev->priv.host_pf_pages -= npages;
 
        mlx5_core_dbg(dev, "npages %d, ec_function %d, func_id 0x%x\n",
                      npages, ec_function, func_id);
@@ -498,6 +504,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
        int outlen = MLX5_ST_SZ_BYTES(manage_pages_out);
        u32 in[MLX5_ST_SZ_DW(manage_pages_in)] = {};
        int num_claimed;
+       u16 func_type;
        u32 *out;
        int err;
        int i;
@@ -549,11 +556,9 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
        if (nclaimed)
                *nclaimed = num_claimed;
 
+       func_type = func_id_to_type(dev, func_id, ec_function);
+       dev->priv.page_counters[func_type] -= num_claimed;
        dev->priv.fw_pages -= num_claimed;
-       if (func_id)
-               dev->priv.vfs_pages -= num_claimed;
-       else if (mlx5_core_is_ecpf(dev) && !ec_function)
-               dev->priv.host_pf_pages -= num_claimed;
 
 out_free:
        kvfree(out);
@@ -706,12 +711,12 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev)
        WARN(dev->priv.fw_pages,
             "FW pages counter is %d after reclaiming all pages\n",
             dev->priv.fw_pages);
-       WARN(dev->priv.vfs_pages,
+       WARN(dev->priv.page_counters[MLX5_VF],
             "VFs FW pages counter is %d after reclaiming all pages\n",
-            dev->priv.vfs_pages);
-       WARN(dev->priv.host_pf_pages,
+            dev->priv.page_counters[MLX5_VF]);
+       WARN(dev->priv.page_counters[MLX5_HOST_PF],
             "External host PF FW pages counter is %d after reclaiming all pages\n",
-            dev->priv.host_pf_pages);
+            dev->priv.page_counters[MLX5_HOST_PF]);
 
        return 0;
 }
index 0777be2..8bce730 100644 (file)
@@ -62,13 +62,12 @@ int mlx5_qos_create_root_node(struct mlx5_core_dev *mdev, u32 *id)
        return mlx5_qos_create_inner_node(mdev, MLX5_QOS_DEFAULT_DWRR_UID, 0, 0, id);
 }
 
-int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 parent_id,
+int mlx5_qos_update_node(struct mlx5_core_dev *mdev,
                         u32 bw_share, u32 max_avg_bw, u32 id)
 {
        u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
        u32 bitmask = 0;
 
-       MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_id);
        MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
        MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_avg_bw);
 
index 125e4e4..624ce82 100644 (file)
@@ -23,7 +23,7 @@ int mlx5_qos_create_leaf_node(struct mlx5_core_dev *mdev, u32 parent_id,
 int mlx5_qos_create_inner_node(struct mlx5_core_dev *mdev, u32 parent_id,
                               u32 bw_share, u32 max_avg_bw, u32 *id);
 int mlx5_qos_create_root_node(struct mlx5_core_dev *mdev, u32 *id);
-int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 parent_id, u32 bw_share,
+int mlx5_qos_update_node(struct mlx5_core_dev *mdev, u32 bw_share,
                         u32 max_avg_bw, u32 id);
 int mlx5_qos_destroy_node(struct mlx5_core_dev *mdev, u32 id);
 
index c0e6c48..3008e9c 100644 (file)
@@ -147,7 +147,7 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf)
 
        mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf);
 
-       if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages))
+       if (mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF]))
                mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
 }
 
index 74cbe53..042ca03 100644 (file)
@@ -3,7 +3,12 @@
 
 #include "dr_types.h"
 
+#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN < 2048)
+/* don't try to optimize STE allocation if the stack is too constaraining */
+#define DR_RULE_MAX_STES_OPTIMIZED 0
+#else
 #define DR_RULE_MAX_STES_OPTIMIZED 5
+#endif
 #define DR_RULE_MAX_STE_CHAIN_OPTIMIZED (DR_RULE_MAX_STES_OPTIMIZED + DR_ACTION_MAX_STES)
 
 static int dr_rule_append_to_miss_list(struct mlx5dr_domain *dmn,
@@ -1133,12 +1138,14 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule,
                         rule->flow_source))
                return 0;
 
+       mlx5dr_domain_nic_lock(nic_dmn);
+
        ret = mlx5dr_matcher_select_builders(matcher,
                                             nic_matcher,
                                             dr_rule_get_ipv(&param->outer),
                                             dr_rule_get_ipv(&param->inner));
        if (ret)
-               return ret;
+               goto err_unlock;
 
        hw_ste_arr_is_opt = nic_matcher->num_of_builders <= DR_RULE_MAX_STES_OPTIMIZED;
        if (likely(hw_ste_arr_is_opt)) {
@@ -1147,12 +1154,12 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule,
                hw_ste_arr = kzalloc((nic_matcher->num_of_builders + DR_ACTION_MAX_STES) *
                                     DR_STE_SIZE, GFP_KERNEL);
 
-               if (!hw_ste_arr)
-                       return -ENOMEM;
+               if (!hw_ste_arr) {
+                       ret = -ENOMEM;
+                       goto err_unlock;
+               }
        }
 
-       mlx5dr_domain_nic_lock(nic_dmn);
-
        ret = mlx5dr_matcher_add_to_tbl_nic(dmn, nic_matcher);
        if (ret)
                goto free_hw_ste;
@@ -1236,11 +1243,12 @@ remove_from_nic_tbl:
                mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher);
 
 free_hw_ste:
-       mlx5dr_domain_nic_unlock(nic_dmn);
-
-       if (unlikely(!hw_ste_arr_is_opt))
+       if (!hw_ste_arr_is_opt)
                kfree(hw_ste_arr);
 
+err_unlock:
+       mlx5dr_domain_nic_unlock(nic_dmn);
+
        return ret;
 }
 
index c22c3ac..09e3277 100644 (file)
@@ -2951,7 +2951,7 @@ struct mlxsw_sp_nexthop_group_info {
           gateway:1, /* routes using the group use a gateway */
           is_resilient:1;
        struct list_head list; /* member in nh_res_grp_list */
-       struct mlxsw_sp_nexthop nexthops[0];
+       struct mlxsw_sp_nexthop nexthops[];
 #define nh_rif nexthops[0].rif
 };
 
index 5314c06..55b484b 100644 (file)
@@ -608,12 +608,12 @@ allocate_new:
                lan966x_fdma_rx_reload(rx);
        }
 
-       if (counter < weight && napi_complete_done(napi, counter))
-               lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA);
-
        if (redirect)
                xdp_do_flush();
 
+       if (counter < weight && napi_complete_done(napi, counter))
+               lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA);
+
        return counter;
 }
 
index cadde20..580c91d 100644 (file)
@@ -1043,11 +1043,6 @@ static int lan966x_probe(struct platform_device *pdev)
                lan966x->base_mac[5] &= 0xf0;
        }
 
-       ports = device_get_named_child_node(&pdev->dev, "ethernet-ports");
-       if (!ports)
-               return dev_err_probe(&pdev->dev, -ENODEV,
-                                    "no ethernet-ports child found\n");
-
        err = lan966x_create_targets(pdev, lan966x);
        if (err)
                return dev_err_probe(&pdev->dev, err,
@@ -1125,6 +1120,11 @@ static int lan966x_probe(struct platform_device *pdev)
                }
        }
 
+       ports = device_get_named_child_node(&pdev->dev, "ethernet-ports");
+       if (!ports)
+               return dev_err_probe(&pdev->dev, -ENODEV,
+                                    "no ethernet-ports child found\n");
+
        /* init switch */
        lan966x_init(lan966x);
        lan966x_stats_init(lan966x);
@@ -1162,6 +1162,8 @@ static int lan966x_probe(struct platform_device *pdev)
                        goto cleanup_ports;
        }
 
+       fwnode_handle_put(ports);
+
        lan966x_mdb_init(lan966x);
        err = lan966x_fdb_init(lan966x);
        if (err)
@@ -1191,6 +1193,7 @@ cleanup_fdb:
        lan966x_fdb_deinit(lan966x);
 
 cleanup_ports:
+       fwnode_handle_put(ports);
        fwnode_handle_put(portnp);
 
        lan966x_cleanup_ports(lan966x);
index f9ebfaa..a834843 100644 (file)
@@ -1073,6 +1073,9 @@ void lan966x_ptp_deinit(struct lan966x *lan966x)
        struct lan966x_port *port;
        int i;
 
+       if (!lan966x->ptp)
+               return;
+
        for (i = 0; i < lan966x->num_phys_ports; i++) {
                port = lan966x->ports[i];
                if (!port)
index d8dc9fb..a54c042 100644 (file)
@@ -95,10 +95,7 @@ lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
        bool found = false;
        u32 val;
 
-       /* Check if the port keyset selection is enabled */
        val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
-       if (!ANA_VCAP_S2_CFG_ENA_GET(val))
-               return -ENOENT;
 
        /* Collect all keysets for the port in a list */
        if (l3_proto == ETH_P_ALL)
index 0ed1ea7..69e7663 100644 (file)
@@ -633,7 +633,7 @@ int sparx5_ptp_init(struct sparx5 *sparx5)
        /* Enable master counters */
        spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG);
 
-       for (i = 0; i < sparx5->port_count; i++) {
+       for (i = 0; i < SPX5_PORTS; i++) {
                port = sparx5->ports[i];
                if (!port)
                        continue;
@@ -649,7 +649,7 @@ void sparx5_ptp_deinit(struct sparx5 *sparx5)
        struct sparx5_port *port;
        int i;
 
-       for (i = 0; i < sparx5->port_count; i++) {
+       for (i = 0; i < SPX5_PORTS; i++) {
                port = sparx5->ports[i];
                if (!port)
                        continue;
index e708c2d..f9b8f37 100644 (file)
@@ -1217,9 +1217,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
        unsigned int max_queues_per_port = num_online_cpus();
        struct gdma_context *gc = pci_get_drvdata(pdev);
        struct gdma_irq_context *gic;
-       unsigned int max_irqs;
-       u16 *cpus;
-       cpumask_var_t req_mask;
+       unsigned int max_irqs, cpu;
        int nvec, irq;
        int err, i = 0, j;
 
@@ -1240,39 +1238,31 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
                goto free_irq_vector;
        }
 
-       if (!zalloc_cpumask_var(&req_mask, GFP_KERNEL)) {
-               err = -ENOMEM;
-               goto free_irq;
-       }
-
-       cpus = kcalloc(nvec, sizeof(*cpus), GFP_KERNEL);
-       if (!cpus) {
-               err = -ENOMEM;
-               goto free_mask;
-       }
-       for (i = 0; i < nvec; i++)
-               cpus[i] = cpumask_local_spread(i, gc->numa_node);
-
        for (i = 0; i < nvec; i++) {
-               cpumask_set_cpu(cpus[i], req_mask);
                gic = &gc->irq_contexts[i];
                gic->handler = NULL;
                gic->arg = NULL;
 
+               if (!i)
+                       snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_hwc@pci:%s",
+                                pci_name(pdev));
+               else
+                       snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_q%d@pci:%s",
+                                i - 1, pci_name(pdev));
+
                irq = pci_irq_vector(pdev, i);
                if (irq < 0) {
                        err = irq;
-                       goto free_mask;
+                       goto free_irq;
                }
 
-               err = request_irq(irq, mana_gd_intr, 0, "mana_intr", gic);
+               err = request_irq(irq, mana_gd_intr, 0, gic->name, gic);
                if (err)
-                       goto free_mask;
-               irq_set_affinity_and_hint(irq, req_mask);
-               cpumask_clear(req_mask);
+                       goto free_irq;
+
+               cpu = cpumask_local_spread(i, gc->numa_node);
+               irq_set_affinity_and_hint(irq, cpumask_of(cpu));
        }
-       free_cpumask_var(req_mask);
-       kfree(cpus);
 
        err = mana_gd_alloc_res_map(nvec, &gc->msix_resource);
        if (err)
@@ -1283,13 +1273,12 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
 
        return 0;
 
-free_mask:
-       free_cpumask_var(req_mask);
-       kfree(cpus);
 free_irq:
        for (j = i - 1; j >= 0; j--) {
                irq = pci_irq_vector(pdev, j);
                gic = &gc->irq_contexts[j];
+
+               irq_update_affinity_hint(irq, NULL);
                free_irq(irq, gic);
        }
 
@@ -1317,6 +1306,9 @@ static void mana_gd_remove_irqs(struct pci_dev *pdev)
                        continue;
 
                gic = &gc->irq_contexts[i];
+
+               /* Need to clear the hint before free_irq */
+               irq_update_affinity_hint(irq, NULL);
                free_irq(irq, gic);
        }
 
index 7c0897e..ee05240 100644 (file)
@@ -605,6 +605,18 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
                flow_rule_match_control(rule, &match);
        }
 
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
+               struct flow_match_vlan match;
+
+               flow_rule_match_vlan(rule, &match);
+               filter->key_type = OCELOT_VCAP_KEY_ANY;
+               filter->vlan.vid.value = match.key->vlan_id;
+               filter->vlan.vid.mask = match.mask->vlan_id;
+               filter->vlan.pcp.value[0] = match.key->vlan_priority;
+               filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
+               match_protocol = false;
+       }
+
        if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
                struct flow_match_eth_addrs match;
 
@@ -737,18 +749,6 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
                match_protocol = false;
        }
 
-       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
-               struct flow_match_vlan match;
-
-               flow_rule_match_vlan(rule, &match);
-               filter->key_type = OCELOT_VCAP_KEY_ANY;
-               filter->vlan.vid.value = match.key->vlan_id;
-               filter->vlan.vid.mask = match.mask->vlan_id;
-               filter->vlan.pcp.value[0] = match.key->vlan_priority;
-               filter->vlan.pcp.mask[0] = match.mask->vlan_priority;
-               match_protocol = false;
-       }
-
 finished_key_parsing:
        if (match_protocol && proto != ETH_P_ALL) {
                if (filter->block_id == VCAP_ES0) {
index 1a82f10..2180ae9 100644 (file)
@@ -335,8 +335,8 @@ static void
 ocelot_populate_ipv6_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV6;
-       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
-       trap->key.ipv4.proto.mask[0] = 0xff;
+       trap->key.ipv6.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv6.proto.mask[0] = 0xff;
        trap->key.ipv6.dport.value = PTP_EV_PORT;
        trap->key.ipv6.dport.mask = 0xffff;
 }
@@ -355,8 +355,8 @@ static void
 ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
 {
        trap->key_type = OCELOT_VCAP_KEY_IPV6;
-       trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
-       trap->key.ipv4.proto.mask[0] = 0xff;
+       trap->key.ipv6.proto.value[0] = IPPROTO_UDP;
+       trap->key.ipv6.proto.mask[0] = 0xff;
        trap->key.ipv6.dport.value = PTP_GEN_PORT;
        trap->key.ipv6.dport.mask = 0xffff;
 }
index a8678d5..060a77f 100644 (file)
@@ -460,6 +460,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
                            sizeof(struct nfp_tun_neigh_v4);
        unsigned long cookie = (unsigned long)neigh;
        struct nfp_flower_priv *priv = app->priv;
+       struct nfp_tun_neigh_lag lag_info;
        struct nfp_neigh_entry *nn_entry;
        u32 port_id;
        u8 mtype;
@@ -468,6 +469,11 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
        if (!port_id)
                return;
 
+       if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT) {
+               memset(&lag_info, 0, sizeof(struct nfp_tun_neigh_lag));
+               nfp_flower_lag_get_info_from_netdev(app, netdev, &lag_info);
+       }
+
        spin_lock_bh(&priv->predt_lock);
        nn_entry = rhashtable_lookup_fast(&priv->neigh_table, &cookie,
                                          neigh_table_params);
@@ -515,7 +521,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
                neigh_ha_snapshot(common->dst_addr, neigh, netdev);
 
                if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT)
-                       nfp_flower_lag_get_info_from_netdev(app, netdev, lag);
+                       memcpy(lag, &lag_info, sizeof(struct nfp_tun_neigh_lag));
                common->port_id = cpu_to_be32(port_id);
 
                if (rhashtable_insert_fast(&priv->neigh_table,
index a4a89ef..cc97b3d 100644 (file)
@@ -293,35 +293,131 @@ nfp_net_set_fec_link_mode(struct nfp_eth_table_port *eth_port,
        }
 }
 
-static const u16 nfp_eth_media_table[] = {
-       [NFP_MEDIA_1000BASE_CX]         = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
-       [NFP_MEDIA_1000BASE_KX]         = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
-       [NFP_MEDIA_10GBASE_KX4]         = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
-       [NFP_MEDIA_10GBASE_KR]          = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
-       [NFP_MEDIA_10GBASE_CX4]         = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
-       [NFP_MEDIA_10GBASE_CR]          = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
-       [NFP_MEDIA_10GBASE_SR]          = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
-       [NFP_MEDIA_10GBASE_ER]          = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
-       [NFP_MEDIA_25GBASE_KR]          = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
-       [NFP_MEDIA_25GBASE_KR_S]        = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
-       [NFP_MEDIA_25GBASE_CR]          = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
-       [NFP_MEDIA_25GBASE_CR_S]        = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
-       [NFP_MEDIA_25GBASE_SR]          = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
-       [NFP_MEDIA_40GBASE_CR4]         = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
-       [NFP_MEDIA_40GBASE_KR4]         = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
-       [NFP_MEDIA_40GBASE_SR4]         = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
-       [NFP_MEDIA_40GBASE_LR4]         = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
-       [NFP_MEDIA_50GBASE_KR]          = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
-       [NFP_MEDIA_50GBASE_SR]          = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
-       [NFP_MEDIA_50GBASE_CR]          = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
-       [NFP_MEDIA_50GBASE_LR]          = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
-       [NFP_MEDIA_50GBASE_ER]          = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
-       [NFP_MEDIA_50GBASE_FR]          = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
-       [NFP_MEDIA_100GBASE_KR4]        = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
-       [NFP_MEDIA_100GBASE_SR4]        = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
-       [NFP_MEDIA_100GBASE_CR4]        = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
-       [NFP_MEDIA_100GBASE_KP4]        = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
-       [NFP_MEDIA_100GBASE_CR10]       = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+static const struct nfp_eth_media_link_mode {
+       u16 ethtool_link_mode;
+       u16 speed;
+} nfp_eth_media_table[NFP_MEDIA_LINK_MODES_NUMBER] = {
+       [NFP_MEDIA_1000BASE_CX] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+               .speed                  = NFP_SPEED_1G,
+       },
+       [NFP_MEDIA_1000BASE_KX] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+               .speed                  = NFP_SPEED_1G,
+       },
+       [NFP_MEDIA_10GBASE_KX4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+               .speed                  = NFP_SPEED_10G,
+       },
+       [NFP_MEDIA_10GBASE_KR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+               .speed                  = NFP_SPEED_10G,
+       },
+       [NFP_MEDIA_10GBASE_CX4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+               .speed                  = NFP_SPEED_10G,
+       },
+       [NFP_MEDIA_10GBASE_CR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
+               .speed                  = NFP_SPEED_10G,
+       },
+       [NFP_MEDIA_10GBASE_SR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+               .speed                  = NFP_SPEED_10G,
+       },
+       [NFP_MEDIA_10GBASE_ER] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+               .speed                  = NFP_SPEED_10G,
+       },
+       [NFP_MEDIA_25GBASE_KR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+               .speed                  = NFP_SPEED_25G,
+       },
+       [NFP_MEDIA_25GBASE_KR_S] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+               .speed                  = NFP_SPEED_25G,
+       },
+       [NFP_MEDIA_25GBASE_CR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+               .speed                  = NFP_SPEED_25G,
+       },
+       [NFP_MEDIA_25GBASE_CR_S] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+               .speed                  = NFP_SPEED_25G,
+       },
+       [NFP_MEDIA_25GBASE_SR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+               .speed                  = NFP_SPEED_25G,
+       },
+       [NFP_MEDIA_40GBASE_CR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+               .speed                  = NFP_SPEED_40G,
+       },
+       [NFP_MEDIA_40GBASE_KR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+               .speed                  = NFP_SPEED_40G,
+       },
+       [NFP_MEDIA_40GBASE_SR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
+               .speed                  = NFP_SPEED_40G,
+       },
+       [NFP_MEDIA_40GBASE_LR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
+               .speed                  = NFP_SPEED_40G,
+       },
+       [NFP_MEDIA_50GBASE_KR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
+               .speed                  = NFP_SPEED_50G,
+       },
+       [NFP_MEDIA_50GBASE_SR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
+               .speed                  = NFP_SPEED_50G,
+       },
+       [NFP_MEDIA_50GBASE_CR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
+               .speed                  = NFP_SPEED_50G,
+       },
+       [NFP_MEDIA_50GBASE_LR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+               .speed                  = NFP_SPEED_50G,
+       },
+       [NFP_MEDIA_50GBASE_ER] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+               .speed                  = NFP_SPEED_50G,
+       },
+       [NFP_MEDIA_50GBASE_FR] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+               .speed                  = NFP_SPEED_50G,
+       },
+       [NFP_MEDIA_100GBASE_KR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+               .speed                  = NFP_SPEED_100G,
+       },
+       [NFP_MEDIA_100GBASE_SR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
+               .speed                  = NFP_SPEED_100G,
+       },
+       [NFP_MEDIA_100GBASE_CR4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+               .speed                  = NFP_SPEED_100G,
+       },
+       [NFP_MEDIA_100GBASE_KP4] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+               .speed                  = NFP_SPEED_100G,
+       },
+       [NFP_MEDIA_100GBASE_CR10] = {
+               .ethtool_link_mode      = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+               .speed                  = NFP_SPEED_100G,
+       },
+};
+
+static const unsigned int nfp_eth_speed_map[NFP_SUP_SPEED_NUMBER] = {
+       [NFP_SPEED_1G]          = SPEED_1000,
+       [NFP_SPEED_10G]         = SPEED_10000,
+       [NFP_SPEED_25G]         = SPEED_25000,
+       [NFP_SPEED_40G]         = SPEED_40000,
+       [NFP_SPEED_50G]         = SPEED_50000,
+       [NFP_SPEED_100G]        = SPEED_100000,
 };
 
 static void nfp_add_media_link_mode(struct nfp_port *port,
@@ -334,8 +430,12 @@ static void nfp_add_media_link_mode(struct nfp_port *port,
        };
        struct nfp_cpp *cpp = port->app->cpp;
 
-       if (nfp_eth_read_media(cpp, &ethm))
+       if (nfp_eth_read_media(cpp, &ethm)) {
+               bitmap_fill(port->speed_bitmap, NFP_SUP_SPEED_NUMBER);
                return;
+       }
+
+       bitmap_zero(port->speed_bitmap, NFP_SUP_SPEED_NUMBER);
 
        for (u32 i = 0; i < 2; i++) {
                supported_modes[i] = le64_to_cpu(ethm.supported_modes[i]);
@@ -344,20 +444,26 @@ static void nfp_add_media_link_mode(struct nfp_port *port,
 
        for (u32 i = 0; i < NFP_MEDIA_LINK_MODES_NUMBER; i++) {
                if (i < 64) {
-                       if (supported_modes[0] & BIT_ULL(i))
-                               __set_bit(nfp_eth_media_table[i],
+                       if (supported_modes[0] & BIT_ULL(i)) {
+                               __set_bit(nfp_eth_media_table[i].ethtool_link_mode,
                                          cmd->link_modes.supported);
+                               __set_bit(nfp_eth_media_table[i].speed,
+                                         port->speed_bitmap);
+                       }
 
                        if (advertised_modes[0] & BIT_ULL(i))
-                               __set_bit(nfp_eth_media_table[i],
+                               __set_bit(nfp_eth_media_table[i].ethtool_link_mode,
                                          cmd->link_modes.advertising);
                } else {
-                       if (supported_modes[1] & BIT_ULL(i - 64))
-                               __set_bit(nfp_eth_media_table[i],
+                       if (supported_modes[1] & BIT_ULL(i - 64)) {
+                               __set_bit(nfp_eth_media_table[i].ethtool_link_mode,
                                          cmd->link_modes.supported);
+                               __set_bit(nfp_eth_media_table[i].speed,
+                                         port->speed_bitmap);
+                       }
 
                        if (advertised_modes[1] & BIT_ULL(i - 64))
-                               __set_bit(nfp_eth_media_table[i],
+                               __set_bit(nfp_eth_media_table[i].ethtool_link_mode,
                                          cmd->link_modes.advertising);
                }
        }
@@ -468,6 +574,22 @@ nfp_net_set_link_ksettings(struct net_device *netdev,
 
        if (cmd->base.speed != SPEED_UNKNOWN) {
                u32 speed = cmd->base.speed / eth_port->lanes;
+               bool is_supported = false;
+
+               for (u32 i = 0; i < NFP_SUP_SPEED_NUMBER; i++) {
+                       if (cmd->base.speed == nfp_eth_speed_map[i] &&
+                           test_bit(i, port->speed_bitmap)) {
+                               is_supported = true;
+                               break;
+                       }
+               }
+
+               if (!is_supported) {
+                       netdev_err(netdev, "Speed %u is not supported.\n",
+                                  cmd->base.speed);
+                       err = -EINVAL;
+                       goto err_bad_set;
+               }
 
                if (req_aneg) {
                        netdev_err(netdev, "Speed changing is not allowed when working on autoneg mode.\n");
index f8cd157..9c04f9f 100644 (file)
@@ -38,6 +38,16 @@ enum nfp_port_flags {
        NFP_PORT_CHANGED = 0,
 };
 
+enum {
+       NFP_SPEED_1G,
+       NFP_SPEED_10G,
+       NFP_SPEED_25G,
+       NFP_SPEED_40G,
+       NFP_SPEED_50G,
+       NFP_SPEED_100G,
+       NFP_SUP_SPEED_NUMBER
+};
+
 /**
  * struct nfp_port - structure representing NFP port
  * @netdev:    backpointer to associated netdev
@@ -52,6 +62,7 @@ enum nfp_port_flags {
  * @eth_forced:        for %NFP_PORT_PHYS_PORT port is forced UP or DOWN, don't change
  * @eth_port:  for %NFP_PORT_PHYS_PORT translated ETH Table port entry
  * @eth_stats: for %NFP_PORT_PHYS_PORT MAC stats if available
+ * @speed_bitmap:      for %NFP_PORT_PHYS_PORT supported speed bitmap
  * @pf_id:     for %NFP_PORT_PF_PORT, %NFP_PORT_VF_PORT ID of the PCI PF (0-3)
  * @vf_id:     for %NFP_PORT_VF_PORT ID of the PCI VF within @pf_id
  * @pf_split:  for %NFP_PORT_PF_PORT %true if PCI PF has more than one vNIC
@@ -78,6 +89,7 @@ struct nfp_port {
                        bool eth_forced;
                        struct nfp_eth_table_port *eth_port;
                        u8 __iomem *eth_stats;
+                       DECLARE_BITMAP(speed_bitmap, NFP_SUP_SPEED_NUMBER);
                };
                /* NFP_PORT_PF_PORT, NFP_PORT_VF_PORT */
                struct {
index 626b911..d911f4f 100644 (file)
@@ -708,9 +708,16 @@ void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb,
                q->lif->index, q->name, q->hw_type, q->hw_index,
                q->head_idx, ring_doorbell);
 
-       if (ring_doorbell)
+       if (ring_doorbell) {
                ionic_dbell_ring(lif->kern_dbpage, q->hw_type,
                                 q->dbval | q->head_idx);
+
+               q->dbell_jiffies = jiffies;
+
+               if (q_to_qcq(q)->napi_qcq)
+                       mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline,
+                                 jiffies + IONIC_NAPI_DEADLINE);
+       }
 }
 
 static bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos)
index 2a1d7b9..bce3ca3 100644 (file)
 #define IONIC_DEV_INFO_REG_COUNT       32
 #define IONIC_DEV_CMD_REG_COUNT                32
 
+#define IONIC_NAPI_DEADLINE            (HZ / 200)      /* 5ms */
+#define IONIC_ADMIN_DOORBELL_DEADLINE  (HZ / 2)        /* 500ms */
+#define IONIC_TX_DOORBELL_DEADLINE     (HZ / 100)      /* 10ms */
+#define IONIC_RX_MIN_DOORBELL_DEADLINE (HZ / 100)      /* 10ms */
+#define IONIC_RX_MAX_DOORBELL_DEADLINE (HZ * 5)        /* 5s */
+
 struct ionic_dev_bar {
        void __iomem *vaddr;
        phys_addr_t bus_addr;
@@ -216,6 +222,8 @@ struct ionic_queue {
        struct ionic_lif *lif;
        struct ionic_desc_info *info;
        u64 dbval;
+       unsigned long dbell_deadline;
+       unsigned long dbell_jiffies;
        u16 head_idx;
        u16 tail_idx;
        unsigned int index;
@@ -361,4 +369,8 @@ void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info,
 int ionic_heartbeat_check(struct ionic *ionic);
 bool ionic_is_fw_running(struct ionic_dev *idev);
 
+bool ionic_adminq_poke_doorbell(struct ionic_queue *q);
+bool ionic_txq_poke_doorbell(struct ionic_queue *q);
+bool ionic_rxq_poke_doorbell(struct ionic_queue *q);
+
 #endif /* _IONIC_DEV_H_ */
index 4dd16c4..63a78a9 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "ionic.h"
 #include "ionic_bus.h"
+#include "ionic_dev.h"
 #include "ionic_lif.h"
 #include "ionic_txrx.h"
 #include "ionic_ethtool.h"
@@ -200,6 +201,13 @@ void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep)
        }
 }
 
+static void ionic_napi_deadline(struct timer_list *timer)
+{
+       struct ionic_qcq *qcq = container_of(timer, struct ionic_qcq, napi_deadline);
+
+       napi_schedule(&qcq->napi);
+}
+
 static irqreturn_t ionic_isr(int irq, void *data)
 {
        struct napi_struct *napi = data;
@@ -269,6 +277,7 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq)
                        .oper = IONIC_Q_ENABLE,
                },
        };
+       int ret;
 
        idev = &lif->ionic->idev;
        dev = lif->ionic->dev;
@@ -276,16 +285,24 @@ static int ionic_qcq_enable(struct ionic_qcq *qcq)
        dev_dbg(dev, "q_enable.index %d q_enable.qtype %d\n",
                ctx.cmd.q_control.index, ctx.cmd.q_control.type);
 
+       if (qcq->flags & IONIC_QCQ_F_INTR)
+               ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
+
+       ret = ionic_adminq_post_wait(lif, &ctx);
+       if (ret)
+               return ret;
+
+       if (qcq->napi.poll)
+               napi_enable(&qcq->napi);
+
        if (qcq->flags & IONIC_QCQ_F_INTR) {
                irq_set_affinity_hint(qcq->intr.vector,
                                      &qcq->intr.affinity_mask);
-               napi_enable(&qcq->napi);
-               ionic_intr_clean(idev->intr_ctrl, qcq->intr.index);
                ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
                                IONIC_INTR_MASK_CLEAR);
        }
 
-       return ionic_adminq_post_wait(lif, &ctx);
+       return 0;
 }
 
 static int ionic_qcq_disable(struct ionic_lif *lif, struct ionic_qcq *qcq, int fw_err)
@@ -316,6 +333,7 @@ static int ionic_qcq_disable(struct ionic_lif *lif, struct ionic_qcq *qcq, int f
                synchronize_irq(qcq->intr.vector);
                irq_set_affinity_hint(qcq->intr.vector, NULL);
                napi_disable(&qcq->napi);
+               del_timer_sync(&qcq->napi_deadline);
        }
 
        /* If there was a previous fw communcation error, don't bother with
@@ -451,6 +469,7 @@ static void ionic_link_qcq_interrupts(struct ionic_qcq *src_qcq,
 
        n_qcq->intr.vector = src_qcq->intr.vector;
        n_qcq->intr.index = src_qcq->intr.index;
+       n_qcq->napi_qcq = src_qcq->napi_qcq;
 }
 
 static int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq)
@@ -564,13 +583,15 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type,
        }
 
        if (flags & IONIC_QCQ_F_NOTIFYQ) {
-               int q_size, cq_size;
+               int q_size;
 
-               /* q & cq need to be contiguous in case of notifyq */
+               /* q & cq need to be contiguous in NotifyQ, so alloc it all in q
+                * and don't alloc qc.  We leave new->qc_size and new->qc_base
+                * as 0 to be sure we don't try to free it later.
+                */
                q_size = ALIGN(num_descs * desc_size, PAGE_SIZE);
-               cq_size = ALIGN(num_descs * cq_desc_size, PAGE_SIZE);
-
-               new->q_size = PAGE_SIZE + q_size + cq_size;
+               new->q_size = PAGE_SIZE + q_size +
+                             ALIGN(num_descs * cq_desc_size, PAGE_SIZE);
                new->q_base = dma_alloc_coherent(dev, new->q_size,
                                                 &new->q_base_pa, GFP_KERNEL);
                if (!new->q_base) {
@@ -773,8 +794,14 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
        dev_dbg(dev, "txq->hw_type %d\n", q->hw_type);
        dev_dbg(dev, "txq->hw_index %d\n", q->hw_index);
 
-       if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
+       q->dbell_deadline = IONIC_TX_DOORBELL_DEADLINE;
+       q->dbell_jiffies = jiffies;
+
+       if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) {
                netif_napi_add(lif->netdev, &qcq->napi, ionic_tx_napi);
+               qcq->napi_qcq = qcq;
+               timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
+       }
 
        qcq->flags |= IONIC_QCQ_F_INITED;
 
@@ -828,11 +855,17 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
        dev_dbg(dev, "rxq->hw_type %d\n", q->hw_type);
        dev_dbg(dev, "rxq->hw_index %d\n", q->hw_index);
 
+       q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE;
+       q->dbell_jiffies = jiffies;
+
        if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state))
                netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi);
        else
                netif_napi_add(lif->netdev, &qcq->napi, ionic_txrx_napi);
 
+       qcq->napi_qcq = qcq;
+       timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
+
        qcq->flags |= IONIC_QCQ_F_INITED;
 
        return 0;
@@ -1150,6 +1183,7 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget)
        struct ionic_dev *idev = &lif->ionic->idev;
        unsigned long irqflags;
        unsigned int flags = 0;
+       bool resched = false;
        int rx_work = 0;
        int tx_work = 0;
        int n_work = 0;
@@ -1187,6 +1221,16 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget)
                ionic_intr_credits(idev->intr_ctrl, intr->index, credits, flags);
        }
 
+       if (!a_work && ionic_adminq_poke_doorbell(&lif->adminqcq->q))
+               resched = true;
+       if (lif->hwstamp_rxq && !rx_work && ionic_rxq_poke_doorbell(&lif->hwstamp_rxq->q))
+               resched = true;
+       if (lif->hwstamp_txq && !tx_work && ionic_txq_poke_doorbell(&lif->hwstamp_txq->q))
+               resched = true;
+       if (resched)
+               mod_timer(&lif->adminqcq->napi_deadline,
+                         jiffies + IONIC_NAPI_DEADLINE);
+
        return work_done;
 }
 
@@ -3245,8 +3289,14 @@ static int ionic_lif_adminq_init(struct ionic_lif *lif)
        dev_dbg(dev, "adminq->hw_type %d\n", q->hw_type);
        dev_dbg(dev, "adminq->hw_index %d\n", q->hw_index);
 
+       q->dbell_deadline = IONIC_ADMIN_DOORBELL_DEADLINE;
+       q->dbell_jiffies = jiffies;
+
        netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi);
 
+       qcq->napi_qcq = qcq;
+       timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0);
+
        napi_enable(&qcq->napi);
 
        if (qcq->flags & IONIC_QCQ_F_INTR)
index a53984b..7345198 100644 (file)
@@ -74,8 +74,10 @@ struct ionic_qcq {
        struct ionic_queue q;
        struct ionic_cq cq;
        struct ionic_intr_info intr;
+       struct timer_list napi_deadline;
        struct napi_struct napi;
        unsigned int flags;
+       struct ionic_qcq *napi_qcq;
        struct dentry *dentry;
 };
 
index a13530e..08c42b0 100644 (file)
@@ -289,6 +289,35 @@ static void ionic_adminq_cb(struct ionic_queue *q,
        complete_all(&ctx->work);
 }
 
+bool ionic_adminq_poke_doorbell(struct ionic_queue *q)
+{
+       struct ionic_lif *lif = q->lif;
+       unsigned long now, then, dif;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&lif->adminq_lock, irqflags);
+
+       if (q->tail_idx == q->head_idx) {
+               spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
+               return false;
+       }
+
+       now = READ_ONCE(jiffies);
+       then = q->dbell_jiffies;
+       dif = now - then;
+
+       if (dif > q->dbell_deadline) {
+               ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
+                                q->dbval | q->head_idx);
+
+               q->dbell_jiffies = now;
+       }
+
+       spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
+
+       return true;
+}
+
 int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
 {
        struct ionic_desc_info *desc_info;
index 0c39774..f761780 100644 (file)
@@ -22,6 +22,67 @@ static inline void ionic_rxq_post(struct ionic_queue *q, bool ring_dbell,
        ionic_q_post(q, ring_dbell, cb_func, cb_arg);
 }
 
+bool ionic_txq_poke_doorbell(struct ionic_queue *q)
+{
+       unsigned long now, then, dif;
+       struct netdev_queue *netdev_txq;
+       struct net_device *netdev;
+
+       netdev = q->lif->netdev;
+       netdev_txq = netdev_get_tx_queue(netdev, q->index);
+
+       HARD_TX_LOCK(netdev, netdev_txq, smp_processor_id());
+
+       if (q->tail_idx == q->head_idx) {
+               HARD_TX_UNLOCK(netdev, netdev_txq);
+               return false;
+       }
+
+       now = READ_ONCE(jiffies);
+       then = q->dbell_jiffies;
+       dif = now - then;
+
+       if (dif > q->dbell_deadline) {
+               ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
+                                q->dbval | q->head_idx);
+
+               q->dbell_jiffies = now;
+       }
+
+       HARD_TX_UNLOCK(netdev, netdev_txq);
+
+       return true;
+}
+
+bool ionic_rxq_poke_doorbell(struct ionic_queue *q)
+{
+       unsigned long now, then, dif;
+
+       /* no lock, called from rx napi or txrx napi, nothing else can fill */
+
+       if (q->tail_idx == q->head_idx)
+               return false;
+
+       now = READ_ONCE(jiffies);
+       then = q->dbell_jiffies;
+       dif = now - then;
+
+       if (dif > q->dbell_deadline) {
+               ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
+                                q->dbval | q->head_idx);
+
+               q->dbell_jiffies = now;
+
+               dif = 2 * q->dbell_deadline;
+               if (dif > IONIC_RX_MAX_DOORBELL_DEADLINE)
+                       dif = IONIC_RX_MAX_DOORBELL_DEADLINE;
+
+               q->dbell_deadline = dif;
+       }
+
+       return true;
+}
+
 static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q)
 {
        return netdev_get_tx_queue(q->lif->netdev, q->index);
@@ -424,6 +485,12 @@ void ionic_rx_fill(struct ionic_queue *q)
 
        ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type,
                         q->dbval | q->head_idx);
+
+       q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE;
+       q->dbell_jiffies = jiffies;
+
+       mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline,
+                 jiffies + IONIC_NAPI_DEADLINE);
 }
 
 void ionic_rx_empty(struct ionic_queue *q)
@@ -511,6 +578,9 @@ int ionic_tx_napi(struct napi_struct *napi, int budget)
                                   work_done, flags);
        }
 
+       if (!work_done && ionic_txq_poke_doorbell(&qcq->q))
+               mod_timer(&qcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE);
+
        return work_done;
 }
 
@@ -544,23 +614,29 @@ int ionic_rx_napi(struct napi_struct *napi, int budget)
                                   work_done, flags);
        }
 
+       if (!work_done && ionic_rxq_poke_doorbell(&qcq->q))
+               mod_timer(&qcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE);
+
        return work_done;
 }
 
 int ionic_txrx_napi(struct napi_struct *napi, int budget)
 {
-       struct ionic_qcq *qcq = napi_to_qcq(napi);
+       struct ionic_qcq *rxqcq = napi_to_qcq(napi);
        struct ionic_cq *rxcq = napi_to_cq(napi);
        unsigned int qi = rxcq->bound_q->index;
+       struct ionic_qcq *txqcq;
        struct ionic_dev *idev;
        struct ionic_lif *lif;
        struct ionic_cq *txcq;
+       bool resched = false;
        u32 rx_work_done = 0;
        u32 tx_work_done = 0;
        u32 flags = 0;
 
        lif = rxcq->bound_q->lif;
        idev = &lif->ionic->idev;
+       txqcq = lif->txqcqs[qi];
        txcq = &lif->txqcqs[qi]->cq;
 
        tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT,
@@ -572,7 +648,7 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
        ionic_rx_fill(rxcq->bound_q);
 
        if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) {
-               ionic_dim_update(qcq, 0);
+               ionic_dim_update(rxqcq, 0);
                flags |= IONIC_INTR_CRED_UNMASK;
                rxcq->bound_intr->rearm_count++;
        }
@@ -583,6 +659,13 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
                                   tx_work_done + rx_work_done, flags);
        }
 
+       if (!rx_work_done && ionic_rxq_poke_doorbell(&rxqcq->q))
+               resched = true;
+       if (!tx_work_done && ionic_txq_poke_doorbell(&txqcq->q))
+               resched = true;
+       if (resched)
+               mod_timer(&rxqcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE);
+
        return rx_work_done;
 }
 
index 7c2af48..cb1746b 100644 (file)
@@ -1438,6 +1438,10 @@ int qede_poll(struct napi_struct *napi, int budget)
        rx_work_done = (likely(fp->type & QEDE_FASTPATH_RX) &&
                        qede_has_rx_work(fp->rxq)) ?
                        qede_rx_int(fp, budget) : 0;
+
+       if (fp->xdp_xmit & QEDE_XDP_REDIRECT)
+               xdp_do_flush();
+
        /* Handle case where we are called by netpoll with a budget of 0 */
        if (rx_work_done < budget || !budget) {
                if (!qede_poll_is_more_work(fp)) {
@@ -1457,9 +1461,6 @@ int qede_poll(struct napi_struct *napi, int budget)
                qede_update_tx_producer(fp->xdp_tx);
        }
 
-       if (fp->xdp_xmit & QEDE_XDP_REDIRECT)
-               xdp_do_flush_map();
-
        return rx_work_done;
 }
 
index 24592d9..dadd61b 100644 (file)
@@ -1996,10 +1996,7 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii)
 
                /* 8168F family. */
                { 0x7c8, 0x488, RTL_GIGA_MAC_VER_38 },
-               /* It seems this chip version never made it to
-                * the wild. Let's disable detection.
-                * { 0x7cf, 0x481,      RTL_GIGA_MAC_VER_36 },
-                */
+               { 0x7cf, 0x481, RTL_GIGA_MAC_VER_36 },
                { 0x7cf, 0x480, RTL_GIGA_MAC_VER_35 },
 
                /* 8168E family. */
index b4e0fc7..0f54849 100644 (file)
@@ -1101,14 +1101,14 @@ static void ravb_error_interrupt(struct net_device *ndev)
        ravb_write(ndev, ~(EIS_QFS | EIS_RESERVED), EIS);
        if (eis & EIS_QFS) {
                ris2 = ravb_read(ndev, RIS2);
-               ravb_write(ndev, ~(RIS2_QFF0 | RIS2_RFFF | RIS2_RESERVED),
+               ravb_write(ndev, ~(RIS2_QFF0 | RIS2_QFF1 | RIS2_RFFF | RIS2_RESERVED),
                           RIS2);
 
                /* Receive Descriptor Empty int */
                if (ris2 & RIS2_QFF0)
                        priv->stats[RAVB_BE].rx_over_errors++;
 
-                   /* Receive Descriptor Empty int */
+               /* Receive Descriptor Empty int */
                if (ris2 & RIS2_QFF1)
                        priv->stats[RAVB_NC].rx_over_errors++;
 
@@ -2973,6 +2973,9 @@ static int __maybe_unused ravb_suspend(struct device *dev)
        else
                ret = ravb_close(ndev);
 
+       if (priv->info->ccc_gac)
+               ravb_ptp_stop(ndev);
+
        return ret;
 }
 
@@ -3011,6 +3014,9 @@ static int __maybe_unused ravb_resume(struct device *dev)
        /* Restore descriptor base address table */
        ravb_write(ndev, priv->desc_bat_dma, DBAT);
 
+       if (priv->info->ccc_gac)
+               ravb_ptp_init(ndev, priv->pdev);
+
        if (netif_running(ndev)) {
                if (priv->wol_enabled) {
                        ret = ravb_wol_restore(ndev);
index 6441892..2370c77 100644 (file)
@@ -1074,8 +1074,11 @@ static struct device_node *rswitch_get_port_node(struct rswitch_device *rdev)
                        port = NULL;
                        goto out;
                }
-               if (index == rdev->etha->index)
+               if (index == rdev->etha->index) {
+                       if (!of_device_is_available(port))
+                               port = NULL;
                        break;
+               }
        }
 
 out:
@@ -1106,7 +1109,7 @@ static int rswitch_etha_get_params(struct rswitch_device *rdev)
 
        port = rswitch_get_port_node(rdev);
        if (!port)
-               return -ENODEV;
+               return 0;       /* ignored */
 
        err = of_get_phy_mode(port, &rdev->etha->phy_interface);
        of_node_put(port);
@@ -1324,13 +1327,13 @@ static int rswitch_ether_port_init_all(struct rswitch_private *priv)
 {
        int i, err;
 
-       for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
+       rswitch_for_each_enabled_port(priv, i) {
                err = rswitch_ether_port_init_one(priv->rdev[i]);
                if (err)
                        goto err_init_one;
        }
 
-       for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
+       rswitch_for_each_enabled_port(priv, i) {
                err = rswitch_serdes_init(priv->rdev[i]);
                if (err)
                        goto err_serdes;
@@ -1339,12 +1342,12 @@ static int rswitch_ether_port_init_all(struct rswitch_private *priv)
        return 0;
 
 err_serdes:
-       for (i--; i >= 0; i--)
+       rswitch_for_each_enabled_port_continue_reverse(priv, i)
                rswitch_serdes_deinit(priv->rdev[i]);
        i = RSWITCH_NUM_PORTS;
 
 err_init_one:
-       for (i--; i >= 0; i--)
+       rswitch_for_each_enabled_port_continue_reverse(priv, i)
                rswitch_ether_port_deinit_one(priv->rdev[i]);
 
        return err;
@@ -1608,6 +1611,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, int index)
        netif_napi_add(ndev, &rdev->napi, rswitch_poll);
 
        port = rswitch_get_port_node(rdev);
+       rdev->disabled = !port;
        err = of_get_ethdev_address(port, ndev);
        of_node_put(port);
        if (err) {
@@ -1707,16 +1711,16 @@ static int rswitch_init(struct rswitch_private *priv)
        if (err)
                goto err_ether_port_init_all;
 
-       for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
+       rswitch_for_each_enabled_port(priv, i) {
                err = register_netdev(priv->rdev[i]->ndev);
                if (err) {
-                       for (i--; i >= 0; i--)
+                       rswitch_for_each_enabled_port_continue_reverse(priv, i)
                                unregister_netdev(priv->rdev[i]->ndev);
                        goto err_register_netdev;
                }
        }
 
-       for (i = 0; i < RSWITCH_NUM_PORTS; i++)
+       rswitch_for_each_enabled_port(priv, i)
                netdev_info(priv->rdev[i]->ndev, "MAC address %pM\n",
                            priv->rdev[i]->ndev->dev_addr);
 
index edbdd1b..49efb0f 100644 (file)
 #define RSWITCH_MAX_NUM_QUEUES 128
 
 #define RSWITCH_NUM_PORTS      3
+#define rswitch_for_each_enabled_port(priv, i)         \
+       for (i = 0; i < RSWITCH_NUM_PORTS; i++)         \
+               if (priv->rdev[i]->disabled)            \
+                       continue;                       \
+               else
+
+#define rswitch_for_each_enabled_port_continue_reverse(priv, i)        \
+       for (i--; i >= 0; i--)                                  \
+               if (priv->rdev[i]->disabled)                    \
+                       continue;                               \
+               else
 
 #define TX_RING_SIZE           1024
 #define RX_RING_SIZE           1024
@@ -938,6 +949,7 @@ struct rswitch_device {
        struct rswitch_gwca_queue *tx_queue;
        struct rswitch_gwca_queue *rx_queue;
        u8 ts_tag;
+       bool disabled;
 
        int port;
        struct rswitch_etha *etha;
index 0556542..3a86f12 100644 (file)
@@ -1003,8 +1003,11 @@ static int efx_pci_probe_post_io(struct efx_nic *efx)
        /* Determine netdevice features */
        net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
                              NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL);
-       if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
+       if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) {
                net_dev->features |= NETIF_F_TSO6;
+               if (efx_has_cap(efx, TX_TSO_V2_ENCAP))
+                       net_dev->hw_enc_features |= NETIF_F_TSO6;
+       }
        /* Check whether device supports TSO */
        if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
                net_dev->features &= ~NETIF_F_ALL_TSO;
index d42e1af..2f7d8e4 100644 (file)
@@ -90,7 +90,6 @@ struct mediatek_dwmac_plat_data {
 struct mediatek_dwmac_variant {
        int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat);
        int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat);
-       void (*dwmac_fix_mac_speed)(void *priv, unsigned int speed);
 
        /* clock ids to be requested */
        const char * const *clk_list;
@@ -443,32 +442,9 @@ static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat)
        return 0;
 }
 
-static void mt8195_fix_mac_speed(void *priv, unsigned int speed)
-{
-       struct mediatek_dwmac_plat_data *priv_plat = priv;
-
-       if ((phy_interface_mode_is_rgmii(priv_plat->phy_mode))) {
-               /* prefer 2ns fixed delay which is controlled by TXC_PHASE_CTRL,
-                * when link speed is 1Gbps with RGMII interface,
-                * Fall back to delay macro circuit for 10/100Mbps link speed.
-                */
-               if (speed == SPEED_1000)
-                       regmap_update_bits(priv_plat->peri_regmap,
-                                          MT8195_PERI_ETH_CTRL0,
-                                          MT8195_RGMII_TXC_PHASE_CTRL |
-                                          MT8195_DLY_GTXC_ENABLE |
-                                          MT8195_DLY_GTXC_INV |
-                                          MT8195_DLY_GTXC_STAGES,
-                                          MT8195_RGMII_TXC_PHASE_CTRL);
-               else
-                       mt8195_set_delay(priv_plat);
-       }
-}
-
 static const struct mediatek_dwmac_variant mt8195_gmac_variant = {
        .dwmac_set_phy_interface = mt8195_set_interface,
        .dwmac_set_delay = mt8195_set_delay,
-       .dwmac_fix_mac_speed = mt8195_fix_mac_speed,
        .clk_list = mt8195_dwmac_clk_l,
        .num_clks = ARRAY_SIZE(mt8195_dwmac_clk_l),
        .dma_bit_mask = 35,
@@ -619,8 +595,6 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev,
        plat->bsp_priv = priv_plat;
        plat->init = mediatek_dwmac_init;
        plat->clks_config = mediatek_dwmac_clks_config;
-       if (priv_plat->variant->dwmac_fix_mac_speed)
-               plat->fix_mac_speed = priv_plat->variant->dwmac_fix_mac_speed;
 
        plat->safety_feat_cfg = devm_kzalloc(&pdev->dev,
                                             sizeof(*plat->safety_feat_cfg),
index 835caa1..7327746 100644 (file)
@@ -560,6 +560,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
        plat_dat->has_gmac4 = 1;
        plat_dat->pmt = 1;
        plat_dat->tso_en = of_property_read_bool(np, "snps,tso");
+       if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
+               plat_dat->rx_clk_runs_in_lpi = 1;
 
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret)
index 9c2d40f..413f660 100644 (file)
@@ -186,11 +186,25 @@ static void dwmac5_handle_dma_err(struct net_device *ndev,
 int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
                              struct stmmac_safety_feature_cfg *safety_feat_cfg)
 {
+       struct stmmac_safety_feature_cfg all_safety_feats = {
+               .tsoee = 1,
+               .mrxpee = 1,
+               .mestee = 1,
+               .mrxee = 1,
+               .mtxee = 1,
+               .epsi = 1,
+               .edpp = 1,
+               .prtyen = 1,
+               .tmouten = 1,
+       };
        u32 value;
 
        if (!asp)
                return -EINVAL;
 
+       if (!safety_feat_cfg)
+               safety_feat_cfg = &all_safety_feats;
+
        /* 1. Enable Safety Features */
        value = readl(ioaddr + MTL_ECC_CONTROL);
        value |= MEEAO; /* MTL ECC Error Addr Status Override */
index f453b0d..35c8dd9 100644 (file)
@@ -551,16 +551,16 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
                p = (char *)priv + offsetof(struct stmmac_priv,
                                            xstats.txq_stats[q].tx_pkt_n);
                for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
-                       *data++ = (*(u64 *)p);
-                       p += sizeof(u64 *);
+                       *data++ = (*(unsigned long *)p);
+                       p += sizeof(unsigned long);
                }
        }
        for (q = 0; q < rx_cnt; q++) {
                p = (char *)priv + offsetof(struct stmmac_priv,
                                            xstats.rxq_stats[q].rx_pkt_n);
                for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
-                       *data++ = (*(u64 *)p);
-                       p += sizeof(u64 *);
+                       *data++ = (*(unsigned long *)p);
+                       p += sizeof(unsigned long);
                }
        }
 }
index c6951c9..1a5b8da 100644 (file)
@@ -1080,7 +1080,8 @@ static void stmmac_mac_link_up(struct phylink_config *config,
 
        stmmac_mac_set(priv, priv->ioaddr, true);
        if (phy && priv->dma_cap.eee) {
-               priv->eee_active = phy_init_eee(phy, 1) >= 0;
+               priv->eee_active =
+                       phy_init_eee(phy, !priv->plat->rx_clk_runs_in_lpi) >= 0;
                priv->eee_enabled = stmmac_eee_init(priv);
                priv->tx_lpi_enabled = priv->eee_enabled;
                stmmac_set_eee_pls(priv, priv->hw, true);
@@ -1150,6 +1151,11 @@ static int stmmac_init_phy(struct net_device *dev)
                int addr = priv->plat->phy_addr;
                struct phy_device *phydev;
 
+               if (addr < 0) {
+                       netdev_err(priv->dev, "no phy found\n");
+                       return -ENODEV;
+               }
+
                phydev = mdiobus_get_phy(priv->mii, addr);
                if (!phydev) {
                        netdev_err(priv->dev, "no phy at addr %d\n", addr);
index fc06dde..b4388ca 100644 (file)
@@ -210,7 +210,10 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
                }
                writel(acr_value, ptpaddr + PTP_ACR);
                mutex_unlock(&priv->aux_ts_lock);
-               ret = 0;
+               /* wait for auxts fifo clear to finish */
+               ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
+                                        !(acr_value & PTP_ACR_ATSFC),
+                                        10, 10000);
                break;
 
        default:
index 9352dad..79f4e13 100644 (file)
@@ -987,9 +987,6 @@ static void netvsc_copy_to_send_buf(struct netvsc_device *net_device,
 void netvsc_dma_unmap(struct hv_device *hv_dev,
                      struct hv_netvsc_packet *packet)
 {
-       u32 page_count = packet->cp_partial ?
-               packet->page_buf_cnt - packet->rmsg_pgcnt :
-               packet->page_buf_cnt;
        int i;
 
        if (!hv_is_isolation_supported())
@@ -998,7 +995,7 @@ void netvsc_dma_unmap(struct hv_device *hv_dev,
        if (!packet->dma_range)
                return;
 
-       for (i = 0; i < page_count; i++)
+       for (i = 0; i < packet->page_buf_cnt; i++)
                dma_unmap_single(&hv_dev->device, packet->dma_range[i].dma,
                                 packet->dma_range[i].mapping_size,
                                 DMA_TO_DEVICE);
@@ -1028,9 +1025,7 @@ static int netvsc_dma_map(struct hv_device *hv_dev,
                          struct hv_netvsc_packet *packet,
                          struct hv_page_buffer *pb)
 {
-       u32 page_count =  packet->cp_partial ?
-               packet->page_buf_cnt - packet->rmsg_pgcnt :
-               packet->page_buf_cnt;
+       u32 page_count = packet->page_buf_cnt;
        dma_addr_t dma;
        int i;
 
@@ -1039,7 +1034,7 @@ static int netvsc_dma_map(struct hv_device *hv_dev,
 
        packet->dma_range = kcalloc(page_count,
                                    sizeof(*packet->dma_range),
-                                   GFP_KERNEL);
+                                   GFP_ATOMIC);
        if (!packet->dma_range)
                return -ENOMEM;
 
index 7552c40..b83390c 100644 (file)
@@ -357,7 +357,7 @@ static const struct ipa_mem ipa_mem_local_data[] = {
 static const struct ipa_mem_data ipa_mem_data = {
        .local_count    = ARRAY_SIZE(ipa_mem_local_data),
        .local          = ipa_mem_local_data,
-       .imem_addr      = 0x146a9000,
+       .imem_addr      = 0x146a8000,
        .imem_size      = 0x00002000,
        .smem_id        = 497,
        .smem_size      = 0x00009000,
index d458a35..c1b3977 100644 (file)
@@ -127,6 +127,16 @@ out_power_put:
        return IRQ_HANDLED;
 }
 
+void ipa_interrupt_irq_disable(struct ipa *ipa)
+{
+       disable_irq(ipa->interrupt->irq);
+}
+
+void ipa_interrupt_irq_enable(struct ipa *ipa)
+{
+       enable_irq(ipa->interrupt->irq);
+}
+
 /* Common function used to enable/disable TX_SUSPEND for an endpoint */
 static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
                                          u32 endpoint_id, bool enable)
index f31fd99..8a1bd5b 100644 (file)
@@ -85,6 +85,22 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt);
  */
 void ipa_interrupt_simulate_suspend(struct ipa_interrupt *interrupt);
 
+/**
+ * ipa_interrupt_irq_enable() - Enable IPA interrupts
+ * @ipa:       IPA pointer
+ *
+ * This enables the IPA interrupt line
+ */
+void ipa_interrupt_irq_enable(struct ipa *ipa);
+
+/**
+ * ipa_interrupt_irq_disable() - Disable IPA interrupts
+ * @ipa:       IPA pointer
+ *
+ * This disables the IPA interrupt line
+ */
+void ipa_interrupt_irq_disable(struct ipa *ipa);
+
 /**
  * ipa_interrupt_config() - Configure the IPA interrupt framework
  * @ipa:       IPA pointer
index 8420f93..8057be8 100644 (file)
@@ -181,6 +181,17 @@ static int ipa_suspend(struct device *dev)
 
        __set_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags);
 
+       /* Increment the disable depth to ensure that the IRQ won't
+        * be re-enabled until the matching _enable call in
+        * ipa_resume(). We do this to ensure that the interrupt
+        * handler won't run whilst PM runtime is disabled.
+        *
+        * Note that disabling the IRQ is NOT the same as disabling
+        * irq wake. If wakeup is enabled for the IPA then the IRQ
+        * will still cause the system to wake up, see irq_set_irq_wake().
+        */
+       ipa_interrupt_irq_disable(ipa);
+
        return pm_runtime_force_suspend(dev);
 }
 
@@ -193,6 +204,12 @@ static int ipa_resume(struct device *dev)
 
        __clear_bit(IPA_POWER_FLAG_SYSTEM, ipa->power->flags);
 
+       /* Now that PM runtime is enabled again it's safe
+        * to turn the IRQ back on and process any data
+        * that was received during suspend.
+        */
+       ipa_interrupt_irq_enable(ipa);
+
        return ret;
 }
 
index 4a2e94f..c4542ec 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/device.h>
@@ -150,6 +151,7 @@ static const struct clk_ops g12a_ephy_pll_ops = {
 
 static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
 {
+       u32 value;
        int ret;
 
        /* Enable the phy clock */
@@ -163,18 +165,25 @@ static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
 
        /* Initialize ephy control */
        writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0);
-       writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
-              FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
-              FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
-              PHY_CNTL1_CLK_EN |
-              PHY_CNTL1_CLKFREQ |
-              PHY_CNTL1_PHY_ENB,
-              priv->regs + ETH_PHY_CNTL1);
+
+       /* Make sure we get a 0 -> 1 transition on the enable bit */
+       value = FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
+               FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
+               FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
+               PHY_CNTL1_CLK_EN |
+               PHY_CNTL1_CLKFREQ;
+       writel(value, priv->regs + ETH_PHY_CNTL1);
        writel(PHY_CNTL2_USE_INTERNAL |
               PHY_CNTL2_SMI_SRC_MAC |
               PHY_CNTL2_RX_CLK_EPHY,
               priv->regs + ETH_PHY_CNTL2);
 
+       value |= PHY_CNTL1_PHY_ENB;
+       writel(value, priv->regs + ETH_PHY_CNTL1);
+
+       /* The phy needs a bit of time to power up */
+       mdelay(10);
+
        return 0;
 }
 
index a6f05e3..b7cb718 100644 (file)
@@ -233,7 +233,8 @@ static int dp83822_config_intr(struct phy_device *phydev)
                                DP83822_ENERGY_DET_INT_EN |
                                DP83822_LINK_QUAL_INT_EN);
 
-               if (!dp83822->fx_enabled)
+               /* Private data pointer is NULL on DP83825/26 */
+               if (!dp83822 || !dp83822->fx_enabled)
                        misr_status |= DP83822_ANEG_COMPLETE_INT_EN |
                                       DP83822_DUP_MODE_CHANGE_INT_EN |
                                       DP83822_SPEED_CHANGED_INT_EN;
@@ -253,7 +254,8 @@ static int dp83822_config_intr(struct phy_device *phydev)
                                DP83822_PAGE_RX_INT_EN |
                                DP83822_EEE_ERROR_CHANGE_INT_EN);
 
-               if (!dp83822->fx_enabled)
+               /* Private data pointer is NULL on DP83825/26 */
+               if (!dp83822 || !dp83822->fx_enabled)
                        misr_status |= DP83822_ANEG_ERR_INT_EN |
                                       DP83822_WOL_PKT_INT_EN;
 
index 1cd604c..16e021b 100644 (file)
@@ -108,7 +108,12 @@ EXPORT_SYMBOL(mdiobus_unregister_device);
 
 struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
 {
-       struct mdio_device *mdiodev = bus->mdio_map[addr];
+       struct mdio_device *mdiodev;
+
+       if (addr < 0 || addr >= ARRAY_SIZE(bus->mdio_map))
+               return NULL;
+
+       mdiodev = bus->mdio_map[addr];
 
        if (!mdiodev)
                return NULL;
index c49062a..a6015cd 100644 (file)
@@ -261,6 +261,8 @@ static struct phy_driver meson_gxl_phy[] = {
                .handle_interrupt = meson_gxl_handle_interrupt,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
+               .read_mmd       = genphy_read_mmd_unsupported,
+               .write_mmd      = genphy_write_mmd_unsupported,
        }, {
                PHY_ID_MATCH_EXACT(0x01803301),
                .name           = "Meson G12A Internal PHY",
@@ -271,6 +273,8 @@ static struct phy_driver meson_gxl_phy[] = {
                .handle_interrupt = meson_gxl_handle_interrupt,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
+               .read_mmd       = genphy_read_mmd_unsupported,
+               .write_mmd      = genphy_write_mmd_unsupported,
        },
 };
 
index 716870a..607aa78 100644 (file)
@@ -1517,7 +1517,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
         * another mac interface, so we should create a device link between
         * phy dev and mac dev.
         */
-       if (phydev->mdio.bus->parent && dev->dev.parent != phydev->mdio.bus->parent)
+       if (dev && phydev->mdio.bus->parent && dev->dev.parent != phydev->mdio.bus->parent)
                phydev->devlink = device_link_add(dev->dev.parent, &phydev->mdio.dev,
                                                  DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
 
index 09cc65c..4d2519c 100644 (file)
@@ -1812,10 +1812,9 @@ int phylink_fwnode_phy_connect(struct phylink *pl,
 
        ret = phy_attach_direct(pl->netdev, phy_dev, flags,
                                pl->link_interface);
-       if (ret) {
-               phy_device_free(phy_dev);
+       phy_device_free(phy_dev);
+       if (ret)
                return ret;
-       }
 
        ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
        if (ret)
index fcd43d6..d10606f 100644 (file)
@@ -1044,7 +1044,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
                        goto err_port_enter;
                }
        }
-       port->dev->priv_flags |= IFF_NO_ADDRCONF;
 
        return 0;
 
@@ -1058,7 +1057,6 @@ static void team_port_leave(struct team *team, struct team_port *port)
 {
        if (team->ops.port_leave)
                team->ops.port_leave(team, port);
-       port->dev->priv_flags &= ~IFF_NO_ADDRCONF;
        dev_put(team->dev);
 }
 
index 8911cd2..c140edb 100644 (file)
@@ -1007,6 +1007,12 @@ static const struct usb_device_id        products[] = {
                                      USB_CDC_SUBCLASS_ETHERNET,
                                      USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
+}, {
+       /* Cinterion PLS62-W modem by GEMALTO/THALES */
+       USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x005b, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long)&wwan_info,
 }, {
        /* Cinterion PLS83/PLS63 modem by GEMALTO/THALES */
        USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0069, USB_CLASS_COMM,
index 2c82fbc..7a2b009 100644 (file)
@@ -57,9 +57,7 @@
 static inline int
 pl_vendor_req(struct usbnet *dev, u8 req, u8 val, u8 index)
 {
-       return usbnet_read_cmd(dev, req,
-                               USB_DIR_IN | USB_TYPE_VENDOR |
-                               USB_RECIP_DEVICE,
+       return usbnet_write_cmd(dev, req, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                val, index, NULL, 0);
 }
 
index a481a1d..23da1d9 100644 (file)
@@ -9836,6 +9836,7 @@ static const struct usb_device_id rtl8152_table[] = {
        REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab),
        REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6),
        REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927),
+       REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0c5e),
        REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101),
        REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x304f),
        REALTEK_USB_DEVICE(VENDOR_ID_LENOVO,  0x3054),
index 5a53e63..3164451 100644 (file)
@@ -413,7 +413,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                /* ignore the CRC length */
                len = (skb->data[1] | (skb->data[2] << 8)) - 4;
 
-               if (len > ETH_FRAME_LEN || len > skb->len)
+               if (len > ETH_FRAME_LEN || len > skb->len || len < 0)
                        return 0;
 
                /* the last packet of current skb */
index 7723b2a..61e33e4 100644 (file)
@@ -1677,13 +1677,13 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
 
        received = virtnet_receive(rq, budget, &xdp_xmit);
 
+       if (xdp_xmit & VIRTIO_XDP_REDIR)
+               xdp_do_flush();
+
        /* Out of packets? */
        if (received < budget)
                virtqueue_napi_complete(napi, rq->vq, received);
 
-       if (xdp_xmit & VIRTIO_XDP_REDIR)
-               xdp_do_flush();
-
        if (xdp_xmit & VIRTIO_XDP_TX) {
                sq = virtnet_xdp_get_sq(vi);
                if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
@@ -1877,8 +1877,10 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        if (sq->vq->num_free < 2+MAX_SKB_FRAGS) {
                netif_stop_subqueue(dev, qnum);
-               if (!use_napi &&
-                   unlikely(!virtqueue_enable_cb_delayed(sq->vq))) {
+               if (use_napi) {
+                       if (unlikely(!virtqueue_enable_cb_delayed(sq->vq)))
+                               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);
                        if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) {
@@ -2156,8 +2158,8 @@ static int virtnet_close(struct net_device *dev)
        cancel_delayed_work_sync(&vi->refill);
 
        for (i = 0; i < vi->max_queue_pairs; i++) {
-               xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq);
                napi_disable(&vi->rq[i].napi);
+               xdp_rxq_info_unreg(&vi->rq[i].xdp_rxq);
                virtnet_napi_tx_disable(&vi->sq[i].napi);
        }
 
index 22edea6..1c53b55 100644 (file)
@@ -1243,9 +1243,11 @@ static int ucc_hdlc_probe(struct platform_device *pdev)
 free_dev:
        free_netdev(dev);
 undo_uhdlc_init:
-       iounmap(utdm->siram);
+       if (utdm)
+               iounmap(utdm->siram);
 unmap_si_regs:
-       iounmap(utdm->si_regs);
+       if (utdm)
+               iounmap(utdm->si_regs);
 free_utdm:
        if (uhdlc_priv->tsa)
                kfree(utdm);
index bff3128..b115902 100644 (file)
@@ -7937,6 +7937,9 @@ cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
 
+       if (chan->flags & IEEE80211_CHAN_DISABLED)
+               return -EINVAL;
+
        /* set_channel */
        chspec = channel_to_chanspec(&cfg->d11inf, chan);
        if (chspec != INVCHANSPEC) {
@@ -7961,7 +7964,7 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct brcmf_dump_survey survey = {};
        struct ieee80211_supported_band *band;
-       struct ieee80211_channel *chan;
+       enum nl80211_band band_id;
        struct cca_msrmnt_query req;
        u32 noise;
        int err;
@@ -7974,26 +7977,25 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
                return -EBUSY;
        }
 
-       band = wiphy->bands[NL80211_BAND_2GHZ];
-       if (band && idx >= band->n_channels) {
-               idx -= band->n_channels;
-               band = NULL;
-       }
+       for (band_id = 0; band_id < NUM_NL80211_BANDS; band_id++) {
+               band = wiphy->bands[band_id];
+               if (!band)
+                       continue;
+               if (idx >= band->n_channels) {
+                       idx -= band->n_channels;
+                       continue;
+               }
 
-       if (!band || idx >= band->n_channels) {
-               band = wiphy->bands[NL80211_BAND_5GHZ];
-               if (idx >= band->n_channels)
-                       return -ENOENT;
+               info->channel = &band->channels[idx];
+               break;
        }
+       if (band_id == NUM_NL80211_BANDS)
+               return -ENOENT;
 
        /* Setting current channel to the requested channel */
-       chan = &band->channels[idx];
-       err = cfg80211_set_channel(wiphy, ndev, chan, NL80211_CHAN_HT20);
-       if (err) {
-               info->channel = chan;
-               info->filled = 0;
+       info->filled = 0;
+       if (cfg80211_set_channel(wiphy, ndev, info->channel, NL80211_CHAN_HT20))
                return 0;
-       }
 
        /* Disable mpc */
        brcmf_set_mpc(ifp, 0);
@@ -8028,7 +8030,6 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
        if (err)
                goto exit;
 
-       info->channel = chan;
        info->noise = noise;
        info->time = ACS_MSRMNT_DELAY;
        info->time_busy = ACS_MSRMNT_DELAY - survey.idle;
@@ -8040,7 +8041,7 @@ brcmf_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
                SURVEY_INFO_TIME_TX;
 
        brcmf_dbg(INFO, "OBSS dump: channel %d: survey duration %d\n",
-                 ieee80211_frequency_to_channel(chan->center_freq),
+                 ieee80211_frequency_to_channel(info->channel->center_freq),
                  ACS_MSRMNT_DELAY);
        brcmf_dbg(INFO, "noise(%d) busy(%llu) rx(%llu) tx(%llu)\n",
                  info->noise, info->time_busy, info->time_rx, info->time_tx);
index a83699d..fdd0c9a 100644 (file)
@@ -79,7 +79,8 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
        /* Apple ARM64 platforms have their own idea of board type, passed in
         * via the device tree. They also have an antenna SKU parameter
         */
-       if (!of_property_read_string(np, "brcm,board-type", &prop))
+       err = of_property_read_string(np, "brcm,board-type", &prop);
+       if (!err)
                settings->board_type = prop;
 
        if (!of_property_read_string(np, "apple,antenna-sku", &prop))
@@ -87,7 +88,7 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
 
        /* Set board-type to the first string of the machine compatible prop */
        root = of_find_node_by_path("/");
-       if (root && !settings->board_type) {
+       if (root && err) {
                char *board_type;
                const char *tmp;
 
index ae57a9a..b67f6d0 100644 (file)
@@ -1228,7 +1228,7 @@ static int brcmf_pcie_init_ringbuffers(struct brcmf_pciedev_info *devinfo)
                                BRCMF_NROF_H2D_COMMON_MSGRINGS;
                max_completionrings = BRCMF_NROF_D2H_COMMON_MSGRINGS;
        }
-       if (max_flowrings > 256) {
+       if (max_flowrings > 512) {
                brcmf_err(bus, "invalid max_flowrings(%d)\n", max_flowrings);
                return -EIO;
        }
index f795548..0616181 100644 (file)
@@ -205,6 +205,52 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
        mt76_dma_sync_idx(dev, q);
 }
 
+static int
+mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
+                   struct mt76_queue_buf *buf, void *data)
+{
+       struct mt76_desc *desc = &q->desc[q->head];
+       struct mt76_queue_entry *entry = &q->entry[q->head];
+       struct mt76_txwi_cache *txwi = NULL;
+       u32 buf1 = 0, ctrl;
+       int idx = q->head;
+       int rx_token;
+
+       ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+
+       if ((q->flags & MT_QFLAG_WED) &&
+           FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
+               txwi = mt76_get_rxwi(dev);
+               if (!txwi)
+                       return -ENOMEM;
+
+               rx_token = mt76_rx_token_consume(dev, data, txwi, buf->addr);
+               if (rx_token < 0) {
+                       mt76_put_rxwi(dev, txwi);
+                       return -ENOMEM;
+               }
+
+               buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);
+               ctrl |= MT_DMA_CTL_TO_HOST;
+       }
+
+       WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr));
+       WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
+       WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
+       WRITE_ONCE(desc->info, 0);
+
+       entry->dma_addr[0] = buf->addr;
+       entry->dma_len[0] = buf->len;
+       entry->txwi = txwi;
+       entry->buf = data;
+       entry->wcid = 0xffff;
+       entry->skip_buf1 = true;
+       q->head = (q->head + 1) % q->ndesc;
+       q->queued++;
+
+       return idx;
+}
+
 static int
 mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
                 struct mt76_queue_buf *buf, int nbufs, u32 info,
@@ -212,65 +258,51 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
 {
        struct mt76_queue_entry *entry;
        struct mt76_desc *desc;
-       u32 ctrl;
        int i, idx = -1;
+       u32 ctrl, next;
+
+       if (txwi) {
+               q->entry[q->head].txwi = DMA_DUMMY_DATA;
+               q->entry[q->head].skip_buf0 = true;
+       }
 
        for (i = 0; i < nbufs; i += 2, buf += 2) {
                u32 buf0 = buf[0].addr, buf1 = 0;
 
                idx = q->head;
-               q->head = (q->head + 1) % q->ndesc;
+               next = (q->head + 1) % q->ndesc;
 
                desc = &q->desc[idx];
                entry = &q->entry[idx];
 
-               if ((q->flags & MT_QFLAG_WED) &&
-                   FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
-                       struct mt76_txwi_cache *t = txwi;
-                       int rx_token;
-
-                       if (!t)
-                               return -ENOMEM;
-
-                       rx_token = mt76_rx_token_consume(dev, (void *)skb, t,
-                                                        buf[0].addr);
-                       buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);
-                       ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len) |
-                              MT_DMA_CTL_TO_HOST;
-               } else {
-                       if (txwi) {
-                               q->entry[q->head].txwi = DMA_DUMMY_DATA;
-                               q->entry[q->head].skip_buf0 = true;
-                       }
-
-                       if (buf[0].skip_unmap)
-                               entry->skip_buf0 = true;
-                       entry->skip_buf1 = i == nbufs - 1;
-
-                       entry->dma_addr[0] = buf[0].addr;
-                       entry->dma_len[0] = buf[0].len;
-
-                       ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
-                       if (i < nbufs - 1) {
-                               entry->dma_addr[1] = buf[1].addr;
-                               entry->dma_len[1] = buf[1].len;
-                               buf1 = buf[1].addr;
-                               ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
-                               if (buf[1].skip_unmap)
-                                       entry->skip_buf1 = true;
-                       }
-
-                       if (i == nbufs - 1)
-                               ctrl |= MT_DMA_CTL_LAST_SEC0;
-                       else if (i == nbufs - 2)
-                               ctrl |= MT_DMA_CTL_LAST_SEC1;
+               if (buf[0].skip_unmap)
+                       entry->skip_buf0 = true;
+               entry->skip_buf1 = i == nbufs - 1;
+
+               entry->dma_addr[0] = buf[0].addr;
+               entry->dma_len[0] = buf[0].len;
+
+               ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+               if (i < nbufs - 1) {
+                       entry->dma_addr[1] = buf[1].addr;
+                       entry->dma_len[1] = buf[1].len;
+                       buf1 = buf[1].addr;
+                       ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
+                       if (buf[1].skip_unmap)
+                               entry->skip_buf1 = true;
                }
 
+               if (i == nbufs - 1)
+                       ctrl |= MT_DMA_CTL_LAST_SEC0;
+               else if (i == nbufs - 2)
+                       ctrl |= MT_DMA_CTL_LAST_SEC1;
+
                WRITE_ONCE(desc->buf0, cpu_to_le32(buf0));
                WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
                WRITE_ONCE(desc->info, cpu_to_le32(info));
                WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
 
+               q->head = next;
                q->queued++;
        }
 
@@ -577,17 +609,9 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
        spin_lock_bh(&q->lock);
 
        while (q->queued < q->ndesc - 1) {
-               struct mt76_txwi_cache *t = NULL;
                struct mt76_queue_buf qbuf;
                void *buf = NULL;
 
-               if ((q->flags & MT_QFLAG_WED) &&
-                   FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
-                       t = mt76_get_rxwi(dev);
-                       if (!t)
-                               break;
-               }
-
                buf = page_frag_alloc(rx_page, q->buf_size, GFP_ATOMIC);
                if (!buf)
                        break;
@@ -601,7 +625,12 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
                qbuf.addr = addr + offset;
                qbuf.len = len - offset;
                qbuf.skip_unmap = false;
-               mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t);
+               if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {
+                       dma_unmap_single(dev->dma_dev, addr, len,
+                                        DMA_FROM_DEVICE);
+                       skb_free_frag(buf);
+                       break;
+               }
                frames++;
        }
 
index 0a95c3d..8388e2a 100644 (file)
@@ -653,6 +653,13 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
 
                desc->buf0 = cpu_to_le32(phy_addr);
                token = mt76_rx_token_consume(&dev->mt76, ptr, t, phy_addr);
+               if (token < 0) {
+                       dma_unmap_single(dev->mt76.dma_dev, phy_addr,
+                                        wed->wlan.rx_size, DMA_TO_DEVICE);
+                       skb_free_frag(ptr);
+                       goto unmap;
+               }
+
                desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN,
                                                      token));
                desc++;
index 24568b9..1f309d0 100644 (file)
@@ -764,11 +764,12 @@ int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
        spin_lock_bh(&dev->rx_token_lock);
        token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size,
                          GFP_ATOMIC);
+       if (token >= 0) {
+               t->ptr = ptr;
+               t->dma_addr = phys;
+       }
        spin_unlock_bh(&dev->rx_token_lock);
 
-       t->ptr = ptr;
-       t->dma_addr = phys;
-
        return token;
 }
 EXPORT_SYMBOL_GPL(mt76_rx_token_consume);
index 82a7458..bf72e5f 100644 (file)
@@ -696,8 +696,8 @@ static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len)
                struct rndis_query      *get;
                struct rndis_query_c    *get_c;
        } u;
-       int ret, buflen;
-       int resplen, respoffs, copylen;
+       int ret;
+       size_t buflen, resplen, respoffs, copylen;
 
        buflen = *len + sizeof(*u.get);
        if (buflen < CONTROL_BUFFER_SIZE)
@@ -732,22 +732,15 @@ static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len)
 
                if (respoffs > buflen) {
                        /* Device returned data offset outside buffer, error. */
-                       netdev_dbg(dev->net, "%s(%s): received invalid "
-                               "data offset: %d > %d\n", __func__,
-                               oid_to_string(oid), respoffs, buflen);
+                       netdev_dbg(dev->net,
+                                  "%s(%s): received invalid data offset: %zu > %zu\n",
+                                  __func__, oid_to_string(oid), respoffs, buflen);
 
                        ret = -EINVAL;
                        goto exit_unlock;
                }
 
-               if ((resplen + respoffs) > buflen) {
-                       /* Device would have returned more data if buffer would
-                        * have been big enough. Copy just the bits that we got.
-                        */
-                       copylen = buflen - respoffs;
-               } else {
-                       copylen = resplen;
-               }
+               copylen = min(resplen, buflen - respoffs);
 
                if (copylen > *len)
                        copylen = *len;
index 7eff353..7ff33c1 100644 (file)
@@ -152,6 +152,15 @@ static irqreturn_t t7xx_dpmaif_isr_handler(int irq, void *data)
        }
 
        t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t t7xx_dpmaif_isr_thread(int irq, void *data)
+{
+       struct dpmaif_isr_para *isr_para = data;
+       struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl;
+
        t7xx_dpmaif_irq_cb(isr_para);
        t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
        return IRQ_HANDLED;
@@ -188,7 +197,7 @@ static void t7xx_dpmaif_register_pcie_irq(struct dpmaif_ctrl *dpmaif_ctrl)
                t7xx_pcie_mac_clear_int(t7xx_dev, int_type);
 
                t7xx_dev->intr_handler[int_type] = t7xx_dpmaif_isr_handler;
-               t7xx_dev->intr_thread[int_type] = NULL;
+               t7xx_dev->intr_thread[int_type] = t7xx_dpmaif_isr_thread;
                t7xx_dev->callback_param[int_type] = isr_para;
 
                t7xx_pcie_mac_clear_int_status(t7xx_dev, int_type);
index aa2174a..f4ff219 100644 (file)
@@ -840,14 +840,13 @@ int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget)
 
        if (!rxq->que_started) {
                atomic_set(&rxq->rx_processing, 0);
+               pm_runtime_put_autosuspend(rxq->dpmaif_ctrl->dev);
                dev_err(rxq->dpmaif_ctrl->dev, "Work RXQ: %d has not been started\n", rxq->index);
                return work_done;
        }
 
-       if (!rxq->sleep_lock_pending) {
-               pm_runtime_get_noresume(rxq->dpmaif_ctrl->dev);
+       if (!rxq->sleep_lock_pending)
                t7xx_pci_disable_sleep(t7xx_dev);
-       }
 
        ret = try_wait_for_completion(&t7xx_dev->sleep_lock_acquire);
        if (!ret) {
@@ -876,22 +875,22 @@ int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget)
                napi_complete_done(napi, work_done);
                t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
                t7xx_dpmaif_dlq_unmask_rx_done(&rxq->dpmaif_ctrl->hw_info, rxq->index);
+               t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev);
+               pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev);
+               pm_runtime_put_autosuspend(rxq->dpmaif_ctrl->dev);
+               atomic_set(&rxq->rx_processing, 0);
        } else {
                t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
        }
 
-       t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev);
-       pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev);
-       pm_runtime_put_noidle(rxq->dpmaif_ctrl->dev);
-       atomic_set(&rxq->rx_processing, 0);
-
        return work_done;
 }
 
 void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int que_mask)
 {
        struct dpmaif_rx_queue *rxq;
-       int qno;
+       struct dpmaif_ctrl *ctrl;
+       int qno, ret;
 
        qno = ffs(que_mask) - 1;
        if (qno < 0 || qno > DPMAIF_RXQ_NUM - 1) {
@@ -900,6 +899,18 @@ void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int
        }
 
        rxq = &dpmaif_ctrl->rxq[qno];
+       ctrl = rxq->dpmaif_ctrl;
+       /* We need to make sure that the modem has been resumed before
+        * calling napi. This can't be done inside the polling function
+        * as we could be blocked waiting for device to be resumed,
+        * which can't be done from softirq context the poll function
+        * is running in.
+        */
+       ret = pm_runtime_resume_and_get(ctrl->dev);
+       if (ret < 0 && ret != -EACCES) {
+               dev_err(ctrl->dev, "Failed to resume device: %d\n", ret);
+               return;
+       }
        napi_schedule(&rxq->napi);
 }
 
index 494a28e..3ef4a8a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/netdev_features.h>
 #include <linux/netdevice.h>
+#include <linux/pm_runtime.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
 #include <linux/wwan.h>
 
 static void t7xx_ccmni_enable_napi(struct t7xx_ccmni_ctrl *ctlb)
 {
-       int i;
+       struct dpmaif_ctrl *ctrl;
+       int i, ret;
+
+       ctrl =  ctlb->hif_ctrl;
 
        if (ctlb->is_napi_en)
                return;
 
        for (i = 0; i < RXQ_NUM; i++) {
+               /* The usage count has to be bumped every time before calling
+                * napi_schedule. It will be decresed in the poll routine,
+                * right after napi_complete_done is called.
+                */
+               ret = pm_runtime_resume_and_get(ctrl->dev);
+               if (ret < 0) {
+                       dev_err(ctrl->dev, "Failed to resume device: %d\n",
+                               ret);
+                       return;
+               }
                napi_enable(ctlb->napi[i]);
                napi_schedule(ctlb->napi[i]);
        }
index 871f2a2..226fc17 100644 (file)
@@ -121,6 +121,8 @@ void t7xx_pci_pm_init_late(struct t7xx_pci_dev *t7xx_dev)
        iowrite32(T7XX_L1_BIT(0), IREG_BASE(t7xx_dev) + ENABLE_ASPM_LOWPWR);
        atomic_set(&t7xx_dev->md_pm_state, MTK_PM_RESUMED);
 
+       pm_runtime_mark_last_busy(&t7xx_dev->pdev->dev);
+       pm_runtime_allow(&t7xx_dev->pdev->dev);
        pm_runtime_put_noidle(&t7xx_dev->pdev->dev);
 }
 
index c1ba429..0016369 100644 (file)
@@ -977,7 +977,7 @@ static int read_xenbus_vif_flags(struct backend_info *be)
        return 0;
 }
 
-static int netback_remove(struct xenbus_device *dev)
+static void netback_remove(struct xenbus_device *dev)
 {
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
@@ -992,7 +992,6 @@ static int netback_remove(struct xenbus_device *dev)
        kfree(be->hotplug_script);
        kfree(be);
        dev_set_drvdata(&dev->dev, NULL);
-       return 0;
 }
 
 /*
index 14aec41..12b0742 100644 (file)
@@ -2646,7 +2646,7 @@ static void xennet_bus_close(struct xenbus_device *dev)
        } while (!ret);
 }
 
-static int xennet_remove(struct xenbus_device *dev)
+static void xennet_remove(struct xenbus_device *dev)
 {
        struct netfront_info *info = dev_get_drvdata(&dev->dev);
 
@@ -2662,8 +2662,6 @@ static int xennet_remove(struct xenbus_device *dev)
                rtnl_unlock();
        }
        xennet_free_netdev(info->netdev);
-
-       return 0;
 }
 
 static const struct xenbus_device_id netfront_ids[] = {
index 6f71ac7..ed9c5e2 100644 (file)
@@ -153,10 +153,17 @@ static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags)
        return usb_submit_urb(phy->ack_urb, flags);
 }
 
+struct pn533_out_arg {
+       struct pn533_usb_phy *phy;
+       struct completion done;
+};
+
 static int pn533_usb_send_frame(struct pn533 *dev,
                                struct sk_buff *out)
 {
        struct pn533_usb_phy *phy = dev->phy;
+       struct pn533_out_arg arg;
+       void *cntx;
        int rc;
 
        if (phy->priv == NULL)
@@ -168,10 +175,17 @@ static int pn533_usb_send_frame(struct pn533 *dev,
        print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
                             out->data, out->len, false);
 
+       init_completion(&arg.done);
+       cntx = phy->out_urb->context;
+       phy->out_urb->context = &arg;
+
        rc = usb_submit_urb(phy->out_urb, GFP_KERNEL);
        if (rc)
                return rc;
 
+       wait_for_completion(&arg.done);
+       phy->out_urb->context = cntx;
+
        if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
                /* request for response for sent packet directly */
                rc = pn533_submit_urb_for_response(phy, GFP_KERNEL);
@@ -408,7 +422,31 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy)
        return arg.rc;
 }
 
-static void pn533_send_complete(struct urb *urb)
+static void pn533_out_complete(struct urb *urb)
+{
+       struct pn533_out_arg *arg = urb->context;
+       struct pn533_usb_phy *phy = arg->phy;
+
+       switch (urb->status) {
+       case 0:
+               break; /* success */
+       case -ECONNRESET:
+       case -ENOENT:
+               dev_dbg(&phy->udev->dev,
+                       "The urb has been stopped (status %d)\n",
+                       urb->status);
+               break;
+       case -ESHUTDOWN:
+       default:
+               nfc_err(&phy->udev->dev,
+                       "Urb failure (status %d)\n",
+                       urb->status);
+       }
+
+       complete(&arg->done);
+}
+
+static void pn533_ack_complete(struct urb *urb)
 {
        struct pn533_usb_phy *phy = urb->context;
 
@@ -496,10 +534,10 @@ static int pn533_usb_probe(struct usb_interface *interface,
 
        usb_fill_bulk_urb(phy->out_urb, phy->udev,
                          usb_sndbulkpipe(phy->udev, out_endpoint),
-                         NULL, 0, pn533_send_complete, phy);
+                         NULL, 0, pn533_out_complete, phy);
        usb_fill_bulk_urb(phy->ack_urb, phy->udev,
                          usb_sndbulkpipe(phy->udev, out_endpoint),
-                         NULL, 0, pn533_send_complete, phy);
+                         NULL, 0, pn533_ack_complete, phy);
 
        switch (id->driver_info) {
        case PN533_DEVICE_STD:
index 79d9312..77b06d5 100644 (file)
@@ -102,6 +102,25 @@ config NVDIMM_KEYS
        depends on ENCRYPTED_KEYS
        depends on (LIBNVDIMM=ENCRYPTED_KEYS) || LIBNVDIMM=m
 
+config NVDIMM_KMSAN
+       bool
+       depends on KMSAN
+       help
+         KMSAN, and other memory debug facilities, increase the size of
+         'struct page' to contain extra metadata. This collides with
+         the NVDIMM capability to store a potentially
+         larger-than-"System RAM" size 'struct page' array in a
+         reservation of persistent memory rather than limited /
+         precious DRAM. However, that reservation needs to persist for
+         the life of the given NVDIMM namespace. If you are using KMSAN
+         to debug an issue unrelated to NVDIMMs or DAX then say N to this
+         option. Otherwise, say Y but understand that any namespaces
+         (with the page array stored pmem) created with this build of
+         the kernel will permanently reserve and strand excess
+         capacity compared to the CONFIG_KMSAN=n case.
+
+         Select N if unsure.
+
 config NVDIMM_TEST_BUILD
        tristate "Build the unit test core"
        depends on m
index 85ca5b4..ec52196 100644 (file)
@@ -652,7 +652,7 @@ void devm_namespace_disable(struct device *dev,
                struct nd_namespace_common *ndns);
 #if IS_ENABLED(CONFIG_ND_CLAIM)
 /* max struct page size independent of kernel config */
-#define MAX_STRUCT_PAGE_SIZE 128
+#define MAX_STRUCT_PAGE_SIZE 64
 int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap);
 #else
 static inline int nvdimm_setup_pfn(struct nd_pfn *nd_pfn,
index 61af072..af7d930 100644 (file)
@@ -13,6 +13,8 @@
 #include "pfn.h"
 #include "nd.h"
 
+static const bool page_struct_override = IS_ENABLED(CONFIG_NVDIMM_KMSAN);
+
 static void nd_pfn_release(struct device *dev)
 {
        struct nd_region *nd_region = to_nd_region(dev->parent);
@@ -758,12 +760,6 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
                return -ENXIO;
        }
 
-       /*
-        * Note, we use 64 here for the standard size of struct page,
-        * debugging options may cause it to be larger in which case the
-        * implementation will limit the pfns advertised through
-        * ->direct_access() to those that are included in the memmap.
-        */
        start = nsio->res.start;
        size = resource_size(&nsio->res);
        npfns = PHYS_PFN(size - SZ_8K);
@@ -782,20 +778,33 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        }
        end_trunc = start + size - ALIGN_DOWN(start + size, align);
        if (nd_pfn->mode == PFN_MODE_PMEM) {
+               unsigned long page_map_size = MAX_STRUCT_PAGE_SIZE * npfns;
+
                /*
                 * The altmap should be padded out to the block size used
                 * when populating the vmemmap. This *should* be equal to
                 * PMD_SIZE for most architectures.
                 *
-                * Also make sure size of struct page is less than 128. We
-                * want to make sure we use large enough size here so that
-                * we don't have a dynamic reserve space depending on
-                * struct page size. But we also want to make sure we notice
-                * when we end up adding new elements to struct page.
+                * Also make sure size of struct page is less than
+                * MAX_STRUCT_PAGE_SIZE. The goal here is compatibility in the
+                * face of production kernel configurations that reduce the
+                * 'struct page' size below MAX_STRUCT_PAGE_SIZE. For debug
+                * kernel configurations that increase the 'struct page' size
+                * above MAX_STRUCT_PAGE_SIZE, the page_struct_override allows
+                * for continuing with the capacity that will be wasted when
+                * reverting to a production kernel configuration. Otherwise,
+                * those configurations are blocked by default.
                 */
-               BUILD_BUG_ON(sizeof(struct page) > MAX_STRUCT_PAGE_SIZE);
-               offset = ALIGN(start + SZ_8K + MAX_STRUCT_PAGE_SIZE * npfns, align)
-                       - start;
+               if (sizeof(struct page) > MAX_STRUCT_PAGE_SIZE) {
+                       if (page_struct_override)
+                               page_map_size = sizeof(struct page) * npfns;
+                       else {
+                               dev_err(&nd_pfn->dev,
+                                       "Memory debug options prevent using pmem for the page map\n");
+                               return -EINVAL;
+                       }
+               }
+               offset = ALIGN(start + SZ_8K + page_map_size, align) - start;
        } else if (nd_pfn->mode == PFN_MODE_RAM)
                offset = ALIGN(start + SZ_8K, align) - start;
        else
@@ -818,7 +827,10 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
        pfn_sb->version_minor = cpu_to_le16(4);
        pfn_sb->end_trunc = cpu_to_le32(end_trunc);
        pfn_sb->align = cpu_to_le32(nd_pfn->align);
-       pfn_sb->page_struct_size = cpu_to_le16(MAX_STRUCT_PAGE_SIZE);
+       if (sizeof(struct page) > MAX_STRUCT_PAGE_SIZE && page_struct_override)
+               pfn_sb->page_struct_size = cpu_to_le16(sizeof(struct page));
+       else
+               pfn_sb->page_struct_size = cpu_to_le16(MAX_STRUCT_PAGE_SIZE);
        pfn_sb->page_size = cpu_to_le32(PAGE_SIZE);
        checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
        pfn_sb->checksum = cpu_to_le64(checksum);
index e36aeb5..b317ce6 100644 (file)
@@ -829,7 +829,23 @@ static void apple_nvme_disable(struct apple_nvme *anv, bool shutdown)
                        apple_nvme_remove_cq(anv);
                }
 
-               nvme_disable_ctrl(&anv->ctrl, shutdown);
+               /*
+                * Always disable the NVMe controller after shutdown.
+                * We need to do this to bring it back up later anyway, and we
+                * can't do it while the firmware is not running (e.g. in the
+                * resume reset path before RTKit is initialized), so for Apple
+                * controllers it makes sense to unconditionally do it here.
+                * Additionally, this sequence of events is reliable, while
+                * others (like disabling after bringing back the firmware on
+                * resume) seem to run into trouble under some circumstances.
+                *
+                * Both U-Boot and m1n1 also use this convention (i.e. an ANS
+                * NVMe controller is handed off with firmware shut down, in an
+                * NVMe disabled state, after a clean shutdown).
+                */
+               if (shutdown)
+                       nvme_disable_ctrl(&anv->ctrl, shutdown);
+               nvme_disable_ctrl(&anv->ctrl, false);
        }
 
        WRITE_ONCE(anv->ioq.enabled, false);
@@ -985,11 +1001,11 @@ static void apple_nvme_reset_work(struct work_struct *work)
                goto out;
        }
 
-       if (anv->ctrl.ctrl_config & NVME_CC_ENABLE)
-               apple_nvme_disable(anv, false);
-
        /* RTKit must be shut down cleanly for the (soft)-reset to work */
        if (apple_rtkit_is_running(anv->rtk)) {
+               /* reset the controller if it is enabled */
+               if (anv->ctrl.ctrl_config & NVME_CC_ENABLE)
+                       apple_nvme_disable(anv, false);
                dev_dbg(anv->dev, "Trying to shut down RTKit before reset.");
                ret = apple_rtkit_shutdown(anv->rtk);
                if (ret)
@@ -1493,7 +1509,7 @@ static int apple_nvme_probe(struct platform_device *pdev)
        }
 
        ret = nvme_init_ctrl(&anv->ctrl, anv->dev, &nvme_ctrl_ops,
-                            NVME_QUIRK_SKIP_CID_GEN);
+                            NVME_QUIRK_SKIP_CID_GEN | NVME_QUIRK_IDENTIFY_CNS);
        if (ret) {
                dev_err_probe(dev, ret, "Failed to initialize nvme_ctrl");
                goto put_dev;
index 4424f53..bdb9749 100644 (file)
@@ -45,6 +45,8 @@ struct nvme_dhchap_queue_context {
        int sess_key_len;
 };
 
+static struct workqueue_struct *nvme_auth_wq;
+
 #define nvme_auth_flags_from_qid(qid) \
        (qid == 0) ? 0 : BLK_MQ_REQ_NOWAIT | BLK_MQ_REQ_RESERVED
 #define nvme_auth_queue_from_qid(ctrl, qid) \
@@ -866,7 +868,7 @@ int nvme_auth_negotiate(struct nvme_ctrl *ctrl, int qid)
 
        chap = &ctrl->dhchap_ctxs[qid];
        cancel_work_sync(&chap->auth_work);
-       queue_work(nvme_wq, &chap->auth_work);
+       queue_work(nvme_auth_wq, &chap->auth_work);
        return 0;
 }
 EXPORT_SYMBOL_GPL(nvme_auth_negotiate);
@@ -1008,10 +1010,15 @@ EXPORT_SYMBOL_GPL(nvme_auth_free);
 
 int __init nvme_init_auth(void)
 {
+       nvme_auth_wq = alloc_workqueue("nvme-auth-wq",
+                              WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
+       if (!nvme_auth_wq)
+               return -ENOMEM;
+
        nvme_chap_buf_cache = kmem_cache_create("nvme-chap-buf-cache",
                                CHAP_BUF_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL);
        if (!nvme_chap_buf_cache)
-               return -ENOMEM;
+               goto err_destroy_workqueue;
 
        nvme_chap_buf_pool = mempool_create(16, mempool_alloc_slab,
                        mempool_free_slab, nvme_chap_buf_cache);
@@ -1021,6 +1028,8 @@ int __init nvme_init_auth(void)
        return 0;
 err_destroy_chap_buf_cache:
        kmem_cache_destroy(nvme_chap_buf_cache);
+err_destroy_workqueue:
+       destroy_workqueue(nvme_auth_wq);
        return -ENOMEM;
 }
 
@@ -1028,4 +1037,5 @@ void __exit nvme_exit_auth(void)
 {
        mempool_destroy(nvme_chap_buf_pool);
        kmem_cache_destroy(nvme_chap_buf_cache);
+       destroy_workqueue(nvme_auth_wq);
 }
index 7be562a..8b64211 100644 (file)
@@ -1093,7 +1093,7 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)
        if (ns) {
                if (ns->head->effects)
                        effects = le32_to_cpu(ns->head->effects->iocs[opcode]);
-               if (ns->head->ids.csi == NVME_CAP_CSS_NVM)
+               if (ns->head->ids.csi == NVME_CSI_NVM)
                        effects |= nvme_known_nvm_effects(opcode);
                if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC))
                        dev_warn_once(ctrl->device,
@@ -4921,7 +4921,9 @@ out_cleanup_admin_q:
        blk_mq_destroy_queue(ctrl->admin_q);
        blk_put_queue(ctrl->admin_q);
 out_free_tagset:
-       blk_mq_free_tag_set(ctrl->admin_tagset);
+       blk_mq_free_tag_set(set);
+       ctrl->admin_q = NULL;
+       ctrl->fabrics_q = NULL;
        return ret;
 }
 EXPORT_SYMBOL_GPL(nvme_alloc_admin_tag_set);
@@ -4983,6 +4985,7 @@ int nvme_alloc_io_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
 
 out_free_tag_set:
        blk_mq_free_tag_set(set);
+       ctrl->connect_q = NULL;
        return ret;
 }
 EXPORT_SYMBOL_GPL(nvme_alloc_io_tag_set);
index 4564f16..456ee42 100644 (file)
@@ -3521,13 +3521,6 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
 
        nvme_fc_init_queue(ctrl, 0);
 
-       ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
-                       &nvme_fc_admin_mq_ops,
-                       struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
-                                   ctrl->lport->ops->fcprqst_priv_sz));
-       if (ret)
-               goto out_free_queues;
-
        /*
         * Would have been nice to init io queues tag set as well.
         * However, we require interaction from the controller
@@ -3537,10 +3530,17 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
 
        ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_fc_ctrl_ops, 0);
        if (ret)
-               goto out_cleanup_tagset;
+               goto out_free_queues;
 
        /* at this point, teardown path changes to ref counting on nvme ctrl */
 
+       ret = nvme_alloc_admin_tag_set(&ctrl->ctrl, &ctrl->admin_tag_set,
+                       &nvme_fc_admin_mq_ops,
+                       struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
+                                   ctrl->lport->ops->fcprqst_priv_sz));
+       if (ret)
+               goto fail_ctrl;
+
        spin_lock_irqsave(&rport->lock, flags);
        list_add_tail(&ctrl->ctrl_list, &rport->ctrl_list);
        spin_unlock_irqrestore(&rport->lock, flags);
@@ -3592,8 +3592,6 @@ fail_ctrl:
 
        return ERR_PTR(-EIO);
 
-out_cleanup_tagset:
-       nvme_remove_admin_tag_set(&ctrl->ctrl);
 out_free_queues:
        kfree(ctrl->queues);
 out_free_ida:
index a863991..06f52db 100644 (file)
@@ -8,14 +8,26 @@
 #include <linux/io_uring.h>
 #include "nvme.h"
 
+enum {
+       NVME_IOCTL_VEC          = (1 << 0),
+       NVME_IOCTL_PARTITION    = (1 << 1),
+};
+
 static bool nvme_cmd_allowed(struct nvme_ns *ns, struct nvme_command *c,
-               fmode_t mode)
+               unsigned int flags, fmode_t mode)
 {
        u32 effects;
 
        if (capable(CAP_SYS_ADMIN))
                return true;
 
+       /*
+        * Do not allow unprivileged passthrough on partitions, as that allows an
+        * escape from the containment of the partition.
+        */
+       if (flags & NVME_IOCTL_PARTITION)
+               return false;
+
        /*
         * Do not allow unprivileged processes to send vendor specific or fabrics
         * commands as we can't be sure about their effects.
@@ -150,7 +162,7 @@ static struct request *nvme_alloc_user_request(struct request_queue *q,
 static int nvme_map_user_request(struct request *req, u64 ubuffer,
                unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
                u32 meta_seed, void **metap, struct io_uring_cmd *ioucmd,
-               bool vec)
+               unsigned int flags)
 {
        struct request_queue *q = req->q;
        struct nvme_ns *ns = q->queuedata;
@@ -163,7 +175,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
                struct iov_iter iter;
 
                /* fixedbufs is only for non-vectored io */
-               if (WARN_ON_ONCE(vec))
+               if (WARN_ON_ONCE(flags & NVME_IOCTL_VEC))
                        return -EINVAL;
                ret = io_uring_cmd_import_fixed(ubuffer, bufflen,
                                rq_data_dir(req), &iter, ioucmd);
@@ -172,8 +184,8 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
                ret = blk_rq_map_user_iov(q, req, NULL, &iter, GFP_KERNEL);
        } else {
                ret = blk_rq_map_user_io(req, NULL, nvme_to_user_ptr(ubuffer),
-                               bufflen, GFP_KERNEL, vec, 0, 0,
-                               rq_data_dir(req));
+                               bufflen, GFP_KERNEL, flags & NVME_IOCTL_VEC, 0,
+                               0, rq_data_dir(req));
        }
 
        if (ret)
@@ -203,9 +215,9 @@ out:
 }
 
 static int nvme_submit_user_cmd(struct request_queue *q,
-               struct nvme_command *cmd, u64 ubuffer,
-               unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
-               u32 meta_seed, u64 *result, unsigned timeout, bool vec)
+               struct nvme_command *cmd, u64 ubuffer, unsigned bufflen,
+               void __user *meta_buffer, unsigned meta_len, u32 meta_seed,
+               u64 *result, unsigned timeout, unsigned int flags)
 {
        struct nvme_ctrl *ctrl;
        struct request *req;
@@ -221,7 +233,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
        req->timeout = timeout;
        if (ubuffer && bufflen) {
                ret = nvme_map_user_request(req, ubuffer, bufflen, meta_buffer,
-                               meta_len, meta_seed, &meta, NULL, vec);
+                               meta_len, meta_seed, &meta, NULL, flags);
                if (ret)
                        return ret;
        }
@@ -304,10 +316,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        c.rw.apptag = cpu_to_le16(io.apptag);
        c.rw.appmask = cpu_to_le16(io.appmask);
 
-       return nvme_submit_user_cmd(ns->queue, &c,
-                       io.addr, length,
-                       metadata, meta_len, lower_32_bits(io.slba), NULL, 0,
-                       false);
+       return nvme_submit_user_cmd(ns->queue, &c, io.addr, length, metadata,
+                       meta_len, lower_32_bits(io.slba), NULL, 0, 0);
 }
 
 static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl,
@@ -325,7 +335,8 @@ static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl,
 }
 
 static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-                       struct nvme_passthru_cmd __user *ucmd, fmode_t mode)
+               struct nvme_passthru_cmd __user *ucmd, unsigned int flags,
+               fmode_t mode)
 {
        struct nvme_passthru_cmd cmd;
        struct nvme_command c;
@@ -353,16 +364,15 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        c.common.cdw14 = cpu_to_le32(cmd.cdw14);
        c.common.cdw15 = cpu_to_le32(cmd.cdw15);
 
-       if (!nvme_cmd_allowed(ns, &c, mode))
+       if (!nvme_cmd_allowed(ns, &c, 0, mode))
                return -EACCES;
 
        if (cmd.timeout_ms)
                timeout = msecs_to_jiffies(cmd.timeout_ms);
 
        status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
-                       cmd.addr, cmd.data_len,
-                       nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
-                       0, &result, timeout, false);
+                       cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata),
+                       cmd.metadata_len, 0, &result, timeout, 0);
 
        if (status >= 0) {
                if (put_user(result, &ucmd->result))
@@ -373,8 +383,8 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 }
 
 static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-                       struct nvme_passthru_cmd64 __user *ucmd, bool vec,
-                       fmode_t mode)
+               struct nvme_passthru_cmd64 __user *ucmd, unsigned int flags,
+               fmode_t mode)
 {
        struct nvme_passthru_cmd64 cmd;
        struct nvme_command c;
@@ -401,16 +411,15 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        c.common.cdw14 = cpu_to_le32(cmd.cdw14);
        c.common.cdw15 = cpu_to_le32(cmd.cdw15);
 
-       if (!nvme_cmd_allowed(ns, &c, mode))
+       if (!nvme_cmd_allowed(ns, &c, flags, mode))
                return -EACCES;
 
        if (cmd.timeout_ms)
                timeout = msecs_to_jiffies(cmd.timeout_ms);
 
        status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c,
-                       cmd.addr, cmd.data_len,
-                       nvme_to_user_ptr(cmd.metadata), cmd.metadata_len,
-                       0, &cmd.result, timeout, vec);
+                       cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata),
+                       cmd.metadata_len, 0, &cmd.result, timeout, flags);
 
        if (status >= 0) {
                if (put_user(cmd.result, &ucmd->result))
@@ -571,7 +580,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        c.common.cdw14 = cpu_to_le32(READ_ONCE(cmd->cdw14));
        c.common.cdw15 = cpu_to_le32(READ_ONCE(cmd->cdw15));
 
-       if (!nvme_cmd_allowed(ns, &c, ioucmd->file->f_mode))
+       if (!nvme_cmd_allowed(ns, &c, 0, ioucmd->file->f_mode))
                return -EACCES;
 
        d.metadata = READ_ONCE(cmd->metadata);
@@ -641,9 +650,9 @@ static int nvme_ctrl_ioctl(struct nvme_ctrl *ctrl, unsigned int cmd,
 {
        switch (cmd) {
        case NVME_IOCTL_ADMIN_CMD:
-               return nvme_user_cmd(ctrl, NULL, argp, mode);
+               return nvme_user_cmd(ctrl, NULL, argp, 0, mode);
        case NVME_IOCTL_ADMIN64_CMD:
-               return nvme_user_cmd64(ctrl, NULL, argp, false, mode);
+               return nvme_user_cmd64(ctrl, NULL, argp, 0, mode);
        default:
                return sed_ioctl(ctrl->opal_dev, cmd, argp);
        }
@@ -668,14 +677,14 @@ struct nvme_user_io32 {
 #endif /* COMPAT_FOR_U64_ALIGNMENT */
 
 static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,
-               void __user *argp, fmode_t mode)
+               void __user *argp, unsigned int flags, fmode_t mode)
 {
        switch (cmd) {
        case NVME_IOCTL_ID:
                force_successful_syscall_return();
                return ns->head->ns_id;
        case NVME_IOCTL_IO_CMD:
-               return nvme_user_cmd(ns->ctrl, ns, argp, mode);
+               return nvme_user_cmd(ns->ctrl, ns, argp, flags, mode);
        /*
         * struct nvme_user_io can have different padding on some 32-bit ABIs.
         * Just accept the compat version as all fields that are used are the
@@ -686,37 +695,40 @@ static int nvme_ns_ioctl(struct nvme_ns *ns, unsigned int cmd,
 #endif
        case NVME_IOCTL_SUBMIT_IO:
                return nvme_submit_io(ns, argp);
-       case NVME_IOCTL_IO64_CMD:
-               return nvme_user_cmd64(ns->ctrl, ns, argp, false, mode);
        case NVME_IOCTL_IO64_CMD_VEC:
-               return nvme_user_cmd64(ns->ctrl, ns, argp, true, mode);
+               flags |= NVME_IOCTL_VEC;
+               fallthrough;
+       case NVME_IOCTL_IO64_CMD:
+               return nvme_user_cmd64(ns->ctrl, ns, argp, flags, mode);
        default:
                return -ENOTTY;
        }
 }
 
-static int __nvme_ioctl(struct nvme_ns *ns, unsigned int cmd, void __user *arg,
-                       fmode_t mode)
-{
-       if (is_ctrl_ioctl(cmd))
-               return nvme_ctrl_ioctl(ns->ctrl, cmd, arg, mode);
-       return nvme_ns_ioctl(ns, cmd, arg, mode);
-}
-
 int nvme_ioctl(struct block_device *bdev, fmode_t mode,
                unsigned int cmd, unsigned long arg)
 {
        struct nvme_ns *ns = bdev->bd_disk->private_data;
+       void __user *argp = (void __user *)arg;
+       unsigned int flags = 0;
 
-       return __nvme_ioctl(ns, cmd, (void __user *)arg, mode);
+       if (bdev_is_partition(bdev))
+               flags |= NVME_IOCTL_PARTITION;
+
+       if (is_ctrl_ioctl(cmd))
+               return nvme_ctrl_ioctl(ns->ctrl, cmd, argp, mode);
+       return nvme_ns_ioctl(ns, cmd, argp, flags, mode);
 }
 
 long nvme_ns_chr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct nvme_ns *ns =
                container_of(file_inode(file)->i_cdev, struct nvme_ns, cdev);
+       void __user *argp = (void __user *)arg;
 
-       return __nvme_ioctl(ns, cmd, (void __user *)arg, file->f_mode);
+       if (is_ctrl_ioctl(cmd))
+               return nvme_ctrl_ioctl(ns->ctrl, cmd, argp, file->f_mode);
+       return nvme_ns_ioctl(ns, cmd, argp, 0, file->f_mode);
 }
 
 static int nvme_uring_cmd_checks(unsigned int issue_flags)
@@ -806,6 +818,10 @@ int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode,
        void __user *argp = (void __user *)arg;
        struct nvme_ns *ns;
        int srcu_idx, ret = -EWOULDBLOCK;
+       unsigned int flags = 0;
+
+       if (bdev_is_partition(bdev))
+               flags |= NVME_IOCTL_PARTITION;
 
        srcu_idx = srcu_read_lock(&head->srcu);
        ns = nvme_find_path(head);
@@ -821,7 +837,7 @@ int nvme_ns_head_ioctl(struct block_device *bdev, fmode_t mode,
                return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx,
                                        mode);
 
-       ret = nvme_ns_ioctl(ns, cmd, argp, mode);
+       ret = nvme_ns_ioctl(ns, cmd, argp, flags, mode);
 out_unlock:
        srcu_read_unlock(&head->srcu, srcu_idx);
        return ret;
@@ -846,7 +862,7 @@ long nvme_ns_head_chr_ioctl(struct file *file, unsigned int cmd,
                return nvme_ns_head_ctrl_ioctl(ns, cmd, argp, head, srcu_idx,
                                file->f_mode);
 
-       ret = nvme_ns_ioctl(ns, cmd, argp, file->f_mode);
+       ret = nvme_ns_ioctl(ns, cmd, argp, 0, file->f_mode);
 out_unlock:
        srcu_read_unlock(&head->srcu, srcu_idx);
        return ret;
@@ -945,7 +961,7 @@ static int nvme_dev_user_cmd(struct nvme_ctrl *ctrl, void __user *argp,
        kref_get(&ns->kref);
        up_read(&ctrl->namespaces_rwsem);
 
-       ret = nvme_user_cmd(ctrl, ns, argp, mode);
+       ret = nvme_user_cmd(ctrl, ns, argp, 0, mode);
        nvme_put_ns(ns);
        return ret;
 
@@ -962,9 +978,9 @@ long nvme_dev_ioctl(struct file *file, unsigned int cmd,
 
        switch (cmd) {
        case NVME_IOCTL_ADMIN_CMD:
-               return nvme_user_cmd(ctrl, NULL, argp, file->f_mode);
+               return nvme_user_cmd(ctrl, NULL, argp, 0, file->f_mode);
        case NVME_IOCTL_ADMIN64_CMD:
-               return nvme_user_cmd64(ctrl, NULL, argp, false, file->f_mode);
+               return nvme_user_cmd64(ctrl, NULL, argp, 0, file->f_mode);
        case NVME_IOCTL_IO_CMD:
                return nvme_dev_user_cmd(ctrl, argp, file->f_mode);
        case NVME_IOCTL_RESET:
index b13bacc..c734934 100644 (file)
@@ -1362,7 +1362,7 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
        else
                nvme_poll_irqdisable(nvmeq);
 
-       if (blk_mq_request_completed(req)) {
+       if (blk_mq_rq_state(req) != MQ_RQ_IN_FLIGHT) {
                dev_warn(dev->ctrl.device,
                         "I/O %d QID %d timeout, completion polled\n",
                         req->tag, nvmeq->qid);
@@ -2533,7 +2533,7 @@ static int nvme_pci_enable(struct nvme_dev *dev)
         */
        result = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
        if (result < 0)
-               return result;
+               goto disable;
 
        dev->ctrl.cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
 
@@ -2586,8 +2586,13 @@ static int nvme_pci_enable(struct nvme_dev *dev)
        pci_enable_pcie_error_reporting(pdev);
        pci_save_state(pdev);
 
-       return nvme_pci_configure_admin_queue(dev);
+       result = nvme_pci_configure_admin_queue(dev);
+       if (result)
+               goto free_irq;
+       return result;
 
+ free_irq:
+       pci_free_irq_vectors(pdev);
  disable:
        pci_disable_device(pdev);
        return result;
@@ -3097,6 +3102,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        nvme_start_ctrl(&dev->ctrl);
        nvme_put_ctrl(&dev->ctrl);
+       flush_work(&dev->ctrl.scan_work);
        return 0;
 
 out_disable:
@@ -3495,7 +3501,8 @@ static const struct pci_device_id nvme_id_table[] = {
                .driver_data = NVME_QUIRK_SINGLE_VECTOR |
                                NVME_QUIRK_128_BYTES_SQES |
                                NVME_QUIRK_SHARED_TAGS |
-                               NVME_QUIRK_SKIP_CID_GEN },
+                               NVME_QUIRK_SKIP_CID_GEN |
+                               NVME_QUIRK_IDENTIFY_CNS },
        { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
        { 0, }
 };
index ab2627e..1ab6601 100644 (file)
@@ -1685,8 +1685,10 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport,
                else {
                        queue = nvmet_fc_alloc_target_queue(iod->assoc, 0,
                                        be16_to_cpu(rqst->assoc_cmd.sqsize));
-                       if (!queue)
+                       if (!queue) {
                                ret = VERR_QUEUE_ALLOC_FAIL;
+                               nvmet_fc_tgt_a_put(iod->assoc);
+                       }
                }
        }
 
index 3413044..39aa279 100644 (file)
@@ -98,6 +98,9 @@ static int brcm_nvram_parse(struct brcm_nvram *priv)
        len = le32_to_cpu(header.len);
 
        data = kzalloc(len, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
        memcpy_fromio(data, priv->base, len);
        data[len - 1] = '\0';
 
index 321d7d6..34ee9d3 100644 (file)
@@ -770,31 +770,32 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
                return ERR_PTR(rval);
        }
 
-       if (config->wp_gpio)
-               nvmem->wp_gpio = config->wp_gpio;
-       else if (!config->ignore_wp)
+       nvmem->id = rval;
+
+       nvmem->dev.type = &nvmem_provider_type;
+       nvmem->dev.bus = &nvmem_bus_type;
+       nvmem->dev.parent = config->dev;
+
+       device_initialize(&nvmem->dev);
+
+       if (!config->ignore_wp)
                nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp",
                                                    GPIOD_OUT_HIGH);
        if (IS_ERR(nvmem->wp_gpio)) {
-               ida_free(&nvmem_ida, nvmem->id);
                rval = PTR_ERR(nvmem->wp_gpio);
-               kfree(nvmem);
-               return ERR_PTR(rval);
+               nvmem->wp_gpio = NULL;
+               goto err_put_device;
        }
 
        kref_init(&nvmem->refcnt);
        INIT_LIST_HEAD(&nvmem->cells);
 
-       nvmem->id = rval;
        nvmem->owner = config->owner;
        if (!nvmem->owner && config->dev->driver)
                nvmem->owner = config->dev->driver->owner;
        nvmem->stride = config->stride ?: 1;
        nvmem->word_size = config->word_size ?: 1;
        nvmem->size = config->size;
-       nvmem->dev.type = &nvmem_provider_type;
-       nvmem->dev.bus = &nvmem_bus_type;
-       nvmem->dev.parent = config->dev;
        nvmem->root_only = config->root_only;
        nvmem->priv = config->priv;
        nvmem->type = config->type;
@@ -822,11 +823,8 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
                break;
        }
 
-       if (rval) {
-               ida_free(&nvmem_ida, nvmem->id);
-               kfree(nvmem);
-               return ERR_PTR(rval);
-       }
+       if (rval)
+               goto err_put_device;
 
        nvmem->read_only = device_property_present(config->dev, "read-only") ||
                           config->read_only || !nvmem->reg_write;
@@ -835,28 +833,22 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
        nvmem->dev.groups = nvmem_dev_groups;
 #endif
 
-       dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
-
-       rval = device_register(&nvmem->dev);
-       if (rval)
-               goto err_put_device;
-
        if (nvmem->nkeepout) {
                rval = nvmem_validate_keepouts(nvmem);
                if (rval)
-                       goto err_device_del;
+                       goto err_put_device;
        }
 
        if (config->compat) {
                rval = nvmem_sysfs_setup_compat(nvmem, config);
                if (rval)
-                       goto err_device_del;
+                       goto err_put_device;
        }
 
        if (config->cells) {
                rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
                if (rval)
-                       goto err_teardown_compat;
+                       goto err_remove_cells;
        }
 
        rval = nvmem_add_cells_from_table(nvmem);
@@ -867,17 +859,20 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
        if (rval)
                goto err_remove_cells;
 
+       dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
+
+       rval = device_add(&nvmem->dev);
+       if (rval)
+               goto err_remove_cells;
+
        blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
 
        return nvmem;
 
 err_remove_cells:
        nvmem_device_remove_all_cells(nvmem);
-err_teardown_compat:
        if (config->compat)
                nvmem_sysfs_remove_compat(nvmem, config);
-err_device_del:
-       device_del(&nvmem->dev);
 err_put_device:
        put_device(&nvmem->dev);
 
@@ -1242,16 +1237,21 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
        if (!cell_np)
                return ERR_PTR(-ENOENT);
 
-       nvmem_np = of_get_next_parent(cell_np);
-       if (!nvmem_np)
+       nvmem_np = of_get_parent(cell_np);
+       if (!nvmem_np) {
+               of_node_put(cell_np);
                return ERR_PTR(-EINVAL);
+       }
 
        nvmem = __nvmem_device_get(nvmem_np, device_match_of_node);
        of_node_put(nvmem_np);
-       if (IS_ERR(nvmem))
+       if (IS_ERR(nvmem)) {
+               of_node_put(cell_np);
                return ERR_CAST(nvmem);
+       }
 
        cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np);
+       of_node_put(cell_np);
        if (!cell_entry) {
                __nvmem_device_put(nvmem);
                return ERR_PTR(-ENOENT);
index 4fcb635..8499892 100644 (file)
@@ -166,6 +166,7 @@ static const struct of_device_id sdam_match_table[] = {
        { .compatible = "qcom,spmi-sdam" },
        {},
 };
+MODULE_DEVICE_TABLE(of, sdam_match_table);
 
 static struct platform_driver sdam_driver = {
        .driver = {
index 5750e1f..92dfe4c 100644 (file)
@@ -41,8 +41,21 @@ static int sunxi_sid_read(void *context, unsigned int offset,
                          void *val, size_t bytes)
 {
        struct sunxi_sid *sid = context;
+       u32 word;
+
+       /* .stride = 4 so offset is guaranteed to be aligned */
+       __ioread32_copy(val, sid->base + sid->value_offset + offset, bytes / 4);
 
-       memcpy_fromio(val, sid->base + sid->value_offset + offset, bytes);
+       val += round_down(bytes, 4);
+       offset += round_down(bytes, 4);
+       bytes = bytes % 4;
+
+       if (!bytes)
+               return 0;
+
+       /* Handle any trailing bytes */
+       word = readl_relaxed(sid->base + sid->value_offset + offset);
+       memcpy(val, &word, bytes);
 
        return 0;
 }
index c34ac33..67763e5 100644 (file)
@@ -965,8 +965,19 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
        }
 
        of_dma_range_parser_init(&parser, node);
-       for_each_of_range(&parser, &range)
+       for_each_of_range(&parser, &range) {
+               if (range.cpu_addr == OF_BAD_ADDR) {
+                       pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
+                              range.bus_addr, node);
+                       continue;
+               }
                num_ranges++;
+       }
+
+       if (!num_ranges) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL);
        if (!r) {
@@ -975,18 +986,16 @@ int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map)
        }
 
        /*
-        * Record all info in the generic DMA ranges array for struct device.
+        * Record all info in the generic DMA ranges array for struct device,
+        * returning an error if we don't find any parsable ranges.
         */
        *map = r;
        of_dma_range_parser_init(&parser, node);
        for_each_of_range(&parser, &range) {
                pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
                         range.bus_addr, range.cpu_addr, range.size);
-               if (range.cpu_addr == OF_BAD_ADDR) {
-                       pr_err("translation of DMA address(%llx) to CPU address failed node(%pOF)\n",
-                              range.bus_addr, node);
+               if (range.cpu_addr == OF_BAD_ADDR)
                        continue;
-               }
                r->cpu_start = range.cpu_addr;
                r->dma_start = range.bus_addr;
                r->size = range.size;
index f08b251..d1a68b6 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/serial_core.h>
 #include <linux/sysfs.h>
 #include <linux/random.h>
-#include <linux/kmemleak.h>
 
 #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 #include <asm/page.h>
@@ -525,12 +524,9 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
                size = dt_mem_next_cell(dt_root_size_cells, &prop);
 
                if (size &&
-                   early_init_dt_reserve_memory(base, size, nomap) == 0) {
+                   early_init_dt_reserve_memory(base, size, nomap) == 0)
                        pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n",
                                uname, &base, (unsigned long)(size / SZ_1M));
-                       if (!nomap)
-                               kmemleak_alloc_phys(base, size, 0);
-               }
                else
                        pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n",
                               uname, &base, (unsigned long)(size / SZ_1M));
index 81c8c22..b3878a9 100644 (file)
@@ -525,6 +525,7 @@ static int __init of_platform_default_populate_init(void)
        if (IS_ENABLED(CONFIG_PPC)) {
                struct device_node *boot_display = NULL;
                struct platform_device *dev;
+               int display_number = 0;
                int ret;
 
                /* Check if we have a MacOS display without a node spec */
@@ -555,16 +556,23 @@ static int __init of_platform_default_populate_init(void)
                        if (!of_get_property(node, "linux,opened", NULL) ||
                            !of_get_property(node, "linux,boot-display", NULL))
                                continue;
-                       dev = of_platform_device_create(node, "of-display", NULL);
+                       dev = of_platform_device_create(node, "of-display.0", NULL);
+                       of_node_put(node);
                        if (WARN_ON(!dev))
                                return -ENOMEM;
                        boot_display = node;
+                       display_number++;
                        break;
                }
                for_each_node_by_type(node, "display") {
+                       char buf[14];
+                       const char *of_display_format = "of-display.%d";
+
                        if (!of_get_property(node, "linux,opened", NULL) || node == boot_display)
                                continue;
-                       of_platform_device_create(node, "of-display", NULL);
+                       ret = snprintf(buf, sizeof(buf), of_display_format, display_number++);
+                       if (ret < sizeof(buf))
+                               of_platform_device_create(node, buf, NULL);
                }
 
        } else {
index d6af572..2a18f7b 100644 (file)
@@ -274,8 +274,7 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
 
        /* We'll use a local copy of buf */
        count = min_t(size_t, count, sizeof(in)-1);
-       strncpy(in, buf, count);
-       in[count] = '\0';
+       strscpy(in, buf, count + 1);
        
        /* Let's clean up the target. 0xff is a blank pattern */
        memset(&hwpath, 0xff, sizeof(hwpath));
@@ -388,8 +387,7 @@ pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count
 
        /* We'll use a local copy of buf */
        count = min_t(size_t, count, sizeof(in)-1);
-       strncpy(in, buf, count);
-       in[count] = '\0';
+       strscpy(in, buf, count + 1);
        
        /* Let's clean up the target. 0 is a blank pattern */
        memset(&layers, 0, sizeof(layers));
@@ -756,8 +754,7 @@ static ssize_t pdcs_auto_write(struct kobject *kobj,
 
        /* We'll use a local copy of buf */
        count = min_t(size_t, count, sizeof(in)-1);
-       strncpy(in, buf, count);
-       in[count] = '\0';
+       strscpy(in, buf, count + 1);
 
        /* Current flags are stored in primary boot path entry */
        pathentry = &pdcspath_entry_primary;
index a0d2713..99ec91e 100644 (file)
@@ -225,7 +225,7 @@ config PCIE_ARTPEC6_EP
 config PCIE_BT1
        tristate "Baikal-T1 PCIe controller"
        depends on MIPS_BAIKAL_T1 || COMPILE_TEST
-       depends on PCI_MSI_IRQ_DOMAIN
+       depends on PCI_MSI
        select PCIE_DW_HOST
        help
          Enables support for the PCIe controller in the Baikal-T1 SoC to work
index fba9548..5641786 100644 (file)
@@ -1665,7 +1665,6 @@ int pci_save_state(struct pci_dev *dev)
                return i;
 
        pci_save_ltr_state(dev);
-       pci_save_aspm_l1ss_state(dev);
        pci_save_dpc_state(dev);
        pci_save_aer_state(dev);
        pci_save_ptm_state(dev);
@@ -1772,7 +1771,6 @@ void pci_restore_state(struct pci_dev *dev)
         * LTR itself (in the PCIe capability).
         */
        pci_restore_ltr_state(dev);
-       pci_restore_aspm_l1ss_state(dev);
 
        pci_restore_pcie_state(dev);
        pci_restore_pasid_state(dev);
@@ -3465,11 +3463,6 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
        if (error)
                pci_err(dev, "unable to allocate suspend buffer for LTR\n");
 
-       error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,
-                                           2 * sizeof(u32));
-       if (error)
-               pci_err(dev, "unable to allocate suspend buffer for ASPM-L1SS\n");
-
        pci_allocate_vc_save_buffers(dev);
 }
 
index 9ed3b55..9049d07 100644 (file)
@@ -566,14 +566,10 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
 void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
-void pci_save_aspm_l1ss_state(struct pci_dev *dev);
-void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
-static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { }
-static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { }
 #endif
 
 #ifdef CONFIG_PCIE_ECRC
index 53a1fa3..4b41845 100644 (file)
@@ -470,31 +470,6 @@ static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
        pci_write_config_dword(pdev, pos, val);
 }
 
-static void aspm_program_l1ss(struct pci_dev *dev, u32 ctl1, u32 ctl2)
-{
-       u16 l1ss = dev->l1ss;
-       u32 l1_2_enable;
-
-       /*
-        * Per PCIe r6.0, sec 5.5.4, T_POWER_ON in PCI_L1SS_CTL2 must be
-        * programmed prior to setting the L1.2 enable bits in PCI_L1SS_CTL1.
-        */
-       pci_write_config_dword(dev, l1ss + PCI_L1SS_CTL2, ctl2);
-
-       /*
-        * In addition, Common_Mode_Restore_Time and LTR_L1.2_THRESHOLD in
-        * PCI_L1SS_CTL1 must be programmed *before* setting the L1.2
-        * enable bits, even though they're all in PCI_L1SS_CTL1.
-        */
-       l1_2_enable = ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
-       ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
-
-       pci_write_config_dword(dev, l1ss + PCI_L1SS_CTL1, ctl1);
-       if (l1_2_enable)
-               pci_write_config_dword(dev, l1ss + PCI_L1SS_CTL1,
-                                      ctl1 | l1_2_enable);
-}
-
 /* Calculate L1.2 PM substate timing parameters */
 static void aspm_calc_l1ss_info(struct pcie_link_state *link,
                                u32 parent_l1ss_cap, u32 child_l1ss_cap)
@@ -504,6 +479,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
        u32 t_common_mode, t_power_on, l1_2_threshold, scale, value;
        u32 ctl1 = 0, ctl2 = 0;
        u32 pctl1, pctl2, cctl1, cctl2;
+       u32 pl1_2_enables, cl1_2_enables;
 
        if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
                return;
@@ -552,21 +528,39 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
            ctl2 == pctl2 && ctl2 == cctl2)
                return;
 
-       pctl1 &= ~(PCI_L1SS_CTL1_CM_RESTORE_TIME |
-                  PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
-                  PCI_L1SS_CTL1_LTR_L12_TH_SCALE);
-       pctl1 |= (ctl1 & (PCI_L1SS_CTL1_CM_RESTORE_TIME |
-                         PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
-                         PCI_L1SS_CTL1_LTR_L12_TH_SCALE));
-       aspm_program_l1ss(parent, pctl1, ctl2);
-
-       cctl1 &= ~(PCI_L1SS_CTL1_CM_RESTORE_TIME |
-                  PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
-                  PCI_L1SS_CTL1_LTR_L12_TH_SCALE);
-       cctl1 |= (ctl1 & (PCI_L1SS_CTL1_CM_RESTORE_TIME |
-                         PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
-                         PCI_L1SS_CTL1_LTR_L12_TH_SCALE));
-       aspm_program_l1ss(child, cctl1, ctl2);
+       /* Disable L1.2 while updating.  See PCIe r5.0, sec 5.5.4, 7.8.3.3 */
+       pl1_2_enables = pctl1 & PCI_L1SS_CTL1_L1_2_MASK;
+       cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK;
+
+       if (pl1_2_enables || cl1_2_enables) {
+               pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
+                                       PCI_L1SS_CTL1_L1_2_MASK, 0);
+               pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                                       PCI_L1SS_CTL1_L1_2_MASK, 0);
+       }
+
+       /* Program T_POWER_ON times in both ports */
+       pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, ctl2);
+       pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2);
+
+       /* Program Common_Mode_Restore_Time in upstream device */
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                               PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1);
+
+       /* Program LTR_L1.2_THRESHOLD time in both ports */
+       pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
+                               PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
+                               PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
+       pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1,
+                               PCI_L1SS_CTL1_LTR_L12_TH_VALUE |
+                               PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1);
+
+       if (pl1_2_enables || cl1_2_enables) {
+               pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0,
+                                       pl1_2_enables);
+               pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0,
+                                       cl1_2_enables);
+       }
 }
 
 static void aspm_l1ss_init(struct pcie_link_state *link)
@@ -757,43 +751,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
                                PCI_L1SS_CTL1_L1SS_MASK, val);
 }
 
-void pci_save_aspm_l1ss_state(struct pci_dev *dev)
-{
-       struct pci_cap_saved_state *save_state;
-       u16 l1ss = dev->l1ss;
-       u32 *cap;
-
-       if (!l1ss)
-               return;
-
-       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
-       if (!save_state)
-               return;
-
-       cap = (u32 *)&save_state->cap.data[0];
-       pci_read_config_dword(dev, l1ss + PCI_L1SS_CTL2, cap++);
-       pci_read_config_dword(dev, l1ss + PCI_L1SS_CTL1, cap++);
-}
-
-void pci_restore_aspm_l1ss_state(struct pci_dev *dev)
-{
-       struct pci_cap_saved_state *save_state;
-       u32 *cap, ctl1, ctl2;
-       u16 l1ss = dev->l1ss;
-
-       if (!l1ss)
-               return;
-
-       save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
-       if (!save_state)
-               return;
-
-       cap = (u32 *)&save_state->cap.data[0];
-       ctl2 = *cap++;
-       ctl1 = *cap;
-       aspm_program_l1ss(dev, ctl1, ctl2);
-}
-
 static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
 {
        pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
index 7378e2f..fcd029c 100644 (file)
@@ -1055,14 +1055,12 @@ out:
        return err;
 }
 
-static int pcifront_xenbus_remove(struct xenbus_device *xdev)
+static void pcifront_xenbus_remove(struct xenbus_device *xdev)
 {
        struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev);
 
        if (pdev)
                free_pdev(pdev);
-
-       return 0;
 }
 
 static const struct xenbus_device_id xenpci_ids[] = {
index b80a9b7..1deb61b 100644 (file)
@@ -1576,7 +1576,6 @@ static int arm_cmn_event_init(struct perf_event *event)
                        hw->dn++;
                        continue;
                }
-               hw->dtcs_used |= arm_cmn_node_to_xp(cmn, dn)->dtc;
                hw->num_dns++;
                if (bynodeid)
                        break;
@@ -1589,6 +1588,12 @@ static int arm_cmn_event_init(struct perf_event *event)
                        nodeid, nid.x, nid.y, nid.port, nid.dev, type);
                return -EINVAL;
        }
+       /*
+        * Keep assuming non-cycles events count in all DTC domains; turns out
+        * it's hard to make a worthwhile optimisation around this, short of
+        * going all-in with domain-local counter allocation as well.
+        */
+       hw->dtcs_used = (1U << cmn->num_dtcs) - 1;
 
        return arm_cmn_validate_group(cmn, event);
 }
index 7585e80..afc6355 100644 (file)
@@ -255,7 +255,7 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
                imx8_phy->perst =
                        devm_reset_control_get_exclusive(dev, "perst");
                if (IS_ERR(imx8_phy->perst))
-                       dev_err_probe(dev, PTR_ERR(imx8_phy->perst),
+                       return dev_err_probe(dev, PTR_ERR(imx8_phy->perst),
                                      "Failed to get PCIE PHY PERST control\n");
        }
 
index 95c6dbb..ce511ad 100644 (file)
@@ -99,6 +99,7 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
        struct gpio_desc *standby_gpio;
        struct gpio_desc *enable_gpio;
        u32 max_bitrate = 0;
+       int err;
 
        can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL);
        if (!can_transceiver_phy)
@@ -124,8 +125,8 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
                return PTR_ERR(phy);
        }
 
-       device_property_read_u32(dev, "max-bitrate", &max_bitrate);
-       if (!max_bitrate)
+       err = device_property_read_u32(dev, "max-bitrate", &max_bitrate);
+       if ((err != -EINVAL) && !max_bitrate)
                dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n");
        phy->attrs.max_link_rate = max_bitrate;
 
index 8807e59..a52a9bf 100644 (file)
@@ -401,26 +401,13 @@ static const struct hsphy_init_seq init_seq_femtophy[] = {
        HSPHY_INIT_CFG(0x90, 0x60, 0),
 };
 
-static const struct hsphy_init_seq init_seq_mdm9607[] = {
-       HSPHY_INIT_CFG(0x80, 0x44, 0),
-       HSPHY_INIT_CFG(0x81, 0x38, 0),
-       HSPHY_INIT_CFG(0x82, 0x24, 0),
-       HSPHY_INIT_CFG(0x83, 0x13, 0),
-};
-
 static const struct hsphy_data hsphy_data_femtophy = {
        .init_seq = init_seq_femtophy,
        .init_seq_num = ARRAY_SIZE(init_seq_femtophy),
 };
 
-static const struct hsphy_data hsphy_data_mdm9607 = {
-       .init_seq = init_seq_mdm9607,
-       .init_seq_num = ARRAY_SIZE(init_seq_mdm9607),
-};
-
 static const struct of_device_id qcom_snps_hsphy_match[] = {
        { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, },
-       { .compatible = "qcom,usb-hs-28nm-mdm9607", .data = &hsphy_data_mdm9607, },
        { },
 };
 MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match);
index ec6594e..e7588a9 100644 (file)
@@ -126,7 +126,7 @@ r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel)
                r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0007);
                r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000);
                r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310);
-               r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x380, 0x0101);
+               r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0101);
                ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x0180, BIT(0), 0);
                if (ret)
                        return ret;
index e6ededc..a0bc10a 100644 (file)
@@ -485,8 +485,10 @@ static int rockchip_usb2phy_power_on(struct phy *phy)
                return ret;
 
        ret = property_enable(base, &rport->port_cfg->phy_sus, false);
-       if (ret)
+       if (ret) {
+               clk_disable_unprepare(rphy->clk480m);
                return ret;
+       }
 
        /* waiting for the utmi_clk to become stable */
        usleep_range(1500, 2000);
index e827b79..56de410 100644 (file)
@@ -254,6 +254,9 @@ static int sp_usb_phy_probe(struct platform_device *pdev)
                return PTR_ERR(usbphy->phy_regs);
 
        usbphy->moon4_res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon4");
+       if (!usbphy->moon4_res_mem)
+               return -EINVAL;
+
        usbphy->moon4_regs = devm_ioremap(&pdev->dev, usbphy->moon4_res_mem->start,
                                          resource_size(usbphy->moon4_res_mem));
        if (!usbphy->moon4_regs)
index 15a3bcf..b905902 100644 (file)
@@ -23,7 +23,7 @@ config PHY_DM816X_USB
 
 config PHY_AM654_SERDES
        tristate "TI AM654 SERDES support"
-       depends on OF && ARCH_K3 || COMPILE_TEST
+       depends on OF && (ARCH_K3 || COMPILE_TEST)
        depends on COMMON_CLK
        select GENERIC_PHY
        select MULTIPLEXER
@@ -35,7 +35,7 @@ config PHY_AM654_SERDES
 
 config PHY_J721E_WIZ
        tristate "TI J721E WIZ (SERDES Wrapper) support"
-       depends on OF && ARCH_K3 || COMPILE_TEST
+       depends on OF && (ARCH_K3 || COMPILE_TEST)
        depends on HAS_IOMEM && OF_ADDRESS
        depends on COMMON_CLK
        select GENERIC_PHY
index 3945612..9c6ee46 100644 (file)
@@ -93,10 +93,19 @@ static int aspeed_sig_expr_enable(struct aspeed_pinmux_data *ctx,
 static int aspeed_sig_expr_disable(struct aspeed_pinmux_data *ctx,
                                   const struct aspeed_sig_expr *expr)
 {
+       int ret;
+
        pr_debug("Disabling signal %s for %s\n", expr->signal,
                 expr->function);
 
-       return aspeed_sig_expr_set(ctx, expr, false);
+       ret = aspeed_sig_expr_eval(ctx, expr, true);
+       if (ret < 0)
+               return ret;
+
+       if (ret)
+               return aspeed_sig_expr_set(ctx, expr, false);
+
+       return 0;
 }
 
 /**
@@ -114,7 +123,7 @@ static int aspeed_disable_sig(struct aspeed_pinmux_data *ctx,
        int ret = 0;
 
        if (!exprs)
-               return true;
+               return -EINVAL;
 
        while (*exprs && !ret) {
                ret = aspeed_sig_expr_disable(ctx, *exprs);
index cc3aaba..e49f271 100644 (file)
@@ -1709,6 +1709,12 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_
 EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data);
 
 #ifdef CONFIG_PM_SLEEP
+static bool __intel_gpio_is_direct_irq(u32 value)
+{
+       return (value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
+              (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO);
+}
+
 static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
 {
        const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
@@ -1742,8 +1748,7 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int
         * See https://bugzilla.kernel.org/show_bug.cgi?id=214749.
         */
        value = readl(intel_get_padcfg(pctrl, pin, PADCFG0));
-       if ((value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
-           (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO))
+       if (__intel_gpio_is_direct_irq(value))
                return true;
 
        return false;
@@ -1873,7 +1878,12 @@ int intel_pinctrl_resume_noirq(struct device *dev)
        for (i = 0; i < pctrl->soc->npins; i++) {
                const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
 
-               if (!intel_pinctrl_should_save(pctrl, desc->number))
+               if (!(intel_pinctrl_should_save(pctrl, desc->number) ||
+                     /*
+                      * If the firmware mangled the register contents too much,
+                      * check the saved value for the Direct IRQ mode.
+                      */
+                     __intel_gpio_is_direct_irq(pads[i].padcfg0)))
                        continue;
 
                intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0);
index 89557c7..09c4dce 100644 (file)
@@ -659,7 +659,7 @@ static const struct mtk_pin_field_calc mt8195_pin_drv_range[] = {
        PIN_FIELD_BASE(10, 10, 4, 0x010, 0x10, 9, 3),
        PIN_FIELD_BASE(11, 11, 4, 0x000, 0x10, 24, 3),
        PIN_FIELD_BASE(12, 12, 4, 0x010, 0x10, 12, 3),
-       PIN_FIELD_BASE(13, 13, 4, 0x010, 0x10, 27, 3),
+       PIN_FIELD_BASE(13, 13, 4, 0x000, 0x10, 27, 3),
        PIN_FIELD_BASE(14, 14, 4, 0x010, 0x10, 15, 3),
        PIN_FIELD_BASE(15, 15, 4, 0x010, 0x10, 0, 3),
        PIN_FIELD_BASE(16, 16, 4, 0x010, 0x10, 18, 3),
@@ -708,7 +708,7 @@ static const struct mtk_pin_field_calc mt8195_pin_drv_range[] = {
        PIN_FIELD_BASE(78, 78, 3, 0x000, 0x10, 15, 3),
        PIN_FIELD_BASE(79, 79, 3, 0x000, 0x10, 18, 3),
        PIN_FIELD_BASE(80, 80, 3, 0x000, 0x10, 21, 3),
-       PIN_FIELD_BASE(81, 81, 3, 0x000, 0x10, 28, 3),
+       PIN_FIELD_BASE(81, 81, 3, 0x000, 0x10, 24, 3),
        PIN_FIELD_BASE(82, 82, 3, 0x000, 0x10, 27, 3),
        PIN_FIELD_BASE(83, 83, 3, 0x010, 0x10, 0, 3),
        PIN_FIELD_BASE(84, 84, 3, 0x010, 0x10, 3, 3),
index 3106a21..d7b244d 100644 (file)
@@ -6,9 +6,10 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/gpio/driver.h>
 #include <linux/pinctrl/pinctrl.h>
+
 #include <linux/mfd/abx500/ab8500.h>
+
 #include "pinctrl-abx500.h"
 
 /* All the pins that can be used for GPIO and some other functions */
index b93af1f..45aa958 100644 (file)
@@ -6,9 +6,10 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/gpio/driver.h>
 #include <linux/pinctrl/pinctrl.h>
+
 #include <linux/mfd/abx500/ab8500.h>
+
 #include "pinctrl-abx500.h"
 
 /* All the pins that can be used for GPIO and some other functions */
index 7aa5345..28c3403 100644 (file)
@@ -6,33 +6,37 @@
  *
  * Driver allows to use AxB5xx unused pins to be used as GPIO
  */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
+#include <linux/bitops.h>
 #include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
 #include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
-#include <linux/pinctrl/pinctrl.h>
+
 #include <linux/pinctrl/consumer.h>
-#include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
 
-#include "pinctrl-abx500.h"
 #include "../core.h"
 #include "../pinconf.h"
 #include "../pinctrl-utils.h"
 
+#include "pinctrl-abx500.h"
+
 /*
  * GPIO registers offset
  * Bank: 0x10
index 90bb12f..d675220 100644 (file)
@@ -2,6 +2,10 @@
 #ifndef PINCTRL_PINCTRL_ABx500_H
 #define PINCTRL_PINCTRL_ABx500_H
 
+#include <linux/types.h>
+
+struct pinctrl_pin_desc;
+
 /* Package definitions */
 #define PINCTRL_AB8500 0
 #define PINCTRL_AB8505 1
index 758d21f..490e095 100644 (file)
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/kernel.h>
+#include <linux/types.h>
+
 #include <linux/pinctrl/pinctrl.h>
+
 #include "pinctrl-nomadik.h"
 
 /* All the pins that can be used for GPIO and some other functions */
index c0d7c86..1552222 100644 (file)
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/kernel.h>
+#include <linux/types.h>
+
 #include <linux/pinctrl/pinctrl.h>
+
 #include "pinctrl-nomadik.h"
 
 /* All the pins that can be used for GPIO and some other functions */
index f7d0251..86a6380 100644 (file)
@@ -7,30 +7,34 @@
  *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
  * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org>
  */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
+#include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/gpio/driver.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/of_address.h>
-#include <linux/bitops.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
-#include <linux/pinctrl/pinconf.h>
-/* Since we request GPIOs from ourself */
-#include <linux/pinctrl/consumer.h>
-#include "pinctrl-nomadik.h"
+
 #include "../core.h"
 #include "../pinctrl-utils.h"
 
+#include "pinctrl-nomadik.h"
+
 /*
  * The GPIO module in the Nomadik family of Systems-on-Chip is an
  * AMBA device, managing 32 pins and alternate functions.  The logic block
@@ -907,8 +911,6 @@ static int nmk_gpio_get_mode(struct nmk_gpio_chip *nmk_chip, int offset)
        return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
 }
 
-#include <linux/seq_file.h>
-
 static void nmk_gpio_dbg_show_one(struct seq_file *s,
        struct pinctrl_dev *pctldev, struct gpio_chip *chip,
        unsigned offset, unsigned gpio)
index 84e2977..1ef2559 100644 (file)
@@ -2,6 +2,11 @@
 #ifndef PINCTRL_PINCTRL_NOMADIK_H
 #define PINCTRL_PINCTRL_NOMADIK_H
 
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <linux/pinctrl/pinctrl.h>
+
 /* Package definitions */
 #define PINCTRL_NMK_STN8815    0
 #define PINCTRL_NMK_DB8500     1
index 9bc6e39..32c3eda 100644 (file)
@@ -365,6 +365,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
 
                        } else {
                                debounce_enable = "  ∅";
+                               time = 0;
                        }
                        snprintf(debounce_value, sizeof(debounce_value), "%u", time * unit);
                        seq_printf(s, "debounce %s (🕑 %sus)| ", debounce_enable, debounce_value);
index da974ff..5eeac92 100644 (file)
@@ -926,19 +926,19 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = {
        RK_MUXROUTE_PMU(0, RK_PB5, 4, 0x0110, WRITE_MASK_VAL(3, 2, 1)), /* PWM1 IO mux M1 */
        RK_MUXROUTE_PMU(0, RK_PC1, 1, 0x0110, WRITE_MASK_VAL(5, 4, 0)), /* PWM2 IO mux M0 */
        RK_MUXROUTE_PMU(0, RK_PB6, 4, 0x0110, WRITE_MASK_VAL(5, 4, 1)), /* PWM2 IO mux M1 */
-       RK_MUXROUTE_PMU(0, RK_PB3, 2, 0x0300, WRITE_MASK_VAL(0, 0, 0)), /* CAN0 IO mux M0 */
+       RK_MUXROUTE_GRF(0, RK_PB3, 2, 0x0300, WRITE_MASK_VAL(0, 0, 0)), /* CAN0 IO mux M0 */
        RK_MUXROUTE_GRF(2, RK_PA1, 4, 0x0300, WRITE_MASK_VAL(0, 0, 1)), /* CAN0 IO mux M1 */
        RK_MUXROUTE_GRF(1, RK_PA1, 3, 0x0300, WRITE_MASK_VAL(2, 2, 0)), /* CAN1 IO mux M0 */
        RK_MUXROUTE_GRF(4, RK_PC3, 3, 0x0300, WRITE_MASK_VAL(2, 2, 1)), /* CAN1 IO mux M1 */
        RK_MUXROUTE_GRF(4, RK_PB5, 3, 0x0300, WRITE_MASK_VAL(4, 4, 0)), /* CAN2 IO mux M0 */
        RK_MUXROUTE_GRF(2, RK_PB2, 4, 0x0300, WRITE_MASK_VAL(4, 4, 1)), /* CAN2 IO mux M1 */
        RK_MUXROUTE_GRF(4, RK_PC4, 1, 0x0300, WRITE_MASK_VAL(6, 6, 0)), /* HPDIN IO mux M0 */
-       RK_MUXROUTE_PMU(0, RK_PC2, 2, 0x0300, WRITE_MASK_VAL(6, 6, 1)), /* HPDIN IO mux M1 */
+       RK_MUXROUTE_GRF(0, RK_PC2, 2, 0x0300, WRITE_MASK_VAL(6, 6, 1)), /* HPDIN IO mux M1 */
        RK_MUXROUTE_GRF(3, RK_PB1, 3, 0x0300, WRITE_MASK_VAL(8, 8, 0)), /* GMAC1 IO mux M0 */
        RK_MUXROUTE_GRF(4, RK_PA7, 3, 0x0300, WRITE_MASK_VAL(8, 8, 1)), /* GMAC1 IO mux M1 */
        RK_MUXROUTE_GRF(4, RK_PD1, 1, 0x0300, WRITE_MASK_VAL(10, 10, 0)), /* HDMITX IO mux M0 */
-       RK_MUXROUTE_PMU(0, RK_PC7, 1, 0x0300, WRITE_MASK_VAL(10, 10, 1)), /* HDMITX IO mux M1 */
-       RK_MUXROUTE_PMU(0, RK_PB6, 1, 0x0300, WRITE_MASK_VAL(14, 14, 0)), /* I2C2 IO mux M0 */
+       RK_MUXROUTE_GRF(0, RK_PC7, 1, 0x0300, WRITE_MASK_VAL(10, 10, 1)), /* HDMITX IO mux M1 */
+       RK_MUXROUTE_GRF(0, RK_PB6, 1, 0x0300, WRITE_MASK_VAL(14, 14, 0)), /* I2C2 IO mux M0 */
        RK_MUXROUTE_GRF(4, RK_PB4, 1, 0x0300, WRITE_MASK_VAL(14, 14, 1)), /* I2C2 IO mux M1 */
        RK_MUXROUTE_GRF(1, RK_PA0, 1, 0x0304, WRITE_MASK_VAL(0, 0, 0)), /* I2C3 IO mux M0 */
        RK_MUXROUTE_GRF(3, RK_PB6, 4, 0x0304, WRITE_MASK_VAL(0, 0, 1)), /* I2C3 IO mux M1 */
@@ -964,7 +964,7 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = {
        RK_MUXROUTE_GRF(4, RK_PC3, 1, 0x0308, WRITE_MASK_VAL(12, 12, 1)), /* PWM15 IO mux M1 */
        RK_MUXROUTE_GRF(3, RK_PD2, 3, 0x0308, WRITE_MASK_VAL(14, 14, 0)), /* SDMMC2 IO mux M0 */
        RK_MUXROUTE_GRF(3, RK_PA5, 5, 0x0308, WRITE_MASK_VAL(14, 14, 1)), /* SDMMC2 IO mux M1 */
-       RK_MUXROUTE_PMU(0, RK_PB5, 2, 0x030c, WRITE_MASK_VAL(0, 0, 0)), /* SPI0 IO mux M0 */
+       RK_MUXROUTE_GRF(0, RK_PB5, 2, 0x030c, WRITE_MASK_VAL(0, 0, 0)), /* SPI0 IO mux M0 */
        RK_MUXROUTE_GRF(2, RK_PD3, 3, 0x030c, WRITE_MASK_VAL(0, 0, 1)), /* SPI0 IO mux M1 */
        RK_MUXROUTE_GRF(2, RK_PB5, 3, 0x030c, WRITE_MASK_VAL(2, 2, 0)), /* SPI1 IO mux M0 */
        RK_MUXROUTE_GRF(3, RK_PC3, 3, 0x030c, WRITE_MASK_VAL(2, 2, 1)), /* SPI1 IO mux M1 */
@@ -973,8 +973,8 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = {
        RK_MUXROUTE_GRF(4, RK_PB3, 4, 0x030c, WRITE_MASK_VAL(6, 6, 0)), /* SPI3 IO mux M0 */
        RK_MUXROUTE_GRF(4, RK_PC2, 2, 0x030c, WRITE_MASK_VAL(6, 6, 1)), /* SPI3 IO mux M1 */
        RK_MUXROUTE_GRF(2, RK_PB4, 2, 0x030c, WRITE_MASK_VAL(8, 8, 0)), /* UART1 IO mux M0 */
-       RK_MUXROUTE_PMU(0, RK_PD1, 1, 0x030c, WRITE_MASK_VAL(8, 8, 1)), /* UART1 IO mux M1 */
-       RK_MUXROUTE_PMU(0, RK_PD1, 1, 0x030c, WRITE_MASK_VAL(10, 10, 0)), /* UART2 IO mux M0 */
+       RK_MUXROUTE_GRF(3, RK_PD6, 4, 0x030c, WRITE_MASK_VAL(8, 8, 1)), /* UART1 IO mux M1 */
+       RK_MUXROUTE_GRF(0, RK_PD1, 1, 0x030c, WRITE_MASK_VAL(10, 10, 0)), /* UART2 IO mux M0 */
        RK_MUXROUTE_GRF(1, RK_PD5, 2, 0x030c, WRITE_MASK_VAL(10, 10, 1)), /* UART2 IO mux M1 */
        RK_MUXROUTE_GRF(1, RK_PA1, 2, 0x030c, WRITE_MASK_VAL(12, 12, 0)), /* UART3 IO mux M0 */
        RK_MUXROUTE_GRF(3, RK_PB7, 4, 0x030c, WRITE_MASK_VAL(12, 12, 1)), /* UART3 IO mux M1 */
@@ -1004,13 +1004,13 @@ static struct rockchip_mux_route_data rk3568_mux_route_data[] = {
        RK_MUXROUTE_GRF(3, RK_PD6, 5, 0x0314, WRITE_MASK_VAL(1, 0, 1)), /* PDM IO mux M1 */
        RK_MUXROUTE_GRF(4, RK_PA0, 4, 0x0314, WRITE_MASK_VAL(1, 0, 1)), /* PDM IO mux M1 */
        RK_MUXROUTE_GRF(3, RK_PC4, 5, 0x0314, WRITE_MASK_VAL(1, 0, 2)), /* PDM IO mux M2 */
-       RK_MUXROUTE_PMU(0, RK_PA5, 3, 0x0314, WRITE_MASK_VAL(3, 2, 0)), /* PCIE20 IO mux M0 */
+       RK_MUXROUTE_GRF(0, RK_PA5, 3, 0x0314, WRITE_MASK_VAL(3, 2, 0)), /* PCIE20 IO mux M0 */
        RK_MUXROUTE_GRF(2, RK_PD0, 4, 0x0314, WRITE_MASK_VAL(3, 2, 1)), /* PCIE20 IO mux M1 */
        RK_MUXROUTE_GRF(1, RK_PB0, 4, 0x0314, WRITE_MASK_VAL(3, 2, 2)), /* PCIE20 IO mux M2 */
-       RK_MUXROUTE_PMU(0, RK_PA4, 3, 0x0314, WRITE_MASK_VAL(5, 4, 0)), /* PCIE30X1 IO mux M0 */
+       RK_MUXROUTE_GRF(0, RK_PA4, 3, 0x0314, WRITE_MASK_VAL(5, 4, 0)), /* PCIE30X1 IO mux M0 */
        RK_MUXROUTE_GRF(2, RK_PD2, 4, 0x0314, WRITE_MASK_VAL(5, 4, 1)), /* PCIE30X1 IO mux M1 */
        RK_MUXROUTE_GRF(1, RK_PA5, 4, 0x0314, WRITE_MASK_VAL(5, 4, 2)), /* PCIE30X1 IO mux M2 */
-       RK_MUXROUTE_PMU(0, RK_PA6, 2, 0x0314, WRITE_MASK_VAL(7, 6, 0)), /* PCIE30X2 IO mux M0 */
+       RK_MUXROUTE_GRF(0, RK_PA6, 2, 0x0314, WRITE_MASK_VAL(7, 6, 0)), /* PCIE30X2 IO mux M0 */
        RK_MUXROUTE_GRF(2, RK_PD4, 4, 0x0314, WRITE_MASK_VAL(7, 6, 1)), /* PCIE30X2 IO mux M1 */
        RK_MUXROUTE_GRF(4, RK_PC2, 4, 0x0314, WRITE_MASK_VAL(7, 6, 2)), /* PCIE30X2 IO mux M2 */
 };
@@ -2436,10 +2436,19 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
        case RK3308:
        case RK3368:
        case RK3399:
+       case RK3568:
        case RK3588:
                pull_type = bank->pull_type[pin_num / 8];
                data >>= bit;
                data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
+               /*
+                * In the TRM, pull-up being 1 for everything except the GPIO0_D3-D6,
+                * where that pull up value becomes 3.
+                */
+               if (ctrl->type == RK3568 && bank->bank_num == 0 && pin_num >= 27 && pin_num <= 30) {
+                       if (data == 3)
+                               data = 1;
+               }
 
                return rockchip_pull_list[pull_type][data];
        default:
@@ -2497,7 +2506,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
                        }
                }
                /*
-                * In the TRM, pull-up being 1 for everything except the GPIO0_D0-D6,
+                * In the TRM, pull-up being 1 for everything except the GPIO0_D3-D6,
                 * where that pull up value becomes 3.
                 */
                if (ctrl->type == RK3568 && bank->bank_num == 0 && pin_num >= 27 && pin_num <= 30) {
index 99c3745..1909237 100644 (file)
@@ -372,6 +372,8 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
        if (!pcs->fmask)
                return 0;
        function = pinmux_generic_get_function(pctldev, fselector);
+       if (!function)
+               return -EINVAL;
        func = function->data;
        if (!func)
                return -EINVAL;
index c3c8c34..e22d03c 100644 (file)
@@ -105,7 +105,7 @@ static const struct pinctrl_pin_desc sm8450_lpi_pins[] = {
 static const char * const swr_tx_clk_groups[] = { "gpio0" };
 static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio14" };
 static const char * const swr_rx_clk_groups[] = { "gpio3" };
-static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5", "gpio15" };
+static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5" };
 static const char * const dmic1_clk_groups[] = { "gpio6" };
 static const char * const dmic1_data_groups[] = { "gpio7" };
 static const char * const dmic2_clk_groups[] = { "gpio8" };
index 2b3335a..2510129 100644 (file)
@@ -499,7 +499,6 @@ static int sppctl_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
        return 0;
 }
 
-#ifdef CONFIG_DEBUG_FS
 static void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
        const char *label;
@@ -521,7 +520,6 @@ static void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                seq_puts(s, "\n");
        }
 }
-#endif
 
 static int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pctl)
 {
@@ -550,9 +548,8 @@ static int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pc
        gchip->get              = sppctl_gpio_get;
        gchip->set              = sppctl_gpio_set;
        gchip->set_config       = sppctl_gpio_set_config;
-#ifdef CONFIG_DEBUG_FS
-       gchip->dbg_show         = sppctl_gpio_dbg_show;
-#endif
+       gchip->dbg_show         = IS_ENABLED(CONFIG_DEBUG_FS) ?
+                                 sppctl_gpio_dbg_show : NULL;
        gchip->base             = -1;
        gchip->ngpio            = sppctl_gpio_list_sz;
        gchip->names            = sppctl_gpio_list_s;
index 43e7651..c6537a1 100644 (file)
@@ -1700,8 +1700,10 @@ int ssam_request_sync(struct ssam_controller *ctrl,
                return status;
 
        status = ssam_request_sync_init(rqst, spec->flags);
-       if (status)
+       if (status) {
+               ssam_request_sync_free(rqst);
                return status;
+       }
 
        ssam_request_sync_set_resp(rqst, rsp);
 
index f556557..6913297 100644 (file)
@@ -916,6 +916,20 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data)
        if (sshp_parse_command(dev, data, &command, &command_data))
                return;
 
+       /*
+        * Check if the message was intended for us. If not, drop it.
+        *
+        * Note: We will need to change this to handle debug messages. On newer
+        * generation devices, these seem to be sent to tid_out=0x03. We as
+        * host can still receive them as they can be forwarded via an override
+        * option on SAM, but doing so does not change tid_out=0x00.
+        */
+       if (command->tid_out != 0x00) {
+               rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n",
+                        command->tid_out);
+               return;
+       }
+
        if (ssh_rqid_is_event(get_unaligned_le16(&command->rqid)))
                ssh_rtl_rx_event(rtl, command, &command_data);
        else
index a825af8..2ce8cb2 100644 (file)
@@ -8,6 +8,7 @@ source "drivers/platform/x86/amd/pmf/Kconfig"
 config AMD_PMC
        tristate "AMD SoC PMC driver"
        depends on ACPI && PCI && RTC_CLASS
+       select SERIO
        help
          The driver provides support for AMD Power Management Controller
          primarily responsible for S2Idle transactions that are driven from
index 439d282..3cbb01e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
+#include <linux/serio.h>
 #include <linux/suspend.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
@@ -160,6 +161,10 @@ static bool enable_stb;
 module_param(enable_stb, bool, 0644);
 MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism");
 
+static bool disable_workarounds;
+module_param(disable_workarounds, bool, 0644);
+MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
+
 static struct amd_pmc_dev pmc;
 static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret);
 static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf);
@@ -653,6 +658,33 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
        return -EINVAL;
 }
 
+static int amd_pmc_czn_wa_irq1(struct amd_pmc_dev *pdev)
+{
+       struct device *d;
+       int rc;
+
+       if (!pdev->major) {
+               rc = amd_pmc_get_smu_version(pdev);
+               if (rc)
+                       return rc;
+       }
+
+       if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65))
+               return 0;
+
+       d = bus_find_device_by_name(&serio_bus, NULL, "serio0");
+       if (!d)
+               return 0;
+       if (device_may_wakeup(d)) {
+               dev_info_once(d, "Disabling IRQ1 wakeup source to avoid platform firmware bug\n");
+               disable_irq_wake(1);
+               device_set_wakeup_enable(d, false);
+       }
+       put_device(d);
+
+       return 0;
+}
+
 static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
 {
        struct rtc_device *rtc_device;
@@ -715,8 +747,8 @@ static void amd_pmc_s2idle_prepare(void)
        /* Reset and Start SMU logging - to monitor the s0i3 stats */
        amd_pmc_setup_smu_logging(pdev);
 
-       /* Activate CZN specific RTC functionality */
-       if (pdev->cpu_id == AMD_CPU_ID_CZN) {
+       /* Activate CZN specific platform bug workarounds */
+       if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) {
                rc = amd_pmc_verify_czn_rtc(pdev, &arg);
                if (rc) {
                        dev_err(pdev->dev, "failed to set RTC: %d\n", rc);
@@ -782,6 +814,25 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
        .check = amd_pmc_s2idle_check,
        .restore = amd_pmc_s2idle_restore,
 };
+
+static int __maybe_unused amd_pmc_suspend_handler(struct device *dev)
+{
+       struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
+
+       if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) {
+               int rc = amd_pmc_czn_wa_irq1(pdev);
+
+               if (rc) {
+                       dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc);
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(amd_pmc_pm, amd_pmc_suspend_handler, NULL);
+
 #endif
 
 static const struct pci_device_id pmc_pci_ids[] = {
@@ -932,7 +983,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
        if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
                err = amd_pmc_s2d_init(dev);
                if (err)
-                       return err;
+                       goto err_pci_dev_put;
        }
 
        platform_set_drvdata(pdev, dev);
@@ -980,6 +1031,9 @@ static struct platform_driver amd_pmc_driver = {
                .name = "amd_pmc",
                .acpi_match_table = amd_pmc_acpi_ids,
                .dev_groups = pmc_groups,
+#ifdef CONFIG_SUSPEND
+               .pm = &amd_pmc_pm,
+#endif
        },
        .probe = amd_pmc_probe,
        .remove = amd_pmc_remove,
index 644af42..96a8e18 100644 (file)
@@ -275,13 +275,8 @@ int amd_pmf_reset_amt(struct amd_pmf_dev *dev)
         */
 
        if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
-               int mode = amd_pmf_get_pprof_modes(dev);
-
-               if (mode < 0)
-                       return mode;
-
                dev_dbg(dev->dev, "resetting AMT thermals\n");
-               amd_pmf_update_slider(dev, SLIDER_OP_SET, mode, NULL);
+               amd_pmf_set_sps_power_limits(dev);
        }
        return 0;
 }
@@ -299,7 +294,5 @@ void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev)
 void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev)
 {
        amd_pmf_load_defaults_auto_mode(dev);
-       /* update the thermal limits for Automode */
-       amd_pmf_set_automode(dev, config_store.current_mode, NULL);
        amd_pmf_init_metrics_table(dev);
 }
index 3f9731a..4beb22a 100644 (file)
@@ -103,7 +103,7 @@ int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_l
 
        src = amd_pmf_cnqf_get_power_source(dev);
 
-       if (dev->current_profile == PLATFORM_PROFILE_BALANCED) {
+       if (is_pprof_balanced(dev)) {
                amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
        } else {
                /*
@@ -307,13 +307,9 @@ static ssize_t cnqf_enable_store(struct device *dev,
                                 const char *buf, size_t count)
 {
        struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
-       int mode, result, src;
+       int result, src;
        bool input;
 
-       mode = amd_pmf_get_pprof_modes(pdev);
-       if (mode < 0)
-               return mode;
-
        result = kstrtobool(buf, &input);
        if (result)
                return result;
@@ -321,11 +317,11 @@ static ssize_t cnqf_enable_store(struct device *dev,
        src = amd_pmf_cnqf_get_power_source(pdev);
        pdev->cnqf_enabled = input;
 
-       if (pdev->cnqf_enabled && pdev->current_profile == PLATFORM_PROFILE_BALANCED) {
+       if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) {
                amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL);
        } else {
                if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
-                       amd_pmf_update_slider(pdev, SLIDER_OP_SET, mode, NULL);
+                       amd_pmf_set_sps_power_limits(pdev);
        }
 
        dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off");
@@ -386,7 +382,7 @@ int amd_pmf_init_cnqf(struct amd_pmf_dev *dev)
        dev->cnqf_enabled = amd_pmf_check_flags(dev);
 
        /* update the thermal for CnQF */
-       if (dev->cnqf_enabled && dev->current_profile == PLATFORM_PROFILE_BALANCED) {
+       if (dev->cnqf_enabled && is_pprof_balanced(dev)) {
                src = amd_pmf_cnqf_get_power_source(dev);
                amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
        }
index a5f5a4b..da23639 100644 (file)
@@ -58,6 +58,25 @@ static bool force_load;
 module_param(force_load, bool, 0444);
 MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
 
+static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
+{
+       struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
+
+       if (event != PSY_EVENT_PROP_CHANGED)
+               return NOTIFY_OK;
+
+       if (is_apmf_func_supported(pmf, APMF_FUNC_AUTO_MODE) ||
+           is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_DC) ||
+           is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_AC)) {
+               if ((pmf->amt_enabled || pmf->cnqf_enabled) && is_pprof_balanced(pmf))
+                       return NOTIFY_DONE;
+       }
+
+       amd_pmf_set_sps_power_limits(pmf);
+
+       return NOTIFY_OK;
+}
+
 static int current_power_limits_show(struct seq_file *seq, void *unused)
 {
        struct amd_pmf_dev *dev = seq->private;
@@ -366,14 +385,18 @@ static int amd_pmf_probe(struct platform_device *pdev)
        if (!dev->regbase)
                return -ENOMEM;
 
+       mutex_init(&dev->lock);
+       mutex_init(&dev->update_mutex);
+
        apmf_acpi_init(dev);
        platform_set_drvdata(pdev, dev);
        amd_pmf_init_features(dev);
        apmf_install_handler(dev);
        amd_pmf_dbgfs_register(dev);
 
-       mutex_init(&dev->lock);
-       mutex_init(&dev->update_mutex);
+       dev->pwr_src_notifier.notifier_call = amd_pmf_pwr_src_notify_call;
+       power_supply_reg_notifier(&dev->pwr_src_notifier);
+
        dev_info(dev->dev, "registered PMF device successfully\n");
 
        return 0;
@@ -383,11 +406,12 @@ static int amd_pmf_remove(struct platform_device *pdev)
 {
        struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
 
-       mutex_destroy(&dev->lock);
-       mutex_destroy(&dev->update_mutex);
+       power_supply_unreg_notifier(&dev->pwr_src_notifier);
        amd_pmf_deinit_features(dev);
        apmf_acpi_deinit(dev);
        amd_pmf_dbgfs_unregister(dev);
+       mutex_destroy(&dev->lock);
+       mutex_destroy(&dev->update_mutex);
        kfree(dev->buf);
        return 0;
 }
index 84bbe2c..06c30cd 100644 (file)
@@ -169,6 +169,7 @@ struct amd_pmf_dev {
        struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */
        bool cnqf_enabled;
        bool cnqf_supported;
+       struct notifier_block pwr_src_notifier;
 };
 
 struct apmf_sps_prop_granular {
@@ -391,9 +392,11 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev);
 void amd_pmf_deinit_sps(struct amd_pmf_dev *dev);
 int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
                                    struct apmf_static_slider_granular_output *output);
+bool is_pprof_balanced(struct amd_pmf_dev *pmf);
 
 
 int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx);
+int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf);
 
 /* Auto Mode Layer */
 int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data);
index dba7e36..bed762d 100644 (file)
@@ -70,6 +70,24 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
        }
 }
 
+int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf)
+{
+       int mode;
+
+       mode = amd_pmf_get_pprof_modes(pmf);
+       if (mode < 0)
+               return mode;
+
+       amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
+
+       return 0;
+}
+
+bool is_pprof_balanced(struct amd_pmf_dev *pmf)
+{
+       return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false;
+}
+
 static int amd_pmf_profile_get(struct platform_profile_handler *pprof,
                               enum platform_profile_option *profile)
 {
@@ -105,15 +123,10 @@ static int amd_pmf_profile_set(struct platform_profile_handler *pprof,
                               enum platform_profile_option profile)
 {
        struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
-       int mode;
 
        pmf->current_profile = profile;
-       mode = amd_pmf_get_pprof_modes(pmf);
-       if (mode < 0)
-               return mode;
 
-       amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
-       return 0;
+       return amd_pmf_set_sps_power_limits(pmf);
 }
 
 int amd_pmf_init_sps(struct amd_pmf_dev *dev)
@@ -123,6 +136,9 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev)
        dev->current_profile = PLATFORM_PROFILE_BALANCED;
        amd_pmf_load_defaults_sps(dev);
 
+       /* update SPS balanced power mode thermals */
+       amd_pmf_set_sps_power_limits(dev);
+
        dev->pprof.profile_get = amd_pmf_profile_get;
        dev->pprof.profile_set = amd_pmf_profile_set;
 
index ca33df7..9333f82 100644 (file)
@@ -64,29 +64,6 @@ struct apple_gmux_data {
 
 static struct apple_gmux_data *apple_gmux_data;
 
-/*
- * gmux port offsets. Many of these are not yet used, but may be in the
- * future, and it's useful to have them documented here anyhow.
- */
-#define GMUX_PORT_VERSION_MAJOR                0x04
-#define GMUX_PORT_VERSION_MINOR                0x05
-#define GMUX_PORT_VERSION_RELEASE      0x06
-#define GMUX_PORT_SWITCH_DISPLAY       0x10
-#define GMUX_PORT_SWITCH_GET_DISPLAY   0x11
-#define GMUX_PORT_INTERRUPT_ENABLE     0x14
-#define GMUX_PORT_INTERRUPT_STATUS     0x16
-#define GMUX_PORT_SWITCH_DDC           0x28
-#define GMUX_PORT_SWITCH_EXTERNAL      0x40
-#define GMUX_PORT_SWITCH_GET_EXTERNAL  0x41
-#define GMUX_PORT_DISCRETE_POWER       0x50
-#define GMUX_PORT_MAX_BRIGHTNESS       0x70
-#define GMUX_PORT_BRIGHTNESS           0x74
-#define GMUX_PORT_VALUE                        0xc2
-#define GMUX_PORT_READ                 0xd0
-#define GMUX_PORT_WRITE                        0xd4
-
-#define GMUX_MIN_IO_LEN                        (GMUX_PORT_BRIGHTNESS + 4)
-
 #define GMUX_INTERRUPT_ENABLE          0xff
 #define GMUX_INTERRUPT_DISABLE         0x00
 
@@ -249,23 +226,6 @@ static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
                gmux_pio_write32(gmux_data, port, val);
 }
 
-static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
-{
-       u16 val;
-
-       outb(0xaa, gmux_data->iostart + 0xcc);
-       outb(0x55, gmux_data->iostart + 0xcd);
-       outb(0x00, gmux_data->iostart + 0xce);
-
-       val = inb(gmux_data->iostart + 0xcc) |
-               (inb(gmux_data->iostart + 0xcd) << 8);
-
-       if (val == 0x55aa)
-               return true;
-
-       return false;
-}
-
 /**
  * DOC: Backlight control
  *
@@ -605,60 +565,43 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
        int ret = -ENXIO;
        acpi_status status;
        unsigned long long gpe;
+       bool indexed = false;
+       u32 version;
 
        if (apple_gmux_data)
                return -EBUSY;
 
+       if (!apple_gmux_detect(pnp, &indexed)) {
+               pr_info("gmux device not present\n");
+               return -ENODEV;
+       }
+
        gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
        if (!gmux_data)
                return -ENOMEM;
        pnp_set_drvdata(pnp, gmux_data);
 
        res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
-       if (!res) {
-               pr_err("Failed to find gmux I/O resource\n");
-               goto err_free;
-       }
-
        gmux_data->iostart = res->start;
        gmux_data->iolen = resource_size(res);
 
-       if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
-               pr_err("gmux I/O region too small (%lu < %u)\n",
-                      gmux_data->iolen, GMUX_MIN_IO_LEN);
-               goto err_free;
-       }
-
        if (!request_region(gmux_data->iostart, gmux_data->iolen,
                            "Apple gmux")) {
                pr_err("gmux I/O already in use\n");
                goto err_free;
        }
 
-       /*
-        * Invalid version information may indicate either that the gmux
-        * device isn't present or that it's a new one that uses indexed
-        * io
-        */
-
-       ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
-       ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
-       ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
-       if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
-               if (gmux_is_indexed(gmux_data)) {
-                       u32 version;
-                       mutex_init(&gmux_data->index_lock);
-                       gmux_data->indexed = true;
-                       version = gmux_read32(gmux_data,
-                               GMUX_PORT_VERSION_MAJOR);
-                       ver_major = (version >> 24) & 0xff;
-                       ver_minor = (version >> 16) & 0xff;
-                       ver_release = (version >> 8) & 0xff;
-               } else {
-                       pr_info("gmux device not present\n");
-                       ret = -ENODEV;
-                       goto err_release;
-               }
+       if (indexed) {
+               mutex_init(&gmux_data->index_lock);
+               gmux_data->indexed = true;
+               version = gmux_read32(gmux_data, GMUX_PORT_VERSION_MAJOR);
+               ver_major = (version >> 24) & 0xff;
+               ver_minor = (version >> 16) & 0xff;
+               ver_release = (version >> 8) & 0xff;
+       } else {
+               ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
+               ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
+               ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
        }
        pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
                ver_release, (gmux_data->indexed ? "indexed" : "classic"));
index c685a70..cb15acd 100644 (file)
@@ -121,6 +121,10 @@ static struct quirk_entry quirk_asus_tablet_mode = {
        .tablet_switch_mode = asus_wmi_lid_flip_rog_devid,
 };
 
+static struct quirk_entry quirk_asus_ignore_fan = {
+       .wmi_ignore_fan = true,
+};
+
 static int dmi_matched(const struct dmi_system_id *dmi)
 {
        pr_info("Identified laptop model '%s'\n", dmi->ident);
@@ -473,6 +477,15 @@ static const struct dmi_system_id asus_quirks[] = {
                },
                .driver_data = &quirk_asus_tablet_mode,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUS VivoBook E410MA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "E410MA"),
+               },
+               .driver_data = &quirk_asus_ignore_fan,
+       },
        {},
 };
 
@@ -511,6 +524,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x30, { KEY_VOLUMEUP } },
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
        { KE_KEY, 0x32, { KEY_MUTE } },
+       { KE_KEY, 0x33, { KEY_SCREENLOCK } },
        { KE_KEY, 0x35, { KEY_SCREENLOCK } },
        { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */
        { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
@@ -544,6 +558,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
        { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
        { KE_KEY, 0x82, { KEY_CAMERA } },
+       { KE_KEY, 0x85, { KEY_CAMERA } },
        { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */
        { KE_KEY, 0x88, { KEY_RFKILL  } }, /* Radio Toggle Key */
        { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
index 6f81b28..1038dfd 100644 (file)
@@ -225,6 +225,7 @@ struct asus_wmi {
 
        int tablet_switch_event_code;
        u32 tablet_switch_dev_id;
+       bool tablet_switch_inverted;
 
        enum fan_type fan_type;
        enum fan_type gpu_fan_type;
@@ -493,6 +494,13 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
 }
 
 /* Input **********************************************************************/
+static void asus_wmi_tablet_sw_report(struct asus_wmi *asus, bool value)
+{
+       input_report_switch(asus->inputdev, SW_TABLET_MODE,
+                           asus->tablet_switch_inverted ? !value : value);
+       input_sync(asus->inputdev);
+}
+
 static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code)
 {
        struct device *dev = &asus->platform_device->dev;
@@ -501,7 +509,7 @@ static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event
        result = asus_wmi_get_devstate_simple(asus, dev_id);
        if (result >= 0) {
                input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
-               input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+               asus_wmi_tablet_sw_report(asus, result);
                asus->tablet_switch_dev_id = dev_id;
                asus->tablet_switch_event_code = event_code;
        } else if (result == -ENODEV) {
@@ -534,6 +542,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
        case asus_wmi_no_tablet_switch:
                break;
        case asus_wmi_kbd_dock_devid:
+               asus->tablet_switch_inverted = true;
                asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE);
                break;
        case asus_wmi_lid_flip_devid:
@@ -573,10 +582,8 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
                return;
 
        result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id);
-       if (result >= 0) {
-               input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
-               input_sync(asus->inputdev);
-       }
+       if (result >= 0)
+               asus_wmi_tablet_sw_report(asus, result);
 }
 
 /* dGPU ********************************************************************/
@@ -2243,7 +2250,9 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
        asus->fan_type = FAN_TYPE_NONE;
        asus->agfn_pwm = -1;
 
-       if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
+       if (asus->driver->quirks->wmi_ignore_fan)
+               asus->fan_type = FAN_TYPE_NONE;
+       else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
                asus->fan_type = FAN_TYPE_SPEC83;
        else if (asus_wmi_has_agfn_fan(asus))
                asus->fan_type = FAN_TYPE_AGFN;
@@ -2436,6 +2445,9 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available,
 
        *available = false;
 
+       if (asus->fan_type == FAN_TYPE_NONE)
+               return 0;
+
        err = fan_curve_get_factory_default(asus, fan_dev);
        if (err) {
                return 0;
index 6531699..a478ebf 100644 (file)
@@ -38,6 +38,7 @@ struct quirk_entry {
        bool store_backlight_power;
        bool wmi_backlight_set_devstate;
        bool wmi_force_als_set;
+       bool wmi_ignore_fan;
        enum asus_wmi_tablet_switch_mode tablet_switch_mode;
        int wapf;
        /*
index 0a259a2..502783a 100644 (file)
@@ -261,6 +261,9 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = {
        { KE_KEY,    0x57, { KEY_BRIGHTNESSDOWN } },
        { KE_KEY,    0x58, { KEY_BRIGHTNESSUP } },
 
+       /*Speaker Mute*/
+       { KE_KEY, 0x109, { KEY_MUTE} },
+
        /* Mic mute */
        { KE_KEY, 0x150, { KEY_MICMUTE } },
 
index c82b3d6..c517bd4 100644 (file)
@@ -61,7 +61,7 @@ static const struct key_entry dell_wmi_keymap_type_0012[] = {
        /* privacy mic mute */
        { KE_KEY, 0x0001, { KEY_MICMUTE } },
        /* privacy camera mute */
-       { KE_SW,  0x0002, { SW_CAMERA_LENS_COVER } },
+       { KE_VSW, 0x0002, { SW_CAMERA_LENS_COVER } },
        { KE_END, 0},
 };
 
@@ -115,11 +115,15 @@ bool dell_privacy_process_event(int type, int code, int status)
 
        switch (code) {
        case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */
-       case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
                priv->last_status = status;
                sparse_keymap_report_entry(priv->input_dev, key, 1, true);
                ret = true;
                break;
+       case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
+               priv->last_status = status;
+               sparse_keymap_report_entry(priv->input_dev, key, !(status & CAMERA_STATUS), false);
+               ret = true;
+               break;
        default:
                dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code);
        }
@@ -292,7 +296,7 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
 {
        struct privacy_wmi_data *priv;
        struct key_entry *keymap;
-       int ret, i;
+       int ret, i, j;
 
        ret = wmi_has_guid(DELL_PRIVACY_GUID);
        if (!ret)
@@ -304,6 +308,11 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
 
        dev_set_drvdata(&wdev->dev, priv);
        priv->wdev = wdev;
+
+       ret = get_current_status(priv->wdev);
+       if (ret)
+               return ret;
+
        /* create evdev passing interface */
        priv->input_dev = devm_input_allocate_device(&wdev->dev);
        if (!priv->input_dev)
@@ -318,9 +327,20 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
        /* remap the keymap code with Dell privacy key type 0x12 as prefix
         * KEY_MICMUTE scancode will be reported as 0x120001
         */
-       for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
-               keymap[i] = dell_wmi_keymap_type_0012[i];
-               keymap[i].code |= (0x0012 << 16);
+       for (i = 0, j = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
+               /*
+                * Unlike keys where only presses matter, userspace may act
+                * on switches in both of their positions. Only register
+                * SW_CAMERA_LENS_COVER if it is actually there.
+                */
+               if (dell_wmi_keymap_type_0012[i].type == KE_VSW &&
+                   dell_wmi_keymap_type_0012[i].sw.code == SW_CAMERA_LENS_COVER &&
+                   !(priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA)))
+                       continue;
+
+               keymap[j] = dell_wmi_keymap_type_0012[i];
+               keymap[j].code |= (0x0012 << 16);
+               j++;
        }
        ret = sparse_keymap_setup(priv->input_dev, keymap, NULL);
        kfree(keymap);
@@ -331,11 +351,12 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
        priv->input_dev->name = "Dell Privacy Driver";
        priv->input_dev->id.bustype = BUS_HOST;
 
-       ret = input_register_device(priv->input_dev);
-       if (ret)
-               return ret;
+       /* Report initial camera-cover status */
+       if (priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA))
+               input_report_switch(priv->input_dev, SW_CAMERA_LENS_COVER,
+                                   !(priv->last_status & CAMERA_STATUS));
 
-       ret = get_current_status(priv->wdev);
+       ret = input_register_device(priv->input_dev);
        if (ret)
                return ret;
 
index 5e7e665..322cfae 100644 (file)
@@ -141,6 +141,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev)
 
 static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H-CF"),
+       DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H WIFI-CF"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE AX V2"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"),
index 0a99058..2ef201b 100644 (file)
@@ -90,6 +90,7 @@ enum hp_wmi_event_ids {
        HPWMI_PEAKSHIFT_PERIOD          = 0x0F,
        HPWMI_BATTERY_CHARGE_PERIOD     = 0x10,
        HPWMI_SANITIZATION_MODE         = 0x17,
+       HPWMI_OMEN_KEY                  = 0x1D,
        HPWMI_SMART_EXPERIENCE_APP      = 0x21,
 };
 
@@ -216,6 +217,8 @@ static const struct key_entry hp_wmi_keymap[] = {
        { KE_KEY, 0x213b,  { KEY_INFO } },
        { KE_KEY, 0x2169,  { KEY_ROTATE_DISPLAY } },
        { KE_KEY, 0x216a,  { KEY_SETUP } },
+       { KE_KEY, 0x21a5,  { KEY_PROG2 } }, /* HP Omen Key */
+       { KE_KEY, 0x21a7,  { KEY_FN_ESC } },
        { KE_KEY, 0x21a9,  { KEY_TOUCHPAD_OFF } },
        { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
        { KE_KEY, 0x231b,  { KEY_HELP } },
@@ -548,7 +551,7 @@ static int __init hp_wmi_enable_hotkeys(void)
 
 static int hp_wmi_set_block(void *data, bool blocked)
 {
-       enum hp_wmi_radio r = (enum hp_wmi_radio) data;
+       enum hp_wmi_radio r = (long)data;
        int query = BIT(r + 8) | ((!blocked) << r);
        int ret;
 
@@ -810,6 +813,7 @@ static void hp_wmi_notify(u32 value, void *context)
        case HPWMI_SMART_ADAPTER:
                break;
        case HPWMI_BEZEL_BUTTON:
+       case HPWMI_OMEN_KEY:
                key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
                if (key_code < 0)
                        break;
index 435d2d3..0eb5bfd 100644 (file)
@@ -1621,6 +1621,12 @@ static const struct dmi_system_id set_fn_lock_led_list[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"),
                }
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion 5 15ARH05"),
+               }
+       },
        {}
 };
 
index b2342b3..74dc2cf 100644 (file)
@@ -181,6 +181,9 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
                return PTR_ERR(int3472->regulator.gpio);
        }
 
+       /* Ensure the pin is in output mode and non-active state */
+       gpiod_direction_output(int3472->regulator.gpio, 0);
+
        cfg.dev = &int3472->adev->dev;
        cfg.init_data = &init_data;
        cfg.ena_gpiod = int3472->regulator.gpio;
index 974a132..c42c3fa 100644 (file)
@@ -168,6 +168,8 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
                        return (PTR_ERR(gpio));
 
                int3472->clock.ena_gpio = gpio;
+               /* Ensure the pin is in output mode and non-active state */
+               gpiod_direction_output(int3472->clock.ena_gpio, 0);
                break;
        case INT3472_GPIO_TYPE_PRIVACY_LED:
                gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
@@ -175,6 +177,8 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
                        return (PTR_ERR(gpio));
 
                int3472->clock.led_gpio = gpio;
+               /* Ensure the pin is in output mode and non-active state */
+               gpiod_direction_output(int3472->clock.led_gpio, 0);
                break;
        default:
                dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
index f1d802f..3a15d32 100644 (file)
@@ -1029,6 +1029,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE,          adl_core_init),
        X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S,        adl_core_init),
        X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE,          mtl_core_init),
+       X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L,        mtl_core_init),
        {}
 };
 
index ca76076..b362241 100644 (file)
@@ -46,7 +46,8 @@ static struct {
        {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE},
        {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E},
        {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E},
-       {SIMATIC_IPC_IPC427G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
+       {SIMATIC_IPC_IPCBX_39A, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
+       {SIMATIC_IPC_IPCPX_39A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G},
 };
 
 static int register_platform_devices(u32 station_id)
index 7156ae2..537d6a2 100644 (file)
@@ -1887,14 +1887,21 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
                break;
        }
 
-       ret = sony_call_snc_handle(handle, probe_base, &result);
-       if (ret)
-               return ret;
+       /*
+        * Only probe if there is a separate probe_base, otherwise the probe call
+        * is equivalent to __sony_nc_kbd_backlight_mode_set(0), resulting in
+        * the keyboard backlight being turned off.
+        */
+       if (probe_base) {
+               ret = sony_call_snc_handle(handle, probe_base, &result);
+               if (ret)
+                       return ret;
 
-       if ((handle == 0x0137 && !(result & 0x02)) ||
-                       !(result & 0x01)) {
-               dprintk("no backlight keyboard found\n");
-               return 0;
+               if ((handle == 0x0137 && !(result & 0x02)) ||
+                               !(result & 0x01)) {
+                       dprintk("no backlight keyboard found\n");
+                       return 0;
+               }
        }
 
        kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
index 1195293..32c1045 100644 (file)
@@ -5563,7 +5563,7 @@ static int light_sysfs_set(struct led_classdev *led_cdev,
 
 static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
 {
-       return (light_get_status() == 1) ? LED_FULL : LED_OFF;
+       return (light_get_status() == 1) ? LED_ON : LED_OFF;
 }
 
 static struct tpacpi_led_classdev tpacpi_led_thinklight = {
@@ -10311,9 +10311,11 @@ static DEFINE_MUTEX(dytc_mutex);
 static int dytc_capabilities;
 static bool dytc_mmc_get_available;
 
-static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
+static int convert_dytc_to_profile(int funcmode, int dytcmode,
+               enum platform_profile_option *profile)
 {
-       if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
+       switch (funcmode) {
+       case DYTC_FUNCTION_MMC:
                switch (dytcmode) {
                case DYTC_MODE_MMC_LOWPOWER:
                        *profile = PLATFORM_PROFILE_LOW_POWER;
@@ -10329,8 +10331,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
                        return -EINVAL;
                }
                return 0;
-       }
-       if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
+       case DYTC_FUNCTION_PSC:
                switch (dytcmode) {
                case DYTC_MODE_PSC_LOWPOWER:
                        *profile = PLATFORM_PROFILE_LOW_POWER;
@@ -10344,6 +10345,14 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
                default: /* Unknown mode */
                        return -EINVAL;
                }
+               return 0;
+       case DYTC_FUNCTION_AMT:
+               /* For now return balanced. It's the closest we have to 'auto' */
+               *profile =  PLATFORM_PROFILE_BALANCED;
+               return 0;
+       default:
+               /* Unknown function */
+               return -EOPNOTSUPP;
        }
        return 0;
 }
@@ -10487,11 +10496,11 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
                        if (err)
                                goto unlock;
                }
-       }
-       if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
+       } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
                err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
                if (err)
                        goto unlock;
+
                /* system supports AMT, activate it when on balanced */
                if (dytc_capabilities & BIT(DYTC_FC_AMT))
                        dytc_control_amt(profile == PLATFORM_PROFILE_BALANCED);
@@ -10507,7 +10516,7 @@ static void dytc_profile_refresh(void)
 {
        enum platform_profile_option profile;
        int output, err = 0;
-       int perfmode;
+       int perfmode, funcmode;
 
        mutex_lock(&dytc_mutex);
        if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
@@ -10515,15 +10524,18 @@ static void dytc_profile_refresh(void)
                        err = dytc_command(DYTC_CMD_MMC_GET, &output);
                else
                        err = dytc_cql_command(DYTC_CMD_GET, &output);
-       } else if (dytc_capabilities & BIT(DYTC_FC_PSC))
+               funcmode = DYTC_FUNCTION_MMC;
+       } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
                err = dytc_command(DYTC_CMD_GET, &output);
-
+               /* Check if we are PSC mode, or have AMT enabled */
+               funcmode = (output >> DYTC_GET_FUNCTION_BIT) & 0xF;
+       }
        mutex_unlock(&dytc_mutex);
        if (err)
                return;
 
        perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
-       convert_dytc_to_profile(perfmode, &profile);
+       convert_dytc_to_profile(funcmode, perfmode, &profile);
        if (profile != dytc_current_profile) {
                dytc_current_profile = profile;
                platform_profile_notify();
index baae312..13802a3 100644 (file)
@@ -264,6 +264,23 @@ static const struct ts_dmi_data connect_tablet9_data = {
        .properties     = connect_tablet9_props,
 };
 
+static const struct property_entry csl_panther_tab_hd_props[] = {
+       PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
+       PROPERTY_ENTRY_U32("touchscreen-min-y", 20),
+       PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
+       PROPERTY_ENTRY_U32("touchscreen-size-y", 1526),
+       PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+       PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+       PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-csl-panther-tab-hd.fw"),
+       PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+       { }
+};
+
+static const struct ts_dmi_data csl_panther_tab_hd_data = {
+       .acpi_name      = "MSSL1680:00",
+       .properties     = csl_panther_tab_hd_props,
+};
+
 static const struct property_entry cube_iwork8_air_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
        PROPERTY_ENTRY_U32("touchscreen-min-y", 3),
@@ -1080,6 +1097,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_BIOS_DATE, "05/07/2016"),
                },
        },
+       {
+               /* Chuwi Vi8 (CWI501) */
+               .driver_data = (void *)&chuwi_vi8_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "i86"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.W86JLBNR01"),
+               },
+       },
        {
                /* Chuwi Vi8 (CWI506) */
                .driver_data = (void *)&chuwi_vi8_data,
@@ -1124,6 +1150,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Tablet 9"),
                },
        },
+       {
+               /* CSL Panther Tab HD */
+               .driver_data = (void *)&csl_panther_tab_hd_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CSL Computer GmbH & Co. KG"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CSL Panther Tab HD"),
+               },
+       },
        {
                /* CUBE iwork8 Air */
                .driver_data = (void *)&cube_iwork8_air_data,
index e01b32d..00828f5 100644 (file)
@@ -498,6 +498,12 @@ static int da9211_i2c_probe(struct i2c_client *i2c)
 
        chip->chip_irq = i2c->irq;
 
+       ret = da9211_regulator_init(chip);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret);
+               return ret;
+       }
+
        if (chip->chip_irq != 0) {
                ret = devm_request_threaded_irq(chip->dev, chip->chip_irq, NULL,
                                        da9211_irq_handler,
@@ -512,11 +518,6 @@ static int da9211_i2c_probe(struct i2c_client *i2c)
                dev_warn(chip->dev, "No IRQ configured\n");
        }
 
-       ret = da9211_regulator_init(chip);
-
-       if (ret < 0)
-               dev_err(chip->dev, "Failed to initialize regulator: %d\n", ret);
-
        return ret;
 }
 
index 43b5b93..ae60213 100644 (file)
@@ -1016,7 +1016,7 @@ static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
        RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_pldo_lv, "vdd-l8-l9"),
        RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_pldo,    "vdd-l8-l9"),
        RPMH_VREG("ldo10",  "ldo%s10", &pmic5_nldo,    "vdd-l1-l4-l10"),
-       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_pldo,    "vdd-l11"),
+       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_nldo,    "vdd-l11"),
        RPMH_VREG("ldo12",  "ldo%s12", &pmic5_pldo,    "vdd-l12"),
        RPMH_VREG("ldo13",  "ldo%s13", &pmic5_pldo,    "vdd-l2-l13-l14"),
        RPMH_VREG("ldo14",  "ldo%s14", &pmic5_pldo,    "vdd-l2-l13-l14"),
index de176c2..2a52c99 100644 (file)
@@ -257,7 +257,7 @@ config RESET_SUNXI
 
 config RESET_TI_SCI
        tristate "TI System Control Interface (TI-SCI) reset driver"
-       depends on TI_SCI_PROTOCOL || COMPILE_TEST
+       depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n)
        help
          This enables the reset driver support over TI System Control Interface
          available on some new TI's SoCs. If you wish to use reset resources
index 146fd5d..15abac9 100644 (file)
@@ -47,7 +47,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct uniphier_glue_reset_priv *priv;
        struct resource *res;
-       resource_size_t size;
        int i, ret;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -60,7 +59,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev)
                return -EINVAL;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       size = resource_size(res);
        priv->rdata.membase = devm_ioremap_resource(dev, res);
        if (IS_ERR(priv->rdata.membase))
                return PTR_ERR(priv->rdata.membase);
@@ -96,7 +94,7 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev)
 
        spin_lock_init(&priv->rdata.lock);
        priv->rdata.rcdev.owner = THIS_MODULE;
-       priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE;
+       priv->rdata.rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE;
        priv->rdata.rcdev.ops = &reset_simple_ops;
        priv->rdata.rcdev.of_node = dev->of_node;
        priv->rdata.active_low = true;
index e991ccc..1e8bc6c 100644 (file)
@@ -188,9 +188,10 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
 
 static int efi_procfs(struct device *dev, struct seq_file *seq)
 {
-       efi_time_t      eft, alm;
-       efi_time_cap_t  cap;
-       efi_bool_t      enabled, pending;
+       efi_time_t        eft, alm;
+       efi_time_cap_t    cap;
+       efi_bool_t        enabled, pending;
+       struct rtc_device *rtc = dev_get_drvdata(dev);
 
        memset(&eft, 0, sizeof(eft));
        memset(&alm, 0, sizeof(alm));
@@ -213,23 +214,25 @@ static int efi_procfs(struct device *dev, struct seq_file *seq)
                /* XXX fixme: convert to string? */
                seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
 
-       seq_printf(seq,
-                  "Alarm Time\t: %u:%u:%u.%09u\n"
-                  "Alarm Date\t: %u-%u-%u\n"
-                  "Alarm Daylight\t: %u\n"
-                  "Enabled\t\t: %s\n"
-                  "Pending\t\t: %s\n",
-                  alm.hour, alm.minute, alm.second, alm.nanosecond,
-                  alm.year, alm.month, alm.day,
-                  alm.daylight,
-                  enabled == 1 ? "yes" : "no",
-                  pending == 1 ? "yes" : "no");
-
-       if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
-               seq_puts(seq, "Timezone\t: unspecified\n");
-       else
-               /* XXX fixme: convert to string? */
-               seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
+       if (test_bit(RTC_FEATURE_ALARM, rtc->features)) {
+               seq_printf(seq,
+                          "Alarm Time\t: %u:%u:%u.%09u\n"
+                          "Alarm Date\t: %u-%u-%u\n"
+                          "Alarm Daylight\t: %u\n"
+                          "Enabled\t\t: %s\n"
+                          "Pending\t\t: %s\n",
+                          alm.hour, alm.minute, alm.second, alm.nanosecond,
+                          alm.year, alm.month, alm.day,
+                          alm.daylight,
+                          enabled == 1 ? "yes" : "no",
+                          pending == 1 ? "yes" : "no");
+
+               if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+                       seq_puts(seq, "Timezone\t: unspecified\n");
+               else
+                       /* XXX fixme: convert to string? */
+                       seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
+       }
 
        /*
         * now prints the capabilities
@@ -269,7 +272,10 @@ static int __init efi_rtc_probe(struct platform_device *dev)
 
        rtc->ops = &efi_rtc_ops;
        clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
-       set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features);
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_WAKEUP_SERVICES))
+               set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, rtc->features);
+       else
+               clear_bit(RTC_FEATURE_ALARM, rtc->features);
 
        device_init_wakeup(&dev->dev, true);
 
index e8e2ab1..4b578e4 100644 (file)
@@ -240,8 +240,8 @@ static int sp_rtc_probe(struct platform_device *plat_dev)
        if (IS_ERR(sp_rtc->reg_base))
                return dev_err_probe(&plat_dev->dev, PTR_ERR(sp_rtc->reg_base),
                                            "%s devm_ioremap_resource fail\n", RTC_REG_NAME);
-       dev_dbg(&plat_dev->dev, "res = 0x%x, reg_base = 0x%lx\n",
-               sp_rtc->res->start, (unsigned long)sp_rtc->reg_base);
+       dev_dbg(&plat_dev->dev, "res = %pR, reg_base = %p\n",
+               sp_rtc->ressp_rtc->reg_base);
 
        sp_rtc->irq = platform_get_irq(plat_dev, 0);
        if (sp_rtc->irq < 0)
index 49cc18a..29a2865 100644 (file)
@@ -981,6 +981,9 @@ queue_rtpg:
  *
  * Returns true if and only if alua_rtpg_work() will be called asynchronously.
  * That function is responsible for calling @qdata->fn().
+ *
+ * Context: may be called from atomic context (alua_check()) only if the caller
+ *     holds an sdev reference.
  */
 static bool alua_rtpg_queue(struct alua_port_group *pg,
                            struct scsi_device *sdev,
@@ -989,8 +992,6 @@ static bool alua_rtpg_queue(struct alua_port_group *pg,
        int start_queue = 0;
        unsigned long flags;
 
-       might_sleep();
-
        if (WARN_ON_ONCE(!pg) || scsi_device_get(sdev))
                return false;
 
index 41ba22f..8c038cc 100644 (file)
@@ -162,7 +162,7 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
 static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
 {
        if (hisi_hba->hw->slot_index_alloc ||
-           slot_idx >= HISI_SAS_UNRESERVED_IPTT) {
+           slot_idx < HISI_SAS_RESERVED_IPTT) {
                spin_lock(&hisi_hba->lock);
                hisi_sas_slot_index_clear(hisi_hba, slot_idx);
                spin_unlock(&hisi_hba->lock);
@@ -704,7 +704,7 @@ static int hisi_sas_init_device(struct domain_device *device)
                int_to_scsilun(0, &lun);
 
                while (retry-- > 0) {
-                       rc = sas_clear_task_set(device, lun.scsi_lun);
+                       rc = sas_abort_task_set(device, lun.scsi_lun);
                        if (rc == TMF_RESP_FUNC_COMPLETE) {
                                hisi_sas_release_task(hisi_hba, device);
                                break;
@@ -1316,7 +1316,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba)
                                device->linkrate = phy->sas_phy.linkrate;
 
                        hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
-               } else
+               } else if (!port->port_attached)
                        port->id = 0xff;
        }
 }
index 4dbf51e..f6da348 100644 (file)
@@ -5850,7 +5850,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h)
 {
        struct Scsi_Host *sh;
 
-       sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
+       sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info));
        if (sh == NULL) {
                dev_err(&h->pdev->dev, "scsi_host_alloc failed\n");
                return -ENOMEM;
index 1d1cf64..0454d94 100644 (file)
@@ -849,7 +849,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
                                       enum iscsi_host_param param, char *buf)
 {
        struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
-       struct iscsi_session *session = tcp_sw_host->session;
+       struct iscsi_session *session;
        struct iscsi_conn *conn;
        struct iscsi_tcp_conn *tcp_conn;
        struct iscsi_sw_tcp_conn *tcp_sw_conn;
@@ -859,6 +859,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
 
        switch (param) {
        case ISCSI_HOST_PARAM_IPADDRESS:
+               session = tcp_sw_host->session;
                if (!session)
                        return -ENOTCONN;
 
@@ -959,11 +960,13 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
        if (!cls_session)
                goto remove_host;
        session = cls_session->dd_data;
-       tcp_sw_host = iscsi_host_priv(shost);
-       tcp_sw_host->session = session;
 
        if (iscsi_tcp_r2tpool_alloc(session))
                goto remove_session;
+
+       /* We are now fully setup so expose the session to sysfs. */
+       tcp_sw_host = iscsi_host_priv(shost);
+       tcp_sw_host->session = session;
        return cls_session;
 
 remove_session:
@@ -983,10 +986,17 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
        if (WARN_ON_ONCE(session->leadconn))
                return;
 
+       iscsi_session_remove(cls_session);
+       /*
+        * Our get_host_param needs to access the session, so remove the
+        * host from sysfs before freeing the session to make sure userspace
+        * is no longer accessing the callout.
+        */
+       iscsi_host_remove(shost, false);
+
        iscsi_tcp_r2tpool_free(cls_session->dd_data);
-       iscsi_session_teardown(cls_session);
 
-       iscsi_host_remove(shost, false);
+       iscsi_session_free(cls_session);
        iscsi_host_free(shost);
 }
 
index ef2fc86..127f3d7 100644 (file)
@@ -3104,17 +3104,32 @@ dec_session_count:
 }
 EXPORT_SYMBOL_GPL(iscsi_session_setup);
 
-/**
- * iscsi_session_teardown - destroy session, host, and cls_session
- * @cls_session: iscsi session
+/*
+ * issi_session_remove - Remove session from iSCSI class.
  */
-void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
+void iscsi_session_remove(struct iscsi_cls_session *cls_session)
 {
        struct iscsi_session *session = cls_session->dd_data;
-       struct module *owner = cls_session->transport->owner;
        struct Scsi_Host *shost = session->host;
 
        iscsi_remove_session(cls_session);
+       /*
+        * host removal only has to wait for its children to be removed from
+        * sysfs, and iscsi_tcp needs to do iscsi_host_remove before freeing
+        * the session, so drop the session count here.
+        */
+       iscsi_host_dec_session_cnt(shost);
+}
+EXPORT_SYMBOL_GPL(iscsi_session_remove);
+
+/**
+ * iscsi_session_free - Free iscsi session and it's resources
+ * @cls_session: iscsi session
+ */
+void iscsi_session_free(struct iscsi_cls_session *cls_session)
+{
+       struct iscsi_session *session = cls_session->dd_data;
+       struct module *owner = cls_session->transport->owner;
 
        iscsi_pool_free(&session->cmdpool);
        kfree(session->password);
@@ -3132,10 +3147,19 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
        kfree(session->discovery_parent_type);
 
        iscsi_free_session(cls_session);
-
-       iscsi_host_dec_session_cnt(shost);
        module_put(owner);
 }
+EXPORT_SYMBOL_GPL(iscsi_session_free);
+
+/**
+ * iscsi_session_teardown - destroy session and cls_session
+ * @cls_session: iscsi session
+ */
+void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
+{
+       iscsi_session_remove(cls_session);
+       iscsi_session_free(cls_session);
+}
 EXPORT_SYMBOL_GPL(iscsi_session_teardown);
 
 /**
index 1ccce70..5e80225 100644 (file)
@@ -889,7 +889,9 @@ void sas_ata_device_link_abort(struct domain_device *device, bool force_reset)
 {
        struct ata_port *ap = device->sata_dev.ap;
        struct ata_link *link = &ap->link;
+       unsigned long flags;
 
+       spin_lock_irqsave(ap->lock, flags);
        device->sata_dev.fis[2] = ATA_ERR | ATA_DRDY; /* tf status */
        device->sata_dev.fis[3] = ATA_ABORTED; /* tf error */
 
@@ -897,6 +899,7 @@ void sas_ata_device_link_abort(struct domain_device *device, bool force_reset)
        if (force_reset)
                link->eh_info.action |= ATA_EH_RESET;
        ata_link_abort(link);
+       spin_unlock_irqrestore(ap->lock, flags);
 }
 EXPORT_SYMBOL_GPL(sas_ata_device_link_abort);
 
index ef86ca4..3bf8cf3 100644 (file)
@@ -1,5 +1,5 @@
 # mpi3mr makefile
-obj-m += mpi3mr.o
+obj-$(CONFIG_SCSI_MPI3MR) += mpi3mr.o
 mpi3mr-y +=  mpi3mr_os.o     \
                mpi3mr_fw.o \
                mpi3mr_app.o \
index 0c4aaba..286a445 100644 (file)
@@ -3633,8 +3633,7 @@ int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc)
        int i, retval = 0, capb = 0;
        u16 message_control;
        u64 dma_mask = mrioc->dma_mask ? mrioc->dma_mask :
-           (((dma_get_required_mask(&pdev->dev) > DMA_BIT_MASK(32)) &&
-           (sizeof(dma_addr_t) > 4)) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
+           ((sizeof(dma_addr_t) > 4) ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
 
        if (pci_enable_device_mem(pdev)) {
                ioc_err(mrioc, "pci_enable_device_mem: failed\n");
index 4e981cc..6906154 100644 (file)
@@ -2992,8 +2992,7 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
        struct sysinfo s;
        u64 coherent_dma_mask, dma_mask;
 
-       if (ioc->is_mcpu_endpoint || sizeof(dma_addr_t) == 4 ||
-           dma_get_required_mask(&pdev->dev) <= DMA_BIT_MASK(32)) {
+       if (ioc->is_mcpu_endpoint || sizeof(dma_addr_t) == 4) {
                ioc->dma_mask = 32;
                coherent_dma_mask = dma_mask = DMA_BIT_MASK(32);
        /* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */
index 1426b9b..9feb032 100644 (file)
@@ -588,8 +588,6 @@ void scsi_device_put(struct scsi_device *sdev)
 {
        struct module *mod = sdev->host->hostt->module;
 
-       might_sleep();
-
        put_device(&sdev->sdev_gendev);
        module_put(mod);
 }
index cc69538..8553277 100644 (file)
@@ -1511,8 +1511,6 @@ static int inquiry_vpd_b0(unsigned char *arr)
        put_unaligned_be64(sdebug_write_same_length, &arr[32]);
 
        return 0x3c; /* Mandatory page length for Logical Block Provisioning */
-
-       return sizeof(vpdb0_data);
 }
 
 /* Block device characteristics VPD page (SBC-3) */
index a7960ad..2aa2c2a 100644 (file)
@@ -231,6 +231,11 @@ scsi_abort_command(struct scsi_cmnd *scmd)
        struct Scsi_Host *shost = sdev->host;
        unsigned long flags;
 
+       if (!shost->hostt->eh_abort_handler) {
+               /* No abort handler, fail command directly */
+               return FAILED;
+       }
+
        if (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) {
                /*
                 * Retry after abort failed, escalate to next level.
index 7a6904a..f9b18fd 100644 (file)
@@ -1232,8 +1232,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
         * that no LUN is present, so don't add sdev in these cases.
         * Two specific examples are:
         * 1) NetApp targets: return PQ=1, PDT=0x1f
-        * 2) IBM/2145 targets: return PQ=1, PDT=0
-        * 3) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
+        * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
         *    in the UFI 1.0 spec (we cannot rely on reserved bits).
         *
         * References:
@@ -1247,8 +1246,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
         * PDT=00h Direct-access device (floppy)
         * PDT=1Fh none (no FDD connected to the requested logical unit)
         */
-       if (((result[0] >> 5) == 1 ||
-           (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f)) &&
+       if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
+           (result[0] & 0x1f) == 0x1f &&
            !scsi_is_wlun(lun)) {
                SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev,
                                        "scsi scan: peripheral device type"
index 981d1ba..8ef9a54 100644 (file)
@@ -451,6 +451,8 @@ static void scsi_device_dev_release(struct device *dev)
        struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL;
        unsigned long flags;
 
+       might_sleep();
+
        scsi_dh_release_device(sdev);
 
        parent = sdev->sdev_gendev.parent;
index 13cfd3e..b9b9730 100644 (file)
@@ -1677,6 +1677,13 @@ static const char *iscsi_session_state_name(int state)
        return name;
 }
 
+static char *iscsi_session_target_state_name[] = {
+       [ISCSI_SESSION_TARGET_UNBOUND]   = "UNBOUND",
+       [ISCSI_SESSION_TARGET_ALLOCATED] = "ALLOCATED",
+       [ISCSI_SESSION_TARGET_SCANNED]   = "SCANNED",
+       [ISCSI_SESSION_TARGET_UNBINDING] = "UNBINDING",
+};
+
 int iscsi_session_chkready(struct iscsi_cls_session *session)
 {
        int err;
@@ -1786,9 +1793,13 @@ static int iscsi_user_scan_session(struct device *dev, void *data)
                if ((scan_data->channel == SCAN_WILD_CARD ||
                     scan_data->channel == 0) &&
                    (scan_data->id == SCAN_WILD_CARD ||
-                    scan_data->id == id))
+                    scan_data->id == id)) {
                        scsi_scan_target(&session->dev, 0, id,
                                         scan_data->lun, scan_data->rescan);
+                       spin_lock_irqsave(&session->lock, flags);
+                       session->target_state = ISCSI_SESSION_TARGET_SCANNED;
+                       spin_unlock_irqrestore(&session->lock, flags);
+               }
        }
 
 user_scan_exit:
@@ -1961,31 +1972,41 @@ static void __iscsi_unbind_session(struct work_struct *work)
        struct iscsi_cls_host *ihost = shost->shost_data;
        unsigned long flags;
        unsigned int target_id;
+       bool remove_target = true;
 
        ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");
 
        /* Prevent new scans and make sure scanning is not in progress */
        mutex_lock(&ihost->mutex);
        spin_lock_irqsave(&session->lock, flags);
-       if (session->target_id == ISCSI_MAX_TARGET) {
+       if (session->target_state == ISCSI_SESSION_TARGET_ALLOCATED) {
+               remove_target = false;
+       } else if (session->target_state != ISCSI_SESSION_TARGET_SCANNED) {
                spin_unlock_irqrestore(&session->lock, flags);
                mutex_unlock(&ihost->mutex);
-               goto unbind_session_exit;
+               ISCSI_DBG_TRANS_SESSION(session,
+                       "Skipping target unbinding: Session is unbound/unbinding.\n");
+               return;
        }
 
+       session->target_state = ISCSI_SESSION_TARGET_UNBINDING;
        target_id = session->target_id;
        session->target_id = ISCSI_MAX_TARGET;
        spin_unlock_irqrestore(&session->lock, flags);
        mutex_unlock(&ihost->mutex);
 
-       scsi_remove_target(&session->dev);
+       if (remove_target)
+               scsi_remove_target(&session->dev);
 
        if (session->ida_used)
                ida_free(&iscsi_sess_ida, target_id);
 
-unbind_session_exit:
        iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
        ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
+
+       spin_lock_irqsave(&session->lock, flags);
+       session->target_state = ISCSI_SESSION_TARGET_UNBOUND;
+       spin_unlock_irqrestore(&session->lock, flags);
 }
 
 static void __iscsi_destroy_session(struct work_struct *work)
@@ -2062,6 +2083,9 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
                session->ida_used = true;
        } else
                session->target_id = target_id;
+       spin_lock_irqsave(&session->lock, flags);
+       session->target_state = ISCSI_SESSION_TARGET_ALLOCATED;
+       spin_unlock_irqrestore(&session->lock, flags);
 
        dev_set_name(&session->dev, "session%u", session->sid);
        err = device_add(&session->dev);
@@ -4369,6 +4393,19 @@ iscsi_session_attr(def_taskmgmt_tmo, ISCSI_PARAM_DEF_TASKMGMT_TMO, 0);
 iscsi_session_attr(discovery_parent_idx, ISCSI_PARAM_DISCOVERY_PARENT_IDX, 0);
 iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);
 
+static ssize_t
+show_priv_session_target_state(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+
+       return sysfs_emit(buf, "%s\n",
+                       iscsi_session_target_state_name[session->target_state]);
+}
+
+static ISCSI_CLASS_ATTR(priv_sess, target_state, S_IRUGO,
+                       show_priv_session_target_state, NULL);
+
 static ssize_t
 show_priv_session_state(struct device *dev, struct device_attribute *attr,
                        char *buf)
@@ -4471,6 +4508,7 @@ static struct attribute *iscsi_session_attrs[] = {
        &dev_attr_sess_boot_target.attr,
        &dev_attr_priv_sess_recovery_tmo.attr,
        &dev_attr_priv_sess_state.attr,
+       &dev_attr_priv_sess_target_state.attr,
        &dev_attr_priv_sess_creator.attr,
        &dev_attr_sess_chap_out_idx.attr,
        &dev_attr_sess_chap_in_idx.attr,
@@ -4584,6 +4622,8 @@ static umode_t iscsi_session_attr_is_visible(struct kobject *kobj,
                return S_IRUGO | S_IWUSR;
        else if (attr == &dev_attr_priv_sess_state.attr)
                return S_IRUGO;
+       else if (attr == &dev_attr_priv_sess_target_state.attr)
+               return S_IRUGO;
        else if (attr == &dev_attr_priv_sess_creator.attr)
                return S_IRUGO;
        else if (attr == &dev_attr_priv_sess_target_id.attr)
index d7a84c0..22705eb 100644 (file)
@@ -1823,6 +1823,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
        ret = storvsc_do_io(dev, cmd_request, get_cpu());
        put_cpu();
 
+       if (ret)
+               scsi_dma_unmap(scmnd);
+
        if (ret == -EAGAIN) {
                /* no more space */
                ret = SCSI_MLQUEUE_DEVICE_BUSY;
index 66b316d..71a3bb8 100644 (file)
@@ -995,7 +995,7 @@ static int scsifront_suspend(struct xenbus_device *dev)
        return err;
 }
 
-static int scsifront_remove(struct xenbus_device *dev)
+static void scsifront_remove(struct xenbus_device *dev)
 {
        struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
 
@@ -1011,8 +1011,6 @@ static int scsifront_remove(struct xenbus_device *dev)
 
        scsifront_free_ring(info);
        scsi_host_put(info->host);
-
-       return 0;
 }
 
 static void scsifront_disconnect(struct vscsifrnt_info *info)
index 0e3b6ba..0f13853 100644 (file)
@@ -212,7 +212,7 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
                break;
        case IMX8MP_HDMIBLK_PD_LCDIF:
                regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
-                               BIT(7) | BIT(16) | BIT(17) | BIT(18) |
+                               BIT(16) | BIT(17) | BIT(18) |
                                BIT(19) | BIT(20));
                regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
                regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
@@ -241,6 +241,7 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
                regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(1));
                break;
        case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
+               regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
                regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
                regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
                regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
@@ -270,7 +271,7 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
                                  BIT(4) | BIT(5) | BIT(6));
                regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
                regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0,
-                                 BIT(7) | BIT(16) | BIT(17) | BIT(18) |
+                                 BIT(16) | BIT(17) | BIT(18) |
                                  BIT(19) | BIT(20));
                break;
        case IMX8MP_HDMIBLK_PD_PAI:
@@ -298,6 +299,7 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
        case IMX8MP_HDMIBLK_PD_HDMI_TX_PHY:
                regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
                regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
+               regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(7));
                regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
                break;
        case IMX8MP_HDMIBLK_PD_HDCP:
@@ -590,7 +592,6 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
                        ret = PTR_ERR(domain->power_dev);
                        goto cleanup_pds;
                }
-               dev_set_name(domain->power_dev, "%s", data->name);
 
                domain->genpd.name = data->name;
                domain->genpd.power_on = imx8mp_blk_ctrl_power_on;
index 28144c6..32ed9dc 100644 (file)
@@ -66,8 +66,8 @@ static u32 __init imx8mq_soc_revision(void)
        ocotp_base = of_iomap(np, 0);
        WARN_ON(!ocotp_base);
        clk = of_clk_get_by_name(np, NULL);
-       if (!clk) {
-               WARN_ON(!clk);
+       if (IS_ERR(clk)) {
+               WARN_ON(IS_ERR(clk));
                return 0;
        }
 
index cd44f17..d51abb4 100644 (file)
@@ -461,9 +461,10 @@ static int apr_add_device(struct device *dev, struct device_node *np,
                goto out;
        }
 
+       /* Protection domain is optional, it does not exist on older platforms */
        ret = of_property_read_string_index(np, "qcom,protection-domain",
                                            1, &adev->service_path);
-       if (ret < 0) {
+       if (ret < 0 && ret != -EINVAL) {
                dev_err(dev, "Failed to read second value of qcom,protection-domain\n");
                goto out;
        }
index e9b854e..144ea68 100644 (file)
@@ -1708,12 +1708,16 @@ static int cpr_probe(struct platform_device *pdev)
 
        ret = of_genpd_add_provider_simple(dev->of_node, &drv->pd);
        if (ret)
-               return ret;
+               goto err_remove_genpd;
 
        platform_set_drvdata(pdev, drv);
        cpr_debugfs_init(drv);
 
        return 0;
+
+err_remove_genpd:
+       pm_genpd_remove(&drv->pd);
+       return ret;
 }
 
 static int cpr_remove(struct platform_device *pdev)
index 520b4cc..91db3c9 100644 (file)
 #define CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op) ( \
        FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, \
                ((op)->data.nbytes >> 16) & 0xffff) | \
-       FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, (op)->dummy.nbytes * 8))
+       FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, \
+                 (op)->dummy.buswidth != 0 ? \
+                 (((op)->dummy.nbytes * 8) / (op)->dummy.buswidth) : \
+                 0))
 
 #define CDNS_XSPI_CMD_FLD_DSEQ_CMD_4(op, chipsel) ( \
        FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_BANK, chipsel) | \
index 99edddf..c3bfb6c 100644 (file)
@@ -366,7 +366,7 @@ static void dw_spi_irq_setup(struct dw_spi *dws)
         * will be adjusted at the final stage of the IRQ-based SPI transfer
         * execution so not to lose the leftover of the incoming data.
         */
-       level = min_t(u16, dws->fifo_len / 2, dws->tx_len);
+       level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len);
        dw_writel(dws, DW_SPI_TXFTLR, level);
        dw_writel(dws, DW_SPI_RXFTLR, level - 1);
 
index 6de8360..9eab6c2 100644 (file)
@@ -1253,6 +1253,11 @@ static int mtk_spi_probe(struct platform_device *pdev)
                dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
                           addr_bits, ret);
 
+       ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
+                              IRQF_TRIGGER_NONE, dev_name(dev), master);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to register irq\n");
+
        pm_runtime_enable(dev);
 
        ret = devm_spi_register_master(dev, master);
@@ -1261,13 +1266,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
                return dev_err_probe(dev, ret, "failed to register master\n");
        }
 
-       ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
-                              IRQF_TRIGGER_NONE, dev_name(dev), master);
-       if (ret) {
-               pm_runtime_disable(dev);
-               return dev_err_probe(dev, ret, "failed to register irq\n");
-       }
-
        return 0;
 }
 
index 3cc7bb4..15f174f 100644 (file)
@@ -2310,7 +2310,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
        if (!of_property_read_u32(nc, "spi-max-frequency", &value))
                spi->max_speed_hz = value;
 
-       if (!of_property_read_u16(nc, "spi-cs-setup-ns", &cs_setup)) {
+       if (!of_property_read_u16(nc, "spi-cs-setup-delay-ns", &cs_setup)) {
                spi->cs_setup.value = cs_setup;
                spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS;
        }
index 6313e7d..a1ea093 100644 (file)
@@ -68,7 +68,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
 
 struct spidev_data {
        dev_t                   devt;
-       spinlock_t              spi_lock;
+       struct mutex            spi_lock;
        struct spi_device       *spi;
        struct list_head        device_entry;
 
@@ -89,23 +89,33 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
 
 /*-------------------------------------------------------------------------*/
 
+static ssize_t
+spidev_sync_unlocked(struct spi_device *spi, struct spi_message *message)
+{
+       ssize_t status;
+
+       status = spi_sync(spi, message);
+       if (status == 0)
+               status = message->actual_length;
+
+       return status;
+}
+
 static ssize_t
 spidev_sync(struct spidev_data *spidev, struct spi_message *message)
 {
-       int status;
+       ssize_t status;
        struct spi_device *spi;
 
-       spin_lock_irq(&spidev->spi_lock);
+       mutex_lock(&spidev->spi_lock);
        spi = spidev->spi;
-       spin_unlock_irq(&spidev->spi_lock);
 
        if (spi == NULL)
                status = -ESHUTDOWN;
        else
-               status = spi_sync(spi, message);
+               status = spidev_sync_unlocked(spi, message);
 
-       if (status == 0)
-               status = message->actual_length;
+       mutex_unlock(&spidev->spi_lock);
 
        return status;
 }
@@ -294,7 +304,7 @@ static int spidev_message(struct spidev_data *spidev,
                spi_message_add_tail(k_tmp, &msg);
        }
 
-       status = spidev_sync(spidev, &msg);
+       status = spidev_sync_unlocked(spidev->spi, &msg);
        if (status < 0)
                goto done;
 
@@ -359,12 +369,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
         * we issue this ioctl.
         */
        spidev = filp->private_data;
-       spin_lock_irq(&spidev->spi_lock);
+       mutex_lock(&spidev->spi_lock);
        spi = spi_dev_get(spidev->spi);
-       spin_unlock_irq(&spidev->spi_lock);
-
-       if (spi == NULL)
+       if (spi == NULL) {
+               mutex_unlock(&spidev->spi_lock);
                return -ESHUTDOWN;
+       }
 
        /* use the buffer lock here for triple duty:
         *  - prevent I/O (from us) so calling spi_setup() is safe;
@@ -508,6 +518,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
        mutex_unlock(&spidev->buf_lock);
        spi_dev_put(spi);
+       mutex_unlock(&spidev->spi_lock);
        return retval;
 }
 
@@ -529,12 +540,12 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
         * we issue this ioctl.
         */
        spidev = filp->private_data;
-       spin_lock_irq(&spidev->spi_lock);
+       mutex_lock(&spidev->spi_lock);
        spi = spi_dev_get(spidev->spi);
-       spin_unlock_irq(&spidev->spi_lock);
-
-       if (spi == NULL)
+       if (spi == NULL) {
+               mutex_unlock(&spidev->spi_lock);
                return -ESHUTDOWN;
+       }
 
        /* SPI_IOC_MESSAGE needs the buffer locked "normally" */
        mutex_lock(&spidev->buf_lock);
@@ -561,6 +572,7 @@ spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
 done:
        mutex_unlock(&spidev->buf_lock);
        spi_dev_put(spi);
+       mutex_unlock(&spidev->spi_lock);
        return retval;
 }
 
@@ -601,7 +613,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
        if (!spidev->tx_buffer) {
                spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);
                if (!spidev->tx_buffer) {
-                       dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
                        status = -ENOMEM;
                        goto err_find_dev;
                }
@@ -610,7 +621,6 @@ static int spidev_open(struct inode *inode, struct file *filp)
        if (!spidev->rx_buffer) {
                spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
                if (!spidev->rx_buffer) {
-                       dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
                        status = -ENOMEM;
                        goto err_alloc_rx_buf;
                }
@@ -640,10 +650,10 @@ static int spidev_release(struct inode *inode, struct file *filp)
        spidev = filp->private_data;
        filp->private_data = NULL;
 
-       spin_lock_irq(&spidev->spi_lock);
+       mutex_lock(&spidev->spi_lock);
        /* ... after we unbound from the underlying device? */
        dofree = (spidev->spi == NULL);
-       spin_unlock_irq(&spidev->spi_lock);
+       mutex_unlock(&spidev->spi_lock);
 
        /* last close? */
        spidev->users--;
@@ -776,7 +786,7 @@ static int spidev_probe(struct spi_device *spi)
 
        /* Initialize the driver data */
        spidev->spi = spi;
-       spin_lock_init(&spidev->spi_lock);
+       mutex_init(&spidev->spi_lock);
        mutex_init(&spidev->buf_lock);
 
        INIT_LIST_HEAD(&spidev->device_entry);
@@ -821,9 +831,9 @@ static void spidev_remove(struct spi_device *spi)
        /* prevent new opens */
        mutex_lock(&device_list_lock);
        /* make sure ops on existing fds can abort cleanly */
-       spin_lock_irq(&spidev->spi_lock);
+       mutex_lock(&spidev->spi_lock);
        spidev->spi = NULL;
-       spin_unlock_irq(&spidev->spi_lock);
+       mutex_unlock(&spidev->spi_lock);
 
        list_del(&spidev->device_entry);
        device_destroy(spidev_class, spidev->devt);
index db1441c..690ab71 100644 (file)
@@ -86,7 +86,7 @@ struct vchiq_service_params_kernel {
 
 struct vchiq_instance;
 
-extern enum vchiq_status vchiq_initialise(struct vchiq_instance **pinstance);
+extern int vchiq_initialise(struct vchiq_instance **pinstance);
 extern enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance);
 extern enum vchiq_status vchiq_connect(struct vchiq_instance *instance);
 extern enum vchiq_status vchiq_open_service(struct vchiq_instance *instance,
index 2851ef6..cd20eb1 100644 (file)
@@ -100,10 +100,10 @@ vchiq_dump_platform_use_state(struct vchiq_state *state);
 extern void
 vchiq_dump_service_use_state(struct vchiq_state *state);
 
-extern enum vchiq_status
+extern int
 vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
                   enum USE_TYPE_E use_type);
-extern enum vchiq_status
+extern int
 vchiq_release_internal(struct vchiq_state *state,
                       struct vchiq_service *service);
 
index bac1114..2b95b45 100644 (file)
@@ -73,8 +73,8 @@ static bool __target_check_io_state(struct se_cmd *se_cmd,
 {
        struct se_session *sess = se_cmd->se_sess;
 
-       assert_spin_locked(&sess->sess_cmd_lock);
-       WARN_ON_ONCE(!irqs_disabled());
+       lockdep_assert_held(&sess->sess_cmd_lock);
+
        /*
         * If command already reached CMD_T_COMPLETE state within
         * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,
index 62c0aa5..0a4eaa3 100644 (file)
@@ -44,11 +44,13 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
                                         int trip, int *temp)
 {
        struct int34x_thermal_zone *d = zone->devdata;
-       int i;
+       int i, ret = 0;
 
        if (d->override_ops && d->override_ops->get_trip_temp)
                return d->override_ops->get_trip_temp(zone, trip, temp);
 
+       mutex_lock(&d->trip_mutex);
+
        if (trip < d->aux_trip_nr)
                *temp = d->aux_trips[trip];
        else if (trip == d->crt_trip_id)
@@ -66,10 +68,12 @@ static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
                        }
                }
                if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
-                       return -EINVAL;
+                       ret = -EINVAL;
        }
 
-       return 0;
+       mutex_unlock(&d->trip_mutex);
+
+       return ret;
 }
 
 static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
@@ -77,11 +81,13 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
                                         enum thermal_trip_type *type)
 {
        struct int34x_thermal_zone *d = zone->devdata;
-       int i;
+       int i, ret = 0;
 
        if (d->override_ops && d->override_ops->get_trip_type)
                return d->override_ops->get_trip_type(zone, trip, type);
 
+       mutex_lock(&d->trip_mutex);
+
        if (trip < d->aux_trip_nr)
                *type = THERMAL_TRIP_PASSIVE;
        else if (trip == d->crt_trip_id)
@@ -99,10 +105,12 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
                        }
                }
                if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
-                       return -EINVAL;
+                       ret = -EINVAL;
        }
 
-       return 0;
+       mutex_unlock(&d->trip_mutex);
+
+       return ret;
 }
 
 static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
@@ -180,6 +188,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone)
        int trip_cnt = int34x_zone->aux_trip_nr;
        int i;
 
+       mutex_lock(&int34x_zone->trip_mutex);
+
        int34x_zone->crt_trip_id = -1;
        if (!int340x_thermal_get_trip_config(int34x_zone->adev->handle, "_CRT",
                                             &int34x_zone->crt_temp))
@@ -207,6 +217,8 @@ int int340x_thermal_read_trips(struct int34x_thermal_zone *int34x_zone)
                int34x_zone->act_trips[i].valid = true;
        }
 
+       mutex_unlock(&int34x_zone->trip_mutex);
+
        return trip_cnt;
 }
 EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
@@ -230,6 +242,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
        if (!int34x_thermal_zone)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&int34x_thermal_zone->trip_mutex);
+
        int34x_thermal_zone->adev = adev;
        int34x_thermal_zone->override_ops = override_ops;
 
@@ -281,6 +295,7 @@ err_thermal_zone:
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
        kfree(int34x_thermal_zone->aux_trips);
 err_trip_alloc:
+       mutex_destroy(&int34x_thermal_zone->trip_mutex);
        kfree(int34x_thermal_zone);
        return ERR_PTR(ret);
 }
@@ -292,6 +307,7 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone
        thermal_zone_device_unregister(int34x_thermal_zone->zone);
        acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
        kfree(int34x_thermal_zone->aux_trips);
+       mutex_destroy(&int34x_thermal_zone->trip_mutex);
        kfree(int34x_thermal_zone);
 }
 EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
index 3b4971d..8f9872a 100644 (file)
@@ -32,6 +32,7 @@ struct int34x_thermal_zone {
        struct thermal_zone_device_ops *override_ops;
        void *priv_data;
        struct acpi_lpat_conversion_table *lpat_table;
+       struct mutex trip_mutex;
 };
 
 struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,
index f17ab23..77bd47d 100644 (file)
@@ -909,15 +909,20 @@ __thermal_cooling_device_register(struct device_node *np,
        cdev->devdata = devdata;
 
        ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
-       if (ret)
-               goto out_kfree_type;
+       if (ret) {
+               kfree(cdev->type);
+               goto out_ida_remove;
+       }
 
        thermal_cooling_device_setup_sysfs(cdev);
+
        ret = dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
        if (ret) {
+               kfree(cdev->type);
                thermal_cooling_device_destroy_sysfs(cdev);
-               goto out_kfree_type;
+               goto out_ida_remove;
        }
+
        ret = device_register(&cdev->device);
        if (ret)
                goto out_kfree_type;
@@ -943,6 +948,8 @@ out_kfree_type:
        thermal_cooling_device_destroy_sysfs(cdev);
        kfree(cdev->type);
        put_device(&cdev->device);
+
+       /* thermal_release() takes care of the rest */
        cdev = NULL;
 out_ida_remove:
        ida_free(&thermal_cdev_ida, id);
index 81252e3..56008eb 100644 (file)
@@ -427,13 +427,6 @@ int tb_retimer_scan(struct tb_port *port, bool add)
 {
        u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
        int ret, i, last_idx = 0;
-       struct usb4_port *usb4;
-
-       usb4 = port->usb4;
-       if (!usb4)
-               return 0;
-
-       pm_runtime_get_sync(&usb4->dev);
 
        /*
         * Send broadcast RT to make sure retimer indices facing this
@@ -441,7 +434,7 @@ int tb_retimer_scan(struct tb_port *port, bool add)
         */
        ret = usb4_port_enumerate_retimers(port);
        if (ret)
-               goto out;
+               return ret;
 
        /*
         * Enable sideband channel for each retimer. We can do this
@@ -471,12 +464,11 @@ int tb_retimer_scan(struct tb_port *port, bool add)
                        break;
        }
 
-       if (!last_idx) {
-               ret = 0;
-               goto out;
-       }
+       if (!last_idx)
+               return 0;
 
        /* Add on-board retimers if they do not exist already */
+       ret = 0;
        for (i = 1; i <= last_idx; i++) {
                struct tb_retimer *rt;
 
@@ -490,10 +482,6 @@ int tb_retimer_scan(struct tb_port *port, bool add)
                }
        }
 
-out:
-       pm_runtime_mark_last_busy(&usb4->dev);
-       pm_runtime_put_autosuspend(&usb4->dev);
-
        return ret;
 }
 
index 4628458..3f1ab30 100644 (file)
@@ -628,11 +628,15 @@ static void tb_scan_port(struct tb_port *port)
                         * Downstream switch is reachable through two ports.
                         * Only scan on the primary port (link_nr == 0).
                         */
+
+       if (port->usb4)
+               pm_runtime_get_sync(&port->usb4->dev);
+
        if (tb_wait_for_port(port, false) <= 0)
-               return;
+               goto out_rpm_put;
        if (port->remote) {
                tb_port_dbg(port, "port already has a remote\n");
-               return;
+               goto out_rpm_put;
        }
 
        tb_retimer_scan(port, true);
@@ -647,12 +651,12 @@ static void tb_scan_port(struct tb_port *port)
                 */
                if (PTR_ERR(sw) == -EIO || PTR_ERR(sw) == -EADDRNOTAVAIL)
                        tb_scan_xdomain(port);
-               return;
+               goto out_rpm_put;
        }
 
        if (tb_switch_configure(sw)) {
                tb_switch_put(sw);
-               return;
+               goto out_rpm_put;
        }
 
        /*
@@ -681,7 +685,7 @@ static void tb_scan_port(struct tb_port *port)
 
        if (tb_switch_add(sw)) {
                tb_switch_put(sw);
-               return;
+               goto out_rpm_put;
        }
 
        /* Link the switches using both links if available */
@@ -733,6 +737,12 @@ static void tb_scan_port(struct tb_port *port)
 
        tb_add_dp_resources(sw);
        tb_scan_switch(sw);
+
+out_rpm_put:
+       if (port->usb4) {
+               pm_runtime_mark_last_busy(&port->usb4->dev);
+               pm_runtime_put_autosuspend(&port->usb4->dev);
+       }
 }
 
 static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
index 2c3cf7f..1fc3c29 100644 (file)
@@ -1275,7 +1275,7 @@ static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel,
                return;
        } else if (!ret) {
                /* Use maximum link rate if the link valid is not set */
-               ret = usb4_usb3_port_max_link_rate(tunnel->src_port);
+               ret = tb_usb3_max_link_rate(tunnel->dst_port, tunnel->src_port);
                if (ret < 0) {
                        tb_tunnel_warn(tunnel, "failed to read maximum link rate\n");
                        return;
index cfa8348..3c51e47 100644 (file)
@@ -1419,12 +1419,19 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
         * registered, we notify the userspace that it has changed.
         */
        if (!update) {
-               struct tb_port *port;
+               /*
+                * Now disable lane 1 if bonding was not enabled. Do
+                * this only if bonding was possible at the beginning
+                * (that is we are the connection manager and there are
+                * two lanes).
+                */
+               if (xd->bonding_possible) {
+                       struct tb_port *port;
 
-               /* Now disable lane 1 if bonding was not enabled */
-               port = tb_port_at(xd->route, tb_xdomain_parent(xd));
-               if (!port->bonded)
-                       tb_port_disable(port->dual_link_port);
+                       port = tb_port_at(xd->route, tb_xdomain_parent(xd));
+                       if (!port->bonded)
+                               tb_port_disable(port->dual_link_port);
+               }
 
                if (device_add(&xd->dev)) {
                        dev_err(&xd->dev, "failed to add XDomain device\n");
index 7c23112..5bddb2f 100644 (file)
@@ -52,17 +52,22 @@ static DEFINE_SPINLOCK(xencons_lock);
 
 static struct xencons_info *vtermno_to_xencons(int vtermno)
 {
-       struct xencons_info *entry, *n, *ret = NULL;
+       struct xencons_info *entry, *ret = NULL;
+       unsigned long flags;
 
-       if (list_empty(&xenconsoles))
-                       return NULL;
+       spin_lock_irqsave(&xencons_lock, flags);
+       if (list_empty(&xenconsoles)) {
+               spin_unlock_irqrestore(&xencons_lock, flags);
+               return NULL;
+       }
 
-       list_for_each_entry_safe(entry, n, &xenconsoles, list) {
+       list_for_each_entry(entry, &xenconsoles, list) {
                if (entry->vtermno == vtermno) {
                        ret  = entry;
                        break;
                }
        }
+       spin_unlock_irqrestore(&xencons_lock, flags);
 
        return ret;
 }
@@ -223,7 +228,7 @@ static int xen_hvm_console_init(void)
 {
        int r;
        uint64_t v = 0;
-       unsigned long gfn;
+       unsigned long gfn, flags;
        struct xencons_info *info;
 
        if (!xen_hvm_domain())
@@ -258,9 +263,9 @@ static int xen_hvm_console_init(void)
                goto err;
        info->vtermno = HVC_COOKIE;
 
-       spin_lock(&xencons_lock);
+       spin_lock_irqsave(&xencons_lock, flags);
        list_add_tail(&info->list, &xenconsoles);
-       spin_unlock(&xencons_lock);
+       spin_unlock_irqrestore(&xencons_lock, flags);
 
        return 0;
 err:
@@ -283,6 +288,7 @@ static int xencons_info_pv_init(struct xencons_info *info, int vtermno)
 static int xen_pv_console_init(void)
 {
        struct xencons_info *info;
+       unsigned long flags;
 
        if (!xen_pv_domain())
                return -ENODEV;
@@ -299,9 +305,9 @@ static int xen_pv_console_init(void)
                /* already configured */
                return 0;
        }
-       spin_lock(&xencons_lock);
+       spin_lock_irqsave(&xencons_lock, flags);
        xencons_info_pv_init(info, HVC_COOKIE);
-       spin_unlock(&xencons_lock);
+       spin_unlock_irqrestore(&xencons_lock, flags);
 
        return 0;
 }
@@ -309,6 +315,7 @@ static int xen_pv_console_init(void)
 static int xen_initial_domain_console_init(void)
 {
        struct xencons_info *info;
+       unsigned long flags;
 
        if (!xen_initial_domain())
                return -ENODEV;
@@ -323,9 +330,9 @@ static int xen_initial_domain_console_init(void)
        info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
        info->vtermno = HVC_COOKIE;
 
-       spin_lock(&xencons_lock);
+       spin_lock_irqsave(&xencons_lock, flags);
        list_add_tail(&info->list, &xenconsoles);
-       spin_unlock(&xencons_lock);
+       spin_unlock_irqrestore(&xencons_lock, flags);
 
        return 0;
 }
@@ -380,10 +387,12 @@ static void xencons_free(struct xencons_info *info)
 
 static int xen_console_remove(struct xencons_info *info)
 {
+       unsigned long flags;
+
        xencons_disconnect_backend(info);
-       spin_lock(&xencons_lock);
+       spin_lock_irqsave(&xencons_lock, flags);
        list_del(&info->list);
-       spin_unlock(&xencons_lock);
+       spin_unlock_irqrestore(&xencons_lock, flags);
        if (info->xbdev != NULL)
                xencons_free(info);
        else {
@@ -394,9 +403,9 @@ static int xen_console_remove(struct xencons_info *info)
        return 0;
 }
 
-static int xencons_remove(struct xenbus_device *dev)
+static void xencons_remove(struct xenbus_device *dev)
 {
-       return xen_console_remove(dev_get_drvdata(&dev->dev));
+       xen_console_remove(dev_get_drvdata(&dev->dev));
 }
 
 static int xencons_connect_backend(struct xenbus_device *dev,
@@ -464,6 +473,7 @@ static int xencons_probe(struct xenbus_device *dev,
 {
        int ret, devid;
        struct xencons_info *info;
+       unsigned long flags;
 
        devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
        if (devid == 0)
@@ -482,9 +492,9 @@ static int xencons_probe(struct xenbus_device *dev,
        ret = xencons_connect_backend(dev, info);
        if (ret < 0)
                goto error;
-       spin_lock(&xencons_lock);
+       spin_lock_irqsave(&xencons_lock, flags);
        list_add_tail(&info->list, &xenconsoles);
-       spin_unlock(&xencons_lock);
+       spin_unlock_irqrestore(&xencons_lock, flags);
 
        return 0;
 
@@ -584,10 +594,12 @@ static int __init xen_hvc_init(void)
 
        info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
        if (IS_ERR(info->hvc)) {
+               unsigned long flags;
+
                r = PTR_ERR(info->hvc);
-               spin_lock(&xencons_lock);
+               spin_lock_irqsave(&xencons_lock, flags);
                list_del(&info->list);
-               spin_unlock(&xencons_lock);
+               spin_unlock_irqrestore(&xencons_lock, flags);
                if (info->irq)
                        unbind_from_irqhandler(info->irq, NULL);
                kfree(info);
index 37d6af2..7fa6650 100644 (file)
@@ -43,15 +43,23 @@ static void __dma_rx_complete(struct uart_8250_port *p)
        struct uart_8250_dma    *dma = p->dma;
        struct tty_port         *tty_port = &p->port.state->port;
        struct dma_tx_state     state;
+       enum dma_status         dma_status;
        int                     count;
 
-       dma->rx_running = 0;
-       dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+       /*
+        * New DMA Rx can be started during the completion handler before it
+        * could acquire port's lock and it might still be ongoing. Don't to
+        * anything in such case.
+        */
+       dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+       if (dma_status == DMA_IN_PROGRESS)
+               return;
 
        count = dma->rx_size - state.residue;
 
        tty_insert_flip_string(tty_port, dma->rx_buf, count);
        p->port.icount.rx += count;
+       dma->rx_running = 0;
 
        tty_flip_buffer_push(tty_port);
 }
@@ -62,9 +70,14 @@ static void dma_rx_complete(void *param)
        struct uart_8250_dma *dma = p->dma;
        unsigned long flags;
 
-       __dma_rx_complete(p);
-
        spin_lock_irqsave(&p->port.lock, flags);
+       if (dma->rx_running)
+               __dma_rx_complete(p);
+
+       /*
+        * Cannot be combined with the previous check because __dma_rx_complete()
+        * changes dma->rx_running.
+        */
        if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
                p->dma->rx_dma(p);
        spin_unlock_irqrestore(&p->port.lock, flags);
index 314a05e..64770c6 100644 (file)
 #define PCI_DEVICE_ID_EXAR_XR17V4358           0x4358
 #define PCI_DEVICE_ID_EXAR_XR17V8358           0x8358
 
+#define PCI_DEVICE_ID_SEALEVEL_710xC           0x1001
+#define PCI_DEVICE_ID_SEALEVEL_720xC           0x1002
+#define PCI_DEVICE_ID_SEALEVEL_740xC           0x1004
+#define PCI_DEVICE_ID_SEALEVEL_780xC           0x1008
+#define PCI_DEVICE_ID_SEALEVEL_716xC           0x1010
+
 #define UART_EXAR_INT0         0x80
 #define UART_EXAR_8XMODE       0x88    /* 8X sampling rate select */
 #define UART_EXAR_SLEEP                0x8b    /* Sleep mode */
@@ -638,6 +644,8 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
                nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1);
        else if (board->num_ports)
                nr_ports = board->num_ports;
+       else if (pcidev->vendor == PCI_VENDOR_ID_SEALEVEL)
+               nr_ports = pcidev->device & 0xff;
        else
                nr_ports = pcidev->device & 0x0f;
 
@@ -864,6 +872,12 @@ static const struct pci_device_id exar_pci_tbl[] = {
        EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4),
        EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4),
        EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8),
+
+       EXAR_DEVICE(SEALEVEL, 710xC, pbn_exar_XR17V35x),
+       EXAR_DEVICE(SEALEVEL, 720xC, pbn_exar_XR17V35x),
+       EXAR_DEVICE(SEALEVEL, 740xC, pbn_exar_XR17V35x),
+       EXAR_DEVICE(SEALEVEL, 780xC, pbn_exar_XR17V35x),
+       EXAR_DEVICE(SEALEVEL, 716xC, pbn_exar_XR17V35x),
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, exar_pci_tbl);
index d75c39f..d8c2f34 100644 (file)
@@ -1466,6 +1466,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
        struct circ_buf *xmit = &uap->port.state->xmit;
        int count = uap->fifosize >> 1;
 
+       if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
+           !uap->rs485_tx_started)
+               pl011_rs485_tx_start(uap);
+
        if (uap->port.x_char) {
                if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
                        return true;
@@ -1477,10 +1481,6 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
                return false;
        }
 
-       if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
-           !uap->rs485_tx_started)
-               pl011_rs485_tx_start(uap);
-
        /* If we are using DMA mode, try to send some characters. */
        if (pl011_dma_tx_irq(uap))
                return true;
index f1c06e1..9cd7479 100644 (file)
@@ -2657,13 +2657,7 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud,
        else if (mr == ATMEL_US_PAR_ODD)
                *parity = 'o';
 
-       /*
-        * The serial core only rounds down when matching this to a
-        * supported baud rate. Make sure we don't end up slightly
-        * lower than one of those, as it would make us fall through
-        * to a much lower baud rate than we really want.
-        */
-       *baud = port->uartclk / (16 * (quot - 1));
+       *baud = port->uartclk / (16 * quot);
 }
 
 static int __init atmel_console_setup(struct console *co, char *options)
index a3ed9b3..7ce7bb1 100644 (file)
@@ -171,6 +171,7 @@ static int configure_kgdboc(void)
        int err = -ENODEV;
        char *cptr = config;
        struct console *cons;
+       int cookie;
 
        if (!strlen(config) || isspace(config[0])) {
                err = 0;
@@ -189,20 +190,9 @@ static int configure_kgdboc(void)
        if (kgdboc_register_kbd(&cptr))
                goto do_register;
 
-       /*
-        * tty_find_polling_driver() can call uart_set_options()
-        * (via poll_init) to configure the uart. Take the console_list_lock
-        * in order to synchronize against register_console(), which can also
-        * configure the uart via uart_set_options(). This also allows safe
-        * traversal of the console list.
-        */
-       console_list_lock();
-
        p = tty_find_polling_driver(cptr, &tty_line);
-       if (!p) {
-               console_list_unlock();
+       if (!p)
                goto noconfig;
-       }
 
        /*
         * Take console_lock to serialize device() callback with
@@ -211,7 +201,8 @@ static int configure_kgdboc(void)
         */
        console_lock();
 
-       for_each_console(cons) {
+       cookie = console_srcu_read_lock();
+       for_each_console_srcu(cons) {
                int idx;
                if (cons->device && cons->device(cons, &idx) == p &&
                    idx == tty_line) {
@@ -219,11 +210,10 @@ static int configure_kgdboc(void)
                        break;
                }
        }
+       console_srcu_read_unlock(cookie);
 
        console_unlock();
 
-       console_list_unlock();
-
        kgdb_tty_driver = p;
        kgdb_tty_line = tty_line;
 
index 3d54a43..9576ba8 100644 (file)
@@ -749,7 +749,7 @@ static void pch_dma_tx_complete(void *arg)
                uart_xmit_advance(port, sg_dma_len(sg));
 
        async_tx_ack(priv->desc_tx);
-       dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE);
+       dma_unmap_sg(port->dev, priv->sg_tx_p, priv->orig_nent, DMA_TO_DEVICE);
        priv->tx_dma_use = 0;
        priv->nent = 0;
        priv->orig_nent = 0;
index b487823..57f04f8 100644 (file)
@@ -864,9 +864,10 @@ out_unlock:
        return IRQ_HANDLED;
 }
 
-static void get_tx_fifo_size(struct qcom_geni_serial_port *port)
+static int setup_fifos(struct qcom_geni_serial_port *port)
 {
        struct uart_port *uport;
+       u32 old_rx_fifo_depth = port->rx_fifo_depth;
 
        uport = &port->uport;
        port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
@@ -874,6 +875,16 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port)
        port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se);
        uport->fifosize =
                (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
+
+       if (port->rx_fifo && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) {
+               port->rx_fifo = devm_krealloc(uport->dev, port->rx_fifo,
+                                             port->rx_fifo_depth * sizeof(u32),
+                                             GFP_KERNEL);
+               if (!port->rx_fifo)
+                       return -ENOMEM;
+       }
+
+       return 0;
 }
 
 
@@ -888,6 +899,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
        u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
        u32 proto;
        u32 pin_swap;
+       int ret;
 
        proto = geni_se_read_proto(&port->se);
        if (proto != GENI_SE_UART) {
@@ -897,7 +909,9 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
 
        qcom_geni_serial_stop_rx(uport);
 
-       get_tx_fifo_size(port);
+       ret = setup_fifos(port);
+       if (ret)
+               return ret;
 
        writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
 
@@ -1516,7 +1530,7 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
+static int qcom_geni_serial_sys_suspend(struct device *dev)
 {
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
        struct uart_port *uport = &port->uport;
@@ -1533,7 +1547,7 @@ static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev)
        return uart_suspend_port(private_data->drv, uport);
 }
 
-static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
+static int qcom_geni_serial_sys_resume(struct device *dev)
 {
        int ret;
        struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
@@ -1581,10 +1595,12 @@ static int qcom_geni_serial_sys_hib_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
-                                       qcom_geni_serial_sys_resume)
-       .restore = qcom_geni_serial_sys_hib_resume,
-       .thaw = qcom_geni_serial_sys_hib_resume,
+       .suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
+       .resume = pm_sleep_ptr(qcom_geni_serial_sys_resume),
+       .freeze = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
+       .poweroff = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
+       .restore = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
+       .thaw = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
 };
 
 static const struct of_device_id qcom_geni_serial_match_table[] = {
index b9fbbee..ec874f3 100644 (file)
@@ -2212,6 +2212,9 @@ EXPORT_SYMBOL_GPL(uart_parse_options);
  * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
  * @bits: number of data bits
  * @flow: flow control character - 'r' (rts)
+ *
+ * Locking: Caller must hold console_list_lock in order to serialize
+ * early initialization of the serial-console lock.
  */
 int
 uart_set_options(struct uart_port *port, struct console *co,
@@ -2619,7 +2622,9 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
 
        if (!ret && options) {
                uart_parse_options(options, &baud, &parity, &bits, &flow);
+               console_list_lock();
                ret = uart_set_options(port, NULL, baud, parity, bits, flow);
+               console_list_unlock();
        }
 out:
        mutex_unlock(&tport->mutex);
index a149003..409e91d 100644 (file)
@@ -797,25 +797,11 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
                spin_unlock(&port->lock);
        }
 
-       if (stm32_usart_rx_dma_enabled(port))
-               return IRQ_WAKE_THREAD;
-       else
-               return IRQ_HANDLED;
-}
-
-static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-       struct tty_port *tport = &port->state->port;
-       struct stm32_port *stm32_port = to_stm32_port(port);
-       unsigned int size;
-       unsigned long flags;
-
        /* Receiver timeout irq for DMA RX */
-       if (!stm32_port->throttled) {
-               spin_lock_irqsave(&port->lock, flags);
+       if (stm32_usart_rx_dma_enabled(port) && !stm32_port->throttled) {
+               spin_lock(&port->lock);
                size = stm32_usart_receive_chars(port, false);
-               uart_unlock_and_check_sysrq_irqrestore(port, flags);
+               uart_unlock_and_check_sysrq(port);
                if (size)
                        tty_flip_buffer_push(tport);
        }
@@ -1015,10 +1001,8 @@ static int stm32_usart_startup(struct uart_port *port)
        u32 val;
        int ret;
 
-       ret = request_threaded_irq(port->irq, stm32_usart_interrupt,
-                                  stm32_usart_threaded_interrupt,
-                                  IRQF_ONESHOT | IRQF_NO_SUSPEND,
-                                  name, port);
+       ret = request_irq(port->irq, stm32_usart_interrupt,
+                         IRQF_NO_SUSPEND, name, port);
        if (ret)
                return ret;
 
@@ -1601,13 +1585,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
        struct dma_slave_config config;
        int ret;
 
-       /*
-        * Using DMA and threaded handler for the console could lead to
-        * deadlocks.
-        */
-       if (uart_console(port))
-               return -ENODEV;
-
        stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L,
                                               &stm32port->rx_dma_buf,
                                               GFP_KERNEL);
index 1850bac..f566eb1 100644 (file)
@@ -386,10 +386,6 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 
        uni_mode = use_unicode(inode);
        attr = use_attributes(inode);
-       ret = -ENXIO;
-       vc = vcs_vc(inode, &viewed);
-       if (!vc)
-               goto unlock_out;
 
        ret = -EINVAL;
        if (pos < 0)
@@ -407,6 +403,11 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
                unsigned int this_round, skip = 0;
                int size;
 
+               ret = -ENXIO;
+               vc = vcs_vc(inode, &viewed);
+               if (!vc)
+                       goto unlock_out;
+
                /* Check whether we are above size each round,
                 * as copy_to_user at the end of this loop
                 * could sleep.
index e18c9f4..3a1c4d3 100644 (file)
@@ -1234,12 +1234,14 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
         * clock scaling is in progress
         */
        ufshcd_scsi_block_requests(hba);
+       mutex_lock(&hba->wb_mutex);
        down_write(&hba->clk_scaling_lock);
 
        if (!hba->clk_scaling.is_allowed ||
            ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
                ret = -EBUSY;
                up_write(&hba->clk_scaling_lock);
+               mutex_unlock(&hba->wb_mutex);
                ufshcd_scsi_unblock_requests(hba);
                goto out;
        }
@@ -1251,12 +1253,16 @@ out:
        return ret;
 }
 
-static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock)
+static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool scale_up)
 {
-       if (writelock)
-               up_write(&hba->clk_scaling_lock);
-       else
-               up_read(&hba->clk_scaling_lock);
+       up_write(&hba->clk_scaling_lock);
+
+       /* Enable Write Booster if we have scaled up else disable it */
+       if (ufshcd_enable_wb_if_scaling_up(hba) && !err)
+               ufshcd_wb_toggle(hba, scale_up);
+
+       mutex_unlock(&hba->wb_mutex);
+
        ufshcd_scsi_unblock_requests(hba);
        ufshcd_release(hba);
 }
@@ -1273,7 +1279,6 @@ static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, bool writelock)
 static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
 {
        int ret = 0;
-       bool is_writelock = true;
 
        ret = ufshcd_clock_scaling_prepare(hba);
        if (ret)
@@ -1302,15 +1307,8 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
                }
        }
 
-       /* Enable Write Booster if we have scaled up else disable it */
-       if (ufshcd_enable_wb_if_scaling_up(hba)) {
-               downgrade_write(&hba->clk_scaling_lock);
-               is_writelock = false;
-               ufshcd_wb_toggle(hba, scale_up);
-       }
-
 out_unprepare:
-       ufshcd_clock_scaling_unprepare(hba, is_writelock);
+       ufshcd_clock_scaling_unprepare(hba, ret, scale_up);
        return ret;
 }
 
@@ -6056,11 +6054,21 @@ void ufshcd_schedule_eh_work(struct ufs_hba *hba)
        }
 }
 
+static void ufshcd_force_error_recovery(struct ufs_hba *hba)
+{
+       spin_lock_irq(hba->host->host_lock);
+       hba->force_reset = true;
+       ufshcd_schedule_eh_work(hba);
+       spin_unlock_irq(hba->host->host_lock);
+}
+
 static void ufshcd_clk_scaling_allow(struct ufs_hba *hba, bool allow)
 {
+       mutex_lock(&hba->wb_mutex);
        down_write(&hba->clk_scaling_lock);
        hba->clk_scaling.is_allowed = allow;
        up_write(&hba->clk_scaling_lock);
+       mutex_unlock(&hba->wb_mutex);
 }
 
 static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend)
@@ -9083,6 +9091,15 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 
                if (!hba->dev_info.b_rpm_dev_flush_capable) {
                        ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
+                       if (ret && pm_op != UFS_SHUTDOWN_PM) {
+                               /*
+                                * If return err in suspend flow, IO will hang.
+                                * Trigger error handler and break suspend for
+                                * error recovery.
+                                */
+                               ufshcd_force_error_recovery(hba);
+                               ret = -EBUSY;
+                       }
                        if (ret)
                                goto enable_scaling;
                }
@@ -9094,6 +9111,15 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
         */
        check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba);
        ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops);
+       if (ret && pm_op != UFS_SHUTDOWN_PM) {
+               /*
+                * If return err in suspend flow, IO will hang.
+                * Trigger error handler and break suspend for
+                * error recovery.
+                */
+               ufshcd_force_error_recovery(hba);
+               ret = -EBUSY;
+       }
        if (ret)
                goto set_dev_active;
 
@@ -9767,6 +9793,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        /* Initialize mutex for exception event control */
        mutex_init(&hba->ee_ctrl_mutex);
 
+       mutex_init(&hba->wb_mutex);
        init_rwsem(&hba->clk_scaling_lock);
 
        ufshcd_init_clk_gating(hba);
index 5adcb34..ccfaebc 100644 (file)
@@ -2614,6 +2614,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep,
        u8 req_on_hw_ring = 0;
        unsigned long flags;
        int ret = 0;
+       int val;
 
        if (!ep || !request || !ep->desc)
                return -EINVAL;
@@ -2649,6 +2650,13 @@ found:
 
        /* Update ring only if removed request is on pending_req_list list */
        if (req_on_hw_ring && link_trb) {
+               /* Stop DMA */
+               writel(EP_CMD_DFLUSH, &priv_dev->regs->ep_cmd);
+
+               /* wait for DFLUSH cleared */
+               readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val,
+                                         !(val & EP_CMD_DFLUSH), 1, 1000);
+
                link_trb->buffer = cpu_to_le32(TRB_BUFFER(priv_ep->trb_pool_dma +
                        ((priv_req->end_trb + 1) * TRB_SIZE)));
                link_trb->control = cpu_to_le32((le32_to_cpu(link_trb->control) & TRB_CYCLE) |
@@ -2660,6 +2668,10 @@ found:
 
        cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET);
 
+       req = cdns3_next_request(&priv_ep->pending_req_list);
+       if (req)
+               cdns3_rearm_transfer(priv_ep, 1);
+
 not_found:
        spin_unlock_irqrestore(&priv_dev->lock, flags);
        return ret;
index 484b1cd..27c6012 100644 (file)
@@ -1294,12 +1294,12 @@ static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
        cable_id = &ci->platdata->id_extcon;
        cable_vbus = &ci->platdata->vbus_extcon;
 
-       if ((!IS_ERR(cable_id->edev) || !IS_ERR(ci->role_switch))
+       if ((!IS_ERR(cable_id->edev) || ci->role_switch)
                && ci->is_otg &&
                (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
                ci_irq(ci);
 
-       if ((!IS_ERR(cable_vbus->edev) || !IS_ERR(ci->role_switch))
+       if ((!IS_ERR(cable_vbus->edev) || ci->role_switch)
                && ci->is_otg &&
                (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
                ci_irq(ci);
index 77e73fc..9eca403 100644 (file)
@@ -44,6 +44,9 @@
 #define USB_PRODUCT_USB5534B                   0x5534
 #define USB_VENDOR_CYPRESS                     0x04b4
 #define USB_PRODUCT_CY7C65632                  0x6570
+#define USB_VENDOR_TEXAS_INSTRUMENTS           0x0451
+#define USB_PRODUCT_TUSB8041_USB3              0x8140
+#define USB_PRODUCT_TUSB8041_USB2              0x8142
 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND       0x01
 #define HUB_QUIRK_DISABLE_AUTOSUSPEND          0x02
 
@@ -5854,6 +5857,16 @@ static const struct usb_device_id hub_id_table[] = {
       .idVendor = USB_VENDOR_GENESYS_LOGIC,
       .bInterfaceClass = USB_CLASS_HUB,
       .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
+    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+                       | USB_DEVICE_ID_MATCH_PRODUCT,
+      .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
+      .idProduct = USB_PRODUCT_TUSB8041_USB2,
+      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
+    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+                       | USB_DEVICE_ID_MATCH_PRODUCT,
+      .idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
+      .idProduct = USB_PRODUCT_TUSB8041_USB3,
+      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
       .bDeviceClass = USB_CLASS_HUB},
     { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
index 079e183..934b3d9 100644 (file)
@@ -526,6 +526,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* DJI CineSSD */
        { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
 
+       /* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */
+       { USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM },
+
        /* DELL USB GEN2 */
        { USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
 
index 6d93428..533baa8 100644 (file)
@@ -37,6 +37,71 @@ bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
 }
 EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);
 
+#define UUID_USB_CONTROLLER_DSM "ce2ee385-00e6-48cb-9f05-2edb927c4899"
+#define USB_DSM_DISABLE_U1_U2_FOR_PORT 5
+
+/**
+ * usb_acpi_port_lpm_incapable - check if lpm should be disabled for a port.
+ * @hdev: USB device belonging to the usb hub
+ * @index: zero based port index
+ *
+ * Some USB3 ports may not support USB3 link power management U1/U2 states
+ * due to different retimer setup. ACPI provides _DSM method which returns 0x01
+ * if U1 and U2 states should be disabled. Evaluate _DSM with:
+ * Arg0: UUID = ce2ee385-00e6-48cb-9f05-2edb927c4899
+ * Arg1: Revision ID = 0
+ * Arg2: Function Index = 5
+ * Arg3: (empty)
+ *
+ * Return 1 if USB3 port is LPM incapable, negative on error, otherwise 0
+ */
+
+int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
+{
+       union acpi_object *obj;
+       acpi_handle port_handle;
+       int port1 = index + 1;
+       guid_t guid;
+       int ret;
+
+       ret = guid_parse(UUID_USB_CONTROLLER_DSM, &guid);
+       if (ret)
+               return ret;
+
+       port_handle = usb_get_hub_port_acpi_handle(hdev, port1);
+       if (!port_handle) {
+               dev_dbg(&hdev->dev, "port-%d no acpi handle\n", port1);
+               return -ENODEV;
+       }
+
+       if (!acpi_check_dsm(port_handle, &guid, 0,
+                           BIT(USB_DSM_DISABLE_U1_U2_FOR_PORT))) {
+               dev_dbg(&hdev->dev, "port-%d no _DSM function %d\n",
+                       port1, USB_DSM_DISABLE_U1_U2_FOR_PORT);
+               return -ENODEV;
+       }
+
+       obj = acpi_evaluate_dsm(port_handle, &guid, 0,
+                               USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL);
+
+       if (!obj)
+               return -ENODEV;
+
+       if (obj->type != ACPI_TYPE_INTEGER) {
+               dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1);
+               ACPI_FREE(obj);
+               return -EINVAL;
+       }
+
+       if (obj->integer.value == 0x01)
+               ret = 1;
+
+       ACPI_FREE(obj);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_acpi_port_lpm_incapable);
+
 /**
  * usb_acpi_set_power_state - control usb port's power via acpi power
  * resource
index b2f72b0..be954a9 100644 (file)
@@ -3,6 +3,7 @@
 config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
        depends on (USB || USB_GADGET) && HAS_DMA
+       depends on (EXTCON || EXTCON=n)
        select USB_XHCI_PLATFORM if USB_XHCI_HCD
        select USB_ROLE_SWITCH if USB_DWC3_DUAL_ROLE
        help
@@ -44,7 +45,6 @@ config USB_DWC3_GADGET
 config USB_DWC3_DUAL_ROLE
        bool "Dual Role mode"
        depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
-       depends on (EXTCON=y || EXTCON=USB_DWC3)
        help
          This is the default mode of working of DWC3 controller where
          both host and gadget features are enabled.
index b0a0351..959fc92 100644 (file)
@@ -901,7 +901,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
        qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
 
        /* enable vbus override for device mode */
-       if (qcom->mode == USB_DR_MODE_PERIPHERAL)
+       if (qcom->mode != USB_DR_MODE_HOST)
                dwc3_qcom_vbus_override_enable(qcom, true);
 
        /* register extcon to override sw_vbus on Vbus change later */
index 87cca81..eb07674 100644 (file)
@@ -1014,7 +1014,6 @@ static int fotg210_udc_start(struct usb_gadget *g,
        int ret;
 
        /* hook up the driver */
-       driver->driver.bus = NULL;
        fotg210->driver = driver;
 
        if (!IS_ERR_OR_NULL(fotg210->phy)) {
index 96121d1..0853536 100644 (file)
@@ -393,6 +393,7 @@ static void gadget_info_attr_release(struct config_item *item)
        WARN_ON(!list_empty(&gi->string_list));
        WARN_ON(!list_empty(&gi->available_func));
        kfree(gi->composite.gadget_driver.function);
+       kfree(gi->composite.gadget_driver.driver.name);
        kfree(gi);
 }
 
@@ -1572,7 +1573,6 @@ static const struct usb_gadget_driver configfs_driver_template = {
        .max_speed      = USB_SPEED_SUPER_PLUS,
        .driver = {
                .owner          = THIS_MODULE,
-               .name           = "configfs-gadget",
        },
        .match_existing_only = 1,
 };
@@ -1623,13 +1623,21 @@ static struct config_group *gadgets_make(
 
        gi->composite.gadget_driver = configfs_driver_template;
 
+       gi->composite.gadget_driver.driver.name = kasprintf(GFP_KERNEL,
+                                                           "configfs-gadget.%s", name);
+       if (!gi->composite.gadget_driver.driver.name)
+               goto err;
+
        gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
        gi->composite.name = gi->composite.gadget_driver.function;
 
        if (!gi->composite.gadget_driver.function)
-               goto err;
+               goto out_free_driver_name;
 
        return &gi->group;
+
+out_free_driver_name:
+       kfree(gi->composite.gadget_driver.driver.name);
 err:
        kfree(gi);
        return ERR_PTR(-ENOMEM);
index 73dc10a..8ad3547 100644 (file)
@@ -279,6 +279,11 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
        struct usb_request *req = ffs->ep0req;
        int ret;
 
+       if (!req) {
+               spin_unlock_irq(&ffs->ev.waitq.lock);
+               return -EINVAL;
+       }
+
        req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
 
        spin_unlock_irq(&ffs->ev.waitq.lock);
@@ -1892,10 +1897,14 @@ static void functionfs_unbind(struct ffs_data *ffs)
        ENTER();
 
        if (!WARN_ON(!ffs->gadget)) {
+               /* dequeue before freeing ep0req */
+               usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
+               mutex_lock(&ffs->mutex);
                usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
                ffs->ep0req = NULL;
                ffs->gadget = NULL;
                clear_bit(FFS_FL_BOUND, &ffs->flags);
+               mutex_unlock(&ffs->mutex);
                ffs_data_put(ffs);
        }
 }
index c36bcfa..424bb3b 100644 (file)
@@ -83,7 +83,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static inline unsigned ncm_bitrate(struct usb_gadget *g)
 {
-       if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
+       if (!g)
+               return 0;
+       else if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER_PLUS)
                return 4250000000U;
        else if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
                return 3750000000U;
index 08726e4..0219cd7 100644 (file)
@@ -1142,6 +1142,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
                }
                std_as_out_if0_desc.bInterfaceNumber = ret;
                std_as_out_if1_desc.bInterfaceNumber = ret;
+               std_as_out_if1_desc.bNumEndpoints = 1;
                uac2->as_out_intf = ret;
                uac2->as_out_alt = 0;
 
index 8f12f3f..e060228 100644 (file)
@@ -798,6 +798,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
        net->max_mtu = GETHER_MAX_MTU_SIZE;
 
        dev->gadget = g;
+       SET_NETDEV_DEV(net, &g->dev);
        SET_NETDEV_DEVTYPE(net, &gadget_type);
 
        status = register_netdev(net);
@@ -872,6 +873,8 @@ int gether_register_netdev(struct net_device *net)
        struct usb_gadget *g;
        int status;
 
+       if (!net->dev.parent)
+               return -EINVAL;
        dev = netdev_priv(net);
        g = dev->gadget;
 
@@ -902,6 +905,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)
 
        dev = netdev_priv(net);
        dev->gadget = g;
+       SET_NETDEV_DEV(net, &g->dev);
 }
 EXPORT_SYMBOL_GPL(gether_set_gadget);
 
index 01c3ead..d605bc2 100644 (file)
@@ -229,6 +229,7 @@ static void put_ep (struct ep_data *data)
  */
 
 static const char *CHIP;
+static DEFINE_MUTEX(sb_mutex);         /* Serialize superblock operations */
 
 /*----------------------------------------------------------------------*/
 
@@ -2010,13 +2011,20 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
 {
        struct inode    *inode;
        struct dev_data *dev;
+       int             rc;
 
-       if (the_device)
-               return -ESRCH;
+       mutex_lock(&sb_mutex);
+
+       if (the_device) {
+               rc = -ESRCH;
+               goto Done;
+       }
 
        CHIP = usb_get_gadget_udc_name();
-       if (!CHIP)
-               return -ENODEV;
+       if (!CHIP) {
+               rc = -ENODEV;
+               goto Done;
+       }
 
        /* superblock */
        sb->s_blocksize = PAGE_SIZE;
@@ -2053,13 +2061,17 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
         * from binding to a controller.
         */
        the_device = dev;
-       return 0;
+       rc = 0;
+       goto Done;
 
-Enomem:
+ Enomem:
        kfree(CHIP);
        CHIP = NULL;
+       rc = -ENOMEM;
 
-       return -ENOMEM;
+ Done:
+       mutex_unlock(&sb_mutex);
+       return rc;
 }
 
 /* "mount -t gadgetfs path /dev/gadget" ends up here */
@@ -2081,6 +2093,7 @@ static int gadgetfs_init_fs_context(struct fs_context *fc)
 static void
 gadgetfs_kill_sb (struct super_block *sb)
 {
+       mutex_lock(&sb_mutex);
        kill_litter_super (sb);
        if (the_device) {
                put_dev (the_device);
@@ -2088,6 +2101,7 @@ gadgetfs_kill_sb (struct super_block *sb)
        }
        kfree(CHIP);
        CHIP = NULL;
+       mutex_unlock(&sb_mutex);
 }
 
 /*----------------------------------------------------------------------*/
index 53e38f8..c06dd1a 100644 (file)
@@ -293,6 +293,7 @@ static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
        (const struct uvc_descriptor_header *) &uvc_format_yuv,
        (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
        (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+       (const struct uvc_descriptor_header *) &uvc_color_matching,
        (const struct uvc_descriptor_header *) &uvc_format_mjpg,
        (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
        (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
@@ -305,6 +306,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
        (const struct uvc_descriptor_header *) &uvc_format_yuv,
        (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
        (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+       (const struct uvc_descriptor_header *) &uvc_color_matching,
        (const struct uvc_descriptor_header *) &uvc_format_mjpg,
        (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
        (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
@@ -317,6 +319,7 @@ static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
        (const struct uvc_descriptor_header *) &uvc_format_yuv,
        (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
        (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+       (const struct uvc_descriptor_header *) &uvc_color_matching,
        (const struct uvc_descriptor_header *) &uvc_format_mjpg,
        (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
        (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
index 2cdb079..d04d72f 100644 (file)
@@ -1830,7 +1830,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
        bcm63xx_select_phy_mode(udc, true);
 
        udc->driver = driver;
-       driver->driver.bus = NULL;
        udc->gadget.dev.of_node = udc->dev->of_node;
 
        spin_unlock_irqrestore(&udc->lock, flags);
index bf74535..3b1cc8f 100644 (file)
@@ -2285,7 +2285,6 @@ static int fsl_qe_start(struct usb_gadget *gadget,
        /* lock is needed but whether should use this lock or another */
        spin_lock_irqsave(&udc->lock, flags);
 
-       driver->driver.bus = NULL;
        /* hook up the driver */
        udc->driver = driver;
        udc->gadget.speed = driver->max_speed;
index 50435e8..a67873a 100644 (file)
@@ -1943,7 +1943,6 @@ static int fsl_udc_start(struct usb_gadget *g,
        /* lock is needed but whether should use this lock or another */
        spin_lock_irqsave(&udc_controller->lock, flags);
 
-       driver->driver.bus = NULL;
        /* hook up the driver */
        udc_controller->driver = driver;
        spin_unlock_irqrestore(&udc_controller->lock, flags);
index 9af8b41..5954800 100644 (file)
@@ -1311,7 +1311,6 @@ static int fusb300_udc_start(struct usb_gadget *g,
        struct fusb300 *fusb300 = to_fusb300(g);
 
        /* hook up the driver */
-       driver->driver.bus = NULL;
        fusb300->driver = driver;
 
        return 0;
index bdc56b2..5ffb3d5 100644 (file)
@@ -1375,7 +1375,6 @@ static int goku_udc_start(struct usb_gadget *g,
        struct goku_udc *dev = to_goku_udc(g);
 
        /* hook up the driver */
-       driver->driver.bus = NULL;
        dev->driver = driver;
 
        /*
index 22096f8..85cdc0a 100644 (file)
@@ -1906,7 +1906,6 @@ static int gr_udc_start(struct usb_gadget *gadget,
        spin_lock(&dev->lock);
 
        /* Hook up the driver */
-       driver->driver.bus = NULL;
        dev->driver = driver;
 
        /* Get ready for host detection */
index c7e421b..06e21ce 100644 (file)
@@ -1454,7 +1454,6 @@ static int m66592_udc_start(struct usb_gadget *g,
        struct m66592 *m66592 = to_m66592(g);
 
        /* hook up the driver */
-       driver->driver.bus = NULL;
        m66592->driver = driver;
 
        m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
index 3074da0..ddf0ed3 100644 (file)
@@ -1108,7 +1108,6 @@ static int max3420_udc_start(struct usb_gadget *gadget,
 
        spin_lock_irqsave(&udc->lock, flags);
        /* hook up the driver */
-       driver->driver.bus = NULL;
        udc->driver = driver;
        udc->gadget.speed = USB_SPEED_FULL;
 
index 598654a..411b617 100644 (file)
@@ -1243,7 +1243,6 @@ static int mv_u3d_start(struct usb_gadget *g,
        }
 
        /* hook up the driver ... */
-       driver->driver.bus = NULL;
        u3d->driver = driver;
 
        u3d->ep0_dir = USB_DIR_OUT;
index fdb17d8..b397f3a 100644 (file)
@@ -1359,7 +1359,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
        spin_lock_irqsave(&udc->lock, flags);
 
        /* hook up the driver ... */
-       driver->driver.bus = NULL;
        udc->driver = driver;
 
        udc->usb_state = USB_STATE_ATTACHED;
index 84605a4..538c1b9 100644 (file)
@@ -1451,7 +1451,6 @@ static int net2272_start(struct usb_gadget *_gadget,
                dev->ep[i].irqs = 0;
        /* hook up the driver ... */
        dev->softconnect = 1;
-       driver->driver.bus = NULL;
        dev->driver = driver;
 
        /* ... then enable host detection and ep0; and we're ready
index d6a6863..1b929c5 100644 (file)
@@ -2423,7 +2423,6 @@ static int net2280_start(struct usb_gadget *_gadget,
                dev->ep[i].irqs = 0;
 
        /* hook up the driver ... */
-       driver->driver.bus = NULL;
        dev->driver = driver;
 
        retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
index bea346e..f660ebf 100644 (file)
@@ -2066,7 +2066,6 @@ static int omap_udc_start(struct usb_gadget *g,
        udc->softconnect = 1;
 
        /* hook up the driver */
-       driver->driver.bus = NULL;
        udc->driver = driver;
        spin_unlock_irqrestore(&udc->lock, flags);
 
index 9bb7a9d..4f86172 100644 (file)
@@ -2908,7 +2908,6 @@ static int pch_udc_start(struct usb_gadget *g,
 {
        struct pch_udc_dev      *dev = to_pch_udc(g);
 
-       driver->driver.bus = NULL;
        dev->driver = driver;
 
        /* get ready for ep0 traffic */
index 52ea4dc..2fc5d4d 100644 (file)
@@ -1933,7 +1933,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
        struct udc *dev = to_amd5536_udc(g);
        u32 tmp;
 
-       driver->driver.bus = NULL;
        dev->driver = driver;
 
        /* Some gadget drivers use both ep0 directions.
index 9cea785..38d06e5 100644 (file)
@@ -29,7 +29,7 @@
 #include "ehci-fsl.h"
 
 #define DRIVER_DESC "Freescale EHCI Host controller driver"
-#define DRV_NAME "ehci-fsl"
+#define DRV_NAME "fsl-ehci"
 
 static struct hc_driver __read_mostly fsl_ehci_hc_driver;
 
index de1b091..46fdab9 100644 (file)
@@ -1530,15 +1530,13 @@ static void xenhcd_backend_changed(struct xenbus_device *dev,
        }
 }
 
-static int xenhcd_remove(struct xenbus_device *dev)
+static void xenhcd_remove(struct xenbus_device *dev)
 {
        struct xenhcd_info *info = dev_get_drvdata(&dev->dev);
        struct usb_hcd *hcd = xenhcd_info_to_hcd(info);
 
        xenhcd_destroy_rings(info);
        usb_put_hcd(hcd);
-
-       return 0;
 }
 
 static int xenhcd_probe(struct xenbus_device *dev,
index 79d679b..fb988e4 100644 (file)
@@ -78,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd";
 static struct hc_driver __read_mostly xhci_pci_hc_driver;
 
 static int xhci_pci_setup(struct usb_hcd *hcd);
+static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
+                                     struct usb_tt *tt, gfp_t mem_flags);
 
 static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
        .reset = xhci_pci_setup,
+       .update_hub_device = xhci_pci_update_hub_device,
 };
 
 /* called after powerup, by probe or system-pm "wakeup" */
@@ -352,8 +355,38 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
                                NULL);
        ACPI_FREE(obj);
 }
+
+static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct xhci_hub *rhub = &xhci->usb3_rhub;
+       int ret;
+       int i;
+
+       /* This is not the usb3 roothub we are looking for */
+       if (hcd != rhub->hcd)
+               return;
+
+       if (hdev->maxchild > rhub->num_ports) {
+               dev_err(&hdev->dev, "USB3 roothub port number mismatch\n");
+               return;
+       }
+
+       for (i = 0; i < hdev->maxchild; i++) {
+               ret = usb_acpi_port_lpm_incapable(hdev, i);
+
+               dev_dbg(&hdev->dev, "port-%d disable U1/U2 _DSM: %d\n", i + 1, ret);
+
+               if (ret >= 0) {
+                       rhub->ports[i]->lpm_incapable = ret;
+                       continue;
+               }
+       }
+}
+
 #else
 static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+static void xhci_find_lpm_incapable_ports(struct usb_hcd *hcd, struct usb_device *hdev) { }
 #endif /* CONFIG_ACPI */
 
 /* called during probe() after chip reset completes */
@@ -386,6 +419,16 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
        return xhci_pci_reinit(xhci, pdev);
 }
 
+static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
+                                     struct usb_tt *tt, gfp_t mem_flags)
+{
+       /* Check if acpi claims some USB3 roothub ports are lpm incapable */
+       if (!hdev->parent)
+               xhci_find_lpm_incapable_ports(hcd, hdev);
+
+       return xhci_update_hub_device(hcd, hdev, tt, mem_flags);
+}
+
 /*
  * We need to register our own PCI probe function (instead of the USB core's
  * function) in order to create a second roothub under xHCI.
@@ -455,6 +498,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (xhci->quirks & XHCI_DEFAULT_PM_RUNTIME_ALLOW)
                pm_runtime_allow(&dev->dev);
 
+       dma_set_max_seg_size(&dev->dev, UINT_MAX);
+
        return 0;
 
 put_usb3_hcd:
index ddc3003..f5b0e1c 100644 (file)
@@ -1169,7 +1169,10 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci,
        struct xhci_virt_ep *ep;
        struct xhci_ring *ring;
 
-       ep = &xhci->devs[slot_id]->eps[ep_index];
+       ep = xhci_get_virt_ep(xhci, slot_id, ep_index);
+       if (!ep)
+               return;
+
        if ((ep->ep_state & EP_HAS_STREAMS) ||
                        (ep->ep_state & EP_GETTING_NO_STREAMS)) {
                int stream_id;
index 79d7931..2b280be 100644 (file)
@@ -3974,6 +3974,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        struct xhci_virt_device *virt_dev;
        struct xhci_slot_ctx *slot_ctx;
+       unsigned long flags;
        int i, ret;
 
        /*
@@ -4000,7 +4001,11 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
                virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
        virt_dev->udev = NULL;
        xhci_disable_slot(xhci, udev->slot_id);
+
+       spin_lock_irqsave(&xhci->lock, flags);
        xhci_free_virt_device(xhci, udev->slot_id);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+
 }
 
 int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
@@ -5044,6 +5049,7 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
                        struct usb_device *udev, enum usb3_link_state state)
 {
        struct xhci_hcd *xhci;
+       struct xhci_port *port;
        u16 hub_encoded_timeout;
        int mel;
        int ret;
@@ -5060,6 +5066,13 @@ static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
        if (xhci_check_tier_policy(xhci, udev, state) < 0)
                return USB3_LPM_DISABLED;
 
+       /* If connected to root port then check port can handle lpm */
+       if (udev->parent && !udev->parent->parent) {
+               port = xhci->usb3_rhub.ports[udev->portnum - 1];
+               if (port->lpm_incapable)
+                       return USB3_LPM_DISABLED;
+       }
+
        hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
        mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
        if (mel < 0) {
@@ -5119,7 +5132,7 @@ static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
 /* Once a hub descriptor is fetched for a device, we need to update the xHC's
  * internal data structures for the device.
  */
-static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
+int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
                        struct usb_tt *tt, gfp_t mem_flags)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -5219,6 +5232,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
        xhci_free_command(xhci, config_cmd);
        return ret;
 }
+EXPORT_SYMBOL_GPL(xhci_update_hub_device);
 
 static int xhci_get_frame(struct usb_hcd *hcd)
 {
@@ -5502,6 +5516,8 @@ void xhci_init_driver(struct hc_driver *drv,
                        drv->check_bandwidth = over->check_bandwidth;
                if (over->reset_bandwidth)
                        drv->reset_bandwidth = over->reset_bandwidth;
+               if (over->update_hub_device)
+                       drv->update_hub_device = over->update_hub_device;
        }
 }
 EXPORT_SYMBOL_GPL(xhci_init_driver);
index c9f06c5..dcee7f3 100644 (file)
@@ -1735,6 +1735,7 @@ struct xhci_port {
        int                     hcd_portnum;
        struct xhci_hub         *rhub;
        struct xhci_port_cap    *port_cap;
+       unsigned int            lpm_incapable:1;
 };
 
 struct xhci_hub {
@@ -1943,6 +1944,8 @@ struct xhci_driver_overrides {
                             struct usb_host_endpoint *ep);
        int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
        void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
+       int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev,
+                           struct usb_tt *tt, gfp_t mem_flags);
 };
 
 #define        XHCI_CFC_DELAY          10
@@ -2122,6 +2125,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
                       struct usb_host_endpoint *ep);
 int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
+                          struct usb_tt *tt, gfp_t mem_flags);
 int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
 int xhci_ext_cap_init(struct xhci_hcd *xhci);
 
index f9427a6..1e3df27 100644 (file)
@@ -814,7 +814,7 @@ static int iowarrior_probe(struct usb_interface *interface,
                        break;
 
                case USB_DEVICE_ID_CODEMERCS_IOW100:
-                       dev->report_size = 13;
+                       dev->report_size = 12;
                        break;
                }
        }
index 94e7966..969c4c4 100644 (file)
 
 #include "onboard_usb_hub.h"
 
+static void onboard_hub_attach_usb_driver(struct work_struct *work);
+
 static struct usb_device_driver onboard_hub_usbdev_driver;
+static DECLARE_WORK(attach_usb_driver_work, onboard_hub_attach_usb_driver);
 
 /************************** Platform driver **************************/
 
@@ -45,7 +48,6 @@ struct onboard_hub {
        bool is_powered_on;
        bool going_away;
        struct list_head udev_list;
-       struct work_struct attach_usb_driver_work;
        struct mutex lock;
 };
 
@@ -271,8 +273,7 @@ static int onboard_hub_probe(struct platform_device *pdev)
         * This needs to be done deferred to avoid self-deadlocks on systems
         * with nested onboard hubs.
         */
-       INIT_WORK(&hub->attach_usb_driver_work, onboard_hub_attach_usb_driver);
-       schedule_work(&hub->attach_usb_driver_work);
+       schedule_work(&attach_usb_driver_work);
 
        return 0;
 }
@@ -285,9 +286,6 @@ static int onboard_hub_remove(struct platform_device *pdev)
 
        hub->going_away = true;
 
-       if (&hub->attach_usb_driver_work != current_work())
-               cancel_work_sync(&hub->attach_usb_driver_work);
-
        mutex_lock(&hub->lock);
 
        /* unbind the USB devices to avoid dangling references to this device */
@@ -433,13 +431,13 @@ static int __init onboard_hub_init(void)
 {
        int ret;
 
-       ret = platform_driver_register(&onboard_hub_driver);
+       ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
        if (ret)
                return ret;
 
-       ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE);
+       ret = platform_driver_register(&onboard_hub_driver);
        if (ret)
-               platform_driver_unregister(&onboard_hub_driver);
+               usb_deregister_device_driver(&onboard_hub_usbdev_driver);
 
        return ret;
 }
@@ -449,6 +447,8 @@ static void __exit onboard_hub_exit(void)
 {
        usb_deregister_device_driver(&onboard_hub_usbdev_driver);
        platform_driver_unregister(&onboard_hub_driver);
+
+       cancel_work_sync(&attach_usb_driver_work);
 }
 module_exit(onboard_hub_exit);
 
index 476f55d..44a21ec 100644 (file)
@@ -411,8 +411,10 @@ static int omap2430_probe(struct platform_device *pdev)
                memset(musb_res, 0, sizeof(*musb_res) * ARRAY_SIZE(musb_res));
 
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (!res)
+               if (!res) {
+                       ret = -EINVAL;
                        goto err2;
+               }
 
                musb_res[i].start = res->start;
                musb_res[i].end = res->end;
index 67372ac..832ad59 100644 (file)
@@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
        { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
        { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
+       { USB_DEVICE(0x0908, 0x0070) }, /* Siemens SCALANCE LPE-9000 USB Serial Console */
        { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
        { USB_DEVICE(0x0988, 0x0578) }, /* Teraoka AD2000 */
        { USB_DEVICE(0x0B00, 0x3070) }, /* Ingenico 3070 */
index dee79c7..ee5ac4e 100644 (file)
@@ -255,10 +255,16 @@ static void option_instat_callback(struct urb *urb);
 #define QUECTEL_PRODUCT_EP06                   0x0306
 #define QUECTEL_PRODUCT_EM05G                  0x030a
 #define QUECTEL_PRODUCT_EM060K                 0x030b
+#define QUECTEL_PRODUCT_EM05G_CS               0x030c
+#define QUECTEL_PRODUCT_EM05CN_SG              0x0310
 #define QUECTEL_PRODUCT_EM05G_SG               0x0311
+#define QUECTEL_PRODUCT_EM05CN                 0x0312
+#define QUECTEL_PRODUCT_EM05G_GR               0x0313
+#define QUECTEL_PRODUCT_EM05G_RS               0x0314
 #define QUECTEL_PRODUCT_EM12                   0x0512
 #define QUECTEL_PRODUCT_RM500Q                 0x0800
 #define QUECTEL_PRODUCT_RM520N                 0x0801
+#define QUECTEL_PRODUCT_EC200U                 0x0901
 #define QUECTEL_PRODUCT_EC200S_CN              0x6002
 #define QUECTEL_PRODUCT_EC200T                 0x6026
 #define QUECTEL_PRODUCT_RM500K                 0x7001
@@ -1159,8 +1165,18 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
          .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
+       { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN, 0xff),
+         .driver_info = RSVD(6) | ZLP },
+       { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05CN_SG, 0xff),
+         .driver_info = RSVD(6) | ZLP },
        { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G, 0xff),
          .driver_info = RSVD(6) | ZLP },
+       { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_CS, 0xff),
+         .driver_info = RSVD(6) | ZLP },
+       { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_GR, 0xff),
+         .driver_info = RSVD(6) | ZLP },
+       { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_RS, 0xff),
+         .driver_info = RSVD(6) | ZLP },
        { USB_DEVICE_INTERFACE_CLASS(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM05G_SG, 0xff),
          .driver_info = RSVD(6) | ZLP },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
@@ -1180,6 +1196,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0xff, 0x30) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0x40) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM520N, 0xff, 0, 0) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) },
index 3f720fa..d73282c 100644 (file)
@@ -116,6 +116,19 @@ static int uas_use_uas_driver(struct usb_interface *intf,
        if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bc2)
                flags |= US_FL_NO_ATA_1X;
 
+       /*
+        * RTL9210-based enclosure from HIKSEMI, MD202 reportedly have issues
+        * with UAS.  This isn't distinguishable with just idVendor and
+        * idProduct, use manufacturer and product too.
+        *
+        * Reported-by: Hongling Zeng <zenghongling@kylinos.cn>
+        */
+       if (le16_to_cpu(udev->descriptor.idVendor) == 0x0bda &&
+                       le16_to_cpu(udev->descriptor.idProduct) == 0x9210 &&
+                       (udev->manufacturer && !strcmp(udev->manufacturer, "HIKSEMI")) &&
+                       (udev->product && !strcmp(udev->product, "MD202")))
+               flags |= US_FL_IGNORE_UAS;
+
        usb_stor_adjust_quirks(udev, &flags);
 
        if (flags & US_FL_IGNORE_UAS) {
index 251778d..c7b763d 100644 (file)
@@ -83,13 +83,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_REPORT_LUNS),
 
-/* Reported-by: Hongling Zeng <zenghongling@kylinos.cn> */
-UNUSUAL_DEV(0x0bda, 0x9210, 0x0000, 0x9999,
-               "Hiksemi",
-               "External HDD",
-               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-               US_FL_IGNORE_UAS),
-
 /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */
 UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999,
                "Initio Corporation",
index de66a29..50b2409 100644 (file)
@@ -419,6 +419,18 @@ static const char * const pin_assignments[] = {
        [DP_PIN_ASSIGN_F] = "F",
 };
 
+/*
+ * Helper function to extract a peripheral's currently supported
+ * Pin Assignments from its DisplayPort alternate mode state.
+ */
+static u8 get_current_pin_assignments(struct dp_altmode *dp)
+{
+       if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_UFP_U_AS_DFP_D)
+               return DP_CAP_PIN_ASSIGN_DFP_D(dp->alt->vdo);
+       else
+               return DP_CAP_PIN_ASSIGN_UFP_D(dp->alt->vdo);
+}
+
 static ssize_t
 pin_assignment_store(struct device *dev, struct device_attribute *attr,
                     const char *buf, size_t size)
@@ -445,10 +457,7 @@ pin_assignment_store(struct device *dev, struct device_attribute *attr,
                goto out_unlock;
        }
 
-       if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D)
-               assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
-       else
-               assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
+       assignments = get_current_pin_assignments(dp);
 
        if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
                ret = -EINVAL;
@@ -485,10 +494,7 @@ static ssize_t pin_assignment_show(struct device *dev,
 
        cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
 
-       if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D)
-               assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
-       else
-               assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
+       assignments = get_current_pin_assignments(dp);
 
        for (i = 0; assignments; assignments >>= 1, i++) {
                if (assignments & 1) {
@@ -529,10 +535,10 @@ int dp_altmode_probe(struct typec_altmode *alt)
        /* FIXME: Port can only be DFP_U. */
 
        /* Make sure we have compatiple pin configurations */
-       if (!(DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) &
-             DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo)) &&
-           !(DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) &
-             DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo)))
+       if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) &
+             DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) &&
+           !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) &
+             DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo)))
                return -ENODEV;
 
        ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group);
index 904c7b4..59b366b 100644 (file)
@@ -4594,14 +4594,13 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_set_state(port, ready_state(port), 0);
                break;
        case DR_SWAP_CHANGE_DR:
-               if (port->data_role == TYPEC_HOST) {
-                       tcpm_unregister_altmodes(port);
+               tcpm_unregister_altmodes(port);
+               if (port->data_role == TYPEC_HOST)
                        tcpm_set_roles(port, true, port->pwr_role,
                                       TYPEC_DEVICE);
-               } else {
+               else
                        tcpm_set_roles(port, true, port->pwr_role,
                                       TYPEC_HOST);
-               }
                tcpm_ams_finish(port);
                tcpm_set_state(port, ready_state(port), 0);
                break;
index eabe519..1cf8947 100644 (file)
@@ -187,6 +187,7 @@ EXPORT_SYMBOL_GPL(ucsi_send_command);
 
 struct ucsi_work {
        struct delayed_work work;
+       struct list_head node;
        unsigned long delay;
        unsigned int count;
        struct ucsi_connector *con;
@@ -202,6 +203,7 @@ static void ucsi_poll_worker(struct work_struct *work)
        mutex_lock(&con->lock);
 
        if (!con->partner) {
+               list_del(&uwork->node);
                mutex_unlock(&con->lock);
                kfree(uwork);
                return;
@@ -209,10 +211,12 @@ static void ucsi_poll_worker(struct work_struct *work)
 
        ret = uwork->cb(con);
 
-       if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT))
+       if (uwork->count-- && (ret == -EBUSY || ret == -ETIMEDOUT)) {
                queue_delayed_work(con->wq, &uwork->work, uwork->delay);
-       else
+       } else {
+               list_del(&uwork->node);
                kfree(uwork);
+       }
 
        mutex_unlock(&con->lock);
 }
@@ -236,6 +240,7 @@ static int ucsi_partner_task(struct ucsi_connector *con,
        uwork->con = con;
        uwork->cb = cb;
 
+       list_add_tail(&uwork->node, &con->partner_tasks);
        queue_delayed_work(con->wq, &uwork->work, delay);
 
        return 0;
@@ -1056,6 +1061,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
        INIT_WORK(&con->work, ucsi_handle_connector_change);
        init_completion(&con->complete);
        mutex_init(&con->lock);
+       INIT_LIST_HEAD(&con->partner_tasks);
        con->num = index + 1;
        con->ucsi = ucsi;
 
@@ -1263,6 +1269,9 @@ err_unregister:
                con->port = NULL;
        }
 
+       kfree(ucsi->connector);
+       ucsi->connector = NULL;
+
 err_reset:
        memset(&ucsi->cap, 0, sizeof(ucsi->cap));
        ucsi_reset_ppm(ucsi);
@@ -1294,7 +1303,8 @@ static void ucsi_resume_work(struct work_struct *work)
 
 int ucsi_resume(struct ucsi *ucsi)
 {
-       queue_work(system_long_wq, &ucsi->resume_work);
+       if (ucsi->connector)
+               queue_work(system_long_wq, &ucsi->resume_work);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ucsi_resume);
@@ -1414,14 +1424,29 @@ void ucsi_unregister(struct ucsi *ucsi)
        /* Disable notifications */
        ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
 
+       if (!ucsi->connector)
+               return;
+
        for (i = 0; i < ucsi->cap.num_connectors; i++) {
                cancel_work_sync(&ucsi->connector[i].work);
                ucsi_unregister_partner(&ucsi->connector[i]);
                ucsi_unregister_altmodes(&ucsi->connector[i],
                                         UCSI_RECIPIENT_CON);
                ucsi_unregister_port_psy(&ucsi->connector[i]);
-               if (ucsi->connector[i].wq)
+
+               if (ucsi->connector[i].wq) {
+                       struct ucsi_work *uwork;
+
+                       mutex_lock(&ucsi->connector[i].lock);
+                       /*
+                        * queue delayed items immediately so they can execute
+                        * and free themselves before the wq is destroyed
+                        */
+                       list_for_each_entry(uwork, &ucsi->connector[i].partner_tasks, node)
+                               mod_delayed_work(ucsi->connector[i].wq, &uwork->work, 0);
+                       mutex_unlock(&ucsi->connector[i].lock);
                        destroy_workqueue(ucsi->connector[i].wq);
+               }
                typec_unregister_port(ucsi->connector[i].port);
        }
 
index c968474..60ce9fb 100644 (file)
@@ -322,6 +322,7 @@ struct ucsi_connector {
        struct work_struct work;
        struct completion complete;
        struct workqueue_struct *wq;
+       struct list_head partner_tasks;
 
        struct typec_port *port;
        struct typec_partner *partner;
index f9c0044..44b2928 100644 (file)
@@ -849,7 +849,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        ret = ifcvf_init_hw(vf, pdev);
        if (ret) {
                IFCVF_ERR(pdev, "Failed to init IFCVF hw\n");
-               return ret;
+               goto err;
        }
 
        for (i = 0; i < vf->nr_vring; i++)
index 23c24fe..2209372 100644 (file)
@@ -1856,24 +1856,33 @@ unwind:
  * significantly boosts non-hugetlbfs mappings and doesn't seem to hurt when
  * hugetlbfs is in use.
  */
-static void vfio_test_domain_fgsp(struct vfio_domain *domain)
+static void vfio_test_domain_fgsp(struct vfio_domain *domain, struct list_head *regions)
 {
-       struct page *pages;
        int ret, order = get_order(PAGE_SIZE * 2);
+       struct vfio_iova *region;
+       struct page *pages;
+       dma_addr_t start;
 
        pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
        if (!pages)
                return;
 
-       ret = iommu_map(domain->domain, 0, page_to_phys(pages), PAGE_SIZE * 2,
-                       IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
-       if (!ret) {
-               size_t unmapped = iommu_unmap(domain->domain, 0, PAGE_SIZE);
+       list_for_each_entry(region, regions, list) {
+               start = ALIGN(region->start, PAGE_SIZE * 2);
+               if (start >= region->end || (region->end - start < PAGE_SIZE * 2))
+                       continue;
 
-               if (unmapped == PAGE_SIZE)
-                       iommu_unmap(domain->domain, PAGE_SIZE, PAGE_SIZE);
-               else
-                       domain->fgsp = true;
+               ret = iommu_map(domain->domain, start, page_to_phys(pages), PAGE_SIZE * 2,
+                               IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+               if (!ret) {
+                       size_t unmapped = iommu_unmap(domain->domain, start, PAGE_SIZE);
+
+                       if (unmapped == PAGE_SIZE)
+                               iommu_unmap(domain->domain, start + PAGE_SIZE, PAGE_SIZE);
+                       else
+                               domain->fgsp = true;
+               }
+               break;
        }
 
        __free_pages(pages, order);
@@ -2326,7 +2335,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
                }
        }
 
-       vfio_test_domain_fgsp(domain);
+       vfio_test_domain_fgsp(domain, &iova_copy);
 
        /* replay mappings on new domains */
        ret = vfio_iommu_replay(iommu, domain);
index 9af19b0..4c538b3 100644 (file)
@@ -1511,6 +1511,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        nvq = &n->vqs[index];
        mutex_lock(&vq->mutex);
 
+       if (fd == -1)
+               vhost_clear_msg(&n->dev);
+
        /* Verify that ring has been setup correctly. */
        if (!vhost_vq_access_ok(vq)) {
                r = -EFAULT;
index dca6346..d5ecb88 100644 (file)
@@ -80,7 +80,7 @@ struct vhost_scsi_cmd {
        struct scatterlist *tvc_prot_sgl;
        struct page **tvc_upages;
        /* Pointer to response header iovec */
-       struct iovec tvc_resp_iov;
+       struct iovec *tvc_resp_iov;
        /* Pointer to vhost_scsi for our device */
        struct vhost_scsi *tvc_vhost;
        /* Pointer to vhost_virtqueue for the cmd */
@@ -563,7 +563,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
                memcpy(v_rsp.sense, cmd->tvc_sense_buf,
                       se_cmd->scsi_sense_length);
 
-               iov_iter_init(&iov_iter, ITER_DEST, &cmd->tvc_resp_iov,
+               iov_iter_init(&iov_iter, ITER_DEST, cmd->tvc_resp_iov,
                              cmd->tvc_in_iovs, sizeof(v_rsp));
                ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
                if (likely(ret == sizeof(v_rsp))) {
@@ -594,6 +594,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
        struct vhost_scsi_cmd *cmd;
        struct vhost_scsi_nexus *tv_nexus;
        struct scatterlist *sg, *prot_sg;
+       struct iovec *tvc_resp_iov;
        struct page **pages;
        int tag;
 
@@ -613,6 +614,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
        sg = cmd->tvc_sgl;
        prot_sg = cmd->tvc_prot_sgl;
        pages = cmd->tvc_upages;
+       tvc_resp_iov = cmd->tvc_resp_iov;
        memset(cmd, 0, sizeof(*cmd));
        cmd->tvc_sgl = sg;
        cmd->tvc_prot_sgl = prot_sg;
@@ -625,6 +627,7 @@ vhost_scsi_get_cmd(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
        cmd->tvc_data_direction = data_direction;
        cmd->tvc_nexus = tv_nexus;
        cmd->inflight = vhost_scsi_get_inflight(vq);
+       cmd->tvc_resp_iov = tvc_resp_iov;
 
        memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE);
 
@@ -935,7 +938,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
        struct iov_iter in_iter, prot_iter, data_iter;
        u64 tag;
        u32 exp_data_len, data_direction;
-       int ret, prot_bytes, c = 0;
+       int ret, prot_bytes, i, c = 0;
        u16 lun;
        u8 task_attr;
        bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
@@ -1092,7 +1095,8 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                }
                cmd->tvc_vhost = vs;
                cmd->tvc_vq = vq;
-               cmd->tvc_resp_iov = vq->iov[vc.out];
+               for (i = 0; i < vc.in ; i++)
+                       cmd->tvc_resp_iov[i] = vq->iov[vc.out + i];
                cmd->tvc_in_iovs = vc.in;
 
                pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
@@ -1461,6 +1465,7 @@ static void vhost_scsi_destroy_vq_cmds(struct vhost_virtqueue *vq)
                kfree(tv_cmd->tvc_sgl);
                kfree(tv_cmd->tvc_prot_sgl);
                kfree(tv_cmd->tvc_upages);
+               kfree(tv_cmd->tvc_resp_iov);
        }
 
        sbitmap_free(&svq->scsi_tags);
@@ -1508,6 +1513,14 @@ static int vhost_scsi_setup_vq_cmds(struct vhost_virtqueue *vq, int max_cmds)
                        goto out;
                }
 
+               tv_cmd->tvc_resp_iov = kcalloc(UIO_MAXIOV,
+                                              sizeof(struct iovec),
+                                              GFP_KERNEL);
+               if (!tv_cmd->tvc_resp_iov) {
+                       pr_err("Unable to allocate tv_cmd->tvc_resp_iov\n");
+                       goto out;
+               }
+
                tv_cmd->tvc_prot_sgl = kcalloc(VHOST_SCSI_PREALLOC_PROT_SGLS,
                                               sizeof(struct scatterlist),
                                               GFP_KERNEL);
index cbe72bf..43c9770 100644 (file)
@@ -661,7 +661,7 @@ void vhost_dev_stop(struct vhost_dev *dev)
 }
 EXPORT_SYMBOL_GPL(vhost_dev_stop);
 
-static void vhost_clear_msg(struct vhost_dev *dev)
+void vhost_clear_msg(struct vhost_dev *dev)
 {
        struct vhost_msg_node *node, *n;
 
@@ -679,6 +679,7 @@ static void vhost_clear_msg(struct vhost_dev *dev)
 
        spin_unlock(&dev->iotlb_lock);
 }
+EXPORT_SYMBOL_GPL(vhost_clear_msg);
 
 void vhost_dev_cleanup(struct vhost_dev *dev)
 {
index d910910..790b296 100644 (file)
@@ -181,6 +181,7 @@ long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, void __user *argp);
 long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp);
 bool vhost_vq_access_ok(struct vhost_virtqueue *vq);
 bool vhost_log_access_ok(struct vhost_dev *);
+void vhost_clear_msg(struct vhost_dev *dev);
 
 int vhost_get_vq_desc(struct vhost_virtqueue *,
                      struct iovec iov[], unsigned int iov_count,
index 1fc8de4..8187a7c 100644 (file)
@@ -49,7 +49,6 @@ struct atmel_lcdfb_info {
        struct clk              *lcdc_clk;
 
        struct backlight_device *backlight;
-       u8                      bl_power;
        u8                      saved_lcdcon;
 
        u32                     pseudo_palette[16];
@@ -109,22 +108,7 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
 static int atmel_bl_update_status(struct backlight_device *bl)
 {
        struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-       int                     power = sinfo->bl_power;
-       int                     brightness = bl->props.brightness;
-
-       /* REVISIT there may be a meaningful difference between
-        * fb_blank and power ... there seem to be some cases
-        * this doesn't handle correctly.
-        */
-       if (bl->props.fb_blank != sinfo->bl_power)
-               power = bl->props.fb_blank;
-       else if (bl->props.power != sinfo->bl_power)
-               power = bl->props.power;
-
-       if (brightness < 0 && power == FB_BLANK_UNBLANK)
-               brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-       else if (power != FB_BLANK_UNBLANK)
-               brightness = 0;
+       int                     brightness = backlight_get_brightness(bl);
 
        lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
        if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
@@ -133,8 +117,6 @@ static int atmel_bl_update_status(struct backlight_device *bl)
        else
                lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
 
-       bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
-
        return 0;
 }
 
@@ -155,8 +137,6 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
        struct backlight_properties props;
        struct backlight_device *bl;
 
-       sinfo->bl_power = FB_BLANK_UNBLANK;
-
        if (sinfo->backlight)
                return;
 
index dd31b9d..36a9ac0 100644 (file)
@@ -1766,12 +1766,10 @@ static int aty128_bl_update_status(struct backlight_device *bd)
        unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
        int level;
 
-       if (bd->props.power != FB_BLANK_UNBLANK ||
-           bd->props.fb_blank != FB_BLANK_UNBLANK ||
-           !par->lcd_on)
+       if (!par->lcd_on)
                level = 0;
        else
-               level = bd->props.brightness;
+               level = backlight_get_brightness(bd);
 
        reg |= LVDS_BL_MOD_EN | LVDS_BLON;
        if (level > 0) {
index d59215a..b02e4e6 100644 (file)
@@ -2219,13 +2219,7 @@ static int aty_bl_update_status(struct backlight_device *bd)
 {
        struct atyfb_par *par = bl_get_data(bd);
        unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
-       int level;
-
-       if (bd->props.power != FB_BLANK_UNBLANK ||
-           bd->props.fb_blank != FB_BLANK_UNBLANK)
-               level = 0;
-       else
-               level = bd->props.brightness;
+       int level = backlight_get_brightness(bd);
 
        reg |= (BLMOD_EN | BIASMOD_EN);
        if (level > 0) {
index d2c1263..427adc8 100644 (file)
@@ -57,11 +57,7 @@ static int radeon_bl_update_status(struct backlight_device *bd)
         * backlight. This provides some greater power saving and the display
         * is useless without backlight anyway.
         */
-        if (bd->props.power != FB_BLANK_UNBLANK ||
-           bd->props.fb_blank != FB_BLANK_UNBLANK)
-               level = 0;
-       else
-               level = bd->props.brightness;
+       level = backlight_get_brightness(bd);
 
        del_timer_sync(&rinfo->lvds_timer);
        radeon_engine_idle();
index 14a7d40..1b14c21 100644 (file)
@@ -2495,9 +2495,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)
+               return -EINVAL;
+
        /* Make sure drawing engine can handle the font */
-       if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
-           !(info->pixmap.blit_y & (1 << (font->height - 1))))
+       if (!(info->pixmap.blit_x & BIT(font->width - 1)) ||
+           !(info->pixmap.blit_y & BIT(font->height - 1)))
                return -EINVAL;
 
        /* Make sure driver can handle the font length */
index b0e690f..79e5bfb 100644 (file)
@@ -1050,7 +1050,7 @@ static u32 fb_get_vblank(u32 hfreq)
 }
 
 /**
- * fb_get_hblank_by_freq - get horizontal blank time given hfreq
+ * fb_get_hblank_by_hfreq - get horizontal blank time given hfreq
  * @hfreq: horizontal freq
  * @xres: horizontal resolution in pixels
  *
index b945b68..76771e1 100644 (file)
@@ -283,12 +283,7 @@ static int mx3fb_bl_get_brightness(struct backlight_device *bl)
 static int mx3fb_bl_update_status(struct backlight_device *bl)
 {
        struct mx3fb_data *fbd = bl_get_data(bl);
-       int brightness = bl->props.brightness;
-
-       if (bl->props.power != FB_BLANK_UNBLANK)
-               brightness = 0;
-       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
-               brightness = 0;
+       int brightness = backlight_get_brightness(bl);
 
        fbd->backlight_level = (fbd->backlight_level & ~0xFF) | brightness;
 
index 2ce5352..503a7a6 100644 (file)
@@ -49,17 +49,11 @@ static int nvidia_bl_update_status(struct backlight_device *bd)
 {
        struct nvidia_par *par = bl_get_data(bd);
        u32 tmp_pcrt, tmp_pmc, fpcontrol;
-       int level;
+       int level = backlight_get_brightness(bd);
 
        if (!par->FlatPanel)
                return 0;
 
-       if (bd->props.power != FB_BLANK_UNBLANK ||
-           bd->props.fb_blank != FB_BLANK_UNBLANK)
-               level = 0;
-       else
-               level = bd->props.brightness;
-
        tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
        tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
        fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
index 1960916..e60a276 100644 (file)
@@ -1197,17 +1197,17 @@ static int nvidia_set_fbinfo(struct fb_info *info)
        return nvidiafb_check_var(&info->var, info);
 }
 
-static u32 nvidia_get_chipset(struct fb_info *info)
+static u32 nvidia_get_chipset(struct pci_dev *pci_dev,
+                             volatile u32 __iomem *REGS)
 {
-       struct nvidia_par *par = info->par;
-       u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
+       u32 id = (pci_dev->vendor << 16) | pci_dev->device;
 
        printk(KERN_INFO PFX "Device ID: %x \n", id);
 
        if ((id & 0xfff0) == 0x00f0 ||
            (id & 0xfff0) == 0x02e0) {
                /* pci-e */
-               id = NV_RD32(par->REGS, 0x1800);
+               id = NV_RD32(REGS, 0x1800);
 
                if ((id & 0x0000ffff) == 0x000010DE)
                        id = 0x10DE0000 | (id >> 16);
@@ -1220,12 +1220,11 @@ static u32 nvidia_get_chipset(struct fb_info *info)
        return id;
 }
 
-static u32 nvidia_get_arch(struct fb_info *info)
+static u32 nvidia_get_arch(u32 Chipset)
 {
-       struct nvidia_par *par = info->par;
        u32 arch = 0;
 
-       switch (par->Chipset & 0x0ff0) {
+       switch (Chipset & 0x0ff0) {
        case 0x0100:            /* GeForce 256 */
        case 0x0110:            /* GeForce2 MX */
        case 0x0150:            /* GeForce2 */
@@ -1278,16 +1277,44 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
        struct fb_info *info;
        unsigned short cmd;
        int ret;
+       volatile u32 __iomem *REGS;
+       int Chipset;
+       u32 Architecture;
 
        NVTRACE_ENTER();
        assert(pd != NULL);
 
+       if (pci_enable_device(pd)) {
+               printk(KERN_ERR PFX "cannot enable PCI device\n");
+               return -ENODEV;
+       }
+
+       /* enable IO and mem if not already done */
+       pci_read_config_word(pd, PCI_COMMAND, &cmd);
+       cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+       pci_write_config_word(pd, PCI_COMMAND, cmd);
+
+       nvidiafb_fix.mmio_start = pci_resource_start(pd, 0);
+       nvidiafb_fix.mmio_len = pci_resource_len(pd, 0);
+
+       REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len);
+       if (!REGS) {
+               printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
+               return -ENODEV;
+       }
+
+       Chipset = nvidia_get_chipset(pd, REGS);
+       Architecture = nvidia_get_arch(Chipset);
+       if (Architecture == 0) {
+               printk(KERN_ERR PFX "unknown NV_ARCH\n");
+               goto err_out;
+       }
+
        ret = aperture_remove_conflicting_pci_devices(pd, "nvidiafb");
        if (ret)
-               return ret;
+               goto err_out;
 
        info = framebuffer_alloc(sizeof(struct nvidia_par), &pd->dev);
-
        if (!info)
                goto err_out;
 
@@ -1298,11 +1325,6 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
        if (info->pixmap.addr == NULL)
                goto err_out_kfree;
 
-       if (pci_enable_device(pd)) {
-               printk(KERN_ERR PFX "cannot enable PCI device\n");
-               goto err_out_enable;
-       }
-
        if (pci_request_regions(pd, "nvidiafb")) {
                printk(KERN_ERR PFX "cannot request PCI regions\n");
                goto err_out_enable;
@@ -1318,34 +1340,17 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
        par->paneltweak = paneltweak;
        par->reverse_i2c = reverse_i2c;
 
-       /* enable IO and mem if not already done */
-       pci_read_config_word(pd, PCI_COMMAND, &cmd);
-       cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-       pci_write_config_word(pd, PCI_COMMAND, cmd);
-
-       nvidiafb_fix.mmio_start = pci_resource_start(pd, 0);
        nvidiafb_fix.smem_start = pci_resource_start(pd, 1);
-       nvidiafb_fix.mmio_len = pci_resource_len(pd, 0);
-
-       par->REGS = ioremap(nvidiafb_fix.mmio_start, nvidiafb_fix.mmio_len);
 
-       if (!par->REGS) {
-               printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
-               goto err_out_free_base0;
-       }
+       par->REGS = REGS;
 
-       par->Chipset = nvidia_get_chipset(info);
-       par->Architecture = nvidia_get_arch(info);
-
-       if (par->Architecture == 0) {
-               printk(KERN_ERR PFX "unknown NV_ARCH\n");
-               goto err_out_arch;
-       }
+       par->Chipset = Chipset;
+       par->Architecture = Architecture;
 
        sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4);
 
        if (NVCommonSetup(info))
-               goto err_out_arch;
+               goto err_out_free_base0;
 
        par->FbAddress = nvidiafb_fix.smem_start;
        par->FbMapSize = par->RamAmountKBytes * 1024;
@@ -1401,7 +1406,6 @@ static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
                goto err_out_iounmap_fb;
        }
 
-
        printk(KERN_INFO PFX
               "PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
               info->fix.id,
@@ -1415,15 +1419,14 @@ err_out_iounmap_fb:
 err_out_free_base1:
        fb_destroy_modedb(info->monspecs.modedb);
        nvidia_delete_i2c_busses(par);
-err_out_arch:
-       iounmap(par->REGS);
- err_out_free_base0:
+err_out_free_base0:
        pci_release_regions(pd);
 err_out_enable:
        kfree(info->pixmap.addr);
 err_out_kfree:
        framebuffer_release(info);
 err_out:
+       iounmap(REGS);
        return -ENODEV;
 }
 
index 4fc4b26..ba94a0a 100644 (file)
@@ -331,13 +331,7 @@ static int dsicm_bl_update_status(struct backlight_device *dev)
        struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
        struct omap_dss_device *in = ddata->in;
        int r;
-       int level;
-
-       if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
-                       dev->props.power == FB_BLANK_UNBLANK)
-               level = dev->props.brightness;
-       else
-               level = 0;
+       int level = backlight_get_brightness(dev);
 
        dev_dbg(&ddata->pdev->dev, "update brightness to %d\n", level);
 
index bc5a44c..ae93785 100644 (file)
@@ -10,6 +10,7 @@
 #define DSS_SUBSYS_NAME "DISPLAY"
 
 #include <linux/kernel.h>
+#include <linux/kstrtox.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/sysfs.h>
@@ -36,7 +37,7 @@ static ssize_t display_enabled_store(struct omap_dss_device *dssdev,
        int r;
        bool enable;
 
-       r = strtobool(buf, &enable);
+       r = kstrtobool(buf, &enable);
        if (r)
                return r;
 
@@ -73,7 +74,7 @@ static ssize_t display_tear_store(struct omap_dss_device *dssdev,
        if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
                return -ENOENT;
 
-       r = strtobool(buf, &te);
+       r = kstrtobool(buf, &te);
        if (r)
                return r;
 
@@ -183,7 +184,7 @@ static ssize_t display_mirror_store(struct omap_dss_device *dssdev,
        if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
                return -ENOENT;
 
-       r = strtobool(buf, &mirror);
+       r = kstrtobool(buf, &mirror);
        if (r)
                return r;
 
index ba21c4a..1b644be 100644 (file)
@@ -10,6 +10,7 @@
 #define DSS_SUBSYS_NAME "MANAGER"
 
 #include <linux/kernel.h>
+#include <linux/kstrtox.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -246,7 +247,7 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
        bool enable;
        int r;
 
-       r = strtobool(buf, &enable);
+       r = kstrtobool(buf, &enable);
        if (r)
                return r;
 
@@ -290,7 +291,7 @@ static ssize_t manager_alpha_blending_enabled_store(
        if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
                return -ENODEV;
 
-       r = strtobool(buf, &enable);
+       r = kstrtobool(buf, &enable);
        if (r)
                return r;
 
@@ -329,7 +330,7 @@ static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
        if (!dss_has_feature(FEAT_CPR))
                return -ENODEV;
 
-       r = strtobool(buf, &enable);
+       r = kstrtobool(buf, &enable);
        if (r)
                return r;
 
index 601c0be..1da4fb1 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/err.h>
 #include <linux/sysfs.h>
 #include <linux/kobject.h>
+#include <linux/kstrtox.h>
 #include <linux/platform_device.h>
 
 #include <video/omapfb_dss.h>
@@ -210,7 +211,7 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
        int r;
        bool enable;
 
-       r = strtobool(buf, &enable);
+       r = kstrtobool(buf, &enable);
        if (r)
                return r;
 
index 06dc41a..831b2c2 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/uaccess.h>
 #include <linux/platform_device.h>
 #include <linux/kernel.h>
+#include <linux/kstrtox.h>
 #include <linux/mm.h>
 #include <linux/omapfb.h>
 
@@ -96,7 +97,7 @@ static ssize_t store_mirror(struct device *dev,
        int r;
        struct fb_var_screeninfo new_var;
 
-       r = strtobool(buf, &mirror);
+       r = kstrtobool(buf, &mirror);
        if (r)
                return r;
 
index 6442781..41edc6e 100644 (file)
@@ -293,13 +293,7 @@ static int riva_bl_update_status(struct backlight_device *bd)
 {
        struct riva_par *par = bl_get_data(bd);
        U032 tmp_pcrt, tmp_pmc;
-       int level;
-
-       if (bd->props.power != FB_BLANK_UNBLANK ||
-           bd->props.fb_blank != FB_BLANK_UNBLANK)
-               level = 0;
-       else
-               level = bd->props.brightness;
+       int level = backlight_get_brightness(bd);
 
        tmp_pmc = NV_RD32(par->riva.PMC, 0x10F0) & 0x0000FFFF;
        tmp_pcrt = NV_RD32(par->riva.PCRTC0, 0x081C) & 0xFFFFFFFC;
index 8752d38..d7f3e62 100644 (file)
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(video,
        "Video memory size in MB, width, height in pixels (default 2,800,600)");
 
 static void xenfb_make_preferred_console(void);
-static int xenfb_remove(struct xenbus_device *);
+static void xenfb_remove(struct xenbus_device *);
 static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);
 static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
 static void xenfb_disconnect_backend(struct xenfb_info *);
@@ -523,7 +523,7 @@ static int xenfb_resume(struct xenbus_device *dev)
        return xenfb_connect_backend(dev, info);
 }
 
-static int xenfb_remove(struct xenbus_device *dev)
+static void xenfb_remove(struct xenbus_device *dev)
 {
        struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 
@@ -538,8 +538,6 @@ static int xenfb_remove(struct xenbus_device *dev)
        vfree(info->gfns);
        vfree(info->fb);
        kfree(info);
-
-       return 0;
 }
 
 static unsigned long vmalloc_to_gfn(void *address)
index f2ae2e5..4a2ddf7 100644 (file)
@@ -1166,6 +1166,8 @@ int w1_process(void *data)
        /* remainder if it woke up early */
        unsigned long jremain = 0;
 
+       atomic_inc(&dev->refcnt);
+
        for (;;) {
 
                if (!jremain && dev->search_count) {
@@ -1193,8 +1195,10 @@ int w1_process(void *data)
                 */
                mutex_unlock(&dev->list_mutex);
 
-               if (kthread_should_stop())
+               if (kthread_should_stop()) {
+                       __set_current_state(TASK_RUNNING);
                        break;
+               }
 
                /* Only sleep when the search is active. */
                if (dev->search_count) {
index b3e1792..3a71c5e 100644 (file)
@@ -51,10 +51,9 @@ static struct w1_master *w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
        dev->search_count       = w1_search_count;
        dev->enable_pullup      = w1_enable_pullup;
 
-       /* 1 for w1_process to decrement
-        * 1 for __w1_remove_master_device to decrement
+       /* For __w1_remove_master_device to decrement
         */
-       atomic_set(&dev->refcnt, 2);
+       atomic_set(&dev->refcnt, 1);
 
        INIT_LIST_HEAD(&dev->slist);
        INIT_LIST_HEAD(&dev->async_list);
index 4cb1087..6ca5d95 100644 (file)
@@ -86,7 +86,7 @@ static int __diag288(unsigned int func, unsigned int timeout,
                "1:\n"
                EX_TABLE(0b, 1b)
                : "+d" (err) : "d"(__func), "d"(__timeout),
-                 "d"(__action), "d"(__len) : "1", "cc");
+                 "d"(__action), "d"(__len) : "1", "cc", "memory");
        return err;
 }
 
@@ -268,12 +268,21 @@ static int __init diag288_init(void)
        char ebc_begin[] = {
                194, 197, 199, 201, 213
        };
+       char *ebc_cmd;
 
        watchdog_set_nowayout(&wdt_dev, nowayout_info);
 
        if (MACHINE_IS_VM) {
-               if (__diag288_vm(WDT_FUNC_INIT, 15,
-                                ebc_begin, sizeof(ebc_begin)) != 0) {
+               ebc_cmd = kmalloc(sizeof(ebc_begin), GFP_KERNEL);
+               if (!ebc_cmd) {
+                       pr_err("The watchdog cannot be initialized\n");
+                       return -ENOMEM;
+               }
+               memcpy(ebc_cmd, ebc_begin, sizeof(ebc_begin));
+               ret = __diag288_vm(WDT_FUNC_INIT, 15,
+                                  ebc_cmd, sizeof(ebc_begin));
+               kfree(ebc_cmd);
+               if (ret != 0) {
                        pr_err("The watchdog cannot be initialized\n");
                        return -EINVAL;
                }
index 28b2a1f..0d4f8f4 100644 (file)
@@ -1181,9 +1181,8 @@ static void pvcalls_back_changed(struct xenbus_device *dev,
        }
 }
 
-static int pvcalls_back_remove(struct xenbus_device *dev)
+static void pvcalls_back_remove(struct xenbus_device *dev)
 {
-       return 0;
 }
 
 static int pvcalls_back_uevent(struct xenbus_device *xdev,
index 1826e8e..d5d589b 100644 (file)
@@ -225,6 +225,8 @@ again:
        return IRQ_HANDLED;
 }
 
+static void free_active_ring(struct sock_mapping *map);
+
 static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
                                   struct sock_mapping *map)
 {
@@ -240,7 +242,7 @@ static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
        for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
                gnttab_end_foreign_access(map->active.ring->ref[i], NULL);
        gnttab_end_foreign_access(map->active.ref, NULL);
-       free_page((unsigned long)map->active.ring);
+       free_active_ring(map);
 
        kfree(map);
 }
@@ -1085,7 +1087,7 @@ static const struct xenbus_device_id pvcalls_front_ids[] = {
        { "" }
 };
 
-static int pvcalls_front_remove(struct xenbus_device *dev)
+static void pvcalls_front_remove(struct xenbus_device *dev)
 {
        struct pvcalls_bedata *bedata;
        struct sock_mapping *map = NULL, *n;
@@ -1121,7 +1123,6 @@ static int pvcalls_front_remove(struct xenbus_device *dev)
        kfree(bedata->ring.sring);
        kfree(bedata);
        xenbus_switch_state(dev, XenbusStateClosed);
-       return 0;
 }
 
 static int pvcalls_front_probe(struct xenbus_device *dev,
index d171091..b11e401 100644 (file)
@@ -716,14 +716,12 @@ out:
        return err;
 }
 
-static int xen_pcibk_xenbus_remove(struct xenbus_device *dev)
+static void xen_pcibk_xenbus_remove(struct xenbus_device *dev)
 {
        struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev);
 
        if (pdev != NULL)
                free_pdev(pdev);
-
-       return 0;
 }
 
 static const struct xenbus_device_id xen_pcibk_ids[] = {
index 6106ed9..954188b 100644 (file)
@@ -1249,7 +1249,7 @@ static void scsiback_release_translation_entry(struct vscsibk_info *info)
        spin_unlock_irqrestore(&info->v2p_lock, flags);
 }
 
-static int scsiback_remove(struct xenbus_device *dev)
+static void scsiback_remove(struct xenbus_device *dev)
 {
        struct vscsibk_info *info = dev_get_drvdata(&dev->dev);
 
@@ -1261,8 +1261,6 @@ static int scsiback_remove(struct xenbus_device *dev)
        gnttab_page_cache_shrink(&info->free_pages, 0);
 
        dev_set_drvdata(&dev->dev, NULL);
-
-       return 0;
 }
 
 static int scsiback_probe(struct xenbus_device *dev,
index cefa222..8daeed3 100644 (file)
@@ -880,7 +880,7 @@ affs_truncate(struct inode *inode)
        if (inode->i_size > AFFS_I(inode)->mmu_private) {
                struct address_space *mapping = inode->i_mapping;
                struct page *page;
-               void *fsdata;
+               void *fsdata = NULL;
                loff_t isize = inode->i_size;
                int res;
 
index 7dcd596..d4ddb20 100644 (file)
@@ -13,6 +13,8 @@
 #include "internal.h"
 #include "afs_cm.h"
 #include "protocol_yfs.h"
+#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
+#include <trace/events/rxrpc.h>
 
 static int afs_deliver_cb_init_call_back_state(struct afs_call *);
 static int afs_deliver_cb_init_call_back_state3(struct afs_call *);
@@ -191,7 +193,7 @@ static void afs_cm_destructor(struct afs_call *call)
  * Abort a service call from within an action function.
  */
 static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error,
-                                  const char *why)
+                                  enum rxrpc_abort_reason why)
 {
        rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
                                abort_code, error, why);
@@ -469,7 +471,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
        if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
                afs_send_empty_reply(call);
        else
-               afs_abort_service_call(call, 1, 1, "K-1");
+               afs_abort_service_call(call, 1, 1, afs_abort_probeuuid_negative);
 
        afs_put_call(call);
        _leave("");
index c62939e..7817e2b 100644 (file)
@@ -13,6 +13,8 @@
 #include "internal.h"
 #include "afs_cm.h"
 #include "protocol_yfs.h"
+#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
+#include <trace/events/rxrpc.h>
 
 struct workqueue_struct *afs_async_calls;
 
@@ -397,7 +399,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
 error_do_abort:
        if (ret != -ECONNABORTED) {
                rxrpc_kernel_abort_call(call->net->socket, rxcall,
-                                       RX_USER_ABORT, ret, "KSD");
+                                       RX_USER_ABORT, ret,
+                                       afs_abort_send_data_error);
        } else {
                len = 0;
                iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
@@ -527,7 +530,8 @@ static void afs_deliver_to_call(struct afs_call *call)
                case -ENOTSUPP:
                        abort_code = RXGEN_OPCODE;
                        rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
-                                               abort_code, ret, "KIV");
+                                               abort_code, ret,
+                                               afs_abort_op_not_supported);
                        goto local_abort;
                case -EIO:
                        pr_err("kAFS: Call %u in bad state %u\n",
@@ -542,12 +546,14 @@ static void afs_deliver_to_call(struct afs_call *call)
                        if (state != AFS_CALL_CL_AWAIT_REPLY)
                                abort_code = RXGEN_SS_UNMARSHAL;
                        rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
-                                               abort_code, ret, "KUM");
+                                               abort_code, ret,
+                                               afs_abort_unmarshal_error);
                        goto local_abort;
                default:
                        abort_code = RX_CALL_DEAD;
                        rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
-                                               abort_code, ret, "KER");
+                                               abort_code, ret,
+                                               afs_abort_general_error);
                        goto local_abort;
                }
        }
@@ -619,7 +625,8 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
                        /* Kill off the call if it's still live. */
                        _debug("call interrupted");
                        if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
-                                                   RX_USER_ABORT, -EINTR, "KWI"))
+                                                   RX_USER_ABORT, -EINTR,
+                                                   afs_abort_interrupted))
                                afs_set_call_complete(call, -EINTR, 0);
                }
        }
@@ -836,7 +843,8 @@ void afs_send_empty_reply(struct afs_call *call)
        case -ENOMEM:
                _debug("oom");
                rxrpc_kernel_abort_call(net->socket, call->rxcall,
-                                       RXGEN_SS_MARSHAL, -ENOMEM, "KOO");
+                                       RXGEN_SS_MARSHAL, -ENOMEM,
+                                       afs_abort_oom);
                fallthrough;
        default:
                _leave(" [error]");
@@ -878,7 +886,8 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
        if (n == -ENOMEM) {
                _debug("oom");
                rxrpc_kernel_abort_call(net->socket, call->rxcall,
-                                       RXGEN_SS_MARSHAL, -ENOMEM, "KOO");
+                                       RXGEN_SS_MARSHAL, -ENOMEM,
+                                       afs_abort_oom);
        }
        _leave(" [error]");
 }
@@ -900,6 +909,7 @@ int afs_extract_data(struct afs_call *call, bool want_more)
        ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter,
                                     &call->iov_len, want_more, &remote_abort,
                                     &call->service_id);
+       trace_afs_receive_data(call, call->iter, want_more, ret);
        if (ret == 0 || ret == -EAGAIN)
                return ret;
 
index de63572..9a780fa 100644 (file)
@@ -2034,7 +2034,7 @@ static int elf_core_dump(struct coredump_params *cprm)
         * The number of segs are recored into ELF header as 16bit value.
         * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
         */
-       segs = cprm->vma_count + elf_core_extra_phdrs();
+       segs = cprm->vma_count + elf_core_extra_phdrs(cprm);
 
        /* for notes section */
        segs++;
@@ -2074,7 +2074,7 @@ static int elf_core_dump(struct coredump_params *cprm)
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
        offset += cprm->vma_data_size;
-       offset += elf_core_extra_data_size();
+       offset += elf_core_extra_data_size(cprm);
        e_shoff = offset;
 
        if (e_phnum == PN_XNUM) {
index 096e352..a05eafc 100644 (file)
@@ -1509,7 +1509,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
        tmp->next = thread_list;
        thread_list = tmp;
 
-       segs = cprm->vma_count + elf_core_extra_phdrs();
+       segs = cprm->vma_count + elf_core_extra_phdrs(cprm);
 
        /* for notes section */
        segs++;
@@ -1555,7 +1555,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
        dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
        offset += cprm->vma_data_size;
-       offset += elf_core_extra_data_size();
+       offset += elf_core_extra_data_size(cprm);
        e_shoff = offset;
 
        if (e_phnum == PN_XNUM) {
index 8aeaada..3aa0422 100644 (file)
@@ -367,7 +367,14 @@ error:
        btrfs_print_tree(eb, 0);
        btrfs_err(fs_info, "block=%llu write time tree block corruption detected",
                  eb->start);
-       WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
+       /*
+        * Be noisy if this is an extent buffer from a log tree. We don't abort
+        * a transaction in case there's a bad log tree extent buffer, we just
+        * fallback to a transaction commit. Still we want to know when there is
+        * a bad log tree extent buffer, as that may signal a bug somewhere.
+        */
+       WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG) ||
+               btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID);
        return ret;
 }
 
index 9bd32da..3bbf870 100644 (file)
@@ -3826,6 +3826,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
        lockend = round_up(start + len, inode->root->fs_info->sectorsize);
        prev_extent_end = lockstart;
 
+       btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
        lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
 
        ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end);
@@ -4019,6 +4020,7 @@ check_eof_delalloc:
 
 out_unlock:
        unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
+       btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
 out:
        free_extent_state(delalloc_cached_state);
        btrfs_free_backref_share_ctx(backref_ctx);
index 834bbcb..af046d2 100644 (file)
@@ -3541,6 +3541,7 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
                struct extent_buffer *leaf = path->nodes[0];
                struct btrfs_file_extent_item *extent;
                u64 extent_end;
+               u8 type;
 
                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
                        ret = btrfs_next_leaf(root, path);
@@ -3596,10 +3597,16 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
 
                extent = btrfs_item_ptr(leaf, path->slots[0],
                                        struct btrfs_file_extent_item);
+               type = btrfs_file_extent_type(leaf, extent);
 
-               if (btrfs_file_extent_disk_bytenr(leaf, extent) == 0 ||
-                   btrfs_file_extent_type(leaf, extent) ==
-                   BTRFS_FILE_EXTENT_PREALLOC) {
+               /*
+                * Can't access the extent's disk_bytenr field if this is an
+                * inline extent, since at that offset, it's where the extent
+                * data starts.
+                */
+               if (type == BTRFS_FILE_EXTENT_PREALLOC ||
+                   (type == BTRFS_FILE_EXTENT_REG &&
+                    btrfs_file_extent_disk_bytenr(leaf, extent) == 0)) {
                        /*
                         * Explicit hole or prealloc extent, search for delalloc.
                         * A prealloc extent is treated like a hole.
index a749367..37b86ac 100644 (file)
@@ -119,6 +119,12 @@ enum {
        /* Indicate that we want to commit the transaction. */
        BTRFS_FS_NEED_TRANS_COMMIT,
 
+       /*
+        * Indicate metadata over-commit is disabled. This is set when active
+        * zone tracking is needed.
+        */
+       BTRFS_FS_NO_OVERCOMMIT,
+
 #if BITS_PER_LONG == 32
        /* Indicate if we have error/warn message printed on 32bit systems */
        BTRFS_FS_32BIT_ERROR,
index d275bf2..af97413 100644 (file)
@@ -2765,9 +2765,19 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
 
                        /*
                         * Old roots should be searched when inserting qgroup
-                        * extent record
+                        * extent record.
+                        *
+                        * But for INCONSISTENT (NO_ACCOUNTING) -> rescan case,
+                        * we may have some record inserted during
+                        * NO_ACCOUNTING (thus no old_roots populated), but
+                        * later we start rescan, which clears NO_ACCOUNTING,
+                        * leaving some inserted records without old_roots
+                        * populated.
+                        *
+                        * Those cases are rare and should not cause too much
+                        * time spent during commit_transaction().
                         */
-                       if (WARN_ON(!record->old_roots)) {
+                       if (!record->old_roots) {
                                /* Search commit root to find old_roots */
                                ret = btrfs_find_all_roots(&ctx, false);
                                if (ret < 0)
@@ -3357,6 +3367,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
        int err = -ENOMEM;
        int ret = 0;
        bool stopped = false;
+       bool did_leaf_rescans = false;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -3377,6 +3388,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
                }
 
                err = qgroup_rescan_leaf(trans, path);
+               did_leaf_rescans = true;
 
                if (err > 0)
                        btrfs_commit_transaction(trans);
@@ -3397,16 +3409,23 @@ out:
        mutex_unlock(&fs_info->qgroup_rescan_lock);
 
        /*
-        * only update status, since the previous part has already updated the
-        * qgroup info.
+        * Only update status, since the previous part has already updated the
+        * qgroup info, and only if we did any actual work. This also prevents
+        * race with a concurrent quota disable, which has already set
+        * fs_info->quota_root to NULL and cleared BTRFS_FS_QUOTA_ENABLED at
+        * btrfs_quota_disable().
         */
-       trans = btrfs_start_transaction(fs_info->quota_root, 1);
-       if (IS_ERR(trans)) {
-               err = PTR_ERR(trans);
+       if (did_leaf_rescans) {
+               trans = btrfs_start_transaction(fs_info->quota_root, 1);
+               if (IS_ERR(trans)) {
+                       err = PTR_ERR(trans);
+                       trans = NULL;
+                       btrfs_err(fs_info,
+                                 "fail to start transaction for status update: %d",
+                                 err);
+               }
+       } else {
                trans = NULL;
-               btrfs_err(fs_info,
-                         "fail to start transaction for status update: %d",
-                         err);
        }
 
        mutex_lock(&fs_info->qgroup_rescan_lock);
index 6a2cf75..ff4b1d5 100644 (file)
@@ -1426,12 +1426,20 @@ static void rbio_update_error_bitmap(struct btrfs_raid_bio *rbio, struct bio *bi
        u32 bio_size = 0;
        struct bio_vec *bvec;
        struct bvec_iter_all iter_all;
+       int i;
 
        bio_for_each_segment_all(bvec, bio, iter_all)
                bio_size += bvec->bv_len;
 
-       bitmap_set(rbio->error_bitmap, total_sector_nr,
-                  bio_size >> rbio->bioc->fs_info->sectorsize_bits);
+       /*
+        * Since we can have multiple bios touching the error_bitmap, we cannot
+        * call bitmap_set() without protection.
+        *
+        * Instead use set_bit() for each bit, as set_bit() itself is atomic.
+        */
+       for (i = total_sector_nr; i < total_sector_nr +
+            (bio_size >> rbio->bioc->fs_info->sectorsize_bits); i++)
+               set_bit(i, rbio->error_bitmap);
 }
 
 /* Verify the data sectors at read time. */
@@ -1886,7 +1894,7 @@ pstripe:
                sector->uptodate = 1;
        }
        if (failb >= 0) {
-               ret = verify_one_sector(rbio, faila, sector_nr);
+               ret = verify_one_sector(rbio, failb, sector_nr);
                if (ret < 0)
                        goto cleanup;
 
index e65e6b6..d50182b 100644 (file)
@@ -8073,10 +8073,10 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg)
        /*
         * Check that we don't overflow at later allocations, we request
         * clone_sources_count + 1 items, and compare to unsigned long inside
-        * access_ok.
+        * access_ok. Also set an upper limit for allocation size so this can't
+        * easily exhaust memory. Max number of clone sources is about 200K.
         */
-       if (arg->clone_sources_count >
-           ULONG_MAX / sizeof(struct clone_root) - 1) {
+       if (arg->clone_sources_count > SZ_8M / sizeof(struct clone_root)) {
                ret = -EINVAL;
                goto out;
        }
index d28ee4e..69c0950 100644 (file)
@@ -407,7 +407,8 @@ int btrfs_can_overcommit(struct btrfs_fs_info *fs_info,
                return 0;
 
        used = btrfs_space_info_used(space_info, true);
-       if (btrfs_is_zoned(fs_info) && (space_info->flags & BTRFS_BLOCK_GROUP_METADATA))
+       if (test_bit(BTRFS_FS_NO_OVERCOMMIT, &fs_info->flags) &&
+           (space_info->flags & BTRFS_BLOCK_GROUP_METADATA))
                avail = 0;
        else
                avail = calc_available_free_space(fs_info, space_info, flush);
index fb52aa0..5859918 100644 (file)
@@ -2980,7 +2980,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                ret = 0;
        if (ret) {
                blk_finish_plug(&plug);
-               btrfs_abort_transaction(trans, ret);
                btrfs_set_log_full_commit(trans);
                mutex_unlock(&root->log_mutex);
                goto out;
@@ -3045,15 +3044,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
 
                blk_finish_plug(&plug);
                btrfs_set_log_full_commit(trans);
-
-               if (ret != -ENOSPC) {
-                       btrfs_abort_transaction(trans, ret);
-                       mutex_unlock(&log_root_tree->log_mutex);
-                       goto out;
-               }
+               if (ret != -ENOSPC)
+                       btrfs_err(fs_info,
+                                 "failed to update log for root %llu ret %d",
+                                 root->root_key.objectid, ret);
                btrfs_wait_tree_log_extents(log, mark);
                mutex_unlock(&log_root_tree->log_mutex);
-               ret = BTRFS_LOG_FORCE_COMMIT;
                goto out;
        }
 
@@ -3112,7 +3108,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                goto out_wake_log_root;
        } else if (ret) {
                btrfs_set_log_full_commit(trans);
-               btrfs_abort_transaction(trans, ret);
                mutex_unlock(&log_root_tree->log_mutex);
                goto out_wake_log_root;
        }
@@ -3581,17 +3576,19 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
 }
 
 static int flush_dir_items_batch(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *log,
+                                struct btrfs_inode *inode,
                                 struct extent_buffer *src,
                                 struct btrfs_path *dst_path,
                                 int start_slot,
                                 int count)
 {
+       struct btrfs_root *log = inode->root->log_root;
        char *ins_data = NULL;
        struct btrfs_item_batch batch;
        struct extent_buffer *dst;
        unsigned long src_offset;
        unsigned long dst_offset;
+       u64 last_index;
        struct btrfs_key key;
        u32 item_size;
        int ret;
@@ -3649,6 +3646,19 @@ static int flush_dir_items_batch(struct btrfs_trans_handle *trans,
        src_offset = btrfs_item_ptr_offset(src, start_slot + count - 1);
        copy_extent_buffer(dst, src, dst_offset, src_offset, batch.total_data_size);
        btrfs_release_path(dst_path);
+
+       last_index = batch.keys[count - 1].offset;
+       ASSERT(last_index > inode->last_dir_index_offset);
+
+       /*
+        * If for some unexpected reason the last item's index is not greater
+        * than the last index we logged, warn and return an error to fallback
+        * to a transaction commit.
+        */
+       if (WARN_ON(last_index <= inode->last_dir_index_offset))
+               ret = -EUCLEAN;
+       else
+               inode->last_dir_index_offset = last_index;
 out:
        kfree(ins_data);
 
@@ -3698,7 +3708,6 @@ static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
                }
 
                di = btrfs_item_ptr(src, i, struct btrfs_dir_item);
-               ctx->last_dir_item_offset = key.offset;
 
                /*
                 * Skip ranges of items that consist only of dir item keys created
@@ -3761,7 +3770,7 @@ static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
        if (batch_size > 0) {
                int ret;
 
-               ret = flush_dir_items_batch(trans, log, src, dst_path,
+               ret = flush_dir_items_batch(trans, inode, src, dst_path,
                                            batch_start, batch_size);
                if (ret < 0)
                        return ret;
@@ -3826,7 +3835,10 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                                              path->slots[0]);
                        if (tmp.type == BTRFS_DIR_INDEX_KEY)
                                last_old_dentry_offset = tmp.offset;
+               } else if (ret < 0) {
+                       err = ret;
                }
+
                goto done;
        }
 
@@ -3846,19 +3858,34 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
                 */
                if (tmp.type == BTRFS_DIR_INDEX_KEY)
                        last_old_dentry_offset = tmp.offset;
+       } else if (ret < 0) {
+               err = ret;
+               goto done;
        }
+
        btrfs_release_path(path);
 
        /*
-        * Find the first key from this transaction again.  See the note for
-        * log_new_dir_dentries, if we're logging a directory recursively we
-        * won't be holding its i_mutex, which means we can modify the directory
-        * while we're logging it.  If we remove an entry between our first
-        * search and this search we'll not find the key again and can just
-        * bail.
+        * Find the first key from this transaction again or the one we were at
+        * in the loop below in case we had to reschedule. We may be logging the
+        * directory without holding its VFS lock, which happen when logging new
+        * dentries (through log_new_dir_dentries()) or in some cases when we
+        * need to log the parent directory of an inode. This means a dir index
+        * key might be deleted from the inode's root, and therefore we may not
+        * find it anymore. If we can't find it, just move to the next key. We
+        * can not bail out and ignore, because if we do that we will simply
+        * not log dir index keys that come after the one that was just deleted
+        * and we can end up logging a dir index range that ends at (u64)-1
+        * (@last_offset is initialized to that), resulting in removing dir
+        * entries we should not remove at log replay time.
         */
 search:
        ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
+       if (ret > 0)
+               ret = btrfs_next_item(root, path);
+       if (ret < 0)
+               err = ret;
+       /* If ret is 1, there are no more keys in the inode's root. */
        if (ret != 0)
                goto done;
 
@@ -4031,7 +4058,6 @@ static noinline int log_directory_changes(struct btrfs_trans_handle *trans,
 
        min_key = BTRFS_DIR_START_INDEX;
        max_key = 0;
-       ctx->last_dir_item_offset = inode->last_dir_index_offset;
 
        while (1) {
                ret = log_dir_items(trans, inode, path, dst_path,
@@ -4043,8 +4069,6 @@ static noinline int log_directory_changes(struct btrfs_trans_handle *trans,
                min_key = max_key + 1;
        }
 
-       inode->last_dir_index_offset = ctx->last_dir_item_offset;
-
        return 0;
 }
 
@@ -5580,8 +5604,10 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
         * LOG_INODE_EXISTS mode) and slow down other fsyncs or transaction
         * commits.
         */
-       if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES)
+       if (ctx->num_conflict_inodes >= MAX_CONFLICT_INODES) {
+               btrfs_set_log_full_commit(trans);
                return BTRFS_LOG_FORCE_COMMIT;
+       }
 
        inode = btrfs_iget(root->fs_info->sb, ino, root);
        /*
index 85b4307..85cd24c 100644 (file)
@@ -24,8 +24,6 @@ struct btrfs_log_ctx {
        bool logging_new_delayed_dentries;
        /* Indicate if the inode being logged was logged before. */
        bool logged_before;
-       /* Tracks the last logged dir item/index key offset. */
-       u64 last_dir_item_offset;
        struct inode *inode;
        struct list_head list;
        /* Only used for fast fsyncs. */
index aa25fa3..df43093 100644 (file)
@@ -403,6 +403,7 @@ void btrfs_free_device(struct btrfs_device *device)
 static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_device *device;
+
        WARN_ON(fs_devices->opened);
        while (!list_empty(&fs_devices->devices)) {
                device = list_entry(fs_devices->devices.next,
@@ -768,8 +769,11 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                                        BTRFS_SUPER_FLAG_CHANGING_FSID_V2);
 
        error = lookup_bdev(path, &path_devt);
-       if (error)
+       if (error) {
+               btrfs_err(NULL, "failed to lookup block device for path %s: %d",
+                         path, error);
                return ERR_PTR(error);
+       }
 
        if (fsid_change_in_progress) {
                if (!has_metadata_uuid)
@@ -836,6 +840,9 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                unsigned int nofs_flag;
 
                if (fs_devices->opened) {
+                       btrfs_err(NULL,
+               "device %s belongs to fsid %pU, and the fs is already mounted",
+                                 path, fs_devices->fsid);
                        mutex_unlock(&fs_devices->device_list_mutex);
                        return ERR_PTR(-EBUSY);
                }
@@ -905,6 +912,9 @@ static noinline struct btrfs_device *device_list_add(const char *path,
                         * generation are equal.
                         */
                        mutex_unlock(&fs_devices->device_list_mutex);
+                       btrfs_err(NULL,
+"device %s already registered with a higher generation, found %llu expect %llu",
+                                 path, found_transid, device->generation);
                        return ERR_PTR(-EEXIST);
                }
 
@@ -1172,9 +1182,22 @@ void btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 
        mutex_lock(&uuid_mutex);
        close_fs_devices(fs_devices);
-       if (!fs_devices->opened)
+       if (!fs_devices->opened) {
                list_splice_init(&fs_devices->seed_list, &list);
 
+               /*
+                * If the struct btrfs_fs_devices is not assembled with any
+                * other device, it can be re-initialized during the next mount
+                * without the needing device-scan step. Therefore, it can be
+                * fully freed.
+                */
+               if (fs_devices->num_devices == 1) {
+                       list_del(&fs_devices->fs_list);
+                       free_fs_devices(fs_devices);
+               }
+       }
+
+
        list_for_each_entry_safe(fs_devices, tmp, &list, seed_list) {
                close_fs_devices(fs_devices);
                list_del(&fs_devices->seed_list);
@@ -1591,7 +1614,7 @@ again:
        if (ret < 0)
                goto out;
 
-       while (1) {
+       while (search_start < search_end) {
                l = path->nodes[0];
                slot = path->slots[0];
                if (slot >= btrfs_header_nritems(l)) {
@@ -1614,6 +1637,9 @@ again:
                if (key.type != BTRFS_DEV_EXTENT_KEY)
                        goto next;
 
+               if (key.offset > search_end)
+                       break;
+
                if (key.offset > search_start) {
                        hole_size = key.offset - search_start;
                        dev_extent_hole_check(device, &search_start, &hole_size,
@@ -1674,6 +1700,7 @@ next:
        else
                ret = 0;
 
+       ASSERT(max_hole_start + max_hole_size <= search_end);
 out:
        btrfs_free_path(path);
        *start = max_hole_start;
@@ -2005,42 +2032,42 @@ static u64 btrfs_num_devices(struct btrfs_fs_info *fs_info)
        return num_devices;
 }
 
+static void btrfs_scratch_superblock(struct btrfs_fs_info *fs_info,
+                                    struct block_device *bdev, int copy_num)
+{
+       struct btrfs_super_block *disk_super;
+       const size_t len = sizeof(disk_super->magic);
+       const u64 bytenr = btrfs_sb_offset(copy_num);
+       int ret;
+
+       disk_super = btrfs_read_disk_super(bdev, bytenr, bytenr);
+       if (IS_ERR(disk_super))
+               return;
+
+       memset(&disk_super->magic, 0, len);
+       folio_mark_dirty(virt_to_folio(disk_super));
+       btrfs_release_disk_super(disk_super);
+
+       ret = sync_blockdev_range(bdev, bytenr, bytenr + len - 1);
+       if (ret)
+               btrfs_warn(fs_info, "error clearing superblock number %d (%d)",
+                       copy_num, ret);
+}
+
 void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
                               struct block_device *bdev,
                               const char *device_path)
 {
-       struct btrfs_super_block *disk_super;
        int copy_num;
 
        if (!bdev)
                return;
 
        for (copy_num = 0; copy_num < BTRFS_SUPER_MIRROR_MAX; copy_num++) {
-               struct page *page;
-               int ret;
-
-               disk_super = btrfs_read_dev_one_super(bdev, copy_num, false);
-               if (IS_ERR(disk_super))
-                       continue;
-
-               if (bdev_is_zoned(bdev)) {
+               if (bdev_is_zoned(bdev))
                        btrfs_reset_sb_log_zones(bdev, copy_num);
-                       continue;
-               }
-
-               memset(&disk_super->magic, 0, sizeof(disk_super->magic));
-
-               page = virt_to_page(disk_super);
-               set_page_dirty(page);
-               lock_page(page);
-               /* write_on_page() unlocks the page */
-               ret = write_one_page(page);
-               if (ret)
-                       btrfs_warn(fs_info,
-                               "error clearing superblock number %d (%d)",
-                               copy_num, ret);
-               btrfs_release_disk_super(disk_super);
-
+               else
+                       btrfs_scratch_superblock(fs_info, bdev, copy_num);
        }
 
        /* Notify udev that device has changed */
index 01a13de..da7bb91 100644 (file)
@@ -63,7 +63,7 @@ struct list_head *zlib_alloc_workspace(unsigned int level)
 
        workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
                        zlib_inflate_workspacesize());
-       workspace->strm.workspace = kvmalloc(workspacesize, GFP_KERNEL);
+       workspace->strm.workspace = kvzalloc(workspacesize, GFP_KERNEL);
        workspace->level = level;
        workspace->buf = NULL;
        /*
index a759668..1f503e8 100644 (file)
@@ -539,6 +539,8 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
                }
                atomic_set(&zone_info->active_zones_left,
                           max_active_zones - nactive);
+               /* Overcommit does not work well with active zone tacking. */
+               set_bit(BTRFS_FS_NO_OVERCOMMIT, &fs_info->flags);
        }
 
        /* Validate superblock log */
index 8c74871..cac4083 100644 (file)
@@ -305,7 +305,7 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
        struct inode *inode = rreq->inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
-       struct ceph_osd_request *req;
+       struct ceph_osd_request *req = NULL;
        struct ceph_vino vino = ceph_vino(inode);
        struct iov_iter iter;
        struct page **pages;
@@ -313,6 +313,11 @@ static void ceph_netfs_issue_read(struct netfs_io_subrequest *subreq)
        int err = 0;
        u64 len = subreq->len;
 
+       if (ceph_inode_is_shutdown(inode)) {
+               err = -EIO;
+               goto out;
+       }
+
        if (ceph_has_inline_data(ci) && ceph_netfs_issue_op_inline(subreq))
                return;
 
@@ -563,6 +568,9 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
 
        dout("writepage %p idx %lu\n", page, page->index);
 
+       if (ceph_inode_is_shutdown(inode))
+               return -EIO;
+
        /* verify this is a writeable snap context */
        snapc = page_snap_context(page);
        if (!snapc) {
@@ -1643,7 +1651,7 @@ int ceph_uninline_data(struct file *file)
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_osd_request *req = NULL;
-       struct ceph_cap_flush *prealloc_cf;
+       struct ceph_cap_flush *prealloc_cf = NULL;
        struct folio *folio = NULL;
        u64 inline_version = CEPH_INLINE_NONE;
        struct page *pages[1];
@@ -1657,6 +1665,11 @@ int ceph_uninline_data(struct file *file)
        dout("uninline_data %p %llx.%llx inline_version %llu\n",
             inode, ceph_vinop(inode), inline_version);
 
+       if (ceph_inode_is_shutdown(inode)) {
+               err = -EIO;
+               goto out;
+       }
+
        if (inline_version == CEPH_INLINE_NONE)
                return 0;
 
index f75ad43..210e400 100644 (file)
@@ -4078,6 +4078,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        void *p, *end;
        struct cap_extra_info extra_info = {};
        bool queue_trunc;
+       bool close_sessions = false;
 
        dout("handle_caps from mds%d\n", session->s_mds);
 
@@ -4215,9 +4216,13 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                realm = NULL;
                if (snaptrace_len) {
                        down_write(&mdsc->snap_rwsem);
-                       ceph_update_snap_trace(mdsc, snaptrace,
-                                              snaptrace + snaptrace_len,
-                                              false, &realm);
+                       if (ceph_update_snap_trace(mdsc, snaptrace,
+                                                  snaptrace + snaptrace_len,
+                                                  false, &realm)) {
+                               up_write(&mdsc->snap_rwsem);
+                               close_sessions = true;
+                               goto done;
+                       }
                        downgrade_write(&mdsc->snap_rwsem);
                } else {
                        down_read(&mdsc->snap_rwsem);
@@ -4277,6 +4282,11 @@ done_unlocked:
        iput(inode);
 out:
        ceph_put_string(extra_info.pool_ns);
+
+       /* Defer closing the sessions after s_mutex lock being released */
+       if (close_sessions)
+               ceph_mdsc_close_sessions(mdsc);
+
        return;
 
 flush_cap_releases:
index 764598e..b5cff85 100644 (file)
@@ -2011,6 +2011,9 @@ static int ceph_zero_partial_object(struct inode *inode,
        loff_t zero = 0;
        int op;
 
+       if (ceph_inode_is_shutdown(inode))
+               return -EIO;
+
        if (!length) {
                op = offset ? CEPH_OSD_OP_DELETE : CEPH_OSD_OP_TRUNCATE;
                length = &zero;
index 26a0a8b..27a245d 100644 (file)
@@ -806,6 +806,9 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
 {
        struct ceph_mds_session *s;
 
+       if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_FENCE_IO)
+               return ERR_PTR(-EIO);
+
        if (mds >= mdsc->mdsmap->possible_max_rank)
                return ERR_PTR(-EINVAL);
 
@@ -1478,6 +1481,9 @@ static int __open_session(struct ceph_mds_client *mdsc,
        int mstate;
        int mds = session->s_mds;
 
+       if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_FENCE_IO)
+               return -EIO;
+
        /* wait for mds to go active? */
        mstate = ceph_mdsmap_get_state(mdsc->mdsmap, mds);
        dout("open_session to mds%d (%s)\n", mds,
@@ -2860,6 +2866,11 @@ static void __do_request(struct ceph_mds_client *mdsc,
                return;
        }
 
+       if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_FENCE_IO) {
+               dout("do_request metadata corrupted\n");
+               err = -EIO;
+               goto finish;
+       }
        if (req->r_timeout &&
            time_after_eq(jiffies, req->r_started + req->r_timeout)) {
                dout("do_request timed out\n");
@@ -3245,6 +3256,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
        u64 tid;
        int err, result;
        int mds = session->s_mds;
+       bool close_sessions = false;
 
        if (msg->front.iov_len < sizeof(*head)) {
                pr_err("mdsc_handle_reply got corrupt (short) reply\n");
@@ -3351,10 +3363,17 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
        realm = NULL;
        if (rinfo->snapblob_len) {
                down_write(&mdsc->snap_rwsem);
-               ceph_update_snap_trace(mdsc, rinfo->snapblob,
+               err = ceph_update_snap_trace(mdsc, rinfo->snapblob,
                                rinfo->snapblob + rinfo->snapblob_len,
                                le32_to_cpu(head->op) == CEPH_MDS_OP_RMSNAP,
                                &realm);
+               if (err) {
+                       up_write(&mdsc->snap_rwsem);
+                       close_sessions = true;
+                       if (err == -EIO)
+                               ceph_msg_dump(msg);
+                       goto out_err;
+               }
                downgrade_write(&mdsc->snap_rwsem);
        } else {
                down_read(&mdsc->snap_rwsem);
@@ -3412,6 +3431,10 @@ out_err:
                                     req->r_end_latency, err);
 out:
        ceph_mdsc_put_request(req);
+
+       /* Defer closing the sessions after s_mutex lock being released */
+       if (close_sessions)
+               ceph_mdsc_close_sessions(mdsc);
        return;
 }
 
@@ -3662,6 +3685,12 @@ static void handle_session(struct ceph_mds_session *session,
                break;
 
        case CEPH_SESSION_FLUSHMSG:
+               /* flush cap releases */
+               spin_lock(&session->s_cap_lock);
+               if (session->s_num_cap_releases)
+                       ceph_flush_cap_releases(mdsc, session);
+               spin_unlock(&session->s_cap_lock);
+
                send_flushmsg_ack(mdsc, session, seq);
                break;
 
@@ -5011,7 +5040,7 @@ static bool done_closing_sessions(struct ceph_mds_client *mdsc, int skipped)
 }
 
 /*
- * called after sb is ro.
+ * called after sb is ro or when metadata corrupted.
  */
 void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
 {
@@ -5301,7 +5330,8 @@ static void mds_peer_reset(struct ceph_connection *con)
        struct ceph_mds_client *mdsc = s->s_mdsc;
 
        pr_warn("mds%d closed our session\n", s->s_mds);
-       send_mds_reconnect(mdsc, s);
+       if (READ_ONCE(mdsc->fsc->mount_state) != CEPH_MOUNT_FENCE_IO)
+               send_mds_reconnect(mdsc, s);
 }
 
 static void mds_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
index e415185..8700720 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/ceph/ceph_debug.h>
 
+#include <linux/fs.h>
 #include <linux/sort.h>
 #include <linux/slab.h>
 #include <linux/iversion.h>
@@ -766,8 +767,10 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc,
        struct ceph_snap_realm *realm;
        struct ceph_snap_realm *first_realm = NULL;
        struct ceph_snap_realm *realm_to_rebuild = NULL;
+       struct ceph_client *client = mdsc->fsc->client;
        int rebuild_snapcs;
        int err = -ENOMEM;
+       int ret;
        LIST_HEAD(dirty_realms);
 
        lockdep_assert_held_write(&mdsc->snap_rwsem);
@@ -884,6 +887,27 @@ fail:
        if (first_realm)
                ceph_put_snap_realm(mdsc, first_realm);
        pr_err("%s error %d\n", __func__, err);
+
+       /*
+        * When receiving a corrupted snap trace we don't know what
+        * exactly has happened in MDS side. And we shouldn't continue
+        * writing to OSD, which may corrupt the snapshot contents.
+        *
+        * Just try to blocklist this kclient and then this kclient
+        * must be remounted to continue after the corrupted metadata
+        * fixed in the MDS side.
+        */
+       WRITE_ONCE(mdsc->fsc->mount_state, CEPH_MOUNT_FENCE_IO);
+       ret = ceph_monc_blocklist_add(&client->monc, &client->msgr.inst.addr);
+       if (ret)
+               pr_err("%s failed to blocklist %s: %d\n", __func__,
+                      ceph_pr_addr(&client->msgr.inst.addr), ret);
+
+       WARN(1, "%s: %s%sdo remount to continue%s",
+            __func__, ret ? "" : ceph_pr_addr(&client->msgr.inst.addr),
+            ret ? "" : " was blocklisted, ",
+            err == -EIO ? " after corrupted snaptrace is fixed" : "");
+
        return err;
 }
 
@@ -984,6 +1008,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
        __le64 *split_inos = NULL, *split_realms = NULL;
        int i;
        int locked_rwsem = 0;
+       bool close_sessions = false;
 
        /* decode */
        if (msg->front.iov_len < sizeof(*h))
@@ -1092,8 +1117,12 @@ skip_inode:
         * update using the provided snap trace. if we are deleting a
         * snap, we can avoid queueing cap_snaps.
         */
-       ceph_update_snap_trace(mdsc, p, e,
-                              op == CEPH_SNAP_OP_DESTROY, NULL);
+       if (ceph_update_snap_trace(mdsc, p, e,
+                                  op == CEPH_SNAP_OP_DESTROY,
+                                  NULL)) {
+               close_sessions = true;
+               goto bad;
+       }
 
        if (op == CEPH_SNAP_OP_SPLIT)
                /* we took a reference when we created the realm, above */
@@ -1112,6 +1141,9 @@ bad:
 out:
        if (locked_rwsem)
                up_write(&mdsc->snap_rwsem);
+
+       if (close_sessions)
+               ceph_mdsc_close_sessions(mdsc);
        return;
 }
 
index 0ed3be7..07c6906 100644 (file)
@@ -100,6 +100,17 @@ struct ceph_mount_options {
        char *mon_addr;
 };
 
+/* mount state */
+enum {
+       CEPH_MOUNT_MOUNTING,
+       CEPH_MOUNT_MOUNTED,
+       CEPH_MOUNT_UNMOUNTING,
+       CEPH_MOUNT_UNMOUNTED,
+       CEPH_MOUNT_SHUTDOWN,
+       CEPH_MOUNT_RECOVER,
+       CEPH_MOUNT_FENCE_IO,
+};
+
 #define CEPH_ASYNC_CREATE_CONFLICT_BITS 8
 
 struct ceph_fs_client {
index 5db73c0..cbc18b4 100644 (file)
@@ -278,6 +278,7 @@ build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp)
         * ( for NTLMSSP_AV_NB_DOMAIN_NAME followed by NTLMSSP_AV_EOL ) +
         * unicode length of a netbios domain name
         */
+       kfree_sensitive(ses->auth_key.response);
        ses->auth_key.len = size + 2 * dlen;
        ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
        if (!ses->auth_key.response) {
index d371259..b2a04b4 100644 (file)
@@ -2606,11 +2606,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
        INIT_LIST_HEAD(&tcon->pending_opens);
        tcon->status = TID_GOOD;
 
-       /* schedule query interfaces poll */
        INIT_DELAYED_WORK(&tcon->query_interfaces,
                          smb2_query_server_interfaces);
-       queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
-                          (SMB_INTERFACE_POLL_INTERVAL * HZ));
+       if (ses->server->dialect >= SMB30_PROT_ID &&
+           (ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
+               /* schedule query interfaces poll */
+               queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
+                                  (SMB_INTERFACE_POLL_INTERVAL * HZ));
+       }
 
        spin_lock(&cifs_tcp_ses_lock);
        list_add(&tcon->tcon_list, &ses->tcon_list);
index 43ad117..ac86bd0 100644 (file)
@@ -269,7 +269,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
                        list_for_each_entry(t, &ce->tlist, list) {
                                seq_printf(m, "  %s%s\n",
                                           t->name,
-                                          ce->tgthint == t ? " (target hint)" : "");
+                                          READ_ONCE(ce->tgthint) == t ? " (target hint)" : "");
                        }
                }
        }
@@ -321,7 +321,7 @@ static inline void dump_tgts(const struct cache_entry *ce)
        cifs_dbg(FYI, "target list:\n");
        list_for_each_entry(t, &ce->tlist, list) {
                cifs_dbg(FYI, "  %s%s\n", t->name,
-                        ce->tgthint == t ? " (target hint)" : "");
+                        READ_ONCE(ce->tgthint) == t ? " (target hint)" : "");
        }
 }
 
@@ -427,7 +427,7 @@ static int cache_entry_hash(const void *data, int size, unsigned int *hash)
 /* Return target hint of a DFS cache entry */
 static inline char *get_tgt_name(const struct cache_entry *ce)
 {
-       struct cache_dfs_tgt *t = ce->tgthint;
+       struct cache_dfs_tgt *t = READ_ONCE(ce->tgthint);
 
        return t ? t->name : ERR_PTR(-ENOENT);
 }
@@ -470,6 +470,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
 static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
                         struct cache_entry *ce, const char *tgthint)
 {
+       struct cache_dfs_tgt *target;
        int i;
 
        ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL);
@@ -496,8 +497,9 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
                ce->numtgts++;
        }
 
-       ce->tgthint = list_first_entry_or_null(&ce->tlist,
-                                              struct cache_dfs_tgt, list);
+       target = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt,
+                                         list);
+       WRITE_ONCE(ce->tgthint, target);
 
        return 0;
 }
@@ -558,7 +560,8 @@ static void remove_oldest_entry_locked(void)
 }
 
 /* Add a new DFS cache entry */
-static int add_cache_entry_locked(struct dfs_info3_param *refs, int numrefs)
+static struct cache_entry *add_cache_entry_locked(struct dfs_info3_param *refs,
+                                                 int numrefs)
 {
        int rc;
        struct cache_entry *ce;
@@ -573,11 +576,11 @@ static int add_cache_entry_locked(struct dfs_info3_param *refs, int numrefs)
 
        rc = cache_entry_hash(refs[0].path_name, strlen(refs[0].path_name), &hash);
        if (rc)
-               return rc;
+               return ERR_PTR(rc);
 
        ce = alloc_cache_entry(refs, numrefs);
        if (IS_ERR(ce))
-               return PTR_ERR(ce);
+               return ce;
 
        spin_lock(&cache_ttl_lock);
        if (!cache_ttl) {
@@ -594,7 +597,7 @@ static int add_cache_entry_locked(struct dfs_info3_param *refs, int numrefs)
 
        atomic_inc(&cache_count);
 
-       return 0;
+       return ce;
 }
 
 /* Check if two DFS paths are equal.  @s1 and @s2 are expected to be in @cache_cp's charset */
@@ -641,7 +644,9 @@ static struct cache_entry *__lookup_cache_entry(const char *path, unsigned int h
  *
  * Use whole path components in the match.  Must be called with htable_rw_lock held.
  *
+ * Return cached entry if successful.
  * Return ERR_PTR(-ENOENT) if the entry is not found.
+ * Return error ptr otherwise.
  */
 static struct cache_entry *lookup_cache_entry(const char *path)
 {
@@ -711,14 +716,15 @@ void dfs_cache_destroy(void)
 static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_info3_param *refs,
                                     int numrefs)
 {
+       struct cache_dfs_tgt *target;
+       char *th = NULL;
        int rc;
-       char *s, *th = NULL;
 
        WARN_ON(!rwsem_is_locked(&htable_rw_lock));
 
-       if (ce->tgthint) {
-               s = ce->tgthint->name;
-               th = kstrdup(s, GFP_ATOMIC);
+       target = READ_ONCE(ce->tgthint);
+       if (target) {
+               th = kstrdup(target->name, GFP_ATOMIC);
                if (!th)
                        return -ENOMEM;
        }
@@ -767,51 +773,75 @@ static int get_dfs_referral(const unsigned int xid, struct cifs_ses *ses, const
  *
  * For interlinks, cifs_mount() and expand_dfs_referral() are supposed to
  * handle them properly.
+ *
+ * On success, return entry with acquired lock for reading, otherwise error ptr.
  */
-static int cache_refresh_path(const unsigned int xid, struct cifs_ses *ses, const char *path)
+static struct cache_entry *cache_refresh_path(const unsigned int xid,
+                                             struct cifs_ses *ses,
+                                             const char *path,
+                                             bool force_refresh)
 {
-       int rc;
-       struct cache_entry *ce;
        struct dfs_info3_param *refs = NULL;
+       struct cache_entry *ce;
        int numrefs = 0;
-       bool newent = false;
+       int rc;
 
        cifs_dbg(FYI, "%s: search path: %s\n", __func__, path);
 
-       down_write(&htable_rw_lock);
+       down_read(&htable_rw_lock);
 
        ce = lookup_cache_entry(path);
        if (!IS_ERR(ce)) {
-               if (!cache_entry_expired(ce)) {
-                       dump_ce(ce);
-                       up_write(&htable_rw_lock);
-                       return 0;
-               }
-       } else {
-               newent = true;
+               if (!force_refresh && !cache_entry_expired(ce))
+                       return ce;
+       } else if (PTR_ERR(ce) != -ENOENT) {
+               up_read(&htable_rw_lock);
+               return ce;
        }
 
        /*
-        * Either the entry was not found, or it is expired.
+        * Unlock shared access as we don't want to hold any locks while getting
+        * a new referral.  The @ses used for performing the I/O could be
+        * reconnecting and it acquires @htable_rw_lock to look up the dfs cache
+        * in order to failover -- if necessary.
+        */
+       up_read(&htable_rw_lock);
+
+       /*
+        * Either the entry was not found, or it is expired, or it is a forced
+        * refresh.
         * Request a new DFS referral in order to create or update a cache entry.
         */
        rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
-       if (rc)
-               goto out_unlock;
+       if (rc) {
+               ce = ERR_PTR(rc);
+               goto out;
+       }
 
        dump_refs(refs, numrefs);
 
-       if (!newent) {
-               rc = update_cache_entry_locked(ce, refs, numrefs);
-               goto out_unlock;
+       down_write(&htable_rw_lock);
+       /* Re-check as another task might have it added or refreshed already */
+       ce = lookup_cache_entry(path);
+       if (!IS_ERR(ce)) {
+               if (force_refresh || cache_entry_expired(ce)) {
+                       rc = update_cache_entry_locked(ce, refs, numrefs);
+                       if (rc)
+                               ce = ERR_PTR(rc);
+               }
+       } else if (PTR_ERR(ce) == -ENOENT) {
+               ce = add_cache_entry_locked(refs, numrefs);
        }
 
-       rc = add_cache_entry_locked(refs, numrefs);
+       if (IS_ERR(ce)) {
+               up_write(&htable_rw_lock);
+               goto out;
+       }
 
-out_unlock:
-       up_write(&htable_rw_lock);
+       downgrade_write(&htable_rw_lock);
+out:
        free_dfs_info_array(refs, numrefs);
-       return rc;
+       return ce;
 }
 
 /*
@@ -878,7 +908,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl)
                }
                it->it_path_consumed = t->path_consumed;
 
-               if (ce->tgthint == t)
+               if (READ_ONCE(ce->tgthint) == t)
                        list_add(&it->it_list, head);
                else
                        list_add_tail(&it->it_list, head);
@@ -931,15 +961,8 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nl
        if (IS_ERR(npath))
                return PTR_ERR(npath);
 
-       rc = cache_refresh_path(xid, ses, npath);
-       if (rc)
-               goto out_free_path;
-
-       down_read(&htable_rw_lock);
-
-       ce = lookup_cache_entry(npath);
+       ce = cache_refresh_path(xid, ses, npath, false);
        if (IS_ERR(ce)) {
-               up_read(&htable_rw_lock);
                rc = PTR_ERR(ce);
                goto out_free_path;
        }
@@ -1002,72 +1025,6 @@ out_unlock:
        return rc;
 }
 
-/**
- * dfs_cache_update_tgthint - update target hint of a DFS cache entry
- *
- * If it doesn't find the cache entry, then it will get a DFS referral for @path
- * and create a new entry.
- *
- * In case the cache entry exists but expired, it will get a DFS referral
- * for @path and then update the respective cache entry.
- *
- * @xid: syscall id
- * @ses: smb session
- * @cp: codepage
- * @remap: type of character remapping for paths
- * @path: path to lookup in DFS referral cache
- * @it: DFS target iterator
- *
- * Return zero if the target hint was updated successfully, otherwise non-zero.
- */
-int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
-                            const struct nls_table *cp, int remap, const char *path,
-                            const struct dfs_cache_tgt_iterator *it)
-{
-       int rc;
-       const char *npath;
-       struct cache_entry *ce;
-       struct cache_dfs_tgt *t;
-
-       npath = dfs_cache_canonical_path(path, cp, remap);
-       if (IS_ERR(npath))
-               return PTR_ERR(npath);
-
-       cifs_dbg(FYI, "%s: update target hint - path: %s\n", __func__, npath);
-
-       rc = cache_refresh_path(xid, ses, npath);
-       if (rc)
-               goto out_free_path;
-
-       down_write(&htable_rw_lock);
-
-       ce = lookup_cache_entry(npath);
-       if (IS_ERR(ce)) {
-               rc = PTR_ERR(ce);
-               goto out_unlock;
-       }
-
-       t = ce->tgthint;
-
-       if (likely(!strcasecmp(it->it_name, t->name)))
-               goto out_unlock;
-
-       list_for_each_entry(t, &ce->tlist, list) {
-               if (!strcasecmp(t->name, it->it_name)) {
-                       ce->tgthint = t;
-                       cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
-                                it->it_name);
-                       break;
-               }
-       }
-
-out_unlock:
-       up_write(&htable_rw_lock);
-out_free_path:
-       kfree(npath);
-       return rc;
-}
-
 /**
  * dfs_cache_noreq_update_tgthint - update target hint of a DFS cache entry
  * without sending any requests to the currently connected server.
@@ -1092,21 +1049,20 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt
 
        cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
 
-       if (!down_write_trylock(&htable_rw_lock))
-               return;
+       down_read(&htable_rw_lock);
 
        ce = lookup_cache_entry(path);
        if (IS_ERR(ce))
                goto out_unlock;
 
-       t = ce->tgthint;
+       t = READ_ONCE(ce->tgthint);
 
        if (unlikely(!strcasecmp(it->it_name, t->name)))
                goto out_unlock;
 
        list_for_each_entry(t, &ce->tlist, list) {
                if (!strcasecmp(t->name, it->it_name)) {
-                       ce->tgthint = t;
+                       WRITE_ONCE(ce->tgthint, t);
                        cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
                                 it->it_name);
                        break;
@@ -1114,7 +1070,7 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt
        }
 
 out_unlock:
-       up_write(&htable_rw_lock);
+       up_read(&htable_rw_lock);
 }
 
 /**
@@ -1299,7 +1255,6 @@ static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, c
         * Resolve share's hostname and check if server address matches.  Otherwise just ignore it
         * as we could not have upcall to resolve hostname or failed to convert ip address.
         */
-       match = true;
        extract_unc_hostname(s1, &host, &hostlen);
        scnprintf(unc, sizeof(unc), "\\\\%.*s", (int)hostlen, host);
 
@@ -1321,35 +1276,37 @@ static bool target_share_equal(struct TCP_Server_Info *server, const char *s1, c
  * Mark dfs tcon for reconnecting when the currently connected tcon does not match any of the new
  * target shares in @refs.
  */
-static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cache_tgt_list *tl,
-                                        const struct dfs_info3_param *refs, int numrefs)
+static void mark_for_reconnect_if_needed(struct TCP_Server_Info *server,
+                                        struct dfs_cache_tgt_list *old_tl,
+                                        struct dfs_cache_tgt_list *new_tl)
 {
-       struct dfs_cache_tgt_iterator *it;
-       int i;
-
-       for (it = dfs_cache_get_tgt_iterator(tl); it; it = dfs_cache_get_next_tgt(tl, it)) {
-               for (i = 0; i < numrefs; i++) {
-                       if (target_share_equal(tcon->ses->server, dfs_cache_get_tgt_name(it),
-                                              refs[i].node_name))
+       struct dfs_cache_tgt_iterator *oit, *nit;
+
+       for (oit = dfs_cache_get_tgt_iterator(old_tl); oit;
+            oit = dfs_cache_get_next_tgt(old_tl, oit)) {
+               for (nit = dfs_cache_get_tgt_iterator(new_tl); nit;
+                    nit = dfs_cache_get_next_tgt(new_tl, nit)) {
+                       if (target_share_equal(server,
+                                              dfs_cache_get_tgt_name(oit),
+                                              dfs_cache_get_tgt_name(nit)))
                                return;
                }
        }
 
        cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__);
-       cifs_signal_cifsd_for_reconnect(tcon->ses->server, true);
+       cifs_signal_cifsd_for_reconnect(server, true);
 }
 
 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
 static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_refresh)
 {
-       struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
+       struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl);
+       struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl);
        struct cifs_ses *ses = CIFS_DFS_ROOT_SES(tcon->ses);
        struct cifs_tcon *ipc = ses->tcon_ipc;
-       struct dfs_info3_param *refs = NULL;
        bool needs_refresh = false;
        struct cache_entry *ce;
        unsigned int xid;
-       int numrefs = 0;
        int rc = 0;
 
        xid = get_xid();
@@ -1358,9 +1315,8 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r
        ce = lookup_cache_entry(path);
        needs_refresh = force_refresh || IS_ERR(ce) || cache_entry_expired(ce);
        if (!IS_ERR(ce)) {
-               rc = get_targets(ce, &tl);
-               if (rc)
-                       cifs_dbg(FYI, "%s: could not get dfs targets: %d\n", __func__, rc);
+               rc = get_targets(ce, &old_tl);
+               cifs_dbg(FYI, "%s: get_targets: %d\n", __func__, rc);
        }
        up_read(&htable_rw_lock);
 
@@ -1377,26 +1333,18 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r
        }
        spin_unlock(&ipc->tc_lock);
 
-       rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
-       if (!rc) {
-               /* Create or update a cache entry with the new referral */
-               dump_refs(refs, numrefs);
-
-               down_write(&htable_rw_lock);
-               ce = lookup_cache_entry(path);
-               if (IS_ERR(ce))
-                       add_cache_entry_locked(refs, numrefs);
-               else if (force_refresh || cache_entry_expired(ce))
-                       update_cache_entry_locked(ce, refs, numrefs);
-               up_write(&htable_rw_lock);
-
-               mark_for_reconnect_if_needed(tcon, &tl, refs, numrefs);
+       ce = cache_refresh_path(xid, ses, path, true);
+       if (!IS_ERR(ce)) {
+               rc = get_targets(ce, &new_tl);
+               up_read(&htable_rw_lock);
+               cifs_dbg(FYI, "%s: get_targets: %d\n", __func__, rc);
+               mark_for_reconnect_if_needed(tcon->ses->server, &old_tl, &new_tl);
        }
 
 out:
        free_xid(xid);
-       dfs_cache_free_tgts(&tl);
-       free_dfs_info_array(refs, numrefs);
+       dfs_cache_free_tgts(&old_tl);
+       dfs_cache_free_tgts(&new_tl);
        return rc;
 }
 
index f7cff0b..be3b5a4 100644 (file)
@@ -35,9 +35,6 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses, const struct nl
                   struct dfs_cache_tgt_list *tgt_list);
 int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
                         struct dfs_cache_tgt_list *tgt_list);
-int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
-                            const struct nls_table *cp, int remap, const char *path,
-                            const struct dfs_cache_tgt_iterator *it);
 void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it);
 int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it,
                               struct dfs_info3_param *ref);
index 22dfc1f..b8d1cba 100644 (file)
@@ -3889,7 +3889,7 @@ uncached_fill_pages(struct TCP_Server_Info *server,
                rdata->got_bytes += result;
        }
 
-       return rdata->got_bytes > 0 && result != -ECONNABORTED ?
+       return result != -ECONNABORTED && rdata->got_bytes > 0 ?
                                                rdata->got_bytes : result;
 }
 
@@ -4665,7 +4665,7 @@ readpages_fill_pages(struct TCP_Server_Info *server,
                rdata->got_bytes += result;
        }
 
-       return rdata->got_bytes > 0 && result != -ECONNABORTED ?
+       return result != -ECONNABORTED && rdata->got_bytes > 0 ?
                                                rdata->got_bytes : result;
 }
 
index bd374fe..a5a097a 100644 (file)
@@ -428,6 +428,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
        oparms.disposition = FILE_CREATE;
        oparms.fid = &fid;
        oparms.reconnect = false;
+       oparms.mode = 0644;
 
        rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
                       NULL, NULL);
index 0b842a0..c47b254 100644 (file)
@@ -815,6 +815,7 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
                return -EINVAL;
        }
        if (tilen) {
+               kfree_sensitive(ses->auth_key.response);
                ses->auth_key.response = kmemdup(bcc_ptr + tioffset, tilen,
                                                 GFP_KERNEL);
                if (!ses->auth_key.response) {
@@ -1428,6 +1429,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
                goto out_put_spnego_key;
        }
 
+       kfree_sensitive(ses->auth_key.response);
        ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
                                         GFP_KERNEL);
        if (!ses->auth_key.response) {
index 5048075..4cb3644 100644 (file)
@@ -562,17 +562,20 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
        if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
                rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
                                         cifs_remap(cifs_sb));
-               if (!rc)
-                       move_cifs_info_to_smb2(&data->fi, &fi);
                *adjustTZ = true;
        }
 
-       if (!rc && (le32_to_cpu(fi.Attributes) & ATTR_REPARSE)) {
+       if (!rc) {
                int tmprc;
                int oplock = 0;
                struct cifs_fid fid;
                struct cifs_open_parms oparms;
 
+               move_cifs_info_to_smb2(&data->fi, &fi);
+
+               if (!(le32_to_cpu(fi.Attributes) & ATTR_REPARSE))
+                       return 0;
+
                oparms.tcon = tcon;
                oparms.cifs_sb = cifs_sb;
                oparms.desired_access = FILE_READ_ATTRIBUTES;
@@ -716,17 +719,25 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
 static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
                          void *buf)
 {
-       FILE_ALL_INFO *fi = buf;
+       struct cifs_open_info_data *data = buf;
+       FILE_ALL_INFO fi = {};
+       int rc;
 
        if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS))
-               return SMBLegacyOpen(xid, oparms->tcon, oparms->path,
-                                    oparms->disposition,
-                                    oparms->desired_access,
-                                    oparms->create_options,
-                                    &oparms->fid->netfid, oplock, fi,
-                                    oparms->cifs_sb->local_nls,
-                                    cifs_remap(oparms->cifs_sb));
-       return CIFS_open(xid, oparms, oplock, fi);
+               rc = SMBLegacyOpen(xid, oparms->tcon, oparms->path,
+                                  oparms->disposition,
+                                  oparms->desired_access,
+                                  oparms->create_options,
+                                  &oparms->fid->netfid, oplock, &fi,
+                                  oparms->cifs_sb->local_nls,
+                                  cifs_remap(oparms->cifs_sb));
+       else
+               rc = CIFS_open(xid, oparms, oplock, &fi);
+
+       if (!rc && data)
+               move_cifs_info_to_smb2(&data->fi, &fi);
+
+       return rc;
 }
 
 static void
@@ -1050,7 +1061,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct inode *newinode = NULL;
        int rc = -EPERM;
-       FILE_ALL_INFO *buf = NULL;
+       struct cifs_open_info_data buf = {};
        struct cifs_io_parms io_parms;
        __u32 oplock = 0;
        struct cifs_fid fid;
@@ -1082,14 +1093,14 @@ cifs_make_node(unsigned int xid, struct inode *inode,
                                            cifs_sb->local_nls,
                                            cifs_remap(cifs_sb));
                if (rc)
-                       goto out;
+                       return rc;
 
                rc = cifs_get_inode_info_unix(&newinode, full_path,
                                              inode->i_sb, xid);
 
                if (rc == 0)
                        d_instantiate(dentry, newinode);
-               goto out;
+               return rc;
        }
 
        /*
@@ -1097,19 +1108,13 @@ cifs_make_node(unsigned int xid, struct inode *inode,
         * support block and char device (no socket & fifo)
         */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
-               goto out;
+               return rc;
 
        if (!S_ISCHR(mode) && !S_ISBLK(mode))
-               goto out;
+               return rc;
 
        cifs_dbg(FYI, "sfu compat create special file\n");
 
-       buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
-       if (buf == NULL) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
        oparms.tcon = tcon;
        oparms.cifs_sb = cifs_sb;
        oparms.desired_access = GENERIC_WRITE;
@@ -1124,21 +1129,21 @@ cifs_make_node(unsigned int xid, struct inode *inode,
                oplock = REQ_OPLOCK;
        else
                oplock = 0;
-       rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
+       rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf);
        if (rc)
-               goto out;
+               return rc;
 
        /*
         * BB Do not bother to decode buf since no local inode yet to put
         * timestamps in, but we can reuse it safely.
         */
 
-       pdev = (struct win_dev *)buf;
+       pdev = (struct win_dev *)&buf.fi;
        io_parms.pid = current->tgid;
        io_parms.tcon = tcon;
        io_parms.offset = 0;
        io_parms.length = sizeof(struct win_dev);
-       iov[1].iov_base = buf;
+       iov[1].iov_base = &buf.fi;
        iov[1].iov_len = sizeof(struct win_dev);
        if (S_ISCHR(mode)) {
                memcpy(pdev->type, "IntxCHR", 8);
@@ -1157,8 +1162,8 @@ cifs_make_node(unsigned int xid, struct inode *inode,
        d_drop(dentry);
 
        /* FIXME: add code here to set EAs */
-out:
-       kfree(buf);
+
+       cifs_free_open_info(&buf);
        return rc;
 }
 
index 2c484d4..2c9ffa9 100644 (file)
@@ -1453,6 +1453,7 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 
        /* keep session key if binding */
        if (!is_binding) {
+               kfree_sensitive(ses->auth_key.response);
                ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
                                                 GFP_KERNEL);
                if (!ses->auth_key.response) {
@@ -1482,8 +1483,11 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
 out_put_spnego_key:
        key_invalidate(spnego_key);
        key_put(spnego_key);
-       if (rc)
+       if (rc) {
                kfree_sensitive(ses->auth_key.response);
+               ses->auth_key.response = NULL;
+               ses->auth_key.len = 0;
+       }
 out:
        sess_data->result = rc;
        sess_data->func = NULL;
@@ -4159,12 +4163,15 @@ smb2_readv_callback(struct mid_q_entry *mid)
                                (struct smb2_hdr *)rdata->iov[0].iov_base;
        struct cifs_credits credits = { .value = 0, .instance = 0 };
        struct smb_rqst rqst = { .rq_iov = &rdata->iov[1],
-                                .rq_nvec = 1,
-                                .rq_pages = rdata->pages,
-                                .rq_offset = rdata->page_offset,
-                                .rq_npages = rdata->nr_pages,
-                                .rq_pagesz = rdata->pagesz,
-                                .rq_tailsz = rdata->tailsz };
+                                .rq_nvec = 1, };
+
+       if (rdata->got_bytes) {
+               rqst.rq_pages = rdata->pages;
+               rqst.rq_offset = rdata->page_offset;
+               rqst.rq_npages = rdata->nr_pages;
+               rqst.rq_pagesz = rdata->pagesz;
+               rqst.rq_tailsz = rdata->tailsz;
+       }
 
        WARN_ONCE(rdata->server != mid->server,
                  "rdata server %p != mid server %p",
index 90789aa..8c816b2 100644 (file)
@@ -1405,6 +1405,7 @@ void smbd_destroy(struct TCP_Server_Info *server)
        destroy_workqueue(info->workqueue);
        log_rdma_event(INFO,  "rdma session destroyed\n");
        kfree(info);
+       server->smbd_conn = NULL;
 }
 
 /*
index de78bde..a25ecec 100644 (file)
@@ -838,6 +838,30 @@ static int __dump_skip(struct coredump_params *cprm, size_t nr)
        }
 }
 
+int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
+{
+       if (cprm->to_skip) {
+               if (!__dump_skip(cprm, cprm->to_skip))
+                       return 0;
+               cprm->to_skip = 0;
+       }
+       return __dump_emit(cprm, addr, nr);
+}
+EXPORT_SYMBOL(dump_emit);
+
+void dump_skip_to(struct coredump_params *cprm, unsigned long pos)
+{
+       cprm->to_skip = pos - cprm->pos;
+}
+EXPORT_SYMBOL(dump_skip_to);
+
+void dump_skip(struct coredump_params *cprm, size_t nr)
+{
+       cprm->to_skip += nr;
+}
+EXPORT_SYMBOL(dump_skip);
+
+#ifdef CONFIG_ELF_CORE
 static int dump_emit_page(struct coredump_params *cprm, struct page *page)
 {
        struct bio_vec bvec = {
@@ -871,30 +895,6 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page)
        return 1;
 }
 
-int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
-{
-       if (cprm->to_skip) {
-               if (!__dump_skip(cprm, cprm->to_skip))
-                       return 0;
-               cprm->to_skip = 0;
-       }
-       return __dump_emit(cprm, addr, nr);
-}
-EXPORT_SYMBOL(dump_emit);
-
-void dump_skip_to(struct coredump_params *cprm, unsigned long pos)
-{
-       cprm->to_skip = pos - cprm->pos;
-}
-EXPORT_SYMBOL(dump_skip_to);
-
-void dump_skip(struct coredump_params *cprm, size_t nr)
-{
-       cprm->to_skip += nr;
-}
-EXPORT_SYMBOL(dump_skip);
-
-#ifdef CONFIG_ELF_CORE
 int dump_user_range(struct coredump_params *cprm, unsigned long start,
                    unsigned long len)
 {
index 481788c..626a615 100644 (file)
@@ -577,26 +577,25 @@ static int erofs_fc_parse_param(struct fs_context *fc,
                }
                ++ctx->devs->extra_devices;
                break;
-       case Opt_fsid:
 #ifdef CONFIG_EROFS_FS_ONDEMAND
+       case Opt_fsid:
                kfree(ctx->fsid);
                ctx->fsid = kstrdup(param->string, GFP_KERNEL);
                if (!ctx->fsid)
                        return -ENOMEM;
-#else
-               errorfc(fc, "fsid option not supported");
-#endif
                break;
        case Opt_domain_id:
-#ifdef CONFIG_EROFS_FS_ONDEMAND
                kfree(ctx->domain_id);
                ctx->domain_id = kstrdup(param->string, GFP_KERNEL);
                if (!ctx->domain_id)
                        return -ENOMEM;
+               break;
 #else
-               errorfc(fc, "domain_id option not supported");
-#endif
+       case Opt_fsid:
+       case Opt_domain_id:
+               errorfc(fc, "%s option not supported", erofs_fs_parameters[opt].name);
                break;
+#endif
        default:
                return -ENOPARAM;
        }
index ccf7c55..5200bb8 100644 (file)
@@ -1032,12 +1032,12 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
 
        if (!be->decompressed_pages)
                be->decompressed_pages =
-                       kvcalloc(be->nr_pages, sizeof(struct page *),
-                                GFP_KERNEL | __GFP_NOFAIL);
+                       kcalloc(be->nr_pages, sizeof(struct page *),
+                               GFP_KERNEL | __GFP_NOFAIL);
        if (!be->compressed_pages)
                be->compressed_pages =
-                       kvcalloc(pclusterpages, sizeof(struct page *),
-                                GFP_KERNEL | __GFP_NOFAIL);
+                       kcalloc(pclusterpages, sizeof(struct page *),
+                               GFP_KERNEL | __GFP_NOFAIL);
 
        z_erofs_parse_out_bvecs(be);
        err2 = z_erofs_parse_in_bvecs(be, &overlapped);
@@ -1085,7 +1085,7 @@ out:
        }
        if (be->compressed_pages < be->onstack_pages ||
            be->compressed_pages >= be->onstack_pages + Z_EROFS_ONSTACK_PAGES)
-               kvfree(be->compressed_pages);
+               kfree(be->compressed_pages);
        z_erofs_fill_other_copies(be, err);
 
        for (i = 0; i < be->nr_pages; ++i) {
@@ -1104,7 +1104,7 @@ out:
        }
 
        if (be->decompressed_pages != be->onstack_pages)
-               kvfree(be->decompressed_pages);
+               kfree(be->decompressed_pages);
 
        pcl->length = 0;
        pcl->partial = true;
index 0150570..98fb90b 100644 (file)
@@ -793,12 +793,16 @@ static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset,
                iomap->type = IOMAP_HOLE;
                iomap->addr = IOMAP_NULL_ADDR;
                /*
-                * No strict rule how to describe extents for post EOF, yet
-                * we need do like below. Otherwise, iomap itself will get
+                * No strict rule on how to describe extents for post EOF, yet
+                * we need to do like below. Otherwise, iomap itself will get
                 * into an endless loop on post EOF.
+                *
+                * Calculate the effective offset by subtracting extent start
+                * (map.m_la) from the requested offset, and add it to length.
+                * (NB: offset >= map.m_la always)
                 */
                if (iomap->offset >= inode->i_size)
-                       iomap->length = length + map.m_la - offset;
+                       iomap->length = length + offset - map.m_la;
        }
        iomap->flags = 0;
        return 0;
index 7decaaf..a2f04a3 100644 (file)
@@ -81,6 +81,8 @@ ext4_xattr_block_cache_find(struct inode *, struct ext4_xattr_header *,
                            struct mb_cache_entry **);
 static __le32 ext4_xattr_hash_entry(char *name, size_t name_len, __le32 *value,
                                    size_t value_count);
+static __le32 ext4_xattr_hash_entry_signed(char *name, size_t name_len, __le32 *value,
+                                   size_t value_count);
 static void ext4_xattr_rehash(struct ext4_xattr_header *);
 
 static const struct xattr_handler * const ext4_xattr_handler_map[] = {
@@ -470,8 +472,22 @@ ext4_xattr_inode_verify_hashes(struct inode *ea_inode,
                tmp_data = cpu_to_le32(hash);
                e_hash = ext4_xattr_hash_entry(entry->e_name, entry->e_name_len,
                                               &tmp_data, 1);
+               /* All good? */
+               if (e_hash == entry->e_hash)
+                       return 0;
+
+               /*
+                * Not good. Maybe the entry hash was calculated
+                * using the buggy signed char version?
+                */
+               e_hash = ext4_xattr_hash_entry_signed(entry->e_name, entry->e_name_len,
+                                                       &tmp_data, 1);
+               /* Still no match - bad */
                if (e_hash != entry->e_hash)
                        return -EFSCORRUPTED;
+
+               /* Let people know about old hash */
+               pr_warn_once("ext4: filesystem with signed xattr name hash");
        }
        return 0;
 }
@@ -3081,7 +3097,29 @@ static __le32 ext4_xattr_hash_entry(char *name, size_t name_len, __le32 *value,
        while (name_len--) {
                hash = (hash << NAME_HASH_SHIFT) ^
                       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
-                      *name++;
+                      (unsigned char)*name++;
+       }
+       while (value_count--) {
+               hash = (hash << VALUE_HASH_SHIFT) ^
+                      (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+                      le32_to_cpu(*value++);
+       }
+       return cpu_to_le32(hash);
+}
+
+/*
+ * ext4_xattr_hash_entry_signed()
+ *
+ * Compute the hash of an extended attribute incorrectly.
+ */
+static __le32 ext4_xattr_hash_entry_signed(char *name, size_t name_len, __le32 *value, size_t value_count)
+{
+       __u32 hash = 0;
+
+       while (name_len--) {
+               hash = (hash << NAME_HASH_SHIFT) ^
+                      (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+                      (signed char)*name++;
        }
        while (value_count--) {
                hash = (hash << VALUE_HASH_SHIFT) ^
index c05c71d..0e2fc08 100644 (file)
@@ -8,7 +8,7 @@ config VXFS_FS
          of SCO UnixWare (and possibly others) and optionally available
          for Sunsoft Solaris, HP-UX and many other operating systems. However
          these particular OS implementations of vxfs may differ in on-disk
-         data endianess and/or superblock offset. The vxfs module has been
+         data endianness and/or superblock offset. The vxfs module has been
          tested with SCO UnixWare and HP-UX B.10.20 (pa-risc 1.1 arch.)
          Currently only readonly access is supported and VxFX versions
          2, 3 and 4. Tests were performed with HP-UX VxFS version 3.
index ab8cedd..cdf991b 100644 (file)
@@ -141,13 +141,14 @@ static bool fscache_is_acquire_pending(struct fscache_volume *volume)
 static void fscache_wait_on_volume_collision(struct fscache_volume *candidate,
                                             unsigned int collidee_debug_id)
 {
-       wait_var_event_timeout(&candidate->flags,
-                              !fscache_is_acquire_pending(candidate), 20 * HZ);
+       wait_on_bit_timeout(&candidate->flags, FSCACHE_VOLUME_ACQUIRE_PENDING,
+                           TASK_UNINTERRUPTIBLE, 20 * HZ);
        if (fscache_is_acquire_pending(candidate)) {
                pr_notice("Potential volume collision new=%08x old=%08x",
                          candidate->debug_id, collidee_debug_id);
                fscache_stat(&fscache_n_volumes_collision);
-               wait_var_event(&candidate->flags, !fscache_is_acquire_pending(candidate));
+               wait_on_bit(&candidate->flags, FSCACHE_VOLUME_ACQUIRE_PENDING,
+                           TASK_UNINTERRUPTIBLE);
        }
 }
 
@@ -279,8 +280,7 @@ static void fscache_create_volume_work(struct work_struct *work)
        fscache_end_cache_access(volume->cache,
                                 fscache_access_acquire_volume_end);
 
-       clear_bit_unlock(FSCACHE_VOLUME_CREATING, &volume->flags);
-       wake_up_bit(&volume->flags, FSCACHE_VOLUME_CREATING);
+       clear_and_wake_up_bit(FSCACHE_VOLUME_CREATING, &volume->flags);
        fscache_put_volume(volume, fscache_volume_put_create_work);
 }
 
@@ -347,8 +347,8 @@ static void fscache_wake_pending_volume(struct fscache_volume *volume,
        hlist_bl_for_each_entry(cursor, p, h, hash_link) {
                if (fscache_volume_same(cursor, volume)) {
                        fscache_see_volume(cursor, fscache_volume_see_hash_wake);
-                       clear_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &cursor->flags);
-                       wake_up_bit(&cursor->flags, FSCACHE_VOLUME_ACQUIRE_PENDING);
+                       clear_and_wake_up_bit(FSCACHE_VOLUME_ACQUIRE_PENDING,
+                                             &cursor->flags);
                        return;
                }
        }
index a4850ae..ad67036 100644 (file)
 #include <linux/posix_acl.h>
 #include <linux/posix_acl_xattr.h>
 
-struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu)
+static struct posix_acl *__fuse_get_acl(struct fuse_conn *fc,
+                                       struct user_namespace *mnt_userns,
+                                       struct inode *inode, int type, bool rcu)
 {
-       struct fuse_conn *fc = get_fuse_conn(inode);
        int size;
        const char *name;
        void *value = NULL;
@@ -25,7 +26,7 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu)
        if (fuse_is_bad(inode))
                return ERR_PTR(-EIO);
 
-       if (!fc->posix_acl || fc->no_getxattr)
+       if (fc->no_getxattr)
                return NULL;
 
        if (type == ACL_TYPE_ACCESS)
@@ -53,6 +54,46 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu)
        return acl;
 }
 
+static inline bool fuse_no_acl(const struct fuse_conn *fc,
+                              const struct inode *inode)
+{
+       /*
+        * Refuse interacting with POSIX ACLs for daemons that
+        * don't support FUSE_POSIX_ACL and are not mounted on
+        * the host to retain backwards compatibility.
+        */
+       return !fc->posix_acl && (i_user_ns(inode) != &init_user_ns);
+}
+
+struct posix_acl *fuse_get_acl(struct user_namespace *mnt_userns,
+                              struct dentry *dentry, int type)
+{
+       struct inode *inode = d_inode(dentry);
+       struct fuse_conn *fc = get_fuse_conn(inode);
+
+       if (fuse_no_acl(fc, inode))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       return __fuse_get_acl(fc, mnt_userns, inode, type, false);
+}
+
+struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu)
+{
+       struct fuse_conn *fc = get_fuse_conn(inode);
+
+       /*
+        * FUSE daemons before FUSE_POSIX_ACL was introduced could get and set
+        * POSIX ACLs without them being used for permission checking by the
+        * vfs. Retain that behavior for backwards compatibility as there are
+        * filesystems that do all permission checking for acls in the daemon
+        * and not in the kernel.
+        */
+       if (!fc->posix_acl)
+               return NULL;
+
+       return __fuse_get_acl(fc, &init_user_ns, inode, type, rcu);
+}
+
 int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
                 struct posix_acl *acl, int type)
 {
@@ -64,7 +105,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
        if (fuse_is_bad(inode))
                return -EIO;
 
-       if (!fc->posix_acl || fc->no_setxattr)
+       if (fc->no_setxattr || fuse_no_acl(fc, inode))
                return -EOPNOTSUPP;
 
        if (type == ACL_TYPE_ACCESS)
@@ -99,7 +140,13 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
                        return ret;
                }
 
-               if (!vfsgid_in_group_p(i_gid_into_vfsgid(&init_user_ns, inode)) &&
+               /*
+                * Fuse daemons without FUSE_POSIX_ACL never changed the passed
+                * through POSIX ACLs. Such daemons don't expect setgid bits to
+                * be stripped.
+                */
+               if (fc->posix_acl &&
+                   !vfsgid_in_group_p(i_gid_into_vfsgid(&init_user_ns, inode)) &&
                    !capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID))
                        extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
 
@@ -108,8 +155,15 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
        } else {
                ret = fuse_removexattr(inode, name);
        }
-       forget_all_cached_acls(inode);
-       fuse_invalidate_attr(inode);
+
+       if (fc->posix_acl) {
+               /*
+                * Fuse daemons without FUSE_POSIX_ACL never cached POSIX ACLs
+                * and didn't invalidate attributes. Retain that behavior.
+                */
+               forget_all_cached_acls(inode);
+               fuse_invalidate_attr(inode);
+       }
 
        return ret;
 }
index cd1a071..2725fb5 100644 (file)
@@ -1942,7 +1942,8 @@ static const struct inode_operations fuse_dir_inode_operations = {
        .permission     = fuse_permission,
        .getattr        = fuse_getattr,
        .listxattr      = fuse_listxattr,
-       .get_inode_acl  = fuse_get_acl,
+       .get_inode_acl  = fuse_get_inode_acl,
+       .get_acl        = fuse_get_acl,
        .set_acl        = fuse_set_acl,
        .fileattr_get   = fuse_fileattr_get,
        .fileattr_set   = fuse_fileattr_set,
@@ -1964,7 +1965,8 @@ static const struct inode_operations fuse_common_inode_operations = {
        .permission     = fuse_permission,
        .getattr        = fuse_getattr,
        .listxattr      = fuse_listxattr,
-       .get_inode_acl  = fuse_get_acl,
+       .get_inode_acl  = fuse_get_inode_acl,
+       .get_acl        = fuse_get_acl,
        .set_acl        = fuse_set_acl,
        .fileattr_get   = fuse_fileattr_get,
        .fileattr_set   = fuse_fileattr_set,
index c673fae..46797a1 100644 (file)
@@ -1264,11 +1264,11 @@ ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
 ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size);
 int fuse_removexattr(struct inode *inode, const char *name);
 extern const struct xattr_handler *fuse_xattr_handlers[];
-extern const struct xattr_handler *fuse_acl_xattr_handlers[];
-extern const struct xattr_handler *fuse_no_acl_xattr_handlers[];
 
 struct posix_acl;
-struct posix_acl *fuse_get_acl(struct inode *inode, int type, bool rcu);
+struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu);
+struct posix_acl *fuse_get_acl(struct user_namespace *mnt_userns,
+                              struct dentry *dentry, int type);
 int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
                 struct posix_acl *acl, int type);
 
index 6b3beda..de9b9ec 100644 (file)
@@ -311,7 +311,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
                fuse_dax_dontcache(inode, attr->flags);
 }
 
-static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
+static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr,
+                           struct fuse_conn *fc)
 {
        inode->i_mode = attr->mode & S_IFMT;
        inode->i_size = attr->size;
@@ -333,6 +334,12 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
                                   new_decode_dev(attr->rdev));
        } else
                BUG();
+       /*
+        * Ensure that we don't cache acls for daemons without FUSE_POSIX_ACL
+        * so they see the exact same behavior as before.
+        */
+       if (!fc->posix_acl)
+               inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;
 }
 
 static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
@@ -372,7 +379,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
                if (!inode)
                        return NULL;
 
-               fuse_init_inode(inode, attr);
+               fuse_init_inode(inode, attr, fc);
                get_fuse_inode(inode)->nodeid = nodeid;
                inode->i_flags |= S_AUTOMOUNT;
                goto done;
@@ -388,7 +395,7 @@ retry:
                if (!fc->writeback_cache || !S_ISREG(attr->mode))
                        inode->i_flags |= S_NOCMTIME;
                inode->i_generation = generation;
-               fuse_init_inode(inode, attr);
+               fuse_init_inode(inode, attr, fc);
                unlock_new_inode(inode);
        } else if (fuse_stale_inode(inode, generation, attr)) {
                /* nodeid was reused, any I/O on the old inode should fail */
@@ -1174,7 +1181,6 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
                        if ((flags & FUSE_POSIX_ACL)) {
                                fc->default_permissions = 1;
                                fc->posix_acl = 1;
-                               fm->sb->s_xattr = fuse_acl_xattr_handlers;
                        }
                        if (flags & FUSE_CACHE_SYMLINKS)
                                fc->cache_symlinks = 1;
@@ -1420,13 +1426,6 @@ static void fuse_sb_defaults(struct super_block *sb)
        if (sb->s_user_ns != &init_user_ns)
                sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
        sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);
-
-       /*
-        * If we are not in the initial user namespace posix
-        * acls must be translated.
-        */
-       if (sb->s_user_ns != &init_user_ns)
-               sb->s_xattr = fuse_no_acl_xattr_handlers;
 }
 
 static int fuse_fill_super_submount(struct super_block *sb,
index 0d3e717..9fe571a 100644 (file)
@@ -203,27 +203,6 @@ static int fuse_xattr_set(const struct xattr_handler *handler,
        return fuse_setxattr(inode, name, value, size, flags, 0);
 }
 
-static bool no_xattr_list(struct dentry *dentry)
-{
-       return false;
-}
-
-static int no_xattr_get(const struct xattr_handler *handler,
-                       struct dentry *dentry, struct inode *inode,
-                       const char *name, void *value, size_t size)
-{
-       return -EOPNOTSUPP;
-}
-
-static int no_xattr_set(const struct xattr_handler *handler,
-                       struct user_namespace *mnt_userns,
-                       struct dentry *dentry, struct inode *nodee,
-                       const char *name, const void *value,
-                       size_t size, int flags)
-{
-       return -EOPNOTSUPP;
-}
-
 static const struct xattr_handler fuse_xattr_handler = {
        .prefix = "",
        .get    = fuse_xattr_get,
@@ -234,33 +213,3 @@ const struct xattr_handler *fuse_xattr_handlers[] = {
        &fuse_xattr_handler,
        NULL
 };
-
-const struct xattr_handler *fuse_acl_xattr_handlers[] = {
-       &posix_acl_access_xattr_handler,
-       &posix_acl_default_xattr_handler,
-       &fuse_xattr_handler,
-       NULL
-};
-
-static const struct xattr_handler fuse_no_acl_access_xattr_handler = {
-       .name  = XATTR_NAME_POSIX_ACL_ACCESS,
-       .flags = ACL_TYPE_ACCESS,
-       .list  = no_xattr_list,
-       .get   = no_xattr_get,
-       .set   = no_xattr_set,
-};
-
-static const struct xattr_handler fuse_no_acl_default_xattr_handler = {
-       .name  = XATTR_NAME_POSIX_ACL_DEFAULT,
-       .flags = ACL_TYPE_ACCESS,
-       .list  = no_xattr_list,
-       .get   = no_xattr_get,
-       .set   = no_xattr_set,
-};
-
-const struct xattr_handler *fuse_no_acl_xattr_handlers[] = {
-       &fuse_no_acl_access_xattr_handler,
-       &fuse_no_acl_default_xattr_handler,
-       &fuse_xattr_handler,
-       NULL
-};
index 7236393..61323de 100644 (file)
@@ -80,6 +80,15 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
        brelse(bd->bd_bh);
 }
 
+static int __gfs2_writepage(struct page *page, struct writeback_control *wbc,
+                      void *data)
+{
+       struct address_space *mapping = data;
+       int ret = mapping->a_ops->writepage(page, wbc);
+       mapping_set_error(mapping, ret);
+       return ret;
+}
+
 /**
  * gfs2_ail1_start_one - Start I/O on a transaction
  * @sdp: The superblock
@@ -131,7 +140,7 @@ __acquires(&sdp->sd_ail_lock)
                if (!mapping)
                        continue;
                spin_unlock(&sdp->sd_ail_lock);
-               ret = filemap_fdatawrite_wbc(mapping, wbc);
+               ret = write_cache_pages(mapping, wbc, __gfs2_writepage, mapping);
                if (need_resched()) {
                        blk_finish_plug(plug);
                        cond_resched();
index 2a39ffb..6e61b5b 100644 (file)
@@ -322,7 +322,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
        dn_off = le32_to_cpu(authblob->DomainName.BufferOffset);
        dn_len = le16_to_cpu(authblob->DomainName.Length);
 
-       if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len)
+       if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len ||
+           nt_len < CIFS_ENCPWD_SIZE)
                return -EINVAL;
 
        /* TODO : use domain name that imported from configuration file */
index 12be838..56be077 100644 (file)
@@ -280,7 +280,7 @@ int ksmbd_conn_handler_loop(void *p)
 {
        struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
        struct ksmbd_transport *t = conn->transport;
-       unsigned int pdu_size;
+       unsigned int pdu_size, max_allowed_pdu_size;
        char hdr_buf[4] = {0,};
        int size;
 
@@ -305,20 +305,36 @@ int ksmbd_conn_handler_loop(void *p)
                pdu_size = get_rfc1002_len(hdr_buf);
                ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
 
+               if (conn->status == KSMBD_SESS_GOOD)
+                       max_allowed_pdu_size =
+                               SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
+               else
+                       max_allowed_pdu_size = SMB3_MAX_MSGSIZE;
+
+               if (pdu_size > max_allowed_pdu_size) {
+                       pr_err_ratelimited("PDU length(%u) excceed maximum allowed pdu size(%u) on connection(%d)\n",
+                                       pdu_size, max_allowed_pdu_size,
+                                       conn->status);
+                       break;
+               }
+
                /*
                 * Check if pdu size is valid (min : smb header size,
                 * max : 0x00FFFFFF).
                 */
                if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE ||
                    pdu_size > MAX_STREAM_PROT_LEN) {
-                       continue;
+                       break;
                }
 
                /* 4 for rfc1002 length field */
                size = pdu_size + 4;
-               conn->request_buf = kvmalloc(size, GFP_KERNEL);
+               conn->request_buf = kvmalloc(size,
+                                            GFP_KERNEL |
+                                            __GFP_NOWARN |
+                                            __GFP_NORETRY);
                if (!conn->request_buf)
-                       continue;
+                       break;
 
                memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
                if (!ksmbd_smb_request(conn))
index b6bd831..fb8b2d5 100644 (file)
@@ -106,7 +106,8 @@ struct ksmbd_startup_request {
        __u32   sub_auth[3];            /* Subauth value for Security ID */
        __u32   smb2_max_credits;       /* MAX credits */
        __u32   smbd_max_io_size;       /* smbd read write size */
-       __u32   reserved[127];          /* Reserved room */
+       __u32   max_connections;        /* Number of maximum simultaneous connections */
+       __u32   reserved[126];          /* Reserved room */
        __u32   ifc_list_sz;            /* interfaces list size */
        __s8    ____payload[];
 };
index 0ae8d08..4d9e0b5 100644 (file)
@@ -242,7 +242,7 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
                return ret;
 
        if (da->version != 3 && da->version != 4) {
-               pr_err("v%d version is not supported\n", da->version);
+               ksmbd_debug(VFS, "v%d version is not supported\n", da->version);
                return -EINVAL;
        }
 
@@ -251,7 +251,7 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
                return ret;
 
        if (da->version != version2) {
-               pr_err("ndr version mismatched(version: %d, version2: %d)\n",
+               ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n",
                       da->version, version2);
                return -EINVAL;
        }
@@ -457,7 +457,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
        if (ret)
                return ret;
        if (acl->version != 4) {
-               pr_err("v%d version is not supported\n", acl->version);
+               ksmbd_debug(VFS, "v%d version is not supported\n", acl->version);
                return -EINVAL;
        }
 
@@ -465,7 +465,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
        if (ret)
                return ret;
        if (acl->version != version2) {
-               pr_err("ndr version mismatched(version: %d, version2: %d)\n",
+               ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n",
                       acl->version, version2);
                return -EINVAL;
        }
index ac9d932..db72781 100644 (file)
@@ -41,6 +41,7 @@ struct ksmbd_server_config {
        unsigned int            share_fake_fscaps;
        struct smb_sid          domain_sid;
        unsigned int            auth_mechs;
+       unsigned int            max_connections;
 
        char                    *conf[SERVER_CONF_WORK_GROUP + 1];
 };
index 14d7f35..d681f91 100644 (file)
@@ -1928,13 +1928,13 @@ int smb2_tree_connect(struct ksmbd_work *work)
        if (conn->posix_ext_supported)
                status.tree_conn->posix_extensions = true;
 
-out_err1:
        rsp->StructureSize = cpu_to_le16(16);
+       inc_rfc1001_len(work->response_buf, 16);
+out_err1:
        rsp->Capabilities = 0;
        rsp->Reserved = 0;
        /* default manual caching */
        rsp->ShareFlags = SMB2_SHAREFLAG_MANUAL_CACHING;
-       inc_rfc1001_len(work->response_buf, 16);
 
        if (!IS_ERR(treename))
                kfree(treename);
@@ -1967,6 +1967,9 @@ out_err1:
                rsp->hdr.Status = STATUS_ACCESS_DENIED;
        }
 
+       if (status.ret != KSMBD_TREE_CONN_STATUS_OK)
+               smb2_set_err_rsp(work);
+
        return rc;
 }
 
@@ -8660,6 +8663,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
 bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
 {
        struct ksmbd_conn *conn = work->conn;
+       struct ksmbd_session *sess = work->sess;
        struct smb2_hdr *rsp = smb2_get_msg(work->response_buf);
 
        if (conn->dialect < SMB30_PROT_ID)
@@ -8669,6 +8673,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
                rsp = ksmbd_resp_buf_next(work);
 
        if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE &&
+           sess->user && !user_guest(sess->user) &&
            rsp->Status == STATUS_SUCCESS)
                return true;
        return false;
index aa5dbe5..0c8a770 100644 (file)
@@ -24,8 +24,9 @@
 
 #define SMB21_DEFAULT_IOSIZE   (1024 * 1024)
 #define SMB3_DEFAULT_TRANS_SIZE        (1024 * 1024)
-#define SMB3_MIN_IOSIZE        (64 * 1024)
-#define SMB3_MAX_IOSIZE        (8 * 1024 * 1024)
+#define SMB3_MIN_IOSIZE                (64 * 1024)
+#define SMB3_MAX_IOSIZE                (8 * 1024 * 1024)
+#define SMB3_MAX_MSGSIZE       (4 * 4096)
 
 /*
  *     Definitions for SMB2 Protocol Data Units (network frames)
index c9aca21..40c721f 100644 (file)
@@ -308,6 +308,9 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
        if (req->smbd_max_io_size)
                init_smbd_max_io_size(req->smbd_max_io_size);
 
+       if (req->max_connections)
+               server_conf.max_connections = req->max_connections;
+
        ret = ksmbd_set_netbios_name(req->netbios_name);
        ret |= ksmbd_set_server_string(req->server_string);
        ret |= ksmbd_set_work_group(req->work_group);
index 63d55f5..603893f 100644 (file)
@@ -15,6 +15,8 @@
 #define IFACE_STATE_DOWN               BIT(0)
 #define IFACE_STATE_CONFIGURED         BIT(1)
 
+static atomic_t active_num_conn;
+
 struct interface {
        struct task_struct      *ksmbd_kthread;
        struct socket           *ksmbd_socket;
@@ -185,8 +187,10 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk)
        struct tcp_transport *t;
 
        t = alloc_transport(client_sk);
-       if (!t)
+       if (!t) {
+               sock_release(client_sk);
                return -ENOMEM;
+       }
 
        csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn);
        if (kernel_getpeername(client_sk, csin) < 0) {
@@ -239,6 +243,15 @@ static int ksmbd_kthread_fn(void *p)
                        continue;
                }
 
+               if (server_conf.max_connections &&
+                   atomic_inc_return(&active_num_conn) >= server_conf.max_connections) {
+                       pr_info_ratelimited("Limit the maximum number of connections(%u)\n",
+                                           atomic_read(&active_num_conn));
+                       atomic_dec(&active_num_conn);
+                       sock_release(client_sk);
+                       continue;
+               }
+
                ksmbd_debug(CONN, "connect success: accepted new connection\n");
                client_sk->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT;
                client_sk->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT;
@@ -295,6 +308,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
        struct msghdr ksmbd_msg;
        struct kvec *iov;
        struct ksmbd_conn *conn = KSMBD_TRANS(t)->conn;
+       int max_retry = 2;
 
        iov = get_conn_iovec(t, nr_segs);
        if (!iov)
@@ -321,9 +335,11 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
                } else if (conn->status == KSMBD_SESS_NEED_RECONNECT) {
                        total_read = -EAGAIN;
                        break;
-               } else if (length == -ERESTARTSYS || length == -EAGAIN) {
+               } else if ((length == -ERESTARTSYS || length == -EAGAIN) &&
+                          max_retry) {
                        usleep_range(1000, 2000);
                        length = 0;
+                       max_retry--;
                        continue;
                } else if (length <= 0) {
                        total_read = -EAGAIN;
@@ -365,6 +381,8 @@ static int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov,
 static void ksmbd_tcp_disconnect(struct ksmbd_transport *t)
 {
        free_transport(TCP_TRANS(t));
+       if (server_conf.max_connections)
+               atomic_dec(&active_num_conn);
 }
 
 static void tcp_destroy_socket(struct socket *ksmbd_socket)
index 45b2c9e..c0950ed 100644 (file)
@@ -661,6 +661,39 @@ static struct shrinker     nfsd_file_shrinker = {
        .seeks = 1,
 };
 
+/**
+ * nfsd_file_cond_queue - conditionally unhash and queue a nfsd_file
+ * @nf: nfsd_file to attempt to queue
+ * @dispose: private list to queue successfully-put objects
+ *
+ * Unhash an nfsd_file, try to get a reference to it, and then put that
+ * reference. If it's the last reference, queue it to the dispose list.
+ */
+static void
+nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose)
+       __must_hold(RCU)
+{
+       int decrement = 1;
+
+       /* If we raced with someone else unhashing, ignore it */
+       if (!nfsd_file_unhash(nf))
+               return;
+
+       /* If we can't get a reference, ignore it */
+       if (!nfsd_file_get(nf))
+               return;
+
+       /* Extra decrement if we remove from the LRU */
+       if (nfsd_file_lru_remove(nf))
+               ++decrement;
+
+       /* If refcount goes to 0, then put on the dispose list */
+       if (refcount_sub_and_test(decrement, &nf->nf_ref)) {
+               list_add(&nf->nf_lru, dispose);
+               trace_nfsd_file_closing(nf);
+       }
+}
+
 /**
  * nfsd_file_queue_for_close: try to close out any open nfsd_files for an inode
  * @inode:   inode on which to close out nfsd_files
@@ -688,30 +721,11 @@ nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)
 
        rcu_read_lock();
        do {
-               int decrement = 1;
-
                nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,
                                       nfsd_file_rhash_params);
                if (!nf)
                        break;
-
-               /* If we raced with someone else unhashing, ignore it */
-               if (!nfsd_file_unhash(nf))
-                       continue;
-
-               /* If we can't get a reference, ignore it */
-               if (!nfsd_file_get(nf))
-                       continue;
-
-               /* Extra decrement if we remove from the LRU */
-               if (nfsd_file_lru_remove(nf))
-                       ++decrement;
-
-               /* If refcount goes to 0, then put on the dispose list */
-               if (refcount_sub_and_test(decrement, &nf->nf_ref)) {
-                       list_add(&nf->nf_lru, dispose);
-                       trace_nfsd_file_closing(nf);
-               }
+               nfsd_file_cond_queue(nf, dispose);
        } while (1);
        rcu_read_unlock();
 }
@@ -928,11 +942,8 @@ __nfsd_file_cache_purge(struct net *net)
 
                nf = rhashtable_walk_next(&iter);
                while (!IS_ERR_OR_NULL(nf)) {
-                       if (!net || nf->nf_net == net) {
-                               nfsd_file_unhash(nf);
-                               nfsd_file_lru_remove(nf);
-                               list_add(&nf->nf_lru, &dispose);
-                       }
+                       if (!net || nf->nf_net == net)
+                               nfsd_file_cond_queue(nf, &dispose);
                        nf = rhashtable_walk_next(&iter);
                }
 
@@ -1071,8 +1082,8 @@ nfsd_file_is_cached(struct inode *inode)
 
 static __be32
 nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                    unsigned int may_flags, struct nfsd_file **pnf,
-                    bool open, bool want_gc)
+                    unsigned int may_flags, struct file *file,
+                    struct nfsd_file **pnf, bool want_gc)
 {
        struct nfsd_file_lookup_key key = {
                .type   = NFSD_FILE_KEY_FULL,
@@ -1147,8 +1158,7 @@ wait_for_construction:
        status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
 out:
        if (status == nfs_ok) {
-               if (open)
-                       this_cpu_inc(nfsd_file_acquisitions);
+               this_cpu_inc(nfsd_file_acquisitions);
                *pnf = nf;
        } else {
                if (refcount_dec_and_test(&nf->nf_ref))
@@ -1158,20 +1168,23 @@ out:
 
 out_status:
        put_cred(key.cred);
-       if (open)
-               trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
+       trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
        return status;
 
 open_file:
        trace_nfsd_file_alloc(nf);
        nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode);
        if (nf->nf_mark) {
-               if (open) {
+               if (file) {
+                       get_file(file);
+                       nf->nf_file = file;
+                       status = nfs_ok;
+                       trace_nfsd_file_opened(nf, status);
+               } else {
                        status = nfsd_open_verified(rqstp, fhp, may_flags,
                                                    &nf->nf_file);
                        trace_nfsd_file_open(nf, status);
-               } else
-                       status = nfs_ok;
+               }
        } else
                status = nfserr_jukebox;
        /*
@@ -1207,7 +1220,7 @@ __be32
 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
                     unsigned int may_flags, struct nfsd_file **pnf)
 {
-       return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, true);
+       return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true);
 }
 
 /**
@@ -1228,28 +1241,30 @@ __be32
 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
                  unsigned int may_flags, struct nfsd_file **pnf)
 {
-       return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, false);
+       return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false);
 }
 
 /**
- * nfsd_file_create - Get a struct nfsd_file, do not open
+ * nfsd_file_acquire_opened - Get a struct nfsd_file using existing open file
  * @rqstp: the RPC transaction being executed
  * @fhp: the NFS filehandle of the file just created
  * @may_flags: NFSD_MAY_ settings for the file
+ * @file: cached, already-open file (may be NULL)
  * @pnf: OUT: new or found "struct nfsd_file" object
  *
- * The nfsd_file_object returned by this API is reference-counted
- * but not garbage-collected. The object is released immediately
- * one RCU grace period after the final nfsd_file_put().
+ * Acquire a nfsd_file object that is not GC'ed. If one doesn't already exist,
+ * and @file is non-NULL, use it to instantiate a new nfsd_file instead of
+ * opening a new one.
  *
  * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in
  * network byte order is returned.
  */
 __be32
-nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                unsigned int may_flags, struct nfsd_file **pnf)
+nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                        unsigned int may_flags, struct file *file,
+                        struct nfsd_file **pnf)
 {
-       return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false, false);
+       return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false);
 }
 
 /*
index b7efb2c..41516a4 100644 (file)
@@ -60,7 +60,8 @@ __be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
                  unsigned int may_flags, struct nfsd_file **nfp);
 __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
                  unsigned int may_flags, struct nfsd_file **nfp);
-__be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
-                 unsigned int may_flags, struct nfsd_file **nfp);
+__be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                 unsigned int may_flags, struct file *file,
+                 struct nfsd_file **nfp);
 int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
 #endif /* _FS_NFSD_FILECACHE_H */
index 8c854ba..51a4b78 100644 (file)
@@ -195,7 +195,7 @@ struct nfsd_net {
 
        atomic_t                nfsd_courtesy_clients;
        struct shrinker         nfsd_client_shrinker;
-       struct delayed_work     nfsd_shrinker_work;
+       struct work_struct      nfsd_shrinker_work;
 };
 
 /* Simple check to find out if a given net was properly initialized */
index bd880d5..f189ba7 100644 (file)
@@ -937,7 +937,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
         * the client wants us to do more in this compound:
         */
        if (!nfsd4_last_compound_op(rqstp))
-               __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
+               clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
 
        /* check stateid */
        status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
@@ -1318,6 +1318,7 @@ try_again:
                        /* allow 20secs for mount/unmount for now - revisit */
                        if (signal_pending(current) ||
                                        (schedule_timeout(20*HZ) == 0)) {
+                               finish_wait(&nn->nfsd_ssc_waitq, &wait);
                                kfree(work);
                                return nfserr_eagain;
                        }
@@ -2607,12 +2608,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
        cstate->minorversion = args->minorversion;
        fh_init(current_fh, NFS4_FHSIZE);
        fh_init(save_fh, NFS4_FHSIZE);
-
        /*
         * Don't use the deferral mechanism for NFSv4; compounds make it
         * too hard to avoid non-idempotency problems.
         */
-       __clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
+       clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
 
        /*
         * According to RFC3010, this takes precedence over all other errors.
@@ -2734,7 +2734,7 @@ encode_op:
 out:
        cstate->status = status;
        /* Reset deferral mechanism for RPC deferrals */
-       __set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
+       set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
        return rpc_success;
 }
 
index 7b2ee53..4ef5293 100644 (file)
@@ -4411,7 +4411,7 @@ nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
        if (!count)
                count = atomic_long_read(&num_delegations);
        if (count)
-               mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0);
+               queue_work(laundry_wq, &nn->nfsd_shrinker_work);
        return (unsigned long)count;
 }
 
@@ -4421,7 +4421,7 @@ nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
        return SHRINK_STOP;
 }
 
-int
+void
 nfsd4_init_leases_net(struct nfsd_net *nn)
 {
        struct sysinfo si;
@@ -4443,16 +4443,6 @@ nfsd4_init_leases_net(struct nfsd_net *nn)
        nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
 
        atomic_set(&nn->nfsd_courtesy_clients, 0);
-       nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
-       nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
-       nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
-       return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client");
-}
-
-void
-nfsd4_leases_net_shutdown(struct nfsd_net *nn)
-{
-       unregister_shrinker(&nn->nfsd_client_shrinker);
 }
 
 static void init_nfs4_replay(struct nfs4_replay *rp)
@@ -5262,18 +5252,10 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
        if (!fp->fi_fds[oflag]) {
                spin_unlock(&fp->fi_lock);
 
-               if (!open->op_filp) {
-                       status = nfsd_file_acquire(rqstp, cur_fh, access, &nf);
-                       if (status != nfs_ok)
-                               goto out_put_access;
-               } else {
-                       status = nfsd_file_create(rqstp, cur_fh, access, &nf);
-                       if (status != nfs_ok)
-                               goto out_put_access;
-                       nf->nf_file = open->op_filp;
-                       open->op_filp = NULL;
-                       trace_nfsd_file_create(rqstp, access, nf);
-               }
+               status = nfsd_file_acquire_opened(rqstp, cur_fh, access,
+                                                 open->op_filp, &nf);
+               if (status != nfs_ok)
+                       goto out_put_access;
 
                spin_lock(&fp->fi_lock);
                if (!fp->fi_fds[oflag]) {
@@ -6243,8 +6225,7 @@ deleg_reaper(struct nfsd_net *nn)
 static void
 nfsd4_state_shrinker_worker(struct work_struct *work)
 {
-       struct delayed_work *dwork = to_delayed_work(work);
-       struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
+       struct nfsd_net *nn = container_of(work, struct nfsd_net,
                                nfsd_shrinker_work);
 
        courtesy_client_reaper(nn);
@@ -8074,11 +8055,20 @@ static int nfs4_state_create_net(struct net *net)
        INIT_LIST_HEAD(&nn->blocked_locks_lru);
 
        INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
-       INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
+       INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
        get_net(net);
 
+       nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
+       nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
+       nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
+
+       if (register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client"))
+               goto err_shrinker;
        return 0;
 
+err_shrinker:
+       put_net(net);
+       kfree(nn->sessionid_hashtbl);
 err_sessionid:
        kfree(nn->unconf_id_hashtbl);
 err_unconf_id:
@@ -8171,6 +8161,8 @@ nfs4_state_shutdown_net(struct net *net)
        struct list_head *pos, *next, reaplist;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
+       unregister_shrinker(&nn->nfsd_client_shrinker);
+       cancel_work(&nn->nfsd_shrinker_work);
        cancel_delayed_work_sync(&nn->laundromat_work);
        locks_end_grace(&nn->nfsd4_manager);
 
index ebb4d02..97edb32 100644 (file)
@@ -2523,7 +2523,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
        argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
 
        if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack)
-               __clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
+               clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
 
        return true;
 }
index d1e581a..c2577ee 100644 (file)
@@ -1457,9 +1457,7 @@ static __net_init int nfsd_init_net(struct net *net)
                goto out_idmap_error;
        nn->nfsd_versions = NULL;
        nn->nfsd4_minorversions = NULL;
-       retval = nfsd4_init_leases_net(nn);
-       if (retval)
-               goto out_drc_error;
+       nfsd4_init_leases_net(nn);
        retval = nfsd_reply_cache_init(nn);
        if (retval)
                goto out_cache_error;
@@ -1469,8 +1467,6 @@ static __net_init int nfsd_init_net(struct net *net)
        return 0;
 
 out_cache_error:
-       nfsd4_leases_net_shutdown(nn);
-out_drc_error:
        nfsd_idmap_shutdown(net);
 out_idmap_error:
        nfsd_export_shutdown(net);
@@ -1486,7 +1482,6 @@ static __net_exit void nfsd_exit_net(struct net *net)
        nfsd_idmap_shutdown(net);
        nfsd_export_shutdown(net);
        nfsd_netns_free_versions(net_generic(net, nfsd_net_id));
-       nfsd4_leases_net_shutdown(nn);
 }
 
 static struct pernet_operations nfsd_net_ops = {
index 93b42ef..fa0144a 100644 (file)
@@ -504,8 +504,7 @@ extern void unregister_cld_notifier(void);
 extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
 #endif
 
-extern int nfsd4_init_leases_net(struct nfsd_net *nn);
-extern void nfsd4_leases_net_shutdown(struct nfsd_net *nn);
+extern void nfsd4_init_leases_net(struct nfsd_net *nn);
 
 #else /* CONFIG_NFSD_V4 */
 static inline int nfsd4_is_junction(struct dentry *dentry)
@@ -513,8 +512,7 @@ static inline int nfsd4_is_junction(struct dentry *dentry)
        return 0;
 }
 
-static inline int nfsd4_init_leases_net(struct nfsd_net *nn) { return 0; };
-static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) {};
+static inline void nfsd4_init_leases_net(struct nfsd_net *nn) { };
 
 #define register_cld_notifier() 0
 #define unregister_cld_notifier() do { } while(0)
index a5570cf..9744443 100644 (file)
@@ -211,7 +211,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
        if (resp->status == nfs_ok)
                resp->status = fh_getattr(&resp->fh, &resp->stat);
        else if (resp->status == nfserr_jukebox)
-               __set_bit(RQ_DROPME, &rqstp->rq_flags);
+               set_bit(RQ_DROPME, &rqstp->rq_flags);
        return rpc_success;
 }
 
@@ -246,7 +246,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)
        if (resp->status == nfs_ok)
                resp->status = fh_getattr(&resp->fh, &resp->stat);
        else if (resp->status == nfserr_jukebox)
-               __set_bit(RQ_DROPME, &rqstp->rq_flags);
+               set_bit(RQ_DROPME, &rqstp->rq_flags);
        return rpc_success;
 }
 
index c852ae8..8f9c82d 100644 (file)
@@ -981,43 +981,6 @@ TRACE_EVENT(nfsd_file_acquire,
        )
 );
 
-TRACE_EVENT(nfsd_file_create,
-       TP_PROTO(
-               const struct svc_rqst *rqstp,
-               unsigned int may_flags,
-               const struct nfsd_file *nf
-       ),
-
-       TP_ARGS(rqstp, may_flags, nf),
-
-       TP_STRUCT__entry(
-               __field(const void *, nf_inode)
-               __field(const void *, nf_file)
-               __field(unsigned long, may_flags)
-               __field(unsigned long, nf_flags)
-               __field(unsigned long, nf_may)
-               __field(unsigned int, nf_ref)
-               __field(u32, xid)
-       ),
-
-       TP_fast_assign(
-               __entry->nf_inode = nf->nf_inode;
-               __entry->nf_file = nf->nf_file;
-               __entry->may_flags = may_flags;
-               __entry->nf_flags = nf->nf_flags;
-               __entry->nf_may = nf->nf_may;
-               __entry->nf_ref = refcount_read(&nf->nf_ref);
-               __entry->xid = be32_to_cpu(rqstp->rq_xid);
-       ),
-
-       TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p",
-               __entry->xid, __entry->nf_inode,
-               show_nfsd_may_flags(__entry->may_flags),
-               __entry->nf_ref, show_nf_flags(__entry->nf_flags),
-               show_nfsd_may_flags(__entry->nf_may), __entry->nf_file
-       )
-);
-
 TRACE_EVENT(nfsd_file_insert_err,
        TP_PROTO(
                const struct svc_rqst *rqstp,
@@ -1079,8 +1042,8 @@ TRACE_EVENT(nfsd_file_cons_err,
        )
 );
 
-TRACE_EVENT(nfsd_file_open,
-       TP_PROTO(struct nfsd_file *nf, __be32 status),
+DECLARE_EVENT_CLASS(nfsd_file_open_class,
+       TP_PROTO(const struct nfsd_file *nf, __be32 status),
        TP_ARGS(nf, status),
        TP_STRUCT__entry(
                __field(void *, nf_inode)       /* cannot be dereferenced */
@@ -1104,6 +1067,17 @@ TRACE_EVENT(nfsd_file_open,
                __entry->nf_file)
 )
 
+#define DEFINE_NFSD_FILE_OPEN_EVENT(name)                                      \
+DEFINE_EVENT(nfsd_file_open_class, name,                                       \
+       TP_PROTO(                                                       \
+               const struct nfsd_file *nf,                             \
+               __be32 status                                           \
+       ),                                                              \
+       TP_ARGS(nf, status))
+
+DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_open);
+DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_opened);
+
 TRACE_EVENT(nfsd_file_is_cached,
        TP_PROTO(
                const struct inode *inode,
index b9d15c3..40ce92a 100644 (file)
@@ -480,9 +480,18 @@ static int __nilfs_btree_get_block(const struct nilfs_bmap *btree, __u64 ptr,
        ret = nilfs_btnode_submit_block(btnc, ptr, 0, REQ_OP_READ, &bh,
                                        &submit_ptr);
        if (ret) {
-               if (ret != -EEXIST)
-                       return ret;
-               goto out_check;
+               if (likely(ret == -EEXIST))
+                       goto out_check;
+               if (ret == -ENOENT) {
+                       /*
+                        * Block address translation failed due to invalid
+                        * value of 'ptr'.  In this case, return internal code
+                        * -EINVAL (broken bmap) to notify bmap layer of fatal
+                        * metadata corruption.
+                        */
+                       ret = -EINVAL;
+               }
+               return ret;
        }
 
        if (ra) {
index 6e4e65e..c14e907 100644 (file)
@@ -792,7 +792,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
        if (!c->metacopy && c->stat.size) {
                err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
                if (err)
-                       return err;
+                       goto out_fput;
        }
 
        err = ovl_copy_up_metadata(c, temp);
@@ -1011,6 +1011,10 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
        if (err)
                return err;
 
+       if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
+           !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
+               return -EOVERFLOW;
+
        ctx.metacopy = ovl_need_meta_copy_up(dentry, ctx.stat.mode, flags);
 
        if (parent) {
index e35a039..af1c49a 100644 (file)
@@ -745,9 +745,7 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
                        page = pfn_swap_entry_to_page(swpent);
        }
        if (page) {
-               int mapcount = page_mapcount(page);
-
-               if (mapcount >= 2)
+               if (page_mapcount(page) >= 2 || hugetlb_pmd_shared(pte))
                        mss->shared_hugetlb += huge_page_size(hstate_vma(vma));
                else
                        mss->private_hugetlb += huge_page_size(hstate_vma(vma));
index b3fdc82..95f8e89 100644 (file)
@@ -183,7 +183,7 @@ static inline int squashfs_block_size(__le32 raw)
 #define SQUASHFS_ID_BLOCK_BYTES(A)     (SQUASHFS_ID_BLOCKS(A) *\
                                        sizeof(u64))
 /* xattr id lookup table defines */
-#define SQUASHFS_XATTR_BYTES(A)                ((A) * sizeof(struct squashfs_xattr_id))
+#define SQUASHFS_XATTR_BYTES(A)                (((u64) (A)) * sizeof(struct squashfs_xattr_id))
 
 #define SQUASHFS_XATTR_BLOCK(A)                (SQUASHFS_XATTR_BYTES(A) / \
                                        SQUASHFS_METADATA_SIZE)
index 659082e..72f6f4b 100644 (file)
@@ -63,7 +63,7 @@ struct squashfs_sb_info {
        long long                               bytes_used;
        unsigned int                            inodes;
        unsigned int                            fragments;
-       int                                     xattr_ids;
+       unsigned int                            xattr_ids;
        unsigned int                            ids;
        bool                                    panic_on_errors;
        const struct squashfs_decompressor_thread_ops *thread_ops;
index d8a270d..f1a463d 100644 (file)
 
 #ifdef CONFIG_SQUASHFS_XATTR
 extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64,
-               u64 *, int *);
+               u64 *, unsigned int *);
 extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *,
                unsigned int *, unsigned long long *);
 #else
 static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
-               u64 start, u64 *xattr_table_start, int *xattr_ids)
+               u64 start, u64 *xattr_table_start, unsigned int *xattr_ids)
 {
        struct squashfs_xattr_id_table *id_table;
 
index 087cab8..b88d19e 100644 (file)
@@ -56,7 +56,7 @@ int squashfs_xattr_lookup(struct super_block *sb, unsigned int index,
  * Read uncompressed xattr id lookup table indexes from disk into memory
  */
 __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 table_start,
-               u64 *xattr_table_start, int *xattr_ids)
+               u64 *xattr_table_start, unsigned int *xattr_ids)
 {
        struct squashfs_sb_info *msblk = sb->s_fs_info;
        unsigned int len, indexes;
@@ -76,7 +76,7 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 table_start,
        /* Sanity check values */
 
        /* there is always at least one xattr id */
-       if (*xattr_ids == 0)
+       if (*xattr_ids <= 0)
                return ERR_PTR(-EINVAL);
 
        len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
index 98ac37e..cc69484 100644 (file)
@@ -108,6 +108,21 @@ static bool userfaultfd_is_initialized(struct userfaultfd_ctx *ctx)
        return ctx->features & UFFD_FEATURE_INITIALIZED;
 }
 
+static void userfaultfd_set_vm_flags(struct vm_area_struct *vma,
+                                    vm_flags_t flags)
+{
+       const bool uffd_wp_changed = (vma->vm_flags ^ flags) & VM_UFFD_WP;
+
+       vma->vm_flags = flags;
+       /*
+        * For shared mappings, we want to enable writenotify while
+        * userfaultfd-wp is enabled (see vma_wants_writenotify()). We'll simply
+        * recalculate vma->vm_page_prot whenever userfaultfd-wp changes.
+        */
+       if ((vma->vm_flags & VM_SHARED) && uffd_wp_changed)
+               vma_set_page_prot(vma);
+}
+
 static int userfaultfd_wake_function(wait_queue_entry_t *wq, unsigned mode,
                                     int wake_flags, void *key)
 {
@@ -618,7 +633,8 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
                for_each_vma(vmi, vma) {
                        if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) {
                                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
-                               vma->vm_flags &= ~__VM_UFFD_FLAGS;
+                               userfaultfd_set_vm_flags(vma,
+                                                        vma->vm_flags & ~__VM_UFFD_FLAGS);
                        }
                }
                mmap_write_unlock(mm);
@@ -652,7 +668,7 @@ int dup_userfaultfd(struct vm_area_struct *vma, struct list_head *fcs)
        octx = vma->vm_userfaultfd_ctx.ctx;
        if (!octx || !(octx->features & UFFD_FEATURE_EVENT_FORK)) {
                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
-               vma->vm_flags &= ~__VM_UFFD_FLAGS;
+               userfaultfd_set_vm_flags(vma, vma->vm_flags & ~__VM_UFFD_FLAGS);
                return 0;
        }
 
@@ -733,7 +749,7 @@ void mremap_userfaultfd_prep(struct vm_area_struct *vma,
        } else {
                /* Drop uffd context if remap feature not enabled */
                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
-               vma->vm_flags &= ~__VM_UFFD_FLAGS;
+               userfaultfd_set_vm_flags(vma, vma->vm_flags & ~__VM_UFFD_FLAGS);
        }
 }
 
@@ -895,7 +911,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
                        prev = vma;
                }
 
-               vma->vm_flags = new_flags;
+               userfaultfd_set_vm_flags(vma, new_flags);
                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
        }
        mmap_write_unlock(mm);
@@ -1463,7 +1479,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                 * the next vma was merged into the current one and
                 * the current one has not been updated yet.
                 */
-               vma->vm_flags = new_flags;
+               userfaultfd_set_vm_flags(vma, new_flags);
                vma->vm_userfaultfd_ctx.ctx = ctx;
 
                if (is_vm_hugetlb_page(vma) && uffd_disable_huge_pmd_share(vma))
@@ -1651,7 +1667,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
                 * the next vma was merged into the current one and
                 * the current one has not been updated yet.
                 */
-               vma->vm_flags = new_flags;
+               userfaultfd_set_vm_flags(vma, new_flags);
                vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
 
        skip:
index 4c16c8c..35f5744 100644 (file)
@@ -4666,7 +4666,12 @@ xfs_btree_space_to_height(
        const unsigned int      *limits,
        unsigned long long      leaf_blocks)
 {
-       unsigned long long      node_blocks = limits[1];
+       /*
+        * The root btree block can have fewer than minrecs pointers in it
+        * because the tree might not be big enough to require that amount of
+        * fanout. Hence it has a minimum size of 2 pointers, not limits[1].
+        */
+       unsigned long long      node_blocks = 2;
        unsigned long long      blocks_left = leaf_blocks - 1;
        unsigned int            height = 1;
 
index ad22a00..f3d328e 100644 (file)
@@ -236,6 +236,7 @@ xfs_extent_busy_update_extent(
                 *
                 */
                busyp->bno = fend;
+               busyp->length = bend - fend;
        } else if (bbno < fbno) {
                /*
                 * Case 8:
index f35e2ce..ddeaccc 100644 (file)
@@ -1853,12 +1853,20 @@ xfs_inodegc_worker(
                                                struct xfs_inodegc, work);
        struct llist_node       *node = llist_del_all(&gc->list);
        struct xfs_inode        *ip, *n;
+       unsigned int            nofs_flag;
 
        WRITE_ONCE(gc->items, 0);
 
        if (!node)
                return;
 
+       /*
+        * We can allocate memory here while doing writeback on behalf of
+        * memory reclaim.  To avoid memory allocation deadlocks set the
+        * task-wide nofs context for the following operations.
+        */
+       nofs_flag = memalloc_nofs_save();
+
        ip = llist_entry(node, struct xfs_inode, i_gclist);
        trace_xfs_inodegc_worker(ip->i_mount, READ_ONCE(gc->shrinker_hits));
 
@@ -1867,6 +1875,8 @@ xfs_inodegc_worker(
                xfs_iflags_set(ip, XFS_INACTIVATING);
                xfs_inodegc_inactivate(ip);
        }
+
+       memalloc_nofs_restore(nofs_flag);
 }
 
 /*
index 13f1b2a..736510b 100644 (file)
@@ -754,7 +754,7 @@ xfs_bulkstat_fmt(
 static int
 xfs_bulk_ireq_setup(
        struct xfs_mount        *mp,
-       struct xfs_bulk_ireq    *hdr,
+       const struct xfs_bulk_ireq *hdr,
        struct xfs_ibulk        *breq,
        void __user             *ubuffer)
 {
@@ -780,7 +780,7 @@ xfs_bulk_ireq_setup(
 
                switch (hdr->ino) {
                case XFS_BULK_IREQ_SPECIAL_ROOT:
-                       hdr->ino = mp->m_sb.sb_rootino;
+                       breq->startino = mp->m_sb.sb_rootino;
                        break;
                default:
                        return -EINVAL;
index 669c1bc..fc1946f 100644 (file)
@@ -83,7 +83,7 @@ xfs_iomap_valid(
        return true;
 }
 
-const struct iomap_page_ops xfs_iomap_page_ops = {
+static const struct iomap_page_ops xfs_iomap_page_ops = {
        .iomap_valid            = xfs_iomap_valid,
 };
 
index ff53d40..e2c542f 100644 (file)
@@ -68,7 +68,7 @@ restart:
 
        while (1) {
                struct xfs_dquot *batch[XFS_DQ_LOOKUP_BATCH];
-               int             error = 0;
+               int             error;
                int             i;
 
                mutex_lock(&qi->qi_tree_lock);
index fe46bce..5535778 100644 (file)
@@ -416,8 +416,6 @@ xfs_reflink_fill_cow_hole(
                goto convert;
        }
 
-       ASSERT(cmap->br_startoff > imap->br_startoff);
-
        /* Allocate the entire reservation as unwritten blocks. */
        nimaps = 1;
        error = xfs_bmapi_write(tp, ip, imap->br_startoff, imap->br_blockcount,
index 2c53fbb..a9c5c3f 100644 (file)
@@ -442,6 +442,10 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
                        data_size = zonefs_check_zone_condition(inode, zone,
                                                                false, false);
                }
+       } else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO &&
+                  data_size > isize) {
+               /* Do not expose garbage data */
+               data_size = isize;
        }
 
        /*
@@ -805,6 +809,24 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
 
        ret = submit_bio_wait(bio);
 
+       /*
+        * If the file zone was written underneath the file system, the zone
+        * write pointer may not be where we expect it to be, but the zone
+        * append write can still succeed. So check manually that we wrote where
+        * we intended to, that is, at zi->i_wpoffset.
+        */
+       if (!ret) {
+               sector_t wpsector =
+                       zi->i_zsector + (zi->i_wpoffset >> SECTOR_SHIFT);
+
+               if (bio->bi_iter.bi_sector != wpsector) {
+                       zonefs_warn(inode->i_sb,
+                               "Corrupted write pointer %llu for zone at %llu\n",
+                               wpsector, zi->i_zsector);
+                       ret = -EIO;
+               }
+       }
+
        zonefs_file_write_dio_end_io(iocb, size, ret, 0);
        trace_zonefs_file_dio_append(inode, size, ret);
 
index cd3b75e..e44be31 100644 (file)
@@ -230,7 +230,8 @@ struct acpi_pnp_type {
        u32 hardware_id:1;
        u32 bus_address:1;
        u32 platform_id:1;
-       u32 reserved:29;
+       u32 backlight:1;
+       u32 reserved:28;
 };
 
 struct acpi_device_pnp {
index c561444..6b487a5 100644 (file)
@@ -108,12 +108,14 @@ struct cppc_perf_caps {
        u32 lowest_nonlinear_perf;
        u32 lowest_freq;
        u32 nominal_freq;
+       u32 energy_perf;
 };
 
 struct cppc_perf_ctrls {
        u32 max_perf;
        u32 min_perf;
        u32 desired_perf;
+       u32 energy_perf;
 };
 
 struct cppc_perf_fb_ctrs {
@@ -149,6 +151,8 @@ extern bool cpc_ffh_supported(void);
 extern bool cpc_supported_by_cpu(void);
 extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
 extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
+extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
+extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
 #else /* !CONFIG_ACPI_CPPC_LIB */
 static inline int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
 {
@@ -202,6 +206,14 @@ static inline int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
 {
        return -ENOTSUPP;
 }
+static inline int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
+{
+       return -ENOTSUPP;
+}
+static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
+{
+       return -ENOTSUPP;
+}
 #endif /* !CONFIG_ACPI_CPPC_LIB */
 
 #endif /* _CPPC_ACPI_H*/
index 4fc8018..1220d18 100644 (file)
@@ -126,11 +126,6 @@ struct drm_client_buffer {
         */
        struct drm_client_dev *client;
 
-       /**
-        * @handle: Buffer handle
-        */
-       u32 handle;
-
        /**
         * @pitch: Buffer pitch
         */
index b111dc7..095370e 100644 (file)
@@ -208,6 +208,18 @@ struct drm_fb_helper {
         * the smem_start field should always be cleared to zero.
         */
        bool hint_leak_smem_start;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+       /**
+        * @fbdefio:
+        *
+        * Temporary storage for the driver's FB deferred I/O handler. If the
+        * driver uses the DRM fbdev emulation layer, this is set by the core
+        * to a generic deferred I/O handler if a driver is preferring to use
+        * a shadow buffer.
+        */
+       struct fb_deferred_io fbdefio;
+#endif
 };
 
 static inline struct drm_fb_helper *
index 4f8c352..6c2a2f2 100644 (file)
@@ -74,6 +74,7 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,
                           struct drm_vma_offset_node *node);
 
 int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag);
+int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag);
 void drm_vma_node_revoke(struct drm_vma_offset_node *node,
                         struct drm_file *tag);
 bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node,
index 87ea905..08d3559 100644 (file)
@@ -303,7 +303,6 @@ static inline int kunit_run_all_tests(void)
  */
 #define kunit_test_init_section_suites(__suites...)                    \
        __kunit_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe),    \
-                           CONCATENATE(__UNIQUE_ID(suites), _probe),   \
                            ##__suites)
 
 #define kunit_test_init_section_suite(suite)   \
@@ -683,8 +682,9 @@ do {                                                                               \
                .right_text = #right,                                          \
        };                                                                     \
                                                                               \
-       if (likely(memcmp(__left, __right, __size) op 0))                      \
-               break;                                                         \
+       if (likely(__left && __right))                                         \
+               if (likely(memcmp(__left, __right, __size) op 0))              \
+                       break;                                                 \
                                                                               \
        _KUNIT_FAILED(test,                                                    \
                      assert_type,                                             \
index 9270cd8..6470f67 100644 (file)
@@ -263,7 +263,7 @@ struct vgic_dist {
        struct vgic_io_device   dist_iodev;
 
        bool                    has_its;
-       bool                    save_its_tables_in_progress;
+       bool                    table_write_in_progress;
 
        /*
         * Contains the attributes and gpa of the LPI configuration table.
index 1c4b865..f5f2241 100644 (file)
 
 #include <linux/pm_qos.h>
 
+#define AMD_CPPC_EPP_PERFORMANCE               0x00
+#define AMD_CPPC_EPP_BALANCE_PERFORMANCE       0x80
+#define AMD_CPPC_EPP_BALANCE_POWERSAVE         0xBF
+#define AMD_CPPC_EPP_POWERSAVE                 0xFF
+
 /*********************************************************************
  *                        AMD P-state INTERFACE                       *
  *********************************************************************/
@@ -47,6 +52,10 @@ struct amd_aperf_mperf {
  * @prev: Last Aperf/Mperf/tsc count value read from register
  * @freq: current cpu frequency value
  * @boost_supported: check whether the Processor or SBIOS supports boost mode
+ * @epp_policy: Last saved policy used to set energy-performance preference
+ * @epp_cached: Cached CPPC energy-performance preference value
+ * @policy: Cpufreq policy value
+ * @cppc_cap1_cached Cached MSR_AMD_CPPC_CAP1 register value
  *
  * The amd_cpudata is key private data for each CPU thread in AMD P-State, and
  * represents all the attributes and goals that AMD P-State requests at runtime.
@@ -72,6 +81,29 @@ struct amd_cpudata {
 
        u64     freq;
        bool    boost_supported;
+
+       /* EPP feature related attributes*/
+       s16     epp_policy;
+       s16     epp_cached;
+       u32     policy;
+       u64     cppc_cap1_cached;
+       bool    suspended;
 };
 
+/*
+ * enum amd_pstate_mode - driver working mode of amd pstate
+ */
+enum amd_pstate_mode {
+       AMD_PSTATE_DISABLE = 0,
+       AMD_PSTATE_PASSIVE,
+       AMD_PSTATE_ACTIVE,
+       AMD_PSTATE_MAX,
+};
+
+static const char * const amd_pstate_mode_string[] = {
+       [AMD_PSTATE_DISABLE]     = "disable",
+       [AMD_PSTATE_PASSIVE]     = "passive",
+       [AMD_PSTATE_ACTIVE]      = "active",
+       NULL,
+};
 #endif /* _LINUX_AMD_PSTATE_H */
index ddb10aa..1f68b49 100644 (file)
 #define LINUX_APPLE_GMUX_H
 
 #include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/pnp.h>
 
 #define GMUX_ACPI_HID "APP000B"
 
+/*
+ * gmux port offsets. Many of these are not yet used, but may be in the
+ * future, and it's useful to have them documented here anyhow.
+ */
+#define GMUX_PORT_VERSION_MAJOR                0x04
+#define GMUX_PORT_VERSION_MINOR                0x05
+#define GMUX_PORT_VERSION_RELEASE      0x06
+#define GMUX_PORT_SWITCH_DISPLAY       0x10
+#define GMUX_PORT_SWITCH_GET_DISPLAY   0x11
+#define GMUX_PORT_INTERRUPT_ENABLE     0x14
+#define GMUX_PORT_INTERRUPT_STATUS     0x16
+#define GMUX_PORT_SWITCH_DDC           0x28
+#define GMUX_PORT_SWITCH_EXTERNAL      0x40
+#define GMUX_PORT_SWITCH_GET_EXTERNAL  0x41
+#define GMUX_PORT_DISCRETE_POWER       0x50
+#define GMUX_PORT_MAX_BRIGHTNESS       0x70
+#define GMUX_PORT_BRIGHTNESS           0x74
+#define GMUX_PORT_VALUE                        0xc2
+#define GMUX_PORT_READ                 0xd0
+#define GMUX_PORT_WRITE                        0xd4
+
+#define GMUX_MIN_IO_LEN                        (GMUX_PORT_BRIGHTNESS + 4)
+
 #if IS_ENABLED(CONFIG_APPLE_GMUX)
+static inline bool apple_gmux_is_indexed(unsigned long iostart)
+{
+       u16 val;
+
+       outb(0xaa, iostart + 0xcc);
+       outb(0x55, iostart + 0xcd);
+       outb(0x00, iostart + 0xce);
+
+       val = inb(iostart + 0xcc) | (inb(iostart + 0xcd) << 8);
+       if (val == 0x55aa)
+               return true;
+
+       return false;
+}
 
 /**
- * apple_gmux_present() - detect if gmux is built into the machine
+ * apple_gmux_detect() - detect if gmux is built into the machine
+ *
+ * @pnp_dev:     Device to probe or NULL to use the first matching device
+ * @indexed_ret: Returns (by reference) if the gmux is indexed or not
+ *
+ * Detect if a supported gmux device is present by actually probing it.
+ * This avoids the false positives returned on some models by
+ * apple_gmux_present().
+ *
+ * Return: %true if a supported gmux ACPI device is detected and the kernel
+ * was configured with CONFIG_APPLE_GMUX, %false otherwise.
+ */
+static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, bool *indexed_ret)
+{
+       u8 ver_major, ver_minor, ver_release;
+       struct device *dev = NULL;
+       struct acpi_device *adev;
+       struct resource *res;
+       bool indexed = false;
+       bool ret = false;
+
+       if (!pnp_dev) {
+               adev = acpi_dev_get_first_match_dev(GMUX_ACPI_HID, NULL, -1);
+               if (!adev)
+                       return false;
+
+               dev = get_device(acpi_get_first_physical_node(adev));
+               acpi_dev_put(adev);
+               if (!dev)
+                       return false;
+
+               pnp_dev = to_pnp_dev(dev);
+       }
+
+       res = pnp_get_resource(pnp_dev, IORESOURCE_IO, 0);
+       if (!res || resource_size(res) < GMUX_MIN_IO_LEN)
+               goto out;
+
+       /*
+        * Invalid version information may indicate either that the gmux
+        * device isn't present or that it's a new one that uses indexed io.
+        */
+       ver_major = inb(res->start + GMUX_PORT_VERSION_MAJOR);
+       ver_minor = inb(res->start + GMUX_PORT_VERSION_MINOR);
+       ver_release = inb(res->start + GMUX_PORT_VERSION_RELEASE);
+       if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
+               indexed = apple_gmux_is_indexed(res->start);
+               if (!indexed)
+                       goto out;
+       }
+
+       if (indexed_ret)
+               *indexed_ret = indexed;
+
+       ret = true;
+out:
+       put_device(dev);
+       return ret;
+}
+
+/**
+ * apple_gmux_present() - check if gmux ACPI device is present
  *
  * Drivers may use this to activate quirks specific to dual GPU MacBook Pros
  * and Mac Pros, e.g. for deferred probing, runtime pm and backlight.
  *
- * Return: %true if gmux is present and the kernel was configured
+ * Return: %true if gmux ACPI device is present and the kernel was configured
  * with CONFIG_APPLE_GMUX, %false otherwise.
  */
 static inline bool apple_gmux_present(void)
@@ -34,6 +134,11 @@ static inline bool apple_gmux_present(void)
        return false;
 }
 
+static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, bool *indexed_ret)
+{
+       return false;
+}
+
 #endif /* !CONFIG_APPLE_GMUX */
 
 #endif /* LINUX_APPLE_GMUX_H */
index 3de24cf..634d37a 100644 (file)
@@ -1832,7 +1832,7 @@ void bpf_prog_inc(struct bpf_prog *prog);
 struct bpf_prog * __must_check bpf_prog_inc_not_zero(struct bpf_prog *prog);
 void bpf_prog_put(struct bpf_prog *prog);
 
-void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock);
+void bpf_prog_free_id(struct bpf_prog *prog);
 void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock);
 
 struct btf_field *btf_record_find(const struct btf_record *rec,
index 00af2c9..4497d0a 100644 (file)
@@ -99,16 +99,6 @@ struct ceph_options {
 
 #define CEPH_AUTH_NAME_DEFAULT   "guest"
 
-/* mount state */
-enum {
-       CEPH_MOUNT_MOUNTING,
-       CEPH_MOUNT_MOUNTED,
-       CEPH_MOUNT_UNMOUNTING,
-       CEPH_MOUNT_UNMOUNTED,
-       CEPH_MOUNT_SHUTDOWN,
-       CEPH_MOUNT_RECOVER,
-};
-
 static inline unsigned long ceph_timeout_jiffies(unsigned long timeout)
 {
        return timeout ?: MAX_SCHEDULE_TIMEOUT;
index 6a94a6e..6562323 100644 (file)
@@ -448,7 +448,7 @@ struct cpufreq_driver {
 #define CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING      BIT(6)
 
 int cpufreq_register_driver(struct cpufreq_driver *driver_data);
-int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
+void cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
 
 bool cpufreq_driver_test_flags(u16 flags);
 const char *cpufreq_get_current_driver(void);
index 4b27519..98598bd 100644 (file)
@@ -668,7 +668,8 @@ extern struct efi {
 
 #define EFI_RT_SUPPORTED_ALL                                   0x3fff
 
-#define EFI_RT_SUPPORTED_TIME_SERVICES                         0x000f
+#define EFI_RT_SUPPORTED_TIME_SERVICES                         0x0003
+#define EFI_RT_SUPPORTED_WAKEUP_SERVICES                       0x000c
 #define EFI_RT_SUPPORTED_VARIABLE_SERVICES                     0x0070
 
 extern struct mm_struct efi_mm;
index 9ec8129..bd55605 100644 (file)
@@ -105,14 +105,14 @@ int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
  * Dumping its extra ELF program headers includes all the other information
  * a debugger needs to easily find how the gate DSO was being used.
  */
-extern Elf_Half elf_core_extra_phdrs(void);
+extern Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm);
 extern int
 elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset);
 extern int
 elf_core_write_extra_data(struct coredump_params *cprm);
-extern size_t elf_core_extra_data_size(void);
+extern size_t elf_core_extra_data_size(struct coredump_params *cprm);
 #else
-static inline Elf_Half elf_core_extra_phdrs(void)
+static inline Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
 {
        return 0;
 }
@@ -127,7 +127,7 @@ static inline int elf_core_write_extra_data(struct coredump_params *cprm)
        return 1;
 }
 
-static inline size_t elf_core_extra_data_size(void)
+static inline size_t elf_core_extra_data_size(struct coredump_params *cprm)
 {
        return 0;
 }
index b986e26..b09f443 100644 (file)
@@ -545,8 +545,8 @@ int zynqmp_pm_request_wake(const u32 node,
                           const u64 address,
                           const enum zynqmp_pm_request_ack ack);
 int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode);
-int zynqmp_pm_set_rpu_mode(u32 node_id, u32 arg1);
-int zynqmp_pm_set_tcm_config(u32 node_id, u32 arg1);
+int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode);
+int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode);
 int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value);
 int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config,
                             u32 value);
@@ -845,12 +845,12 @@ static inline int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mo
        return -ENODEV;
 }
 
-static inline int zynqmp_pm_set_rpu_mode(u32 node_id, u32 arg1)
+static inline int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode)
 {
        return -ENODEV;
 }
 
-static inline int zynqmp_pm_set_tcm_config(u32 node_id, u32 arg1)
+static inline int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode)
 {
        return -ENODEV;
 }
index 034b110..e098f38 100644 (file)
@@ -200,7 +200,7 @@ static inline void *kmap_local_pfn(unsigned long pfn)
 static inline void __kunmap_local(const void *addr)
 {
 #ifdef ARCH_HAS_FLUSH_ON_KUNMAP
-       kunmap_flush_on_unmap(addr);
+       kunmap_flush_on_unmap(PTR_ALIGN_DOWN(addr, PAGE_SIZE));
 #endif
 }
 
@@ -227,7 +227,7 @@ static inline void *kmap_atomic_pfn(unsigned long pfn)
 static inline void __kunmap_atomic(const void *addr)
 {
 #ifdef ARCH_HAS_FLUSH_ON_KUNMAP
-       kunmap_flush_on_unmap(addr);
+       kunmap_flush_on_unmap(PTR_ALIGN_DOWN(addr, PAGE_SIZE));
 #endif
        pagefault_enable();
        if (IS_ENABLED(CONFIG_PREEMPT_RT))
index 551834c..db194e2 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/fs.h>
 #include <linux/hugetlb_inline.h>
 #include <linux/cgroup.h>
+#include <linux/page_ref.h>
 #include <linux/list.h>
 #include <linux/kref.h>
 #include <linux/pgtable.h>
@@ -1187,6 +1188,18 @@ static inline __init void hugetlb_cma_reserve(int order)
 }
 #endif
 
+#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
+static inline bool hugetlb_pmd_shared(pte_t *pte)
+{
+       return page_count(virt_to_page(pte)) > 1;
+}
+#else
+static inline bool hugetlb_pmd_shared(pte_t *pte)
+{
+       return false;
+}
+#endif
+
 bool want_pmd_share(struct vm_area_struct *vma, unsigned long addr);
 
 #ifndef __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
index d3c8203..85dc9b8 100644 (file)
@@ -1666,10 +1666,13 @@ void mem_cgroup_track_foreign_dirty_slowpath(struct folio *folio,
 static inline void mem_cgroup_track_foreign_dirty(struct folio *folio,
                                                  struct bdi_writeback *wb)
 {
+       struct mem_cgroup *memcg;
+
        if (mem_cgroup_disabled())
                return;
 
-       if (unlikely(&folio_memcg(folio)->css != wb->memcg_css))
+       memcg = folio_memcg(folio);
+       if (unlikely(memcg && &memcg->css != wb->memcg_css))
                mem_cgroup_track_foreign_dirty_slowpath(folio, wb);
 }
 
index d476255..333c1fe 100644 (file)
@@ -315,7 +315,7 @@ struct mlx5_cmd {
        struct mlx5_cmd_debug dbg;
        struct cmd_msg_cache cache[MLX5_NUM_COMMAND_CACHES];
        int checksum_disabled;
-       struct mlx5_cmd_stats *stats;
+       struct mlx5_cmd_stats stats[MLX5_CMD_OP_MAX];
 };
 
 struct mlx5_cmd_mailbox {
@@ -573,6 +573,14 @@ struct mlx5_debugfs_entries {
        struct dentry *lag_debugfs;
 };
 
+enum mlx5_func_type {
+       MLX5_PF,
+       MLX5_VF,
+       MLX5_SF,
+       MLX5_HOST_PF,
+       MLX5_FUNC_TYPE_NUM,
+};
+
 struct mlx5_ft_pool;
 struct mlx5_priv {
        /* IRQ table valid only for real pci devices PF or VF */
@@ -583,11 +591,10 @@ struct mlx5_priv {
        struct mlx5_nb          pg_nb;
        struct workqueue_struct *pg_wq;
        struct xarray           page_root_xa;
-       u32                     fw_pages;
        atomic_t                reg_pages;
        struct list_head        free_list;
-       u32                     vfs_pages;
-       u32                     host_pf_pages;
+       u32                     fw_pages;
+       u32                     page_counters[MLX5_FUNC_TYPE_NUM];
        u32                     fw_pages_alloc_failed;
        u32                     give_pages_dropped;
        u32                     reclaim_pages_discard;
index f3f196e..8f85716 100644 (file)
@@ -1270,10 +1270,10 @@ static inline void folio_put_refs(struct folio *folio, int refs)
                __folio_put(folio);
 }
 
-/**
- * release_pages - release an array of pages or folios
+/*
+ * union release_pages_arg - an array of pages or folios
  *
- * This just releases a simple array of multiple pages, and
+ * release_pages() releases a simple array of multiple pages, and
  * accepts various different forms of said page array: either
  * a regular old boring array of pages, an array of folios, or
  * an array of encoded page pointers.
index e8ed225..ff3f3f2 100644 (file)
@@ -413,8 +413,7 @@ static inline void free_anon_vma_name(struct vm_area_struct *vma)
         * Not using anon_vma_name because it generates a warning if mmap_lock
         * is not held, which might be the case here.
         */
-       if (!vma->vm_file)
-               anon_vma_name_put(vma->anon_name);
+       anon_vma_name_put(vma->anon_name);
 }
 
 static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
index 3b84750..9757067 100644 (file)
@@ -581,7 +581,7 @@ struct vm_area_struct {
        /*
         * For private and shared anonymous mappings, a pointer to a null
         * terminated string containing the name given to the vma, or NULL if
-        * unnamed. Serialized by mmap_sem. Use anon_vma_name to access.
+        * unnamed. Serialized by mmap_lock. Use anon_vma_name to access.
         */
        struct anon_vma_name *anon_name;
 #endif
index 2576555..a3f8cdc 100644 (file)
@@ -7,7 +7,6 @@
 #define __LINUX_MTD_SPI_NOR_H
 
 #include <linux/bitops.h>
-#include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/spi/spi-mem.h>
 
index 50caa11..bb15c92 100644 (file)
@@ -70,7 +70,6 @@ struct nvmem_keepout {
  * @word_size: Minimum read/write access granularity.
  * @stride:    Minimum read/write access stride.
  * @priv:      User context passed to read/write callbacks.
- * @wp-gpio:   Write protect pin
  * @ignore_wp:  Write Protect pin is managed by the provider.
  *
  * Note: A default "nvmem<id>" name will be assigned to the device if
@@ -85,7 +84,6 @@ struct nvmem_config {
        const char              *name;
        int                     id;
        struct module           *owner;
-       struct gpio_desc        *wp_gpio;
        const struct nvmem_cell_info    *cells;
        int                     ncells;
        const struct nvmem_keepout *keepout;
index 2e677e6..d7c2d33 100644 (file)
@@ -301,7 +301,7 @@ static inline bool folio_ref_try_add_rcu(struct folio *folio, int count)
  *
  * You can also use this function if you're holding a lock that prevents
  * pages being frozen & removed; eg the i_pages lock for the page cache
- * or the mmap_sem or page table lock for page tables.  In this case,
+ * or the mmap_lock or page table lock for page tables.  In this case,
  * it will always succeed, and you could have used a plain folio_get(),
  * but it's sometimes more convenient to have a common function called
  * from both locked and RCU-protected contexts.
index 632320e..a48bb52 100644 (file)
@@ -32,7 +32,8 @@ enum simatic_ipc_station_ids {
        SIMATIC_IPC_IPC477E = 0x00000A02,
        SIMATIC_IPC_IPC127E = 0x00000D01,
        SIMATIC_IPC_IPC227G = 0x00000F01,
-       SIMATIC_IPC_IPC427G = 0x00001001,
+       SIMATIC_IPC_IPCBX_39A = 0x00001001,
+       SIMATIC_IPC_IPCPX_39A = 0x00001002,
 };
 
 static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len)
index 93cd34f..035d964 100644 (file)
@@ -379,9 +379,13 @@ const struct dev_pm_ops name = { \
        const struct dev_pm_ops name;                                   \
        __EXPORT_SYMBOL(name, sec, ns);                                 \
        const struct dev_pm_ops name
+#define EXPORT_PM_FN_GPL(name)         EXPORT_SYMBOL_GPL(name)
+#define EXPORT_PM_FN_NS_GPL(name, ns)  EXPORT_SYMBOL_NS_GPL(name, ns)
 #else
 #define _EXPORT_DEV_PM_OPS(name, sec, ns)                              \
        static __maybe_unused const struct dev_pm_ops __static_##name
+#define EXPORT_PM_FN_GPL(name)
+#define EXPORT_PM_FN_NS_GPL(name, ns)
 #endif
 
 #define EXPORT_DEV_PM_OPS(name) _EXPORT_DEV_PM_OPS(name, "", "")
index f7f1272..9a60f45 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef __ASSEMBLER__
 #include <linux/types.h>
 
-#ifdef CONFIG_ARCH_OMAP1_ANY
+#ifdef CONFIG_ARCH_OMAP1
 /*
  * NOTE: Please use ioremap + __raw_read/write where possible instead of these
  */
@@ -15,7 +15,7 @@ extern u32 omap_readl(u32 pa);
 extern void omap_writeb(u8 v, u32 pa);
 extern void omap_writew(u16 v, u32 pa);
 extern void omap_writel(u32 v, u32 pa);
-#else
+#elif defined(CONFIG_COMPILE_TEST)
 static inline u8 omap_readb(u32 pa)  { return 0; }
 static inline u16 omap_readw(u32 pa) { return 0; }
 static inline u32 omap_readl(u32 pa) { return 0; }
index 1341f7d..be48f1c 100644 (file)
@@ -476,6 +476,15 @@ extern int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
 #define atomic_dec_and_lock_irqsave(atomic, lock, flags) \
                __cond_lock(lock, _atomic_dec_and_lock_irqsave(atomic, lock, &(flags)))
 
+extern int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock);
+#define atomic_dec_and_raw_lock(atomic, lock) \
+               __cond_lock(lock, _atomic_dec_and_raw_lock(atomic, lock))
+
+extern int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock_t *lock,
+                                       unsigned long *flags);
+#define atomic_dec_and_raw_lock_irqsave(atomic, lock, flags) \
+               __cond_lock(lock, _atomic_dec_and_raw_lock_irqsave(atomic, lock, &(flags)))
+
 int __alloc_bucket_spinlocks(spinlock_t **locks, unsigned int *lock_mask,
                             size_t max_size, unsigned int cpu_mult,
                             gfp_t gfp, const char *name,
index 83ca2e8..a152678 100644 (file)
@@ -252,6 +252,7 @@ struct plat_stmmacenet_data {
        int rss_en;
        int mac_port_sel_speed;
        bool en_tx_lpi_clockgating;
+       bool rx_clk_runs_in_lpi;
        int has_xgmac;
        bool vlan_fail_q_en;
        u8 vlan_fail_q;
index 2787b84..0ceed49 100644 (file)
@@ -418,8 +418,7 @@ extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
 extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                                  unsigned long nr_pages,
                                                  gfp_t gfp_mask,
-                                                 unsigned int reclaim_options,
-                                                 nodemask_t *nodemask);
+                                                 unsigned int reclaim_options);
 extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem,
                                                gfp_t gfp_mask, bool noswap,
                                                pg_data_t *pgdat,
index 20c0ff5..7d68a5c 100644 (file)
@@ -198,8 +198,8 @@ static __always_inline int __calc_tpm2_event_size(struct tcg_pcr_event2_head *ev
         * The loop below will unmap these fields if the log is larger than
         * one page, so save them here for reference:
         */
-       count = READ_ONCE(event->count);
-       event_type = READ_ONCE(event->event_type);
+       count = event->count;
+       event_type = event->event_type;
 
        /* Verify that it's the log header */
        if (event_header->pcr_idx != 0 ||
index 4342e99..0e37322 100644 (file)
@@ -270,6 +270,7 @@ struct trace_event_fields {
                        const int  align;
                        const int  is_signed;
                        const int  filter_type;
+                       const int  len;
                };
                int (*define_fields)(struct trace_event_call *);
        };
index 7d5325d..86d1c8e 100644 (file)
@@ -267,16 +267,15 @@ static inline void *usb_get_intfdata(struct usb_interface *intf)
 }
 
 /**
- * usb_set_intfdata() - associate driver-specific data with the interface
- * @intf: the usb interface
- * @data: pointer to the device priv structure or %NULL
+ * usb_set_intfdata() - associate driver-specific data with an interface
+ * @intf: USB interface
+ * @data: driver data
  *
- * Drivers should use this function in their probe() to associate their
- * driver-specific data with the usb interface.
+ * Drivers can use this function in their probe() callbacks to associate
+ * driver-specific data with an interface.
  *
- * When disconnecting, the core will take care of setting @intf back to %NULL,
- * so no actions are needed on the driver side. The interface should not be set
- * to %NULL before all actions completed (e.g. no outsanding URB remaining).
+ * Note that there is generally no need to clear the driver-data pointer even
+ * if some drivers do so for historical or implementation-specific reasons.
  */
 static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
 {
@@ -774,11 +773,14 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf);
 extern int usb_acpi_set_power_state(struct usb_device *hdev, int index,
        bool enable);
 extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index);
+extern int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index);
 #else
 static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index,
        bool enable) { return 0; }
 static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
        { return true; }
+static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index)
+       { return 0; }
 #endif
 
 /* USB autosuspend and autoresume */
index 72299f2..43db6e4 100644 (file)
  */
 #define find_closest_descending(x, a, as) __find_closest(x, a, as, >=)
 
+/**
+ * is_insidevar - check if the @ptr points inside the @var memory range.
+ * @ptr:       the pointer to a memory address.
+ * @var:       the variable which address and size identify the memory range.
+ *
+ * Evaluates to true if the address in @ptr lies within the memory
+ * range allocated to @var.
+ */
+#define is_insidevar(ptr, var)                                         \
+       ((uintptr_t)(ptr) >= (uintptr_t)(var) &&                        \
+        (uintptr_t)(ptr) <  (uintptr_t)(var) + sizeof(var))
+
 #endif
index d5a5ae9..ba717ea 100644 (file)
@@ -15,6 +15,7 @@ struct key;
 struct sock;
 struct socket;
 struct rxrpc_call;
+enum rxrpc_abort_reason;
 
 enum rxrpc_interruptibility {
        RXRPC_INTERRUPTIBLE,    /* Call is interruptible */
@@ -55,7 +56,7 @@ int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
 int rxrpc_kernel_recv_data(struct socket *, struct rxrpc_call *,
                           struct iov_iter *, size_t *, bool, u32 *, u16 *);
 bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *,
-                            u32, int, const char *);
+                            u32, int, enum rxrpc_abort_reason);
 void rxrpc_kernel_end_call(struct socket *, struct rxrpc_call *);
 void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
                           struct sockaddr_rxrpc *);
index 689da32..e3235b9 100644 (file)
@@ -1832,8 +1832,6 @@ struct ieee80211_vif_cfg {
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void \*).
  * @txq: the multicast data TX queue
- * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
- *     protected by fq->lock.
  * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
  *     &enum ieee80211_offload_flags.
  * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
@@ -1863,8 +1861,6 @@ struct ieee80211_vif {
        bool probe_req_reg;
        bool rx_mcast_action_reg;
 
-       bool txqs_stopped[IEEE80211_NUM_ACS];
-
        struct ieee80211_vif *mbssid_tx_vif;
 
        /* must be last */
index b3ba046..56189e4 100644 (file)
@@ -336,9 +336,12 @@ struct gdma_queue_spec {
        };
 };
 
+#define MANA_IRQ_NAME_SZ 32
+
 struct gdma_irq_context {
        void (*handler)(void *arg);
        void *arg;
+       char name[MANA_IRQ_NAME_SZ];
 };
 
 struct gdma_context {
index d551771..af4aa66 100644 (file)
@@ -1288,4 +1288,11 @@ void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx);
 
 int sch_frag_xmit_hook(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb));
 
+/* Make sure qdisc is no longer in SCHED state. */
+static inline void qdisc_synchronize(const struct Qdisc *q)
+{
+       while (test_bit(__QDISC_STATE_SCHED, &q->state))
+               msleep(1);
+}
+
 #endif
index 695eebc..e39fb07 100644 (file)
@@ -422,6 +422,8 @@ extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
 extern struct iscsi_cls_session *
 iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
                    uint16_t, int, int, uint32_t, unsigned int);
+void iscsi_session_remove(struct iscsi_cls_session *cls_session);
+void iscsi_session_free(struct iscsi_cls_session *cls_session);
 extern void iscsi_session_teardown(struct iscsi_cls_session *);
 extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
 extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
index cab52b0..34c0370 100644 (file)
@@ -236,6 +236,14 @@ enum {
        ISCSI_SESSION_FREE,
 };
 
+enum {
+       ISCSI_SESSION_TARGET_UNBOUND,
+       ISCSI_SESSION_TARGET_ALLOCATED,
+       ISCSI_SESSION_TARGET_SCANNED,
+       ISCSI_SESSION_TARGET_UNBINDING,
+       ISCSI_SESSION_TARGET_MAX,
+};
+
 #define ISCSI_MAX_TARGET -1
 
 struct iscsi_cls_session {
@@ -264,6 +272,7 @@ struct iscsi_cls_session {
         */
        pid_t creator;
        int state;
+       int target_state;                       /* session target bind state */
        int sid;                                /* session id */
        void *dd_data;                          /* LLD private data */
        struct device dev;      /* sysfs transport/container device */
index ab95559..73cac8d 100644 (file)
@@ -170,7 +170,7 @@ struct rpi_firmware_clk_rate_request {
 
 #define RPI_FIRMWARE_CLK_RATE_REQUEST(_id)     \
        {                                       \
-               .id = _id,                      \
+               .id = cpu_to_le32(_id),         \
        }
 
 #if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
index 5f9dd73..283db0e 100644 (file)
 /*
  * Declare tracing information enums and their string mappings for display.
  */
+#define rxrpc_abort_reasons \
+       /* AFS errors */                                                \
+       EM(afs_abort_general_error,             "afs-error")            \
+       EM(afs_abort_interrupted,               "afs-intr")             \
+       EM(afs_abort_oom,                       "afs-oom")              \
+       EM(afs_abort_op_not_supported,          "afs-op-notsupp")       \
+       EM(afs_abort_probeuuid_negative,        "afs-probeuuid-neg")    \
+       EM(afs_abort_send_data_error,           "afs-send-data")        \
+       EM(afs_abort_unmarshal_error,           "afs-unmarshal")        \
+       /* rxperf errors */                                             \
+       EM(rxperf_abort_general_error,          "rxperf-error")         \
+       EM(rxperf_abort_oom,                    "rxperf-oom")           \
+       EM(rxperf_abort_op_not_supported,       "rxperf-op-notsupp")    \
+       EM(rxperf_abort_unmarshal_error,        "rxperf-unmarshal")     \
+       /* RxKAD security errors */                                     \
+       EM(rxkad_abort_1_short_check,           "rxkad1-short-check")   \
+       EM(rxkad_abort_1_short_data,            "rxkad1-short-data")    \
+       EM(rxkad_abort_1_short_encdata,         "rxkad1-short-encdata") \
+       EM(rxkad_abort_1_short_header,          "rxkad1-short-hdr")     \
+       EM(rxkad_abort_2_short_check,           "rxkad2-short-check")   \
+       EM(rxkad_abort_2_short_data,            "rxkad2-short-data")    \
+       EM(rxkad_abort_2_short_header,          "rxkad2-short-hdr")     \
+       EM(rxkad_abort_2_short_len,             "rxkad2-short-len")     \
+       EM(rxkad_abort_bad_checksum,            "rxkad2-bad-cksum")     \
+       EM(rxkad_abort_chall_key_expired,       "rxkad-chall-key-exp")  \
+       EM(rxkad_abort_chall_level,             "rxkad-chall-level")    \
+       EM(rxkad_abort_chall_no_key,            "rxkad-chall-nokey")    \
+       EM(rxkad_abort_chall_short,             "rxkad-chall-short")    \
+       EM(rxkad_abort_chall_version,           "rxkad-chall-version")  \
+       EM(rxkad_abort_resp_bad_callid,         "rxkad-resp-bad-callid") \
+       EM(rxkad_abort_resp_bad_checksum,       "rxkad-resp-bad-cksum") \
+       EM(rxkad_abort_resp_bad_param,          "rxkad-resp-bad-param") \
+       EM(rxkad_abort_resp_call_ctr,           "rxkad-resp-call-ctr") \
+       EM(rxkad_abort_resp_call_state,         "rxkad-resp-call-state") \
+       EM(rxkad_abort_resp_key_expired,        "rxkad-resp-key-exp")   \
+       EM(rxkad_abort_resp_key_rejected,       "rxkad-resp-key-rej")   \
+       EM(rxkad_abort_resp_level,              "rxkad-resp-level")     \
+       EM(rxkad_abort_resp_nokey,              "rxkad-resp-nokey")     \
+       EM(rxkad_abort_resp_ooseq,              "rxkad-resp-ooseq")     \
+       EM(rxkad_abort_resp_short,              "rxkad-resp-short")     \
+       EM(rxkad_abort_resp_short_tkt,          "rxkad-resp-short-tkt") \
+       EM(rxkad_abort_resp_tkt_aname,          "rxkad-resp-tk-aname")  \
+       EM(rxkad_abort_resp_tkt_expired,        "rxkad-resp-tk-exp")    \
+       EM(rxkad_abort_resp_tkt_future,         "rxkad-resp-tk-future") \
+       EM(rxkad_abort_resp_tkt_inst,           "rxkad-resp-tk-inst")   \
+       EM(rxkad_abort_resp_tkt_len,            "rxkad-resp-tk-len")    \
+       EM(rxkad_abort_resp_tkt_realm,          "rxkad-resp-tk-realm")  \
+       EM(rxkad_abort_resp_tkt_short,          "rxkad-resp-tk-short")  \
+       EM(rxkad_abort_resp_tkt_sinst,          "rxkad-resp-tk-sinst")  \
+       EM(rxkad_abort_resp_tkt_sname,          "rxkad-resp-tk-sname")  \
+       EM(rxkad_abort_resp_unknown_tkt,        "rxkad-resp-unknown-tkt") \
+       EM(rxkad_abort_resp_version,            "rxkad-resp-version")   \
+       /* rxrpc errors */                                              \
+       EM(rxrpc_abort_call_improper_term,      "call-improper-term")   \
+       EM(rxrpc_abort_call_reset,              "call-reset")           \
+       EM(rxrpc_abort_call_sendmsg,            "call-sendmsg")         \
+       EM(rxrpc_abort_call_sock_release,       "call-sock-rel")        \
+       EM(rxrpc_abort_call_sock_release_tba,   "call-sock-rel-tba")    \
+       EM(rxrpc_abort_call_timeout,            "call-timeout")         \
+       EM(rxrpc_abort_no_service_key,          "no-serv-key")          \
+       EM(rxrpc_abort_nomem,                   "nomem")                \
+       EM(rxrpc_abort_service_not_offered,     "serv-not-offered")     \
+       EM(rxrpc_abort_shut_down,               "shut-down")            \
+       EM(rxrpc_abort_unsupported_security,    "unsup-sec")            \
+       EM(rxrpc_badmsg_bad_abort,              "bad-abort")            \
+       EM(rxrpc_badmsg_bad_jumbo,              "bad-jumbo")            \
+       EM(rxrpc_badmsg_short_ack,              "short-ack")            \
+       EM(rxrpc_badmsg_short_ack_info,         "short-ack-info")       \
+       EM(rxrpc_badmsg_short_hdr,              "short-hdr")            \
+       EM(rxrpc_badmsg_unsupported_packet,     "unsup-pkt")            \
+       EM(rxrpc_badmsg_zero_call,              "zero-call")            \
+       EM(rxrpc_badmsg_zero_seq,               "zero-seq")             \
+       EM(rxrpc_badmsg_zero_service,           "zero-service")         \
+       EM(rxrpc_eproto_ackr_outside_window,    "ackr-out-win")         \
+       EM(rxrpc_eproto_ackr_sack_overflow,     "ackr-sack-over")       \
+       EM(rxrpc_eproto_ackr_short_sack,        "ackr-short-sack")      \
+       EM(rxrpc_eproto_ackr_zero,              "ackr-zero")            \
+       EM(rxrpc_eproto_bad_upgrade,            "bad-upgrade")          \
+       EM(rxrpc_eproto_data_after_last,        "data-after-last")      \
+       EM(rxrpc_eproto_different_last,         "diff-last")            \
+       EM(rxrpc_eproto_early_reply,            "early-reply")          \
+       EM(rxrpc_eproto_improper_term,          "improper-term")        \
+       EM(rxrpc_eproto_no_client_call,         "no-cl-call")           \
+       EM(rxrpc_eproto_no_client_conn,         "no-cl-conn")           \
+       EM(rxrpc_eproto_no_service_call,        "no-sv-call")           \
+       EM(rxrpc_eproto_reupgrade,              "re-upgrade")           \
+       EM(rxrpc_eproto_rxnull_challenge,       "rxnull-chall")         \
+       EM(rxrpc_eproto_rxnull_response,        "rxnull-resp")          \
+       EM(rxrpc_eproto_tx_rot_last,            "tx-rot-last")          \
+       EM(rxrpc_eproto_unexpected_ack,         "unex-ack")             \
+       EM(rxrpc_eproto_unexpected_ackall,      "unex-ackall")          \
+       EM(rxrpc_eproto_unexpected_implicit_end, "unex-impl-end")       \
+       EM(rxrpc_eproto_unexpected_reply,       "unex-reply")           \
+       EM(rxrpc_eproto_wrong_security,         "wrong-sec")            \
+       EM(rxrpc_recvmsg_excess_data,           "recvmsg-excess")       \
+       EM(rxrpc_recvmsg_short_data,            "recvmsg-short")        \
+       E_(rxrpc_sendmsg_late_send,             "sendmsg-late")
+
 #define rxrpc_call_poke_traces \
+       EM(rxrpc_call_poke_abort,               "Abort")        \
+       EM(rxrpc_call_poke_complete,            "Compl")        \
        EM(rxrpc_call_poke_error,               "Error")        \
        EM(rxrpc_call_poke_idle,                "Idle")         \
        EM(rxrpc_call_poke_start,               "Start")        \
 #define rxrpc_skb_traces \
        EM(rxrpc_skb_eaten_by_unshare,          "ETN unshare  ") \
        EM(rxrpc_skb_eaten_by_unshare_nomem,    "ETN unshar-nm") \
+       EM(rxrpc_skb_get_conn_secured,          "GET conn-secd") \
        EM(rxrpc_skb_get_conn_work,             "GET conn-work") \
        EM(rxrpc_skb_get_local_work,            "GET locl-work") \
        EM(rxrpc_skb_get_reject_work,           "GET rej-work ") \
        EM(rxrpc_skb_new_error_report,          "NEW error-rpt") \
        EM(rxrpc_skb_new_jumbo_subpacket,       "NEW jumbo-sub") \
        EM(rxrpc_skb_new_unshared,              "NEW unshared ") \
+       EM(rxrpc_skb_put_conn_secured,          "PUT conn-secd") \
        EM(rxrpc_skb_put_conn_work,             "PUT conn-work") \
        EM(rxrpc_skb_put_error_report,          "PUT error-rep") \
        EM(rxrpc_skb_put_input,                 "PUT input    ") \
 #define rxrpc_peer_traces \
        EM(rxrpc_peer_free,                     "FREE        ") \
        EM(rxrpc_peer_get_accept,               "GET accept  ") \
-       EM(rxrpc_peer_get_activate_call,        "GET act-call") \
        EM(rxrpc_peer_get_bundle,               "GET bundle  ") \
        EM(rxrpc_peer_get_client_conn,          "GET cln-conn") \
        EM(rxrpc_peer_get_input,                "GET input   ") \
        EM(rxrpc_peer_put_bundle,               "PUT bundle  ") \
        EM(rxrpc_peer_put_call,                 "PUT call    ") \
        EM(rxrpc_peer_put_conn,                 "PUT conn    ") \
-       EM(rxrpc_peer_put_discard_tmp,          "PUT disc-tmp") \
        EM(rxrpc_peer_put_input,                "PUT input   ") \
        EM(rxrpc_peer_put_input_error,          "PUT inpt-err") \
        E_(rxrpc_peer_put_keepalive,            "PUT keepaliv")
        EM(rxrpc_bundle_get_client_call,        "GET clt-call") \
        EM(rxrpc_bundle_get_client_conn,        "GET clt-conn") \
        EM(rxrpc_bundle_get_service_conn,       "GET svc-conn") \
+       EM(rxrpc_bundle_put_call,               "PUT call    ") \
        EM(rxrpc_bundle_put_conn,               "PUT conn    ") \
        EM(rxrpc_bundle_put_discard,            "PUT discard ") \
        E_(rxrpc_bundle_new,                    "NEW         ")
        EM(rxrpc_conn_get_call_input,           "GET inp-call") \
        EM(rxrpc_conn_get_conn_input,           "GET inp-conn") \
        EM(rxrpc_conn_get_idle,                 "GET idle    ") \
-       EM(rxrpc_conn_get_poke,                 "GET poke    ") \
+       EM(rxrpc_conn_get_poke_abort,           "GET pk-abort") \
+       EM(rxrpc_conn_get_poke_timer,           "GET poke    ") \
        EM(rxrpc_conn_get_service_conn,         "GET svc-conn") \
        EM(rxrpc_conn_new_client,               "NEW client  ") \
        EM(rxrpc_conn_new_service,              "NEW service ") \
        EM(rxrpc_conn_put_call,                 "PUT call    ") \
        EM(rxrpc_conn_put_call_input,           "PUT inp-call") \
        EM(rxrpc_conn_put_conn_input,           "PUT inp-conn") \
-       EM(rxrpc_conn_put_discard,              "PUT discard ") \
        EM(rxrpc_conn_put_discard_idle,         "PUT disc-idl") \
        EM(rxrpc_conn_put_local_dead,           "PUT loc-dead") \
        EM(rxrpc_conn_put_noreuse,              "PUT noreuse ") \
        EM(rxrpc_conn_put_service_reaped,       "PUT svc-reap") \
        EM(rxrpc_conn_put_unbundle,             "PUT unbundle") \
        EM(rxrpc_conn_put_unidle,               "PUT unidle  ") \
+       EM(rxrpc_conn_put_work,                 "PUT work    ") \
        EM(rxrpc_conn_queue_challenge,          "QUE chall   ") \
        EM(rxrpc_conn_queue_retry_work,         "QUE retry-wk") \
        EM(rxrpc_conn_queue_rx_work,            "QUE rx-work ") \
-       EM(rxrpc_conn_queue_timer,              "QUE timer   ") \
        EM(rxrpc_conn_see_new_service_conn,     "SEE new-svc ") \
        EM(rxrpc_conn_see_reap_service,         "SEE reap-svc") \
        E_(rxrpc_conn_see_work,                 "SEE work    ")
        EM(rxrpc_client_chan_activate,          "ChActv") \
        EM(rxrpc_client_chan_disconnect,        "ChDisc") \
        EM(rxrpc_client_chan_pass,              "ChPass") \
-       EM(rxrpc_client_chan_wait_failed,       "ChWtFl") \
        EM(rxrpc_client_cleanup,                "Clean ") \
        EM(rxrpc_client_discard,                "Discar") \
-       EM(rxrpc_client_duplicate,              "Duplic") \
        EM(rxrpc_client_exposed,                "Expose") \
        EM(rxrpc_client_replace,                "Replac") \
+       EM(rxrpc_client_queue_new_call,         "Q-Call") \
        EM(rxrpc_client_to_active,              "->Actv") \
        E_(rxrpc_client_to_idle,                "->Idle")
 
 #define rxrpc_call_traces \
+       EM(rxrpc_call_get_io_thread,            "GET iothread") \
        EM(rxrpc_call_get_input,                "GET input   ") \
        EM(rxrpc_call_get_kernel_service,       "GET krnl-srv") \
        EM(rxrpc_call_get_notify_socket,        "GET notify  ") \
        EM(rxrpc_call_new_prealloc_service,     "NEW prealloc") \
        EM(rxrpc_call_put_discard_prealloc,     "PUT disc-pre") \
        EM(rxrpc_call_put_discard_error,        "PUT disc-err") \
+       EM(rxrpc_call_put_io_thread,            "PUT iothread") \
        EM(rxrpc_call_put_input,                "PUT input   ") \
        EM(rxrpc_call_put_kernel,               "PUT kernel  ") \
        EM(rxrpc_call_put_poke,                 "PUT poke    ") \
        EM(rxrpc_call_put_sendmsg,              "PUT sendmsg ") \
        EM(rxrpc_call_put_unnotify,             "PUT unnotify") \
        EM(rxrpc_call_put_userid_exists,        "PUT u-exists") \
+       EM(rxrpc_call_put_userid,               "PUT user-id ") \
        EM(rxrpc_call_see_accept,               "SEE accept  ") \
        EM(rxrpc_call_see_activate_client,      "SEE act-clnt") \
        EM(rxrpc_call_see_connect_failed,       "SEE con-fail") \
        EM(rxrpc_call_see_connected,            "SEE connect ") \
+       EM(rxrpc_call_see_disconnected,         "SEE disconn ") \
        EM(rxrpc_call_see_distribute_error,     "SEE dist-err") \
        EM(rxrpc_call_see_input,                "SEE input   ") \
        EM(rxrpc_call_see_release,              "SEE release ") \
 #define EM(a, b) a,
 #define E_(a, b) a
 
+enum rxrpc_abort_reason                { rxrpc_abort_reasons } __mode(byte);
 enum rxrpc_bundle_trace                { rxrpc_bundle_traces } __mode(byte);
 enum rxrpc_call_poke_trace     { rxrpc_call_poke_traces } __mode(byte);
 enum rxrpc_call_trace          { rxrpc_call_traces } __mode(byte);
@@ -404,9 +509,13 @@ enum rxrpc_txqueue_trace   { rxrpc_txqueue_traces } __mode(byte);
  */
 #undef EM
 #undef E_
+
+#ifndef RXRPC_TRACE_ONLY_DEFINE_ENUMS
+
 #define EM(a, b) TRACE_DEFINE_ENUM(a);
 #define E_(a, b) TRACE_DEFINE_ENUM(a);
 
+rxrpc_abort_reasons;
 rxrpc_bundle_traces;
 rxrpc_call_poke_traces;
 rxrpc_call_traces;
@@ -657,14 +766,14 @@ TRACE_EVENT(rxrpc_rx_done,
            );
 
 TRACE_EVENT(rxrpc_abort,
-           TP_PROTO(unsigned int call_nr, const char *why, u32 cid, u32 call_id,
-                    rxrpc_seq_t seq, int abort_code, int error),
+           TP_PROTO(unsigned int call_nr, enum rxrpc_abort_reason why,
+                    u32 cid, u32 call_id, rxrpc_seq_t seq, int abort_code, int error),
 
            TP_ARGS(call_nr, why, cid, call_id, seq, abort_code, error),
 
            TP_STRUCT__entry(
                    __field(unsigned int,               call_nr         )
-                   __array(char,                       why, 4          )
+                   __field(enum rxrpc_abort_reason,    why             )
                    __field(u32,                        cid             )
                    __field(u32,                        call_id         )
                    __field(rxrpc_seq_t,                seq             )
@@ -673,8 +782,8 @@ TRACE_EVENT(rxrpc_abort,
                             ),
 
            TP_fast_assign(
-                   memcpy(__entry->why, why, 4);
                    __entry->call_nr = call_nr;
+                   __entry->why = why;
                    __entry->cid = cid;
                    __entry->call_id = call_id;
                    __entry->abort_code = abort_code;
@@ -685,7 +794,8 @@ TRACE_EVENT(rxrpc_abort,
            TP_printk("c=%08x %08x:%08x s=%u a=%d e=%d %s",
                      __entry->call_nr,
                      __entry->cid, __entry->call_id, __entry->seq,
-                     __entry->abort_code, __entry->error, __entry->why)
+                     __entry->abort_code, __entry->error,
+                     __print_symbolic(__entry->why, rxrpc_abort_reasons))
            );
 
 TRACE_EVENT(rxrpc_call_complete,
@@ -1521,30 +1631,6 @@ TRACE_EVENT(rxrpc_improper_term,
                      __entry->abort_code)
            );
 
-TRACE_EVENT(rxrpc_rx_eproto,
-           TP_PROTO(struct rxrpc_call *call, rxrpc_serial_t serial,
-                    const char *why),
-
-           TP_ARGS(call, serial, why),
-
-           TP_STRUCT__entry(
-                   __field(unsigned int,               call            )
-                   __field(rxrpc_serial_t,             serial          )
-                   __field(const char *,               why             )
-                            ),
-
-           TP_fast_assign(
-                   __entry->call = call ? call->debug_id : 0;
-                   __entry->serial = serial;
-                   __entry->why = why;
-                          ),
-
-           TP_printk("c=%08x EPROTO %08x %s",
-                     __entry->call,
-                     __entry->serial,
-                     __entry->why)
-           );
-
 TRACE_EVENT(rxrpc_connect_call,
            TP_PROTO(struct rxrpc_call *call),
 
@@ -1842,6 +1928,8 @@ TRACE_EVENT(rxrpc_call_poked,
 
 #undef EM
 #undef E_
+
+#endif /* RXRPC_TRACE_ONLY_DEFINE_ENUMS */
 #endif /* _TRACE_RXRPC_H */
 
 /* This part must be outside protection */
index affd541..b6f679a 100644 (file)
@@ -26,7 +26,8 @@
 #define __array(_type, _item, _len) {                                  \
        .type = #_type"["__stringify(_len)"]", .name = #_item,          \
        .size = sizeof(_type[_len]), .align = ALIGN_STRUCTFIELD(_type), \
-       .is_signed = is_signed_type(_type), .filter_type = FILTER_OTHER },
+       .is_signed = is_signed_type(_type), .filter_type = FILTER_OTHER,\
+       .len = _len },
 
 #undef __dynamic_array
 #define __dynamic_array(_type, _item, _len) {                          \
index 0512fde..7b158fc 100644 (file)
@@ -64,6 +64,7 @@ struct drm_virtgpu_map {
        __u32 pad;
 };
 
+/* fence_fd is modified on success if VIRTGPU_EXECBUF_FENCE_FD_OUT flag is set. */
 struct drm_virtgpu_execbuffer {
        __u32 flags;
        __u32 size;
index 874a923..283dec7 100644 (file)
@@ -18,6 +18,7 @@
 #ifndef _UAPI_LINUX_IP_H
 #define _UAPI_LINUX_IP_H
 #include <linux/types.h>
+#include <linux/stddef.h>
 #include <asm/byteorder.h>
 
 #define IPTOS_TOS_MASK         0x1E
index 81f4243..53326df 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/libc-compat.h>
 #include <linux/types.h>
+#include <linux/stddef.h>
 #include <linux/in6.h>
 #include <asm/byteorder.h>
 
index c742469..2d6f80d 100644 (file)
@@ -15,8 +15,7 @@ enum sctp_conntrack {
        SCTP_CONNTRACK_SHUTDOWN_RECD,
        SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
        SCTP_CONNTRACK_HEARTBEAT_SENT,
-       SCTP_CONNTRACK_HEARTBEAT_ACKED,
-       SCTP_CONNTRACK_DATA_SENT,
+       SCTP_CONNTRACK_HEARTBEAT_ACKED, /* no longer used */
        SCTP_CONNTRACK_MAX
 };
 
index 94e7403..aa805e6 100644 (file)
@@ -94,8 +94,7 @@ enum ctattr_timeout_sctp {
        CTA_TIMEOUT_SCTP_SHUTDOWN_RECD,
        CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT,
        CTA_TIMEOUT_SCTP_HEARTBEAT_SENT,
-       CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED,
-       CTA_TIMEOUT_SCTP_DATA_SENT,
+       CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED, /* no longer used */
        __CTA_TIMEOUT_SCTP_MAX
 };
 #define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1)
index 3511095..42a40ad 100644 (file)
@@ -58,7 +58,7 @@
 
 #define PSCI_1_1_FN_SYSTEM_RESET2              PSCI_0_2_FN(18)
 #define PSCI_1_1_FN_MEM_PROTECT                        PSCI_0_2_FN(19)
-#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE    PSCI_0_2_FN(19)
+#define PSCI_1_1_FN_MEM_PROTECT_CHECK_RANGE    PSCI_0_2_FN(20)
 
 #define PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND      PSCI_0_2_FN64(12)
 #define PSCI_1_0_FN64_NODE_HW_STATE            PSCI_0_2_FN64(13)
@@ -67,7 +67,7 @@
 #define PSCI_1_0_FN64_STAT_COUNT               PSCI_0_2_FN64(17)
 
 #define PSCI_1_1_FN64_SYSTEM_RESET2            PSCI_0_2_FN64(18)
-#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE  PSCI_0_2_FN64(19)
+#define PSCI_1_1_FN64_MEM_PROTECT_CHECK_RANGE  PSCI_0_2_FN64(20)
 
 /* PSCI v0.2 power state encoding for CPU_SUSPEND function */
 #define PSCI_0_2_POWER_STATE_ID_MASK           0xffff
index 5cf81df..727084c 100644 (file)
@@ -808,6 +808,7 @@ struct ufs_hba_monitor {
  * @urgent_bkops_lvl: keeps track of urgent bkops level for device
  * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
  *  device is known or not.
+ * @wb_mutex: used to serialize devfreq and sysfs write booster toggling
  * @clk_scaling_lock: used to serialize device commands and clock scaling
  * @desc_size: descriptor sizes reported by device
  * @scsi_block_reqs_cnt: reference counting for scsi block requests
@@ -951,6 +952,7 @@ struct ufs_hba {
        enum bkops_status urgent_bkops_lvl;
        bool is_urgent_bkops_lvl_checked;
 
+       struct mutex wb_mutex;
        struct rw_semaphore clk_scaling_lock;
        unsigned char desc_size[QUERY_DESC_IDN_MAX];
        atomic_t scsi_block_reqs_cnt;
index eaa932b..ad4fb4e 100644 (file)
@@ -117,7 +117,7 @@ struct xenbus_driver {
                     const struct xenbus_device_id *id);
        void (*otherend_changed)(struct xenbus_device *dev,
                                 enum xenbus_state backend_state);
-       int (*remove)(struct xenbus_device *dev);
+       void (*remove)(struct xenbus_device *dev);
        int (*suspend)(struct xenbus_device *dev);
        int (*resume)(struct xenbus_device *dev);
        int (*uevent)(struct xenbus_device *, struct kobj_uevent_env *);
index 7e5c3dd..44e90b2 100644 (file)
@@ -204,7 +204,7 @@ config LOCALVERSION_AUTO
          appended after any matching localversion* files, and after the value
          set in CONFIG_LOCALVERSION.
 
-         (The actual string used here is the first eight characters produced
+         (The actual string used here is the first 12 characters produced
          by running the command:
 
            $ git rev-parse --verify HEAD
@@ -776,7 +776,7 @@ config PRINTK_SAFE_LOG_BUF_SHIFT
        depends on PRINTK
        help
          Select the size of an alternate printk per-CPU buffer where messages
-         printed from usafe contexts are temporary stored. One example would
+         printed from unsafe contexts are temporary stored. One example would
          be NMI messages, another one - printk recursion. The messages are
          copied to the main log buffer in a safe context to avoid a deadlock.
          The value defines the size as a power of 2.
@@ -894,13 +894,17 @@ config CC_IMPLICIT_FALLTHROUGH
        default "-Wimplicit-fallthrough=5" if CC_IS_GCC && $(cc-option,-Wimplicit-fallthrough=5)
        default "-Wimplicit-fallthrough" if CC_IS_CLANG && $(cc-option,-Wunreachable-code-fallthrough)
 
-# Currently, disable gcc-12 array-bounds globally.
+# Currently, disable gcc-11,12 array-bounds globally.
 # We may want to target only particular configurations some day.
+config GCC11_NO_ARRAY_BOUNDS
+       def_bool y
+
 config GCC12_NO_ARRAY_BOUNDS
        def_bool y
 
 config CC_NO_ARRAY_BOUNDS
        bool
+       default y if CC_IS_GCC && GCC_VERSION >= 110000 && GCC_VERSION < 120000 && GCC11_NO_ARRAY_BOUNDS
        default y if CC_IS_GCC && GCC_VERSION >= 120000 && GCC_VERSION < 130000 && GCC12_NO_ARRAY_BOUNDS
 
 #
index 8316c23..26de459 100644 (file)
@@ -59,3 +59,4 @@ include/generated/utsversion.h: FORCE
 
 $(obj)/version-timestamp.o: include/generated/utsversion.h
 CFLAGS_version-timestamp.o := -include include/generated/utsversion.h
+KASAN_SANITIZE_version-timestamp.o := n
index 179e93b..043cbf8 100644 (file)
@@ -2,7 +2,6 @@
 
 #include <generated/compile.h>
 #include <generated/utsrelease.h>
-#include <linux/version.h>
 #include <linux/proc_ns.h>
 #include <linux/refcount.h>
 #include <linux/uts.h>
index 2e04850..882bd56 100644 (file)
@@ -170,12 +170,11 @@ static __cold void __io_uring_show_fdinfo(struct io_ring_ctx *ctx,
                xa_for_each(&ctx->personalities, index, cred)
                        io_uring_show_cred(m, index, cred);
        }
-       if (has_lock)
-               mutex_unlock(&ctx->uring_lock);
 
        seq_puts(m, "PollList:\n");
        for (i = 0; i < (1U << ctx->cancel_table.hash_bits); i++) {
                struct io_hash_bucket *hb = &ctx->cancel_table.hbs[i];
+               struct io_hash_bucket *hbl = &ctx->cancel_table_locked.hbs[i];
                struct io_kiocb *req;
 
                spin_lock(&hb->lock);
@@ -183,8 +182,17 @@ static __cold void __io_uring_show_fdinfo(struct io_ring_ctx *ctx,
                        seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
                                        task_work_pending(req->task));
                spin_unlock(&hb->lock);
+
+               if (!has_lock)
+                       continue;
+               hlist_for_each_entry(req, &hbl->list, hash_node)
+                       seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
+                                       task_work_pending(req->task));
        }
 
+       if (has_lock)
+               mutex_unlock(&ctx->uring_lock);
+
        seq_puts(m, "CqOverflowList:\n");
        spin_lock(&ctx->completion_lock);
        list_for_each_entry(ocqe, &ctx->cq_overflow_list, list) {
index 992dcd9..411bb2d 100644 (file)
@@ -1230,7 +1230,12 @@ static void io_wq_cancel_tw_create(struct io_wq *wq)
 
                worker = container_of(cb, struct io_worker, create_work);
                io_worker_cancel_cb(worker);
-               kfree(worker);
+               /*
+                * Only the worker continuation helper has worker allocated and
+                * hence needs freeing.
+                */
+               if (cb->func == create_worker_cont)
+                       kfree(worker);
        }
 }
 
index 2ac1cd8..db623b3 100644 (file)
@@ -1765,17 +1765,12 @@ queue:
        }
        spin_unlock(&ctx->completion_lock);
 
-       ret = io_req_prep_async(req);
-       if (ret) {
-fail:
-               io_req_defer_failed(req, ret);
-               return;
-       }
        io_prep_async_link(req);
        de = kmalloc(sizeof(*de), GFP_KERNEL);
        if (!de) {
                ret = -ENOMEM;
-               goto fail;
+               io_req_defer_failed(req, ret);
+               return;
        }
 
        spin_lock(&ctx->completion_lock);
@@ -2048,13 +2043,16 @@ static void io_queue_sqe_fallback(struct io_kiocb *req)
                req->flags &= ~REQ_F_HARDLINK;
                req->flags |= REQ_F_LINK;
                io_req_defer_failed(req, req->cqe.res);
-       } else if (unlikely(req->ctx->drain_active)) {
-               io_drain_req(req);
        } else {
                int ret = io_req_prep_async(req);
 
-               if (unlikely(ret))
+               if (unlikely(ret)) {
                        io_req_defer_failed(req, ret);
+                       return;
+               }
+
+               if (unlikely(req->ctx->drain_active))
+                       io_drain_req(req);
                else
                        io_queue_iowq(req, NULL);
        }
@@ -3674,7 +3672,7 @@ static __cold int io_uring_create(unsigned entries, struct io_uring_params *p,
 
        if (ctx->flags & IORING_SETUP_SINGLE_ISSUER
            && !(ctx->flags & IORING_SETUP_R_DISABLED))
-               ctx->submitter_task = get_task_struct(current);
+               WRITE_ONCE(ctx->submitter_task, get_task_struct(current));
 
        file = io_uring_get_file(ctx);
        if (IS_ERR(file)) {
@@ -3868,7 +3866,7 @@ static int io_register_enable_rings(struct io_ring_ctx *ctx)
                return -EBADFD;
 
        if (ctx->flags & IORING_SETUP_SINGLE_ISSUER && !ctx->submitter_task)
-               ctx->submitter_task = get_task_struct(current);
+               WRITE_ONCE(ctx->submitter_task, get_task_struct(current));
 
        if (ctx->restrictions.registered)
                ctx->restricted = 1;
index 2d3cd94..15602a1 100644 (file)
@@ -25,6 +25,28 @@ struct io_msg {
        u32 flags;
 };
 
+static void io_double_unlock_ctx(struct io_ring_ctx *octx)
+{
+       mutex_unlock(&octx->uring_lock);
+}
+
+static int io_double_lock_ctx(struct io_ring_ctx *octx,
+                             unsigned int issue_flags)
+{
+       /*
+        * To ensure proper ordering between the two ctxs, we can only
+        * attempt a trylock on the target. If that fails and we already have
+        * the source ctx lock, punt to io-wq.
+        */
+       if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+               if (!mutex_trylock(&octx->uring_lock))
+                       return -EAGAIN;
+               return 0;
+       }
+       mutex_lock(&octx->uring_lock);
+       return 0;
+}
+
 void io_msg_ring_cleanup(struct io_kiocb *req)
 {
        struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
@@ -36,6 +58,29 @@ void io_msg_ring_cleanup(struct io_kiocb *req)
        msg->src_file = NULL;
 }
 
+static inline bool io_msg_need_remote(struct io_ring_ctx *target_ctx)
+{
+       if (!target_ctx->task_complete)
+               return false;
+       return current != target_ctx->submitter_task;
+}
+
+static int io_msg_exec_remote(struct io_kiocb *req, task_work_func_t func)
+{
+       struct io_ring_ctx *ctx = req->file->private_data;
+       struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
+       struct task_struct *task = READ_ONCE(ctx->submitter_task);
+
+       if (unlikely(!task))
+               return -EOWNERDEAD;
+
+       init_task_work(&msg->tw, func);
+       if (task_work_add(ctx->submitter_task, &msg->tw, TWA_SIGNAL))
+               return -EOWNERDEAD;
+
+       return IOU_ISSUE_SKIP_COMPLETE;
+}
+
 static void io_msg_tw_complete(struct callback_head *head)
 {
        struct io_msg *msg = container_of(head, struct io_msg, tw);
@@ -43,61 +88,54 @@ static void io_msg_tw_complete(struct callback_head *head)
        struct io_ring_ctx *target_ctx = req->file->private_data;
        int ret = 0;
 
-       if (current->flags & PF_EXITING)
+       if (current->flags & PF_EXITING) {
                ret = -EOWNERDEAD;
-       else if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
-               ret = -EOVERFLOW;
+       } else {
+               /*
+                * If the target ring is using IOPOLL mode, then we need to be
+                * holding the uring_lock for posting completions. Other ring
+                * types rely on the regular completion locking, which is
+                * handled while posting.
+                */
+               if (target_ctx->flags & IORING_SETUP_IOPOLL)
+                       mutex_lock(&target_ctx->uring_lock);
+               if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
+                       ret = -EOVERFLOW;
+               if (target_ctx->flags & IORING_SETUP_IOPOLL)
+                       mutex_unlock(&target_ctx->uring_lock);
+       }
 
        if (ret < 0)
                req_set_fail(req);
        io_req_queue_tw_complete(req, ret);
 }
 
-static int io_msg_ring_data(struct io_kiocb *req)
+static int io_msg_ring_data(struct io_kiocb *req, unsigned int issue_flags)
 {
        struct io_ring_ctx *target_ctx = req->file->private_data;
        struct io_msg *msg = io_kiocb_to_cmd(req, struct io_msg);
+       int ret;
 
        if (msg->src_fd || msg->dst_fd || msg->flags)
                return -EINVAL;
+       if (target_ctx->flags & IORING_SETUP_R_DISABLED)
+               return -EBADFD;
 
-       if (target_ctx->task_complete && current != target_ctx->submitter_task) {
-               init_task_work(&msg->tw, io_msg_tw_complete);
-               if (task_work_add(target_ctx->submitter_task, &msg->tw,
-                                 TWA_SIGNAL_NO_IPI))
-                       return -EOWNERDEAD;
-
-               atomic_or(IORING_SQ_TASKRUN, &target_ctx->rings->sq_flags);
-               return IOU_ISSUE_SKIP_COMPLETE;
-       }
-
-       if (io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
-               return 0;
+       if (io_msg_need_remote(target_ctx))
+               return io_msg_exec_remote(req, io_msg_tw_complete);
 
-       return -EOVERFLOW;
-}
-
-static void io_double_unlock_ctx(struct io_ring_ctx *octx,
-                                unsigned int issue_flags)
-{
-       mutex_unlock(&octx->uring_lock);
-}
-
-static int io_double_lock_ctx(struct io_ring_ctx *octx,
-                             unsigned int issue_flags)
-{
-       /*
-        * To ensure proper ordering between the two ctxs, we can only
-        * attempt a trylock on the target. If that fails and we already have
-        * the source ctx lock, punt to io-wq.
-        */
-       if (!(issue_flags & IO_URING_F_UNLOCKED)) {
-               if (!mutex_trylock(&octx->uring_lock))
+       ret = -EOVERFLOW;
+       if (target_ctx->flags & IORING_SETUP_IOPOLL) {
+               if (unlikely(io_double_lock_ctx(target_ctx, issue_flags)))
                        return -EAGAIN;
-               return 0;
+               if (io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
+                       ret = 0;
+               io_double_unlock_ctx(target_ctx);
+       } else {
+               if (io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
+                       ret = 0;
        }
-       mutex_lock(&octx->uring_lock);
-       return 0;
+       return ret;
 }
 
 static struct file *io_msg_grab_file(struct io_kiocb *req, unsigned int issue_flags)
@@ -148,7 +186,7 @@ static int io_msg_install_complete(struct io_kiocb *req, unsigned int issue_flag
        if (!io_post_aux_cqe(target_ctx, msg->user_data, msg->len, 0))
                ret = -EOVERFLOW;
 out_unlock:
-       io_double_unlock_ctx(target_ctx, issue_flags);
+       io_double_unlock_ctx(target_ctx);
        return ret;
 }
 
@@ -174,6 +212,8 @@ static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags)
 
        if (target_ctx == ctx)
                return -EINVAL;
+       if (target_ctx->flags & IORING_SETUP_R_DISABLED)
+               return -EBADFD;
        if (!src_file) {
                src_file = io_msg_grab_file(req, issue_flags);
                if (!src_file)
@@ -182,14 +222,8 @@ static int io_msg_send_fd(struct io_kiocb *req, unsigned int issue_flags)
                req->flags |= REQ_F_NEED_CLEANUP;
        }
 
-       if (target_ctx->task_complete && current != target_ctx->submitter_task) {
-               init_task_work(&msg->tw, io_msg_tw_fd_complete);
-               if (task_work_add(target_ctx->submitter_task, &msg->tw,
-                                 TWA_SIGNAL))
-                       return -EOWNERDEAD;
-
-               return IOU_ISSUE_SKIP_COMPLETE;
-       }
+       if (io_msg_need_remote(target_ctx))
+               return io_msg_exec_remote(req, io_msg_tw_fd_complete);
        return io_msg_install_complete(req, issue_flags);
 }
 
@@ -224,7 +258,7 @@ int io_msg_ring(struct io_kiocb *req, unsigned int issue_flags)
 
        switch (msg->cmd) {
        case IORING_MSG_DATA:
-               ret = io_msg_ring_data(req);
+               ret = io_msg_ring_data(req, issue_flags);
                break;
        case IORING_MSG_SEND_FD:
                ret = io_msg_send_fd(req, issue_flags);
index fbc34a7..90326b2 100644 (file)
@@ -62,6 +62,7 @@ struct io_sr_msg {
        u16                             flags;
        /* initialised and used only by !msg send variants */
        u16                             addr_len;
+       u16                             buf_group;
        void __user                     *addr;
        /* used only for send zerocopy */
        struct io_kiocb                 *notif;
@@ -580,6 +581,15 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                if (req->opcode == IORING_OP_RECV && sr->len)
                        return -EINVAL;
                req->flags |= REQ_F_APOLL_MULTISHOT;
+               /*
+                * Store the buffer group for this multishot receive separately,
+                * as if we end up doing an io-wq based issue that selects a
+                * buffer, it has to be committed immediately and that will
+                * clear ->buf_list. This means we lose the link to the buffer
+                * list, and the eventual buffer put on completion then cannot
+                * restore it.
+                */
+               sr->buf_group = req->buf_index;
        }
 
 #ifdef CONFIG_COMPAT
@@ -596,6 +606,7 @@ static inline void io_recv_prep_retry(struct io_kiocb *req)
 
        sr->done_io = 0;
        sr->len = 0; /* get from the provided buffer */
+       req->buf_index = sr->buf_group;
 }
 
 /*
index ee7da61..2ac1366 100644 (file)
@@ -223,21 +223,22 @@ enum {
        IOU_POLL_DONE = 0,
        IOU_POLL_NO_ACTION = 1,
        IOU_POLL_REMOVE_POLL_USE_RES = 2,
+       IOU_POLL_REISSUE = 3,
 };
 
 /*
  * All poll tw should go through this. Checks for poll events, manages
  * references, does rewait, etc.
  *
- * Returns a negative error on failure. IOU_POLL_NO_ACTION when no action require,
- * which is either spurious wakeup or multishot CQE is served.
- * IOU_POLL_DONE when it's done with the request, then the mask is stored in req->cqe.res.
- * IOU_POLL_REMOVE_POLL_USE_RES indicates to remove multishot poll and that the result
- * is stored in req->cqe.
+ * Returns a negative error on failure. IOU_POLL_NO_ACTION when no action
+ * require, which is either spurious wakeup or multishot CQE is served.
+ * IOU_POLL_DONE when it's done with the request, then the mask is stored in
+ * req->cqe.res. IOU_POLL_REMOVE_POLL_USE_RES indicates to remove multishot
+ * poll and that the result is stored in req->cqe.
  */
 static int io_poll_check_events(struct io_kiocb *req, bool *locked)
 {
-       int v, ret;
+       int v;
 
        /* req->task == current here, checking PF_EXITING is safe */
        if (unlikely(req->task->flags & PF_EXITING))
@@ -276,10 +277,19 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
                if (!req->cqe.res) {
                        struct poll_table_struct pt = { ._key = req->apoll_events };
                        req->cqe.res = vfs_poll(req->file, &pt) & req->apoll_events;
+                       /*
+                        * We got woken with a mask, but someone else got to
+                        * it first. The above vfs_poll() doesn't add us back
+                        * to the waitqueue, so if we get nothing back, we
+                        * should be safe and attempt a reissue.
+                        */
+                       if (unlikely(!req->cqe.res)) {
+                               /* Multishot armed need not reissue */
+                               if (!(req->apoll_events & EPOLLONESHOT))
+                                       continue;
+                               return IOU_POLL_REISSUE;
+                       }
                }
-
-               if ((unlikely(!req->cqe.res)))
-                       continue;
                if (req->apoll_events & EPOLLONESHOT)
                        return IOU_POLL_DONE;
 
@@ -294,7 +304,7 @@ static int io_poll_check_events(struct io_kiocb *req, bool *locked)
                                return IOU_POLL_REMOVE_POLL_USE_RES;
                        }
                } else {
-                       ret = io_poll_issue(req, locked);
+                       int ret = io_poll_issue(req, locked);
                        if (ret == IOU_STOP_MULTISHOT)
                                return IOU_POLL_REMOVE_POLL_USE_RES;
                        if (ret < 0)
@@ -330,6 +340,9 @@ static void io_poll_task_func(struct io_kiocb *req, bool *locked)
 
                        poll = io_kiocb_to_cmd(req, struct io_poll);
                        req->cqe.res = mangle_poll(req->cqe.res & poll->events);
+               } else if (ret == IOU_POLL_REISSUE) {
+                       io_req_task_submit(req, locked);
+                       return;
                } else if (ret != IOU_POLL_REMOVE_POLL_USE_RES) {
                        req->cqe.res = ret;
                        req_set_fail(req);
@@ -342,7 +355,7 @@ static void io_poll_task_func(struct io_kiocb *req, bool *locked)
 
                if (ret == IOU_POLL_REMOVE_POLL_USE_RES)
                        io_req_task_complete(req, locked);
-               else if (ret == IOU_POLL_DONE)
+               else if (ret == IOU_POLL_DONE || ret == IOU_POLL_REISSUE)
                        io_req_task_submit(req, locked);
                else
                        io_req_defer_failed(req, ret);
@@ -533,6 +546,14 @@ static bool io_poll_can_finish_inline(struct io_kiocb *req,
        return pt->owning || io_poll_get_ownership(req);
 }
 
+static void io_poll_add_hash(struct io_kiocb *req)
+{
+       if (req->flags & REQ_F_HASH_LOCKED)
+               io_poll_req_insert_locked(req);
+       else
+               io_poll_req_insert(req);
+}
+
 /*
  * Returns 0 when it's handed over for polling. The caller owns the requests if
  * it returns non-zero, but otherwise should not touch it. Negative values
@@ -591,18 +612,17 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
 
        if (mask &&
           ((poll->events & (EPOLLET|EPOLLONESHOT)) == (EPOLLET|EPOLLONESHOT))) {
-               if (!io_poll_can_finish_inline(req, ipt))
+               if (!io_poll_can_finish_inline(req, ipt)) {
+                       io_poll_add_hash(req);
                        return 0;
+               }
                io_poll_remove_entries(req);
                ipt->result_mask = mask;
                /* no one else has access to the req, forget about the ref */
                return 1;
        }
 
-       if (req->flags & REQ_F_HASH_LOCKED)
-               io_poll_req_insert_locked(req);
-       else
-               io_poll_req_insert(req);
+       io_poll_add_hash(req);
 
        if (mask && (poll->events & EPOLLET) &&
            io_poll_can_finish_inline(req, ipt)) {
index 8227af2..9c3ddd4 100644 (file)
@@ -1062,7 +1062,11 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
                        continue;
 
                req->cqe.flags = io_put_kbuf(req, 0);
-               io_fill_cqe_req(req->ctx, req);
+               if (unlikely(!__io_fill_cqe_req(ctx, req))) {
+                       spin_lock(&ctx->completion_lock);
+                       io_req_cqe_overflow(req);
+                       spin_unlock(&ctx->completion_lock);
+               }
        }
 
        if (unlikely(!nr_events))
index a4a41ee..e14c822 100644 (file)
@@ -51,7 +51,6 @@ BTF_SET_END(bpf_lsm_current_hooks)
  */
 BTF_SET_START(bpf_lsm_locked_sockopt_hooks)
 #ifdef CONFIG_SECURITY_NETWORK
-BTF_ID(func, bpf_lsm_socket_sock_rcv_skb)
 BTF_ID(func, bpf_lsm_sock_graft)
 BTF_ID(func, bpf_lsm_inet_csk_clone)
 BTF_ID(func, bpf_lsm_inet_conn_established)
index f7dd8af..b7017ca 100644 (file)
@@ -7782,9 +7782,9 @@ int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_c
 
        sort(tab->dtors, tab->cnt, sizeof(tab->dtors[0]), btf_id_cmp_func, NULL);
 
-       return 0;
 end:
-       btf_free_dtor_kfunc_tab(btf);
+       if (ret)
+               btf_free_dtor_kfunc_tab(btf);
        btf_put(btf);
        return ret;
 }
index 5aa2b55..66bded1 100644 (file)
@@ -152,7 +152,7 @@ static inline int htab_lock_bucket(const struct bpf_htab *htab,
 {
        unsigned long flags;
 
-       hash = hash & HASHTAB_MAP_LOCK_MASK;
+       hash = hash & min_t(u32, HASHTAB_MAP_LOCK_MASK, htab->n_buckets - 1);
 
        preempt_disable();
        if (unlikely(__this_cpu_inc_return(*(htab->map_locked[hash])) != 1)) {
@@ -171,7 +171,7 @@ static inline void htab_unlock_bucket(const struct bpf_htab *htab,
                                      struct bucket *b, u32 hash,
                                      unsigned long flags)
 {
-       hash = hash & HASHTAB_MAP_LOCK_MASK;
+       hash = hash & min_t(u32, HASHTAB_MAP_LOCK_MASK, htab->n_buckets - 1);
        raw_spin_unlock_irqrestore(&b->raw_lock, flags);
        __this_cpu_dec(*(htab->map_locked[hash]));
        preempt_enable();
index ebcc3dd..1db1564 100644 (file)
@@ -71,7 +71,7 @@ static int bpf_mem_cache_idx(size_t size)
        if (size <= 192)
                return size_index[(size - 1) / 8] - 1;
 
-       return fls(size - 1) - 1;
+       return fls(size - 1) - 2;
 }
 
 #define NUM_CACHES 11
index 13e4efc..190d9f9 100644 (file)
@@ -216,9 +216,6 @@ static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
        if (offload->dev_state)
                offload->offdev->ops->destroy(prog);
 
-       /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
-       bpf_prog_free_id(prog, true);
-
        list_del_init(&offload->offloads);
        kfree(offload);
        prog->aux->offload = NULL;
index 64131f8..ecca936 100644 (file)
@@ -1972,7 +1972,7 @@ static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
                return;
        if (audit_enabled == AUDIT_OFF)
                return;
-       if (op == BPF_AUDIT_LOAD)
+       if (!in_irq() && !irqs_disabled())
                ctx = audit_context();
        ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
        if (unlikely(!ab))
@@ -2001,7 +2001,7 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
        return id > 0 ? 0 : id;
 }
 
-void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
+void bpf_prog_free_id(struct bpf_prog *prog)
 {
        unsigned long flags;
 
@@ -2013,18 +2013,10 @@ void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
        if (!prog->aux->id)
                return;
 
-       if (do_idr_lock)
-               spin_lock_irqsave(&prog_idr_lock, flags);
-       else
-               __acquire(&prog_idr_lock);
-
+       spin_lock_irqsave(&prog_idr_lock, flags);
        idr_remove(&prog_idr, prog->aux->id);
        prog->aux->id = 0;
-
-       if (do_idr_lock)
-               spin_unlock_irqrestore(&prog_idr_lock, flags);
-       else
-               __release(&prog_idr_lock);
+       spin_unlock_irqrestore(&prog_idr_lock, flags);
 }
 
 static void __bpf_prog_put_rcu(struct rcu_head *rcu)
@@ -2067,17 +2059,15 @@ static void bpf_prog_put_deferred(struct work_struct *work)
        prog = aux->prog;
        perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
        bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
+       bpf_prog_free_id(prog);
        __bpf_prog_put_noref(prog, true);
 }
 
-static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
+static void __bpf_prog_put(struct bpf_prog *prog)
 {
        struct bpf_prog_aux *aux = prog->aux;
 
        if (atomic64_dec_and_test(&aux->refcnt)) {
-               /* bpf_prog_free_id() must be called first */
-               bpf_prog_free_id(prog, do_idr_lock);
-
                if (in_irq() || irqs_disabled()) {
                        INIT_WORK(&aux->work, bpf_prog_put_deferred);
                        schedule_work(&aux->work);
@@ -2089,7 +2079,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
 
 void bpf_prog_put(struct bpf_prog *prog)
 {
-       __bpf_prog_put(prog, true);
+       __bpf_prog_put(prog);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_put);
 
index 85f96c1..7ee2188 100644 (file)
@@ -2748,6 +2748,12 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
                         */
                        if (insn->src_reg == 0 && is_callback_calling_function(insn->imm))
                                return -ENOTSUPP;
+                       /* kfunc with imm==0 is invalid and fixup_kfunc_call will
+                        * catch this error later. Make backtracking conservative
+                        * with ENOTSUPP.
+                        */
+                       if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL && insn->imm == 0)
+                               return -ENOTSUPP;
                        /* regular helper call sets R0 */
                        *reg_mask &= ~1;
                        if (*reg_mask & 0x3f) {
@@ -3237,13 +3243,24 @@ static bool __is_pointer_value(bool allow_ptr_leaks,
        return reg->type != SCALAR_VALUE;
 }
 
+/* Copy src state preserving dst->parent and dst->live fields */
+static void copy_register_state(struct bpf_reg_state *dst, const struct bpf_reg_state *src)
+{
+       struct bpf_reg_state *parent = dst->parent;
+       enum bpf_reg_liveness live = dst->live;
+
+       *dst = *src;
+       dst->parent = parent;
+       dst->live = live;
+}
+
 static void save_register_state(struct bpf_func_state *state,
                                int spi, struct bpf_reg_state *reg,
                                int size)
 {
        int i;
 
-       state->stack[spi].spilled_ptr = *reg;
+       copy_register_state(&state->stack[spi].spilled_ptr, reg);
        if (size == BPF_REG_SIZE)
                state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN;
 
@@ -3289,7 +3306,9 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
                bool sanitize = reg && is_spillable_regtype(reg->type);
 
                for (i = 0; i < size; i++) {
-                       if (state->stack[spi].slot_type[i] == STACK_INVALID) {
+                       u8 type = state->stack[spi].slot_type[i];
+
+                       if (type != STACK_MISC && type != STACK_ZERO) {
                                sanitize = true;
                                break;
                        }
@@ -3569,7 +3588,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
                                 */
                                s32 subreg_def = state->regs[dst_regno].subreg_def;
 
-                               state->regs[dst_regno] = *reg;
+                               copy_register_state(&state->regs[dst_regno], reg);
                                state->regs[dst_regno].subreg_def = subreg_def;
                        } else {
                                for (i = 0; i < size; i++) {
@@ -3590,7 +3609,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
 
                if (dst_regno >= 0) {
                        /* restore register state from stack */
-                       state->regs[dst_regno] = *reg;
+                       copy_register_state(&state->regs[dst_regno], reg);
                        /* mark reg as written since spilled pointer state likely
                         * has its liveness marks cleared by is_state_visited()
                         * which resets stack/reg liveness for state transitions
@@ -9584,7 +9603,7 @@ do_sim:
         */
        if (!ptr_is_dst_reg) {
                tmp = *dst_reg;
-               *dst_reg = *ptr_reg;
+               copy_register_state(dst_reg, ptr_reg);
        }
        ret = sanitize_speculative_path(env, NULL, env->insn_idx + 1,
                                        env->insn_idx);
@@ -10837,7 +10856,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                                         * to propagate min/max range.
                                         */
                                        src_reg->id = ++env->id_gen;
-                               *dst_reg = *src_reg;
+                               copy_register_state(dst_reg, src_reg);
                                dst_reg->live |= REG_LIVE_WRITTEN;
                                dst_reg->subreg_def = DEF_NOT_SUBREG;
                        } else {
@@ -10848,7 +10867,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                                                insn->src_reg);
                                        return -EACCES;
                                } else if (src_reg->type == SCALAR_VALUE) {
-                                       *dst_reg = *src_reg;
+                                       copy_register_state(dst_reg, src_reg);
                                        /* Make sure ID is cleared otherwise
                                         * dst_reg min/max could be incorrectly
                                         * propagated into src_reg by find_equal_scalars()
@@ -11647,7 +11666,7 @@ static void find_equal_scalars(struct bpf_verifier_state *vstate,
 
        bpf_for_each_reg_in_vstate(vstate, state, reg, ({
                if (reg->type == SCALAR_VALUE && reg->id == known_reg->id)
-                       *reg = *known_reg;
+                       copy_register_state(reg, known_reg);
        }));
 }
 
index a29c0b1..ca826bd 100644 (file)
@@ -1205,12 +1205,13 @@ void rebuild_sched_domains(void)
 /**
  * update_tasks_cpumask - Update the cpumasks of tasks in the cpuset.
  * @cs: the cpuset in which each task's cpus_allowed mask needs to be changed
+ * @new_cpus: the temp variable for the new effective_cpus mask
  *
  * Iterate through each task of @cs updating its cpus_allowed to the
  * effective cpuset's.  As this function is called with cpuset_rwsem held,
  * cpuset membership stays stable.
  */
-static void update_tasks_cpumask(struct cpuset *cs)
+static void update_tasks_cpumask(struct cpuset *cs, struct cpumask *new_cpus)
 {
        struct css_task_iter it;
        struct task_struct *task;
@@ -1224,7 +1225,10 @@ static void update_tasks_cpumask(struct cpuset *cs)
                if (top_cs && (task->flags & PF_KTHREAD) &&
                    kthread_is_per_cpu(task))
                        continue;
-               set_cpus_allowed_ptr(task, cs->effective_cpus);
+
+               cpumask_and(new_cpus, cs->effective_cpus,
+                           task_cpu_possible_mask(task));
+               set_cpus_allowed_ptr(task, new_cpus);
        }
        css_task_iter_end(&it);
 }
@@ -1346,7 +1350,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
                 * A parent can be left with no CPU as long as there is no
                 * task directly associated with the parent partition.
                 */
-               if (!cpumask_intersects(cs->cpus_allowed, parent->effective_cpus) &&
+               if (cpumask_subset(parent->effective_cpus, cs->cpus_allowed) &&
                    partition_is_populated(parent, cs))
                        return PERR_NOCPUS;
 
@@ -1509,7 +1513,7 @@ static int update_parent_subparts_cpumask(struct cpuset *cs, int cmd,
        spin_unlock_irq(&callback_lock);
 
        if (adding || deleting)
-               update_tasks_cpumask(parent);
+               update_tasks_cpumask(parent, tmp->new_cpus);
 
        /*
         * Set or clear CS_SCHED_LOAD_BALANCE when partcmd_update, if necessary.
@@ -1661,7 +1665,7 @@ update_parent_subparts:
                WARN_ON(!is_in_v2_mode() &&
                        !cpumask_equal(cp->cpus_allowed, cp->effective_cpus));
 
-               update_tasks_cpumask(cp);
+               update_tasks_cpumask(cp, tmp->new_cpus);
 
                /*
                 * On legacy hierarchy, if the effective cpumask of any non-
@@ -2309,7 +2313,7 @@ static int update_prstate(struct cpuset *cs, int new_prs)
                }
        }
 
-       update_tasks_cpumask(parent);
+       update_tasks_cpumask(parent, tmpmask.new_cpus);
 
        if (parent->child_ecpus_count)
                update_sibling_cpumasks(parent, cs, &tmpmask);
@@ -2324,6 +2328,7 @@ out:
                new_prs = -new_prs;
        spin_lock_irq(&callback_lock);
        cs->partition_root_state = new_prs;
+       WRITE_ONCE(cs->prs_err, err);
        spin_unlock_irq(&callback_lock);
        /*
         * Update child cpusets, if present.
@@ -3347,7 +3352,7 @@ hotplug_update_tasks_legacy(struct cpuset *cs,
         * as the tasks will be migrated to an ancestor.
         */
        if (cpus_updated && !cpumask_empty(cs->cpus_allowed))
-               update_tasks_cpumask(cs);
+               update_tasks_cpumask(cs, new_cpus);
        if (mems_updated && !nodes_empty(cs->mems_allowed))
                update_tasks_nodemask(cs);
 
@@ -3384,7 +3389,7 @@ hotplug_update_tasks(struct cpuset *cs,
        spin_unlock_irq(&callback_lock);
 
        if (cpus_updated)
-               update_tasks_cpumask(cs);
+               update_tasks_cpumask(cs, new_cpus);
        if (mems_updated)
                update_tasks_nodemask(cs);
 }
@@ -3691,15 +3696,38 @@ void __init cpuset_init_smp(void)
  * Description: Returns the cpumask_var_t cpus_allowed of the cpuset
  * attached to the specified @tsk.  Guaranteed to return some non-empty
  * subset of cpu_online_mask, even if this means going outside the
- * tasks cpuset.
+ * tasks cpuset, except when the task is in the top cpuset.
  **/
 
 void cpuset_cpus_allowed(struct task_struct *tsk, struct cpumask *pmask)
 {
        unsigned long flags;
+       struct cpuset *cs;
 
        spin_lock_irqsave(&callback_lock, flags);
-       guarantee_online_cpus(tsk, pmask);
+       rcu_read_lock();
+
+       cs = task_cs(tsk);
+       if (cs != &top_cpuset)
+               guarantee_online_cpus(tsk, pmask);
+       /*
+        * Tasks in the top cpuset won't get update to their cpumasks
+        * when a hotplug online/offline event happens. So we include all
+        * offline cpus in the allowed cpu list.
+        */
+       if ((cs == &top_cpuset) || cpumask_empty(pmask)) {
+               const struct cpumask *possible_mask = task_cpu_possible_mask(tsk);
+
+               /*
+                * We first exclude cpus allocated to partitions. If there is no
+                * allowable online cpu left, we fall back to all possible cpus.
+                */
+               cpumask_andnot(pmask, possible_mask, top_cpuset.subparts_cpus);
+               if (!cpumask_intersects(pmask, cpu_online_mask))
+                       cpumask_copy(pmask, possible_mask);
+       }
+
+       rcu_read_unlock();
        spin_unlock_irqrestore(&callback_lock, flags);
 }
 
index d56328e..c4be13e 100644 (file)
@@ -4813,19 +4813,17 @@ find_get_pmu_context(struct pmu *pmu, struct perf_event_context *ctx,
 
                cpc = per_cpu_ptr(pmu->cpu_pmu_context, event->cpu);
                epc = &cpc->epc;
-
+               raw_spin_lock_irq(&ctx->lock);
                if (!epc->ctx) {
                        atomic_set(&epc->refcount, 1);
                        epc->embedded = 1;
-                       raw_spin_lock_irq(&ctx->lock);
                        list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list);
                        epc->ctx = ctx;
-                       raw_spin_unlock_irq(&ctx->lock);
                } else {
                        WARN_ON_ONCE(epc->ctx != ctx);
                        atomic_inc(&epc->refcount);
                }
-
+               raw_spin_unlock_irq(&ctx->lock);
                return epc;
        }
 
@@ -4896,33 +4894,30 @@ static void free_epc_rcu(struct rcu_head *head)
 
 static void put_pmu_ctx(struct perf_event_pmu_context *epc)
 {
+       struct perf_event_context *ctx = epc->ctx;
        unsigned long flags;
 
-       if (!atomic_dec_and_test(&epc->refcount))
+       /*
+        * XXX
+        *
+        * lockdep_assert_held(&ctx->mutex);
+        *
+        * can't because of the call-site in _free_event()/put_event()
+        * which isn't always called under ctx->mutex.
+        */
+       if (!atomic_dec_and_raw_lock_irqsave(&epc->refcount, &ctx->lock, flags))
                return;
 
-       if (epc->ctx) {
-               struct perf_event_context *ctx = epc->ctx;
+       WARN_ON_ONCE(list_empty(&epc->pmu_ctx_entry));
 
-               /*
-                * XXX
-                *
-                * lockdep_assert_held(&ctx->mutex);
-                *
-                * can't because of the call-site in _free_event()/put_event()
-                * which isn't always called under ctx->mutex.
-                */
-
-               WARN_ON_ONCE(list_empty(&epc->pmu_ctx_entry));
-               raw_spin_lock_irqsave(&ctx->lock, flags);
-               list_del_init(&epc->pmu_ctx_entry);
-               epc->ctx = NULL;
-               raw_spin_unlock_irqrestore(&ctx->lock, flags);
-       }
+       list_del_init(&epc->pmu_ctx_entry);
+       epc->ctx = NULL;
 
        WARN_ON_ONCE(!list_empty(&epc->pinned_active));
        WARN_ON_ONCE(!list_empty(&epc->flexible_active));
 
+       raw_spin_unlock_irqrestore(&ctx->lock, flags);
+
        if (epc->embedded)
                return;
 
index 473036b..81b97f0 100755 (executable)
@@ -14,6 +14,8 @@ include/
 arch/$SRCARCH/include/
 "
 
+type cpio > /dev/null
+
 # Support incremental builds by skipping archive generation
 # if timestamps of files being archived are not changed.
 
index 8fe1da9..798a904 100644 (file)
@@ -114,7 +114,7 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
 {
        struct irqchip_fwid *fwid;
 
-       if (WARN_ON(!is_fwnode_irqchip(fwnode)))
+       if (!fwnode || WARN_ON(!is_fwnode_irqchip(fwnode)))
                return;
 
        fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
@@ -1915,7 +1915,7 @@ static void debugfs_add_domain_dir(struct irq_domain *d)
 
 static void debugfs_remove_domain_dir(struct irq_domain *d)
 {
-       debugfs_remove(debugfs_lookup(d->name, domain_dir));
+       debugfs_lookup_and_remove(d->name, domain_dir);
 }
 
 void __init irq_domain_debugfs_init(struct dentry *root)
index 955267b..783a3e6 100644 (file)
@@ -1000,7 +1000,7 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid,
 fail:
        msi_unlock_descs(dev);
 free_fwnode:
-       kfree(fwnode);
+       irq_domain_free_fwnode(fwnode);
 free_bundle:
        kfree(bundle);
        return false;
@@ -1013,6 +1013,7 @@ free_bundle:
  */
 void msi_remove_device_irq_domain(struct device *dev, unsigned int domid)
 {
+       struct fwnode_handle *fwnode = NULL;
        struct msi_domain_info *info;
        struct irq_domain *domain;
 
@@ -1025,7 +1026,10 @@ void msi_remove_device_irq_domain(struct device *dev, unsigned int domid)
 
        dev->msi.data->__domains[domid].domain = NULL;
        info = domain->host_data;
+       if (irq_domain_is_msi_device(domain))
+               fwnode = domain->fwnode;
        irq_domain_remove(domain);
+       irq_domain_free_fwnode(fwnode);
        kfree(container_of(info, struct msi_domain_template, info));
 
 unlock:
index f35d9cc..bfbc12d 100644 (file)
@@ -157,14 +157,11 @@ static void test_kallsyms_compression_ratio(void)
 static int lookup_name(void *data, const char *name, struct module *mod, unsigned long addr)
 {
        u64 t0, t1, t;
-       unsigned long flags;
        struct test_stat *stat = (struct test_stat *)data;
 
-       local_irq_save(flags);
-       t0 = sched_clock();
+       t0 = ktime_get_ns();
        (void)kallsyms_lookup_name(name);
-       t1 = sched_clock();
-       local_irq_restore(flags);
+       t1 = ktime_get_ns();
 
        t = t1 - t0;
        if (t < stat->min)
@@ -234,18 +231,15 @@ static int find_symbol(void *data, const char *name, struct module *mod, unsigne
 static void test_perf_kallsyms_on_each_symbol(void)
 {
        u64 t0, t1;
-       unsigned long flags;
        struct test_stat stat;
 
        memset(&stat, 0, sizeof(stat));
        stat.max = INT_MAX;
        stat.name = stub_name;
        stat.perf = 1;
-       local_irq_save(flags);
-       t0 = sched_clock();
+       t0 = ktime_get_ns();
        kallsyms_on_each_symbol(find_symbol, &stat);
-       t1 = sched_clock();
-       local_irq_restore(flags);
+       t1 = ktime_get_ns();
        pr_info("kallsyms_on_each_symbol() traverse all: %lld ns\n", t1 - t0);
 }
 
@@ -270,17 +264,14 @@ static int match_symbol(void *data, unsigned long addr)
 static void test_perf_kallsyms_on_each_match_symbol(void)
 {
        u64 t0, t1;
-       unsigned long flags;
        struct test_stat stat;
 
        memset(&stat, 0, sizeof(stat));
        stat.max = INT_MAX;
        stat.name = stub_name;
-       local_irq_save(flags);
-       t0 = sched_clock();
+       t0 = ktime_get_ns();
        kallsyms_on_each_match_symbol(match_symbol, stat.name, &stat);
-       t1 = sched_clock();
-       local_irq_restore(flags);
+       t1 = ktime_get_ns();
        pr_info("kallsyms_on_each_match_symbol() traverse all: %lld ns\n", t1 - t0);
 }
 
index dcec1b7..a60c561 100644 (file)
@@ -159,7 +159,7 @@ static bool __report_matches(const struct expect_report *r)
        const bool is_assert = (r->access[0].type | r->access[1].type) & KCSAN_ACCESS_ASSERT;
        bool ret = false;
        unsigned long flags;
-       typeof(observed.lines) expect;
+       typeof(*observed.lines) *expect;
        const char *end;
        char *cur;
        int i;
@@ -168,6 +168,10 @@ static bool __report_matches(const struct expect_report *r)
        if (!report_available())
                return false;
 
+       expect = kmalloc(sizeof(observed.lines), GFP_KERNEL);
+       if (WARN_ON(!expect))
+               return false;
+
        /* Generate expected report contents. */
 
        /* Title */
@@ -253,6 +257,7 @@ static bool __report_matches(const struct expect_report *r)
                strstr(observed.lines[2], expect[1])));
 out:
        spin_unlock_irqrestore(&observed.lock, flags);
+       kfree(expect);
        return ret;
 }
 
index 010cf4e..728f434 100644 (file)
@@ -901,8 +901,9 @@ static int __sched rt_mutex_adjust_prio_chain(struct task_struct *task,
                 * then we need to wake the new top waiter up to try
                 * to get the lock.
                 */
-               if (prerequeue_top_waiter != rt_mutex_top_waiter(lock))
-                       wake_up_state(waiter->task, waiter->wake_state);
+               top_waiter = rt_mutex_top_waiter(lock);
+               if (prerequeue_top_waiter != top_waiter)
+                       wake_up_state(top_waiter->task, top_waiter->wake_state);
                raw_spin_unlock_irq(&lock->wait_lock);
                return 0;
        }
index 48568a0..4ac3fe4 100644 (file)
@@ -2393,7 +2393,8 @@ static bool finished_loading(const char *name)
        sched_annotate_sleep();
        mutex_lock(&module_mutex);
        mod = find_module_all(name, strlen(name), true);
-       ret = !mod || mod->state == MODULE_STATE_LIVE;
+       ret = !mod || mod->state == MODULE_STATE_LIVE
+               || mod->state == MODULE_STATE_GOING;
        mutex_unlock(&module_mutex);
 
        return ret;
@@ -2569,20 +2570,35 @@ static int add_unformed_module(struct module *mod)
 
        mod->state = MODULE_STATE_UNFORMED;
 
-again:
        mutex_lock(&module_mutex);
        old = find_module_all(mod->name, strlen(mod->name), true);
        if (old != NULL) {
-               if (old->state != MODULE_STATE_LIVE) {
+               if (old->state == MODULE_STATE_COMING
+                   || old->state == MODULE_STATE_UNFORMED) {
                        /* Wait in case it fails to load. */
                        mutex_unlock(&module_mutex);
                        err = wait_event_interruptible(module_wq,
                                               finished_loading(mod->name));
                        if (err)
                                goto out_unlocked;
-                       goto again;
+
+                       /* The module might have gone in the meantime. */
+                       mutex_lock(&module_mutex);
+                       old = find_module_all(mod->name, strlen(mod->name),
+                                             true);
                }
-               err = -EEXIST;
+
+               /*
+                * We are here only when the same module was being loaded. Do
+                * not try to load it again right now. It prevents long delays
+                * caused by serialized module load failures. It might happen
+                * when more devices of the same type trigger load of
+                * a particular module.
+                */
+               if (old && old->state == MODULE_STATE_LIVE)
+                       err = -EEXIST;
+               else
+                       err = -EBUSY;
                goto out;
        }
        mod_update_bounds(mod);
index 60a1d30..4b31629 100644 (file)
@@ -118,7 +118,6 @@ config PM_SLEEP
        def_bool y
        depends on SUSPEND || HIBERNATE_CALLBACKS
        select PM
-       select SRCU
 
 config PM_SLEEP_SMP
        def_bool y
index 277434b..36a1df4 100644 (file)
@@ -581,7 +581,7 @@ static int save_image(struct swap_map_handle *handle,
        return ret;
 }
 
-/**
+/*
  * Structure used for CRC32.
  */
 struct crc_data {
@@ -596,7 +596,7 @@ struct crc_data {
        unsigned char *unc[LZO_THREADS];          /* uncompressed data */
 };
 
-/**
+/*
  * CRC32 update function that runs in its own thread.
  */
 static int crc32_threadfn(void *data)
@@ -623,7 +623,7 @@ static int crc32_threadfn(void *data)
        }
        return 0;
 }
-/**
+/*
  * Structure used for LZO data compression.
  */
 struct cmp_data {
@@ -640,7 +640,7 @@ struct cmp_data {
        unsigned char wrk[LZO1X_1_MEM_COMPRESS];  /* compression workspace */
 };
 
-/**
+/*
  * Compression function that runs in its own thread.
  */
 static int lzo_compress_threadfn(void *data)
@@ -948,9 +948,9 @@ out_finish:
        return error;
 }
 
-/**
+/*
  *     The following functions allow us to read data using a swap map
- *     in a file-alike way
+ *     in a file-like way.
  */
 
 static void release_swap_reader(struct swap_map_handle *handle)
@@ -1107,7 +1107,7 @@ static int load_image(struct swap_map_handle *handle,
        return ret;
 }
 
-/**
+/*
  * Structure used for LZO data decompression.
  */
 struct dec_data {
@@ -1123,7 +1123,7 @@ struct dec_data {
        unsigned char cmp[LZO_CMP_SIZE];          /* compressed buffer */
 };
 
-/**
+/*
  * Decompression function that runs in its own thread.
  */
 static int lzo_decompress_threadfn(void *data)
index 7decf1e..a5ed2e5 100644 (file)
@@ -123,6 +123,7 @@ bool console_srcu_read_lock_is_held(void)
 {
        return srcu_read_lock_held(&console_srcu);
 }
+EXPORT_SYMBOL(console_srcu_read_lock_is_held);
 #endif
 
 enum devkmsg_log_bits {
@@ -1891,6 +1892,7 @@ static void console_lock_spinning_enable(void)
 /**
  * console_lock_spinning_disable_and_check - mark end of code where another
  *     thread was able to busy wait and check if there is a waiter
+ * @cookie: cookie returned from console_srcu_read_lock()
  *
  * This is called at the end of the section where spinning is allowed.
  * It has two functions. First, it is a signal that it is no longer
index 25b582b..e838feb 100644 (file)
@@ -2604,27 +2604,71 @@ void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
                .user_mask = NULL,
                .flags     = SCA_USER,  /* clear the user requested mask */
        };
+       union cpumask_rcuhead {
+               cpumask_t cpumask;
+               struct rcu_head rcu;
+       };
 
        __do_set_cpus_allowed(p, &ac);
-       kfree(ac.user_mask);
+
+       /*
+        * Because this is called with p->pi_lock held, it is not possible
+        * to use kfree() here (when PREEMPT_RT=y), therefore punt to using
+        * kfree_rcu().
+        */
+       kfree_rcu((union cpumask_rcuhead *)ac.user_mask, rcu);
+}
+
+static cpumask_t *alloc_user_cpus_ptr(int node)
+{
+       /*
+        * See do_set_cpus_allowed() above for the rcu_head usage.
+        */
+       int size = max_t(int, cpumask_size(), sizeof(struct rcu_head));
+
+       return kmalloc_node(size, GFP_KERNEL, node);
 }
 
 int dup_user_cpus_ptr(struct task_struct *dst, struct task_struct *src,
                      int node)
 {
+       cpumask_t *user_mask;
        unsigned long flags;
 
-       if (!src->user_cpus_ptr)
+       /*
+        * Always clear dst->user_cpus_ptr first as their user_cpus_ptr's
+        * may differ by now due to racing.
+        */
+       dst->user_cpus_ptr = NULL;
+
+       /*
+        * This check is racy and losing the race is a valid situation.
+        * It is not worth the extra overhead of taking the pi_lock on
+        * every fork/clone.
+        */
+       if (data_race(!src->user_cpus_ptr))
                return 0;
 
-       dst->user_cpus_ptr = kmalloc_node(cpumask_size(), GFP_KERNEL, node);
-       if (!dst->user_cpus_ptr)
+       user_mask = alloc_user_cpus_ptr(node);
+       if (!user_mask)
                return -ENOMEM;
 
-       /* Use pi_lock to protect content of user_cpus_ptr */
+       /*
+        * Use pi_lock to protect content of user_cpus_ptr
+        *
+        * Though unlikely, user_cpus_ptr can be reset to NULL by a concurrent
+        * do_set_cpus_allowed().
+        */
        raw_spin_lock_irqsave(&src->pi_lock, flags);
-       cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
+       if (src->user_cpus_ptr) {
+               swap(dst->user_cpus_ptr, user_mask);
+               cpumask_copy(dst->user_cpus_ptr, src->user_cpus_ptr);
+       }
        raw_spin_unlock_irqrestore(&src->pi_lock, flags);
+
+       if (unlikely(user_mask))
+               kfree(user_mask);
+
        return 0;
 }
 
@@ -3581,6 +3625,11 @@ static inline bool rq_has_pinned_tasks(struct rq *rq)
        return false;
 }
 
+static inline cpumask_t *alloc_user_cpus_ptr(int node)
+{
+       return NULL;
+}
+
 #endif /* !CONFIG_SMP */
 
 static void
@@ -5504,7 +5553,9 @@ void scheduler_tick(void)
        unsigned long thermal_pressure;
        u64 resched_latency;
 
-       arch_scale_freq_tick();
+       if (housekeeping_cpu(cpu, HK_TYPE_TICK))
+               arch_scale_freq_tick();
+
        sched_clock_tick();
 
        rq_lock(rq, &rf);
@@ -8239,12 +8290,18 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
        if (retval)
                goto out_put_task;
 
-       user_mask = kmalloc(cpumask_size(), GFP_KERNEL);
-       if (!user_mask) {
+       /*
+        * With non-SMP configs, user_cpus_ptr/user_mask isn't used and
+        * alloc_user_cpus_ptr() returns NULL.
+        */
+       user_mask = alloc_user_cpus_ptr(NUMA_NO_NODE);
+       if (user_mask) {
+               cpumask_copy(user_mask, in_mask);
+       } else if (IS_ENABLED(CONFIG_SMP)) {
                retval = -ENOMEM;
                goto out_put_task;
        }
-       cpumask_copy(user_mask, in_mask);
+
        ac = (struct affinity_context){
                .new_mask  = in_mask,
                .user_mask = user_mask,
index c36aa54..0f87369 100644 (file)
@@ -7229,10 +7229,10 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
        eenv_task_busy_time(&eenv, p, prev_cpu);
 
        for (; pd; pd = pd->next) {
+               unsigned long util_min = p_util_min, util_max = p_util_max;
                unsigned long cpu_cap, cpu_thermal_cap, util;
                unsigned long cur_delta, max_spare_cap = 0;
                unsigned long rq_util_min, rq_util_max;
-               unsigned long util_min, util_max;
                unsigned long prev_spare_cap = 0;
                int max_spare_cap_cpu = -1;
                unsigned long base_energy;
@@ -7251,6 +7251,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
                eenv.pd_cap = 0;
 
                for_each_cpu(cpu, cpus) {
+                       struct rq *rq = cpu_rq(cpu);
+
                        eenv.pd_cap += cpu_thermal_cap;
 
                        if (!cpumask_test_cpu(cpu, sched_domain_span(sd)))
@@ -7269,24 +7271,19 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
                         * much capacity we can get out of the CPU; this is
                         * aligned with sched_cpu_util().
                         */
-                       if (uclamp_is_used()) {
-                               if (uclamp_rq_is_idle(cpu_rq(cpu))) {
-                                       util_min = p_util_min;
-                                       util_max = p_util_max;
-                               } else {
-                                       /*
-                                        * Open code uclamp_rq_util_with() except for
-                                        * the clamp() part. Ie: apply max aggregation
-                                        * only. util_fits_cpu() logic requires to
-                                        * operate on non clamped util but must use the
-                                        * max-aggregated uclamp_{min, max}.
-                                        */
-                                       rq_util_min = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MIN);
-                                       rq_util_max = uclamp_rq_get(cpu_rq(cpu), UCLAMP_MAX);
-
-                                       util_min = max(rq_util_min, p_util_min);
-                                       util_max = max(rq_util_max, p_util_max);
-                               }
+                       if (uclamp_is_used() && !uclamp_rq_is_idle(rq)) {
+                               /*
+                                * Open code uclamp_rq_util_with() except for
+                                * the clamp() part. Ie: apply max aggregation
+                                * only. util_fits_cpu() logic requires to
+                                * operate on non clamped util but must use the
+                                * max-aggregated uclamp_{min, max}.
+                                */
+                               rq_util_min = uclamp_rq_get(rq, UCLAMP_MIN);
+                               rq_util_max = uclamp_rq_get(rq, UCLAMP_MAX);
+
+                               util_min = max(rq_util_min, p_util_min);
+                               util_max = max(rq_util_max, p_util_max);
                        }
                        if (!util_fits_cpu(util, util_min, util_max, cpu))
                                continue;
@@ -8871,16 +8868,23 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu)
         *   * Thermal pressure will impact all cpus in this perf domain
         *     equally.
         */
-       if (static_branch_unlikely(&sched_asym_cpucapacity)) {
+       if (sched_energy_enabled()) {
                unsigned long inv_cap = capacity_orig - thermal_load_avg(rq);
-               struct perf_domain *pd = rcu_dereference(rq->rd->pd);
+               struct perf_domain *pd;
 
+               rcu_read_lock();
+
+               pd = rcu_dereference(rq->rd->pd);
                rq->cpu_capacity_inverted = 0;
 
                for (; pd; pd = pd->next) {
                        struct cpumask *pd_span = perf_domain_span(pd);
                        unsigned long pd_cap_orig, pd_cap;
 
+                       /* We can't be inverted against our own pd */
+                       if (cpumask_test_cpu(cpu_of(rq), pd_span))
+                               continue;
+
                        cpu = cpumask_any(pd_span);
                        pd_cap_orig = arch_scale_cpu_capacity(cpu);
 
@@ -8905,6 +8909,8 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu)
                                break;
                        }
                }
+
+               rcu_read_unlock();
        }
 
        trace_sched_cpu_capacity_tp(rq);
index 5fd54bf..88b31f0 100644 (file)
@@ -1442,6 +1442,8 @@ static int do_prlimit(struct task_struct *tsk, unsigned int resource,
 
        if (resource >= RLIM_NLIMITS)
                return -EINVAL;
+       resource = array_index_nospec(resource, RLIM_NLIMITS);
+
        if (new_rlim) {
                if (new_rlim->rlim_cur > new_rlim->rlim_max)
                        return -EINVAL;
index 475ecce..5e2c2c2 100644 (file)
@@ -18,7 +18,7 @@
 #include "tick-internal.h"
 
 /**
- * tick_program_event
+ * tick_program_event - program the CPU local timer device for the next event
  */
 int tick_program_event(ktime_t expires, int force)
 {
@@ -99,7 +99,7 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
 }
 
 /**
- * tick_check_oneshot_mode - check whether the system is in oneshot mode
+ * tick_oneshot_mode_active - check whether the system is in oneshot mode
  *
  * returns 1 when either nohz or highres are enabled. otherwise 0.
  */
index 526257b..f4198af 100644 (file)
@@ -462,7 +462,7 @@ struct __kernel_old_timeval ns_to_kernel_old_timeval(s64 nsec)
 EXPORT_SYMBOL(ns_to_kernel_old_timeval);
 
 /**
- * set_normalized_timespec - set timespec sec and nsec parts and normalize
+ * set_normalized_timespec64 - set timespec sec and nsec parts and normalize
  *
  * @ts:                pointer to timespec variable to be set
  * @sec:       seconds to set
@@ -526,7 +526,7 @@ struct timespec64 ns_to_timespec64(s64 nsec)
 EXPORT_SYMBOL(ns_to_timespec64);
 
 /**
- * msecs_to_jiffies: - convert milliseconds to jiffies
+ * __msecs_to_jiffies: - convert milliseconds to jiffies
  * @m: time in milliseconds
  *
  * conversion is done as follows:
@@ -541,12 +541,12 @@ EXPORT_SYMBOL(ns_to_timespec64);
  *   handling any 32-bit overflows.
  *   for the details see __msecs_to_jiffies()
  *
- * msecs_to_jiffies() checks for the passed in value being a constant
+ * __msecs_to_jiffies() checks for the passed in value being a constant
  * via __builtin_constant_p() allowing gcc to eliminate most of the
  * code, __msecs_to_jiffies() is called if the value passed does not
  * allow constant folding and the actual conversion must be done at
  * runtime.
- * the _msecs_to_jiffies helpers are the HZ dependent conversion
+ * The _msecs_to_jiffies helpers are the HZ dependent conversion
  * routines found in include/linux/jiffies.h
  */
 unsigned long __msecs_to_jiffies(const unsigned int m)
index f72b9f1..5579ead 100644 (file)
@@ -1590,10 +1590,10 @@ void __weak read_persistent_clock64(struct timespec64 *ts)
 /**
  * read_persistent_wall_and_boot_offset - Read persistent clock, and also offset
  *                                        from the boot.
+ * @wall_time:   current time as returned by persistent clock
+ * @boot_offset:  offset that is defined as wall_time - boot_time
  *
  * Weak dummy function for arches that do not yet support it.
- * @wall_time: - current time as returned by persistent clock
- * @boot_offset: - offset that is defined as wall_time - boot_time
  *
  * The default function calculates offset based on the current value of
  * local_clock(). This way architectures that support sched_clock() but don't
@@ -1701,7 +1701,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
 }
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
-/**
+/*
  * We have three kinds of time sources to use for sleep time
  * injection, the preference order is:
  * 1) non-stop clocksource
@@ -1722,7 +1722,7 @@ bool timekeeping_rtc_skipresume(void)
        return !suspend_timing_needed;
 }
 
-/**
+/*
  * 1) can be determined whether to use or not only when doing
  * timekeeping_resume() which is invoked after rtc_suspend(),
  * so we can't skip rtc_suspend() surely if system has 1).
index 1975452..d704304 100644 (file)
@@ -933,8 +933,8 @@ config RING_BUFFER_RECORD_RECURSION
        default y
        help
          The ring buffer has its own internal recursion. Although when
-         recursion happens it wont cause harm because of the protection,
-         but it does cause an unwanted overhead. Enabling this option will
+         recursion happens it won't cause harm because of the protection,
+         but it does cause unwanted overhead. Enabling this option will
          place where recursion was detected into the ftrace "recursed_functions"
          file.
 
@@ -1017,8 +1017,8 @@ config RING_BUFFER_STARTUP_TEST
         The test runs for 10 seconds. This will slow your boot time
         by at least 10 more seconds.
 
-        At the end of the test, statics and more checks are done.
-        It will output the stats of each per cpu buffer. What
+        At the end of the test, statistics and more checks are done.
+        It will output the stats of each per cpu buffer: What
         was written, the sizes, what was read, what was lost, and
         other similar details.
 
index 3bbd3f0..c09792c 100644 (file)
@@ -833,6 +833,7 @@ static void do_bpf_send_signal(struct irq_work *entry)
 
        work = container_of(entry, struct send_signal_irq_work, irq_work);
        group_send_sig_info(work->sig, SEND_SIG_PRIV, work->task, work->type);
+       put_task_struct(work->task);
 }
 
 static int bpf_send_signal_common(u32 sig, enum pid_type type)
@@ -848,6 +849,9 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type)
                return -EPERM;
        if (unlikely(!nmi_uaccess_okay()))
                return -EPERM;
+       /* Task should not be pid=1 to avoid kernel panic. */
+       if (unlikely(is_global_init(current)))
+               return -EPERM;
 
        if (irqs_disabled()) {
                /* Do an early check on signal validity. Otherwise,
@@ -864,7 +868,7 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type)
                 * to the irq_work. The current task may change when queued
                 * irq works get executed.
                 */
-               work->task = current;
+               work->task = get_task_struct(current);
                work->sig = sig;
                work->type = type;
                irq_work_queue(&work->irq_work);
index 442438b..750aa3f 100644 (file)
@@ -1248,12 +1248,17 @@ static void free_ftrace_hash_rcu(struct ftrace_hash *hash)
        call_rcu(&hash->rcu, __free_ftrace_hash_rcu);
 }
 
+/**
+ * ftrace_free_filter - remove all filters for an ftrace_ops
+ * @ops - the ops to remove the filters from
+ */
 void ftrace_free_filter(struct ftrace_ops *ops)
 {
        ftrace_ops_init(ops);
        free_ftrace_hash(ops->func_hash->filter_hash);
        free_ftrace_hash(ops->func_hash->notrace_hash);
 }
+EXPORT_SYMBOL_GPL(ftrace_free_filter);
 
 static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
 {
@@ -5839,6 +5844,10 @@ EXPORT_SYMBOL_GPL(modify_ftrace_direct_multi);
  *
  * Filters denote which functions should be enabled when tracing is enabled
  * If @ip is NULL, it fails to update filter.
+ *
+ * This can allocate memory which must be freed before @ops can be freed,
+ * either by removing each filtered addr or by using
+ * ftrace_free_filter(@ops).
  */
 int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip,
                         int remove, int reset)
@@ -5858,7 +5867,11 @@ EXPORT_SYMBOL_GPL(ftrace_set_filter_ip);
  *
  * 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.
- */
+ *
+ * This can allocate memory which must be freed before @ops can be freed,
+ * either by removing each filtered addr or by using
+ * ftrace_free_filter(@ops).
+*/
 int ftrace_set_filter_ips(struct ftrace_ops *ops, unsigned long *ips,
                          unsigned int cnt, int remove, int reset)
 {
@@ -5900,6 +5913,10 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
  *
  * 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.
+ *
+ * This can allocate memory which must be freed before @ops can be freed,
+ * either by removing each filtered addr or by using
+ * ftrace_free_filter(@ops).
  */
 int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
                       int len, int reset)
@@ -5919,6 +5936,10 @@ EXPORT_SYMBOL_GPL(ftrace_set_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
  * for tracing.
+ *
+ * This can allocate memory which must be freed before @ops can be freed,
+ * either by removing each filtered addr or by using
+ * ftrace_free_filter(@ops).
  */
 int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
                        int len, int reset)
index 6c97cc2..7e90618 100644 (file)
@@ -516,7 +516,7 @@ static ssize_t enabled_monitors_write(struct file *filp, const char __user *user
        struct rv_monitor_def *mdef;
        int retval = -EINVAL;
        bool enable = true;
-       char *ptr = buff;
+       char *ptr;
        int len;
 
        if (count < 1 || count > MAX_RV_MONITOR_NAME_SIZE + 1)
index a555a86..c9e40f6 100644 (file)
@@ -9148,9 +9148,6 @@ buffer_percent_write(struct file *filp, const char __user *ubuf,
        if (val > 100)
                return -EINVAL;
 
-       if (!val)
-               val = 1;
-
        tr->buffer_percent = val;
 
        (*ppos)++;
@@ -10295,6 +10292,8 @@ void __init early_trace_init(void)
                        static_key_enable(&tracepoint_printk_key.key);
        }
        tracer_alloc_buffers();
+
+       init_events();
 }
 
 void __init trace_init(void)
index e46a492..085a31b 100644 (file)
@@ -1282,6 +1282,7 @@ struct ftrace_event_field {
        int                     offset;
        int                     size;
        int                     is_signed;
+       int                     len;
 };
 
 struct prog_entry;
@@ -1490,6 +1491,7 @@ extern void trace_event_enable_cmd_record(bool enable);
 extern void trace_event_enable_tgid_record(bool enable);
 
 extern int event_trace_init(void);
+extern int init_events(void);
 extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
 extern int event_trace_del_tracer(struct trace_array *tr);
 extern void __trace_early_add_events(struct trace_array *tr);
index 33e0b4f..6a46967 100644 (file)
@@ -114,7 +114,7 @@ trace_find_event_field(struct trace_event_call *call, char *name)
 
 static int __trace_define_field(struct list_head *head, const char *type,
                                const char *name, int offset, int size,
-                               int is_signed, int filter_type)
+                               int is_signed, int filter_type, int len)
 {
        struct ftrace_event_field *field;
 
@@ -133,6 +133,7 @@ static int __trace_define_field(struct list_head *head, const char *type,
        field->offset = offset;
        field->size = size;
        field->is_signed = is_signed;
+       field->len = len;
 
        list_add(&field->link, head);
 
@@ -150,14 +151,28 @@ int trace_define_field(struct trace_event_call *call, const char *type,
 
        head = trace_get_fields(call);
        return __trace_define_field(head, type, name, offset, size,
-                                   is_signed, filter_type);
+                                   is_signed, filter_type, 0);
 }
 EXPORT_SYMBOL_GPL(trace_define_field);
 
+int trace_define_field_ext(struct trace_event_call *call, const char *type,
+                      const char *name, int offset, int size, int is_signed,
+                      int filter_type, int len)
+{
+       struct list_head *head;
+
+       if (WARN_ON(!call->class))
+               return 0;
+
+       head = trace_get_fields(call);
+       return __trace_define_field(head, type, name, offset, size,
+                                   is_signed, filter_type, len);
+}
+
 #define __generic_field(type, item, filter_type)                       \
        ret = __trace_define_field(&ftrace_generic_fields, #type,       \
                                   #item, 0, 0, is_signed_type(type),   \
-                                  filter_type);                        \
+                                  filter_type, 0);                     \
        if (ret)                                                        \
                return ret;
 
@@ -166,7 +181,7 @@ EXPORT_SYMBOL_GPL(trace_define_field);
                                   "common_" #item,                     \
                                   offsetof(typeof(ent), item),         \
                                   sizeof(ent.item),                    \
-                                  is_signed_type(type), FILTER_OTHER); \
+                                  is_signed_type(type), FILTER_OTHER, 0);      \
        if (ret)                                                        \
                return ret;
 
@@ -1588,12 +1603,17 @@ static int f_show(struct seq_file *m, void *v)
                seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
                           field->type, field->name, field->offset,
                           field->size, !!field->is_signed);
-       else
-               seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
+       else if (field->len)
+               seq_printf(m, "\tfield:%.*s %s[%d];\toffset:%u;\tsize:%u;\tsigned:%d;\n",
                           (int)(array_descriptor - field->type),
                           field->type, field->name,
-                          array_descriptor, field->offset,
+                          field->len, field->offset,
                           field->size, !!field->is_signed);
+       else
+               seq_printf(m, "\tfield:%.*s %s[];\toffset:%u;\tsize:%u;\tsigned:%d;\n",
+                               (int)(array_descriptor - field->type),
+                               field->type, field->name,
+                               field->offset, field->size, !!field->is_signed);
 
        return 0;
 }
@@ -2379,9 +2399,10 @@ event_define_fields(struct trace_event_call *call)
                        }
 
                        offset = ALIGN(offset, field->align);
-                       ret = trace_define_field(call, field->type, field->name,
+                       ret = trace_define_field_ext(call, field->type, field->name,
                                                 offset, field->size,
-                                                field->is_signed, field->filter_type);
+                                                field->is_signed, field->filter_type,
+                                                field->len);
                        if (WARN_ON_ONCE(ret)) {
                                pr_err("error code is %d\n", ret);
                                break;
index 96acc2b..e095c3b 100644 (file)
@@ -128,7 +128,7 @@ static bool is_not(const char *str)
 }
 
 /**
- * prog_entry - a singe entry in the filter program
+ * struct prog_entry - a singe entry in the filter program
  * @target:         Index to jump to on a branch (actually one minus the index)
  * @when_to_branch:  The value of the result of the predicate to do a branch
  * @pred:           The predicate to execute.
@@ -140,16 +140,16 @@ struct prog_entry {
 };
 
 /**
- * update_preds- assign a program entry a label target
+ * update_preds - assign a program entry a label target
  * @prog: The program array
  * @N: The index of the current entry in @prog
- * @when_to_branch: What to assign a program entry for its branch condition
+ * @invert: What to assign a program entry for its branch condition
  *
  * The program entry at @N has a target that points to the index of a program
  * entry that can have its target and when_to_branch fields updated.
  * Update the current program entry denoted by index @N target field to be
  * that of the updated entry. This will denote the entry to update if
- * we are processing an "||" after an "&&"
+ * we are processing an "||" after an "&&".
  */
 static void update_preds(struct prog_entry *prog, int N, int invert)
 {
index fcaf226..5edbf6b 100644 (file)
@@ -1988,6 +1988,8 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
                hist_field->fn_num = flags & HIST_FIELD_FL_LOG2 ? HIST_FIELD_FN_LOG2 :
                        HIST_FIELD_FN_BUCKET;
                hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL);
+               if (!hist_field->operands[0])
+                       goto free;
                hist_field->size = hist_field->operands[0]->size;
                hist_field->type = kstrdup_const(hist_field->operands[0]->type, GFP_KERNEL);
                if (!hist_field->type)
index d960f6b..58f3946 100644 (file)
@@ -111,7 +111,8 @@ static void __always_unused ____ftrace_check_##name(void)           \
 #define __array(_type, _item, _len) {                                  \
        .type = #_type"["__stringify(_len)"]", .name = #_item,          \
        .size = sizeof(_type[_len]), .align = __alignof__(_type),       \
-       is_signed_type(_type), .filter_type = FILTER_OTHER },
+       is_signed_type(_type), .filter_type = FILTER_OTHER,                     \
+       .len = _len },
 
 #undef __array_desc
 #define __array_desc(_type, _container, _item, _len) __array(_type, _item, _len)
index 94c1b5e..210e1f1 100644 (file)
@@ -147,9 +147,8 @@ static void osnoise_unregister_instance(struct trace_array *tr)
         * register/unregister serialization is provided by trace's
         * trace_types_lock.
         */
-       lockdep_assert_held(&trace_types_lock);
-
-       list_for_each_entry_rcu(inst, &osnoise_instances, list) {
+       list_for_each_entry_rcu(inst, &osnoise_instances, list,
+                               lockdep_is_held(&trace_types_lock)) {
                if (inst->tr == tr) {
                        list_del_rcu(&inst->list);
                        found = 1;
index 57a13b6..bd475a0 100644 (file)
@@ -1535,7 +1535,7 @@ static struct trace_event *events[] __initdata = {
        NULL
 };
 
-__init static int init_events(void)
+__init int init_events(void)
 {
        struct trace_event *event;
        int i, ret;
@@ -1548,4 +1548,3 @@ __init static int init_events(void)
 
        return 0;
 }
-early_initcall(init_events);
index 881c3f8..02ee440 100644 (file)
@@ -754,6 +754,7 @@ config DEBUG_KMEMLEAK
        select KALLSYMS
        select CRC32
        select STACKDEPOT
+       select STACKDEPOT_ALWAYS_INIT if !DEBUG_KMEMLEAK_DEFAULT_OFF
        help
          Say Y here if you want to enable the memory leak
          detector. The memory allocation/freeing is traced in a way
@@ -1207,7 +1208,7 @@ config SCHED_DEBUG
        depends on DEBUG_KERNEL && PROC_FS
        default y
        help
-         If you say Y here, the /proc/sched_debug file will be provided
+         If you say Y here, the /sys/kernel/debug/sched file will be provided
          that can help debug the scheduler. The runtime overhead of this
          option is minimal.
 
@@ -1917,7 +1918,7 @@ config FUNCTION_ERROR_INJECTION
        help
          Add fault injections into various functions that are annotated with
          ALLOW_ERROR_INJECTION() in the kernel. BPF may also modify the return
-         value of theses functions. This is useful to test error paths of code.
+         value of these functions. This is useful to test error paths of code.
 
          If unsure, say N
 
@@ -2566,6 +2567,15 @@ 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.
+
 config IS_SIGNED_TYPE_KUNIT_TEST
        tristate "Test is_signed_type() macro" if !KUNIT_ALL_TESTS
        depends on KUNIT
index 375575a..4dedd61 100644 (file)
@@ -194,7 +194,7 @@ config KCSAN_WEAK_MEMORY
          Enable support for modeling a subset of weak memory, which allows
          detecting a subset of data races due to missing memory barriers.
 
-         Depends on KCSAN_STRICT, because the options strenghtening certain
+         Depends on KCSAN_STRICT, because the options strengthening certain
          plain accesses by default (depending on !KCSAN_STRICT) reduce the
          ability to detect any data races invoving reordered accesses, in
          particular reordered writes.
index 9555b68..1dcca8f 100644 (file)
@@ -49,3 +49,34 @@ int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
        return 0;
 }
 EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave);
+
+int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)
+{
+       /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
+       if (atomic_add_unless(atomic, -1, 1))
+               return 0;
+
+       /* Otherwise do it the slow way */
+       raw_spin_lock(lock);
+       if (atomic_dec_and_test(atomic))
+               return 1;
+       raw_spin_unlock(lock);
+       return 0;
+}
+EXPORT_SYMBOL(_atomic_dec_and_raw_lock);
+
+int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock_t *lock,
+                                    unsigned long *flags)
+{
+       /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
+       if (atomic_add_unless(atomic, -1, 1))
+               return 0;
+
+       /* Otherwise do it the slow way */
+       raw_spin_lock_irqsave(lock, *flags);
+       if (atomic_dec_and_test(atomic))
+               return 1;
+       raw_spin_unlock_irqrestore(lock, *flags);
+       return 0;
+}
+EXPORT_SYMBOL(_atomic_dec_and_raw_lock_irqsave);
index f5b50ba..05a0965 100644 (file)
@@ -241,24 +241,34 @@ void kunit_mem_assert_format(const struct kunit_assert *assert,
        mem_assert = container_of(assert, struct kunit_mem_assert,
                                  assert);
 
-       string_stream_add(stream,
-                         KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
-                         mem_assert->text->left_text,
-                         mem_assert->text->operation,
-                         mem_assert->text->right_text);
+       if (!mem_assert->left_value) {
+               string_stream_add(stream,
+                                 KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n",
+                                 mem_assert->text->left_text);
+       } else if (!mem_assert->right_value) {
+               string_stream_add(stream,
+                                 KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n",
+                                 mem_assert->text->right_text);
+       } else {
+               string_stream_add(stream,
+                               KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
+                               mem_assert->text->left_text,
+                               mem_assert->text->operation,
+                               mem_assert->text->right_text);
 
-       string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
-                         mem_assert->text->left_text);
-       kunit_assert_hexdump(stream, mem_assert->left_value,
-                            mem_assert->right_value, mem_assert->size);
+               string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
+                               mem_assert->text->left_text);
+               kunit_assert_hexdump(stream, mem_assert->left_value,
+                                       mem_assert->right_value, mem_assert->size);
 
-       string_stream_add(stream, "\n");
+               string_stream_add(stream, "\n");
 
-       string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
-                         mem_assert->text->right_text);
-       kunit_assert_hexdump(stream, mem_assert->right_value,
-                            mem_assert->left_value, mem_assert->size);
+               string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
+                               mem_assert->text->right_text);
+               kunit_assert_hexdump(stream, mem_assert->right_value,
+                                       mem_assert->left_value, mem_assert->size);
 
-       kunit_assert_print_msg(message, stream);
+               kunit_assert_print_msg(message, stream);
+       }
 }
 EXPORT_SYMBOL_GPL(kunit_mem_assert_format);
index c9ebf97..890ba5b 100644 (file)
@@ -21,6 +21,7 @@
 #include "try-catch-impl.h"
 
 DEFINE_STATIC_KEY_FALSE(kunit_running);
+EXPORT_SYMBOL_GPL(kunit_running);
 
 #if IS_BUILTIN(CONFIG_KUNIT)
 /*
index 45e93ec..2afe4c5 100644 (file)
@@ -23,7 +23,6 @@
                }                                                               \
                if (!--retry)                                                   \
                        break;                                                  \
-               cpu_relax();                                                    \
        }                                                                       \
 } while (0)
 
index 26e2045..5a97639 100644 (file)
@@ -670,12 +670,13 @@ static inline unsigned long mte_pivot(const struct maple_enode *mn,
                                 unsigned char piv)
 {
        struct maple_node *node = mte_to_node(mn);
+       enum maple_type type = mte_node_type(mn);
 
-       if (piv >= mt_pivots[piv]) {
+       if (piv >= mt_pivots[type]) {
                WARN_ON(1);
                return 0;
        }
-       switch (mte_node_type(mn)) {
+       switch (type) {
        case maple_arange_64:
                return node->ma64.pivot[piv];
        case maple_range_64:
@@ -4887,7 +4888,7 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
        unsigned long *pivots, *gaps;
        void __rcu **slots;
        unsigned long gap = 0;
-       unsigned long max, min, index;
+       unsigned long max, min;
        unsigned char offset;
 
        if (unlikely(mas_is_err(mas)))
@@ -4909,8 +4910,7 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
                min = mas_safe_min(mas, pivots, --offset);
 
        max = mas_safe_pivot(mas, pivots, offset, type);
-       index = mas->index;
-       while (index <= max) {
+       while (mas->index <= max) {
                gap = 0;
                if (gaps)
                        gap = gaps[offset];
@@ -4941,10 +4941,8 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
                min = mas_safe_min(mas, pivots, offset);
        }
 
-       if (unlikely(index > max)) {
-               mas_set_err(mas, -EBUSY);
-               return false;
-       }
+       if (unlikely((mas->index > max) || (size - 1 > max - mas->index)))
+               goto no_space;
 
        if (unlikely(ma_is_leaf(type))) {
                mas->offset = offset;
@@ -4961,9 +4959,11 @@ static bool mas_rev_awalk(struct ma_state *mas, unsigned long size)
        return false;
 
 ascend:
-       if (mte_is_root(mas->node))
-               mas_set_err(mas, -EBUSY);
+       if (!mte_is_root(mas->node))
+               return false;
 
+no_space:
+       mas_set_err(mas, -EBUSY);
        return false;
 }
 
index 8912855..887926f 100644 (file)
@@ -309,6 +309,8 @@ 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 9055e8b..489e15b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/jiffies.h>
+#include <linux/nospec.h>
 #include <linux/skbuff.h>
 #include <linux/string.h>
 #include <linux/types.h>
@@ -381,6 +382,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
        if (type <= 0 || type > maxtype)
                return 0;
 
+       type = array_index_nospec(type, maxtype + 1);
        pt = &policy[type];
 
        BUG_ON(pt->type > NLA_TYPE_MAX);
@@ -596,6 +598,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
                        }
                        continue;
                }
+               type = array_index_nospec(type, maxtype + 1);
                if (policy) {
                        int err = validate_nla(nla, maxtype, policy,
                                               validate, extack, depth);
index f72aa50..8d7519a 100644 (file)
@@ -470,22 +470,27 @@ int sg_alloc_append_table_from_pages(struct sg_append_table *sgt_append,
                return -EOPNOTSUPP;
 
        if (sgt_append->prv) {
+               unsigned long next_pfn = (page_to_phys(sg_page(sgt_append->prv)) +
+                       sgt_append->prv->offset + sgt_append->prv->length) / PAGE_SIZE;
+
                if (WARN_ON(offset))
                        return -EINVAL;
 
                /* Merge contiguous pages into the last SG */
                prv_len = sgt_append->prv->length;
-               last_pg = sg_page(sgt_append->prv);
-               while (n_pages && pages_are_mergeable(pages[0], last_pg)) {
-                       if (sgt_append->prv->length + PAGE_SIZE > max_segment)
-                               break;
-                       sgt_append->prv->length += PAGE_SIZE;
-                       last_pg = pages[0];
-                       pages++;
-                       n_pages--;
+               if (page_to_pfn(pages[0]) == next_pfn) {
+                       last_pg = pfn_to_page(next_pfn - 1);
+                       while (n_pages && pages_are_mergeable(pages[0], last_pg)) {
+                               if (sgt_append->prv->length + PAGE_SIZE > max_segment)
+                                       break;
+                               sgt_append->prv->length += PAGE_SIZE;
+                               last_pg = pages[0];
+                               pages++;
+                               n_pages--;
+                       }
+                       if (!n_pages)
+                               goto out;
                }
-               if (!n_pages)
-                       goto out;
        }
 
        /* compute number of contiguous chunks */
index 497fc93..ec847bf 100644 (file)
@@ -2517,6 +2517,91 @@ static noinline void check_bnode_min_spanning(struct maple_tree *mt)
        mt_set_non_kernel(0);
 }
 
+static noinline void check_empty_area_window(struct maple_tree *mt)
+{
+       unsigned long i, nr_entries = 20;
+       MA_STATE(mas, mt, 0, 0);
+
+       for (i = 1; i <= nr_entries; i++)
+               mtree_store_range(mt, i*10, i*10 + 9,
+                                 xa_mk_value(i), GFP_KERNEL);
+
+       /* Create another hole besides the one at 0 */
+       mtree_store_range(mt, 160, 169, NULL, GFP_KERNEL);
+
+       /* Check lower bounds that don't fit */
+       rcu_read_lock();
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 5, 90, 10) != -EBUSY);
+
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 6, 90, 5) != -EBUSY);
+
+       /* Check lower bound that does fit */
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 5, 90, 5) != 0);
+       MT_BUG_ON(mt, mas.index != 5);
+       MT_BUG_ON(mt, mas.last != 9);
+       rcu_read_unlock();
+
+       /* Check one gap that doesn't fit and one that does */
+       rcu_read_lock();
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 5, 217, 9) != 0);
+       MT_BUG_ON(mt, mas.index != 161);
+       MT_BUG_ON(mt, mas.last != 169);
+
+       /* Check one gap that does fit above the min */
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 100, 218, 3) != 0);
+       MT_BUG_ON(mt, mas.index != 216);
+       MT_BUG_ON(mt, mas.last != 218);
+
+       /* Check size that doesn't fit any gap */
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 100, 218, 16) != -EBUSY);
+
+       /*
+        * Check size that doesn't fit the lower end of the window but
+        * does fit the gap
+        */
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 167, 200, 4) != -EBUSY);
+
+       /*
+        * Check size that doesn't fit the upper end of the window but
+        * does fit the gap
+        */
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area_rev(&mas, 100, 162, 4) != -EBUSY);
+
+       /* Check mas_empty_area forward */
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area(&mas, 0, 100, 9) != 0);
+       MT_BUG_ON(mt, mas.index != 0);
+       MT_BUG_ON(mt, mas.last != 8);
+
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area(&mas, 0, 100, 4) != 0);
+       MT_BUG_ON(mt, mas.index != 0);
+       MT_BUG_ON(mt, mas.last != 3);
+
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area(&mas, 0, 100, 11) != -EBUSY);
+
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area(&mas, 5, 100, 6) != -EBUSY);
+
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area(&mas, 0, 8, 10) != -EBUSY);
+
+       mas_reset(&mas);
+       mas_empty_area(&mas, 100, 165, 3);
+
+       mas_reset(&mas);
+       MT_BUG_ON(mt, mas_empty_area(&mas, 100, 163, 6) != -EBUSY);
+       rcu_read_unlock();
+}
+
 static DEFINE_MTREE(tree);
 static int maple_tree_seed(void)
 {
@@ -2765,6 +2850,10 @@ static int maple_tree_seed(void)
        check_bnode_min_spanning(&tree);
        mtree_destroy(&tree);
 
+       mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
+       check_empty_area_window(&tree);
+       mtree_destroy(&tree);
+
 #if defined(BENCH)
 skip:
 #endif
index 6bdc1cd..ec10506 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/**
+/*
  * lib/minmax.c: windowed min/max tracker
  *
  * Kathleen Nichols' algorithm for tracking the minimum (or maximum)
index ca16035..8238e83 100644 (file)
@@ -1839,6 +1839,7 @@ static unsigned long fast_find_migrateblock(struct compact_control *cc)
                                        pfn = cc->zone->zone_start_pfn;
                                cc->fast_search_fail = 0;
                                found_block = true;
+                               set_pageblock_skip(freepage);
                                break;
                        }
                }
index db89523..bdbfeb6 100644 (file)
@@ -94,6 +94,8 @@ static int hugetlb_acct_memory(struct hstate *h, long delta);
 static void hugetlb_vma_lock_free(struct vm_area_struct *vma);
 static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma);
 static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma);
+static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
+               unsigned long start, unsigned long end);
 
 static inline bool subpool_is_free(struct hugepage_subpool *spool)
 {
@@ -1181,7 +1183,7 @@ void hugetlb_dup_vma_private(struct vm_area_struct *vma)
 
 /*
  * Reset and decrement one ref on hugepage private reservation.
- * Called with mm->mmap_sem writer semaphore held.
+ * Called with mm->mmap_lock writer semaphore held.
  * This function should be only used by move_vma() and operate on
  * same sized vma. It should never come here with last ref on the
  * reservation.
@@ -4834,6 +4836,25 @@ static int hugetlb_vm_op_split(struct vm_area_struct *vma, unsigned long addr)
 {
        if (addr & ~(huge_page_mask(hstate_vma(vma))))
                return -EINVAL;
+
+       /*
+        * PMD sharing is only possible for PUD_SIZE-aligned address ranges
+        * in HugeTLB VMAs. If we will lose PUD_SIZE alignment due to this
+        * split, unshare PMDs in the PUD_SIZE interval surrounding addr now.
+        */
+       if (addr & ~PUD_MASK) {
+               /*
+                * hugetlb_vm_op_split is called right before we attempt to
+                * split the VMA. We will need to unshare PMDs in the old and
+                * new VMAs, so let's unshare before we split.
+                */
+               unsigned long floor = addr & PUD_MASK;
+               unsigned long ceil = floor + PUD_SIZE;
+
+               if (floor >= vma->vm_start && ceil <= vma->vm_end)
+                       hugetlb_unshare_pmds(vma, floor, ceil);
+       }
+
        return 0;
 }
 
@@ -5030,6 +5051,9 @@ again:
                                entry = huge_pte_clear_uffd_wp(entry);
                        set_huge_pte_at(dst, addr, dst_pte, entry);
                } else if (unlikely(is_pte_marker(entry))) {
+                       /* No swap on hugetlb */
+                       WARN_ON_ONCE(
+                           is_swapin_error_entry(pte_to_swp_entry(entry)));
                        /*
                         * We copy the pte marker only if the dst vma has
                         * uffd-wp enabled.
@@ -5131,7 +5155,7 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
 
        /*
         * We don't have to worry about the ordering of src and dst ptlocks
-        * because exclusive mmap_sem (or the i_mmap_lock) prevents deadlock.
+        * because exclusive mmap_lock (or the i_mmap_lock) prevents deadlock.
         */
        if (src_ptl != dst_ptl)
                spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
@@ -6639,8 +6663,17 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
                spinlock_t *ptl;
                ptep = huge_pte_offset(mm, address, psize);
                if (!ptep) {
-                       address |= last_addr_mask;
-                       continue;
+                       if (!uffd_wp) {
+                               address |= last_addr_mask;
+                               continue;
+                       }
+                       /*
+                        * Userfaultfd wr-protect requires pgtable
+                        * pre-allocations to install pte markers.
+                        */
+                       ptep = huge_pte_alloc(mm, vma, address, psize);
+                       if (!ptep)
+                               break;
                }
                ptl = huge_pte_lock(h, mm, ptep);
                if (huge_pmd_unshare(mm, vma, address, ptep)) {
@@ -6658,16 +6691,13 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
                }
                pte = huge_ptep_get(ptep);
                if (unlikely(is_hugetlb_entry_hwpoisoned(pte))) {
-                       spin_unlock(ptl);
-                       continue;
-               }
-               if (unlikely(is_hugetlb_entry_migration(pte))) {
+                       /* Nothing to do. */
+               } else if (unlikely(is_hugetlb_entry_migration(pte))) {
                        swp_entry_t entry = pte_to_swp_entry(pte);
                        struct page *page = pfn_swap_entry_to_page(entry);
+                       pte_t newpte = pte;
 
-                       if (!is_readable_migration_entry(entry)) {
-                               pte_t newpte;
-
+                       if (is_writable_migration_entry(entry)) {
                                if (PageAnon(page))
                                        entry = make_readable_exclusive_migration_entry(
                                                                swp_offset(entry));
@@ -6675,25 +6705,22 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
                                        entry = make_readable_migration_entry(
                                                                swp_offset(entry));
                                newpte = swp_entry_to_pte(entry);
-                               if (uffd_wp)
-                                       newpte = pte_swp_mkuffd_wp(newpte);
-                               else if (uffd_wp_resolve)
-                                       newpte = pte_swp_clear_uffd_wp(newpte);
-                               set_huge_pte_at(mm, address, ptep, newpte);
                                pages++;
                        }
-                       spin_unlock(ptl);
-                       continue;
-               }
-               if (unlikely(pte_marker_uffd_wp(pte))) {
-                       /*
-                        * This is changing a non-present pte into a none pte,
-                        * no need for huge_ptep_modify_prot_start/commit().
-                        */
+
+                       if (uffd_wp)
+                               newpte = pte_swp_mkuffd_wp(newpte);
+                       else if (uffd_wp_resolve)
+                               newpte = pte_swp_clear_uffd_wp(newpte);
+                       if (!pte_same(pte, newpte))
+                               set_huge_pte_at(mm, address, ptep, newpte);
+               } else if (unlikely(is_pte_marker(pte))) {
+                       /* No other markers apply for now. */
+                       WARN_ON_ONCE(!pte_marker_uffd_wp(pte));
                        if (uffd_wp_resolve)
+                               /* Safe to modify directly (non-present->none). */
                                huge_pte_clear(mm, address, ptep, psize);
-               }
-               if (!huge_pte_none(pte)) {
+               } else if (!huge_pte_none(pte)) {
                        pte_t old_pte;
                        unsigned int shift = huge_page_shift(hstate_vma(vma));
 
@@ -7328,26 +7355,21 @@ void move_hugetlb_state(struct folio *old_folio, struct folio *new_folio, int re
        }
 }
 
-/*
- * This function will unconditionally remove all the shared pmd pgtable entries
- * within the specific vma for a hugetlbfs memory range.
- */
-void hugetlb_unshare_all_pmds(struct vm_area_struct *vma)
+static void hugetlb_unshare_pmds(struct vm_area_struct *vma,
+                                  unsigned long start,
+                                  unsigned long end)
 {
        struct hstate *h = hstate_vma(vma);
        unsigned long sz = huge_page_size(h);
        struct mm_struct *mm = vma->vm_mm;
        struct mmu_notifier_range range;
-       unsigned long address, start, end;
+       unsigned long address;
        spinlock_t *ptl;
        pte_t *ptep;
 
        if (!(vma->vm_flags & VM_MAYSHARE))
                return;
 
-       start = ALIGN(vma->vm_start, PUD_SIZE);
-       end = ALIGN_DOWN(vma->vm_end, PUD_SIZE);
-
        if (start >= end)
                return;
 
@@ -7379,6 +7401,16 @@ void hugetlb_unshare_all_pmds(struct vm_area_struct *vma)
        mmu_notifier_invalidate_range_end(&range);
 }
 
+/*
+ * This function will unconditionally remove all the shared pmd pgtable entries
+ * within the specific vma for a hugetlbfs memory range.
+ */
+void hugetlb_unshare_all_pmds(struct vm_area_struct *vma)
+{
+       hugetlb_unshare_pmds(vma, ALIGN(vma->vm_start, PUD_SIZE),
+                       ALIGN_DOWN(vma->vm_end, PUD_SIZE));
+}
+
 #ifdef CONFIG_CMA
 static bool cma_reserve_called __initdata;
 
index 1d02757..22598b2 100644 (file)
@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);
  * Whether the KASAN KUnit test suite is currently being executed.
  * Updated in kasan_test.c.
  */
-bool kasan_kunit_executing;
+static bool kasan_kunit_executing;
 
 void kasan_kunit_test_suite_start(void)
 {
index 5cb401a..90acfea 100644 (file)
@@ -847,6 +847,10 @@ static int hugepage_vma_revalidate(struct mm_struct *mm, unsigned long address,
        return SCAN_SUCCEED;
 }
 
+/*
+ * See pmd_trans_unstable() for how the result may change out from
+ * underneath us, even if we hold mmap_lock in read.
+ */
 static int find_pmd_or_thp_or_none(struct mm_struct *mm,
                                   unsigned long address,
                                   pmd_t **pmd)
@@ -865,8 +869,12 @@ static int find_pmd_or_thp_or_none(struct mm_struct *mm,
 #endif
        if (pmd_none(pmde))
                return SCAN_PMD_NONE;
+       if (!pmd_present(pmde))
+               return SCAN_PMD_NULL;
        if (pmd_trans_huge(pmde))
                return SCAN_PMD_MAPPED;
+       if (pmd_devmap(pmde))
+               return SCAN_PMD_NULL;
        if (pmd_bad(pmde))
                return SCAN_PMD_NULL;
        return SCAN_SUCCEED;
@@ -1460,14 +1468,6 @@ int collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
        if (!hugepage_vma_check(vma, vma->vm_flags, false, false, false))
                return SCAN_VMA_CHECK;
 
-       /*
-        * Symmetry with retract_page_tables(): Exclude MAP_PRIVATE mappings
-        * that got written to. Without this, we'd have to also lock the
-        * anon_vma if one exists.
-        */
-       if (vma->anon_vma)
-               return SCAN_VMA_CHECK;
-
        /* Keep pmd pgtable for uffd-wp; see comment in retract_page_tables() */
        if (userfaultfd_wp(vma))
                return SCAN_PTE_UFFD_WP;
@@ -1567,8 +1567,14 @@ int collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
        }
 
        /* step 4: remove pte entries */
+       /* we make no change to anon, but protect concurrent anon page lookup */
+       if (vma->anon_vma)
+               anon_vma_lock_write(vma->anon_vma);
+
        collapse_and_free_pmd(mm, vma, haddr, pmd);
 
+       if (vma->anon_vma)
+               anon_vma_unlock_write(vma->anon_vma);
        i_mmap_unlock_write(vma->vm_file->f_mapping);
 
 maybe_install_pmd:
@@ -1644,7 +1650,7 @@ static int retract_page_tables(struct address_space *mapping, pgoff_t pgoff,
                 * has higher cost too. It would also probably require locking
                 * the anon_vma.
                 */
-               if (vma->anon_vma) {
+               if (READ_ONCE(vma->anon_vma)) {
                        result = SCAN_PAGE_ANON;
                        goto next;
                }
@@ -1672,6 +1678,18 @@ static int retract_page_tables(struct address_space *mapping, pgoff_t pgoff,
                result = SCAN_PTE_MAPPED_HUGEPAGE;
                if ((cc->is_khugepaged || is_target) &&
                    mmap_write_trylock(mm)) {
+                       /*
+                        * Re-check whether we have an ->anon_vma, because
+                        * collapse_and_free_pmd() requires that either no
+                        * ->anon_vma exists or the anon_vma is locked.
+                        * We already checked ->anon_vma above, but that check
+                        * is racy because ->anon_vma can be populated under the
+                        * mmap lock in read mode.
+                        */
+                       if (vma->anon_vma) {
+                               result = SCAN_PAGE_ANON;
+                               goto unlock_next;
+                       }
                        /*
                         * When a vma is registered with uffd-wp, we can't
                         * recycle the pmd pgtable because there can be pte
@@ -2649,7 +2667,7 @@ int madvise_collapse(struct vm_area_struct *vma, struct vm_area_struct **prev,
                                goto out_nolock;
                        }
 
-                       hend = vma->vm_end & HPAGE_PMD_MASK;
+                       hend = min(hend, vma->vm_end & HPAGE_PMD_MASK);
                }
                mmap_assert_locked(mm);
                memset(cc->node_load, 0, sizeof(cc->node_load));
index 92f670e..55dc8b8 100644 (file)
@@ -2070,8 +2070,10 @@ static int __init kmemleak_boot_config(char *str)
                return -EINVAL;
        if (strcmp(str, "off") == 0)
                kmemleak_disable();
-       else if (strcmp(str, "on") == 0)
+       else if (strcmp(str, "on") == 0) {
                kmemleak_skip_disable = 1;
+               stack_depot_want_early_init();
+       }
        else
                return -EINVAL;
        return 0;
@@ -2093,7 +2095,6 @@ void __init kmemleak_init(void)
        if (kmemleak_error)
                return;
 
-       stack_depot_init();
        jiffies_min_age = msecs_to_jiffies(MSECS_MIN_AGE);
        jiffies_scan_wait = msecs_to_jiffies(SECS_SCAN_WAIT * 1000);
 
index a56a6d1..b6ea204 100644 (file)
@@ -130,7 +130,7 @@ static int replace_anon_vma_name(struct vm_area_struct *vma,
 #endif /* CONFIG_ANON_VMA_NAME */
 /*
  * Update the vm_flags on region of a vma, splitting it or merging it as
- * necessary.  Must be called with mmap_sem held for writing;
+ * necessary.  Must be called with mmap_lock held for writing;
  * Caller should ensure anon_name stability by raising its refcount even when
  * anon_name belongs to a valid vma because this function might free that vma.
  */
index ab457f0..73afff8 100644 (file)
@@ -63,7 +63,6 @@
 #include <linux/resume_user_mode.h>
 #include <linux/psi.h>
 #include <linux/seq_buf.h>
-#include <linux/parser.h>
 #include "internal.h"
 #include <net/sock.h>
 #include <net/ip.h>
@@ -2393,8 +2392,7 @@ static unsigned long reclaim_high(struct mem_cgroup *memcg,
                psi_memstall_enter(&pflags);
                nr_reclaimed += try_to_free_mem_cgroup_pages(memcg, nr_pages,
                                                        gfp_mask,
-                                                       MEMCG_RECLAIM_MAY_SWAP,
-                                                       NULL);
+                                                       MEMCG_RECLAIM_MAY_SWAP);
                psi_memstall_leave(&pflags);
        } while ((memcg = parent_mem_cgroup(memcg)) &&
                 !mem_cgroup_is_root(memcg));
@@ -2685,8 +2683,7 @@ retry:
 
        psi_memstall_enter(&pflags);
        nr_reclaimed = try_to_free_mem_cgroup_pages(mem_over_limit, nr_pages,
-                                                   gfp_mask, reclaim_options,
-                                                   NULL);
+                                                   gfp_mask, reclaim_options);
        psi_memstall_leave(&pflags);
 
        if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
@@ -3506,8 +3503,7 @@ static int mem_cgroup_resize_max(struct mem_cgroup *memcg,
                }
 
                if (!try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL,
-                                       memsw ? 0 : MEMCG_RECLAIM_MAY_SWAP,
-                                       NULL)) {
+                                       memsw ? 0 : MEMCG_RECLAIM_MAY_SWAP)) {
                        ret = -EBUSY;
                        break;
                }
@@ -3618,8 +3614,7 @@ static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
                        return -EINTR;
 
                if (!try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL,
-                                                 MEMCG_RECLAIM_MAY_SWAP,
-                                                 NULL))
+                                                 MEMCG_RECLAIM_MAY_SWAP))
                        nr_retries--;
        }
 
@@ -6429,8 +6424,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
                }
 
                reclaimed = try_to_free_mem_cgroup_pages(memcg, nr_pages - high,
-                                       GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP,
-                                       NULL);
+                                       GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP);
 
                if (!reclaimed && !nr_retries--)
                        break;
@@ -6479,8 +6473,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
 
                if (nr_reclaims) {
                        if (!try_to_free_mem_cgroup_pages(memcg, nr_pages - max,
-                                       GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP,
-                                       NULL))
+                                       GFP_KERNEL, MEMCG_RECLAIM_MAY_SWAP))
                                nr_reclaims--;
                        continue;
                }
@@ -6603,54 +6596,21 @@ static ssize_t memory_oom_group_write(struct kernfs_open_file *of,
        return nbytes;
 }
 
-enum {
-       MEMORY_RECLAIM_NODES = 0,
-       MEMORY_RECLAIM_NULL,
-};
-
-static const match_table_t if_tokens = {
-       { MEMORY_RECLAIM_NODES, "nodes=%s" },
-       { MEMORY_RECLAIM_NULL, NULL },
-};
-
 static ssize_t memory_reclaim(struct kernfs_open_file *of, char *buf,
                              size_t nbytes, loff_t off)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
        unsigned int nr_retries = MAX_RECLAIM_RETRIES;
        unsigned long nr_to_reclaim, nr_reclaimed = 0;
-       unsigned int reclaim_options = MEMCG_RECLAIM_MAY_SWAP |
-                                      MEMCG_RECLAIM_PROACTIVE;
-       char *old_buf, *start;
-       substring_t args[MAX_OPT_ARGS];
-       int token;
-       char value[256];
-       nodemask_t nodemask = NODE_MASK_ALL;
-
-       buf = strstrip(buf);
-
-       old_buf = buf;
-       nr_to_reclaim = memparse(buf, &buf) / PAGE_SIZE;
-       if (buf == old_buf)
-               return -EINVAL;
+       unsigned int reclaim_options;
+       int err;
 
        buf = strstrip(buf);
+       err = page_counter_memparse(buf, "", &nr_to_reclaim);
+       if (err)
+               return err;
 
-       while ((start = strsep(&buf, " ")) != NULL) {
-               if (!strlen(start))
-                       continue;
-               token = match_token(start, if_tokens, args);
-               match_strlcpy(value, args, sizeof(value));
-               switch (token) {
-               case MEMORY_RECLAIM_NODES:
-                       if (nodelist_parse(value, nodemask) < 0)
-                               return -EINVAL;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       }
-
+       reclaim_options = MEMCG_RECLAIM_MAY_SWAP | MEMCG_RECLAIM_PROACTIVE;
        while (nr_reclaimed < nr_to_reclaim) {
                unsigned long reclaimed;
 
@@ -6667,8 +6627,7 @@ static ssize_t memory_reclaim(struct kernfs_open_file *of, char *buf,
 
                reclaimed = try_to_free_mem_cgroup_pages(memcg,
                                                nr_to_reclaim - nr_reclaimed,
-                                               GFP_KERNEL, reclaim_options,
-                                               &nodemask);
+                                               GFP_KERNEL, reclaim_options);
 
                if (!reclaimed && !nr_retries--)
                        return -EAGAIN;
index aad226d..3e836fe 100644 (file)
@@ -828,12 +828,8 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                        return -EBUSY;
                return -ENOENT;
        } else if (is_pte_marker_entry(entry)) {
-               /*
-                * We're copying the pgtable should only because dst_vma has
-                * uffd-wp enabled, do sanity check.
-                */
-               WARN_ON_ONCE(!userfaultfd_wp(dst_vma));
-               set_pte_at(dst_mm, addr, dst_pte, pte);
+               if (is_swapin_error_entry(entry) || userfaultfd_wp(dst_vma))
+                       set_pte_at(dst_mm, addr, dst_pte, pte);
                return 0;
        }
        if (!userfaultfd_wp(dst_vma))
@@ -3629,8 +3625,12 @@ static vm_fault_t pte_marker_clear(struct vm_fault *vmf)
        /*
         * Be careful so that we will only recover a special uffd-wp pte into a
         * none pte.  Otherwise it means the pte could have changed, so retry.
+        *
+        * This should also cover the case where e.g. the pte changed
+        * quickly from a PTE_MARKER_UFFD_WP into PTE_MARKER_SWAPIN_ERROR.
+        * So is_pte_marker() check is not enough to safely drop the pte.
         */
-       if (is_pte_marker(*vmf->pte))
+       if (pte_same(vmf->orig_pte, *vmf->pte))
                pte_clear(vmf->vma->vm_mm, vmf->address, vmf->pte);
        pte_unmap_unlock(vmf->pte, vmf->ptl);
        return 0;
index 02c8a71..f940395 100644 (file)
@@ -600,7 +600,8 @@ static int queue_pages_hugetlb(pte_t *pte, unsigned long hmask,
 
        /* With MPOL_MF_MOVE, we migrate only unshared hugepage. */
        if (flags & (MPOL_MF_MOVE_ALL) ||
-           (flags & MPOL_MF_MOVE && page_mapcount(page) == 1)) {
+           (flags & MPOL_MF_MOVE && page_mapcount(page) == 1 &&
+            !hugetlb_pmd_shared(pte))) {
                if (isolate_hugetlb(page, qp->pagelist) &&
                        (flags & MPOL_MF_STRICT))
                        /*
index 87d9293..425a934 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1524,6 +1524,10 @@ int vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot)
        if (vma_soft_dirty_enabled(vma) && !is_vm_hugetlb_page(vma))
                return 1;
 
+       /* Do we need write faults for uffd-wp tracking? */
+       if (userfaultfd_wp(vma))
+               return 1;
+
        /* Specialty mapping? */
        if (vm_flags & VM_PFNMAP)
                return 0;
@@ -2290,7 +2294,7 @@ static inline int munmap_sidetree(struct vm_area_struct *vma,
  * @start: The aligned start address to munmap.
  * @end: The aligned end address to munmap.
  * @uf: The userfaultfd list_head
- * @downgrade: Set to true to attempt a write downgrade of the mmap_sem
+ * @downgrade: Set to true to attempt a write downgrade of the mmap_lock
  *
  * If @downgrade is true, check return code for potential release of the lock.
  */
@@ -2465,7 +2469,7 @@ map_count_exceeded:
  * @len: The length of the range to munmap
  * @uf: The userfaultfd list_head
  * @downgrade: set to true if the user wants to attempt to write_downgrade the
- * mmap_sem
+ * mmap_lock
  *
  * This function takes a @mas that is either pointing to the previous VMA or set
  * to MA_START and sets it up to remove the mapping(s).  The @len will be
index 908df12..61cf600 100644 (file)
@@ -245,7 +245,13 @@ static unsigned long change_pte_range(struct mmu_gather *tlb,
                                        newpte = pte_swp_mksoft_dirty(newpte);
                                if (pte_swp_uffd_wp(oldpte))
                                        newpte = pte_swp_mkuffd_wp(newpte);
-                       } else if (pte_marker_entry_uffd_wp(entry)) {
+                       } else if (is_pte_marker_entry(entry)) {
+                               /*
+                                * Ignore swapin errors unconditionally,
+                                * because any access should sigbus anyway.
+                                */
+                               if (is_swapin_error_entry(entry))
+                                       continue;
                                /*
                                 * If this is uffd-wp pte marker and we'd like
                                 * to unprotect it, drop it; the next page
index fe587c5..930f65c 100644 (file)
@@ -1027,16 +1027,29 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
                        }
 
                        /*
-                        * Function vma_merge() is called on the extension we are adding to
-                        * the already existing vma, vma_merge() will merge this extension with
-                        * the already existing vma (expand operation itself) and possibly also
-                        * with the next vma if it becomes adjacent to the expanded vma and
-                        * otherwise compatible.
+                        * Function vma_merge() is called on the extension we
+                        * are adding to the already existing vma, vma_merge()
+                        * will merge this extension with the already existing
+                        * vma (expand operation itself) and possibly also with
+                        * the next vma if it becomes adjacent to the expanded
+                        * vma and  otherwise compatible.
+                        *
+                        * However, vma_merge() can currently fail due to
+                        * is_mergeable_vma() check for vm_ops->close (see the
+                        * comment there). Yet this should not prevent vma
+                        * expanding, so perform a simple expand for such vma.
+                        * Ideally the check for close op should be only done
+                        * when a vma would be actually removed due to a merge.
                         */
-                       vma = vma_merge(mm, vma, extension_start, extension_end,
+                       if (!vma->vm_ops || !vma->vm_ops->close) {
+                               vma = vma_merge(mm, vma, extension_start, extension_end,
                                        vma->vm_flags, vma->anon_vma, vma->vm_file,
                                        extension_pgoff, vma_policy(vma),
                                        vma->vm_userfaultfd_ctx, anon_vma_name(vma));
+                       } else if (vma_adjust(vma, vma->vm_start, addr + new_len,
+                                  vma->vm_pgoff, NULL)) {
+                               vma = NULL;
+                       }
                        if (!vma) {
                                vm_unacct_memory(pages);
                                ret = -ENOMEM;
index 214c70e..5b83938 100644 (file)
@@ -559,7 +559,6 @@ void vma_mas_remove(struct vm_area_struct *vma, struct ma_state *mas)
 
 static void setup_vma_to_mm(struct vm_area_struct *vma, struct mm_struct *mm)
 {
-       mm->map_count++;
        vma->vm_mm = mm;
 
        /* add the VMA to the mapping */
@@ -587,6 +586,7 @@ static void mas_add_vma_to_mm(struct ma_state *mas, struct mm_struct *mm,
        BUG_ON(!vma->vm_region);
 
        setup_vma_to_mm(vma, mm);
+       mm->map_count++;
 
        /* add the VMA to the tree */
        vma_mas_store(vma, mas);
@@ -1240,6 +1240,7 @@ share:
 error_just_free:
        up_write(&nommu_region_sem);
 error:
+       mas_destroy(&mas);
        if (region->vm_file)
                fput(region->vm_file);
        kmem_cache_free(vm_region_jar, region);
@@ -1250,7 +1251,6 @@ error:
 
 sharing_violation:
        up_write(&nommu_region_sem);
-       mas_destroy(&mas);
        pr_warn("Attempt to share mismatched mappings\n");
        ret = -EINVAL;
        goto error;
@@ -1347,6 +1347,7 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
        if (vma->vm_file)
                return -ENOMEM;
 
+       mm = vma->vm_mm;
        if (mm->map_count >= sysctl_max_map_count)
                return -ENOMEM;
 
@@ -1398,6 +1399,7 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
        mas_set_range(&mas, vma->vm_start, vma->vm_end - 1);
        mas_store(&mas, vma);
        vma_mas_store(new, &mas);
+       mm->map_count++;
        return 0;
 
 err_mas_preallocate:
@@ -1509,7 +1511,8 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len, struct list
 erase_whole_vma:
        if (delete_vma_from_mm(vma))
                ret = -ENOMEM;
-       delete_vma(mm, vma);
+       else
+               delete_vma(mm, vma);
        return ret;
 }
 
index 0745aed..3bb3484 100644 (file)
@@ -5631,9 +5631,12 @@ EXPORT_SYMBOL(get_zeroed_page);
  */
 void __free_pages(struct page *page, unsigned int order)
 {
+       /* get PageHead before we drop reference */
+       int head = PageHead(page);
+
        if (put_page_testzero(page))
                free_the_page(page, order);
-       else if (!PageHead(page))
+       else if (!head)
                while (order-- > 0)
                        free_the_page(page + (1 << order), order);
 }
index c301487..0005ab2 100644 (file)
@@ -478,12 +478,10 @@ bool shmem_is_huge(struct vm_area_struct *vma, struct inode *inode,
        if (vma && ((vma->vm_flags & VM_NOHUGEPAGE) ||
            test_bit(MMF_DISABLE_THP, &vma->vm_mm->flags)))
                return false;
-       if (shmem_huge_force)
-               return true;
-       if (shmem_huge == SHMEM_HUGE_FORCE)
-               return true;
        if (shmem_huge == SHMEM_HUGE_DENY)
                return false;
+       if (shmem_huge_force || shmem_huge == SHMEM_HUGE_FORCE)
+               return true;
 
        switch (SHMEM_SB(inode->i_sb)->huge) {
        case SHMEM_HUGE_ALWAYS:
index 7a269db..29300fc 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2211,6 +2211,8 @@ static int drain_freelist(struct kmem_cache *cache,
                raw_spin_unlock_irq(&n->list_lock);
                slab_destroy(cache, slab);
                nr_freed++;
+
+               cond_resched();
        }
 out:
        return nr_freed;
index 908a529..4fa440e 100644 (file)
@@ -1100,6 +1100,7 @@ start_over:
                        goto check_out;
                pr_debug("scan_swap_map of si %d failed to find offset\n",
                        si->type);
+               cond_resched();
 
                spin_lock(&swap_avail_lock);
 nextsi:
index bd6637f..bf3eedf 100644 (file)
@@ -3323,13 +3323,16 @@ void lru_gen_migrate_mm(struct mm_struct *mm)
        if (mem_cgroup_disabled())
                return;
 
+       /* migration can happen before addition */
+       if (!mm->lru_gen.memcg)
+               return;
+
        rcu_read_lock();
        memcg = mem_cgroup_from_task(task);
        rcu_read_unlock();
        if (memcg == mm->lru_gen.memcg)
                return;
 
-       VM_WARN_ON_ONCE(!mm->lru_gen.memcg);
        VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list));
 
        lru_gen_del_mm(mm);
@@ -6754,8 +6757,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
 unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                                           unsigned long nr_pages,
                                           gfp_t gfp_mask,
-                                          unsigned int reclaim_options,
-                                          nodemask_t *nodemask)
+                                          unsigned int reclaim_options)
 {
        unsigned long nr_reclaimed;
        unsigned int noreclaim_flag;
@@ -6770,7 +6772,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
                .may_unmap = 1,
                .may_swap = !!(reclaim_options & MEMCG_RECLAIM_MAY_SWAP),
                .proactive = !!(reclaim_options & MEMCG_RECLAIM_PROACTIVE),
-               .nodemask = nodemask,
        };
        /*
         * Traverse the ZONELIST_FALLBACK zonelist of the current node to put
index 9445bee..702bc3f 100644 (file)
  * have room for two bit at least.
  */
 #define OBJ_ALLOCATED_TAG 1
-#define OBJ_TAG_BITS 1
+
+#ifdef CONFIG_ZPOOL
+/*
+ * The second least-significant bit in the object's header identifies if the
+ * value stored at the header is a deferred handle from the last reclaim
+ * attempt.
+ *
+ * As noted above, this is valid because we have room for two bits.
+ */
+#define OBJ_DEFERRED_HANDLE_TAG        2
+#define OBJ_TAG_BITS   2
+#define OBJ_TAG_MASK   (OBJ_ALLOCATED_TAG | OBJ_DEFERRED_HANDLE_TAG)
+#else
+#define OBJ_TAG_BITS   1
+#define OBJ_TAG_MASK   OBJ_ALLOCATED_TAG
+#endif /* CONFIG_ZPOOL */
+
 #define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS - OBJ_TAG_BITS)
 #define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
 
@@ -222,6 +238,12 @@ struct link_free {
                 * Handle of allocated object.
                 */
                unsigned long handle;
+#ifdef CONFIG_ZPOOL
+               /*
+                * Deferred handle of a reclaimed object.
+                */
+               unsigned long deferred_handle;
+#endif
        };
 };
 
@@ -272,8 +294,6 @@ struct zspage {
        /* links the zspage to the lru list in the pool */
        struct list_head lru;
        bool under_reclaim;
-       /* list of unfreed handles whose objects have been reclaimed */
-       unsigned long *deferred_handles;
 #endif
 
        struct zs_pool *pool;
@@ -897,7 +917,8 @@ static unsigned long handle_to_obj(unsigned long handle)
        return *(unsigned long *)handle;
 }
 
-static bool obj_allocated(struct page *page, void *obj, unsigned long *phandle)
+static bool obj_tagged(struct page *page, void *obj, unsigned long *phandle,
+               int tag)
 {
        unsigned long handle;
        struct zspage *zspage = get_zspage(page);
@@ -908,13 +929,27 @@ static bool obj_allocated(struct page *page, void *obj, unsigned long *phandle)
        } else
                handle = *(unsigned long *)obj;
 
-       if (!(handle & OBJ_ALLOCATED_TAG))
+       if (!(handle & tag))
                return false;
 
-       *phandle = handle & ~OBJ_ALLOCATED_TAG;
+       /* Clear all tags before returning the handle */
+       *phandle = handle & ~OBJ_TAG_MASK;
        return true;
 }
 
+static inline bool obj_allocated(struct page *page, void *obj, unsigned long *phandle)
+{
+       return obj_tagged(page, obj, phandle, OBJ_ALLOCATED_TAG);
+}
+
+#ifdef CONFIG_ZPOOL
+static bool obj_stores_deferred_handle(struct page *page, void *obj,
+               unsigned long *phandle)
+{
+       return obj_tagged(page, obj, phandle, OBJ_DEFERRED_HANDLE_TAG);
+}
+#endif
+
 static void reset_page(struct page *page)
 {
        __ClearPageMovable(page);
@@ -946,22 +981,36 @@ unlock:
 }
 
 #ifdef CONFIG_ZPOOL
+static unsigned long find_deferred_handle_obj(struct size_class *class,
+               struct page *page, int *obj_idx);
+
 /*
  * Free all the deferred handles whose objects are freed in zs_free.
  */
-static void free_handles(struct zs_pool *pool, struct zspage *zspage)
+static void free_handles(struct zs_pool *pool, struct size_class *class,
+               struct zspage *zspage)
 {
-       unsigned long handle = (unsigned long)zspage->deferred_handles;
+       int obj_idx = 0;
+       struct page *page = get_first_page(zspage);
+       unsigned long handle;
 
-       while (handle) {
-               unsigned long nxt_handle = handle_to_obj(handle);
+       while (1) {
+               handle = find_deferred_handle_obj(class, page, &obj_idx);
+               if (!handle) {
+                       page = get_next_page(page);
+                       if (!page)
+                               break;
+                       obj_idx = 0;
+                       continue;
+               }
 
                cache_free_handle(pool, handle);
-               handle = nxt_handle;
+               obj_idx++;
        }
 }
 #else
-static inline void free_handles(struct zs_pool *pool, struct zspage *zspage) {}
+static inline void free_handles(struct zs_pool *pool, struct size_class *class,
+               struct zspage *zspage) {}
 #endif
 
 static void __free_zspage(struct zs_pool *pool, struct size_class *class,
@@ -979,7 +1028,7 @@ static void __free_zspage(struct zs_pool *pool, struct size_class *class,
        VM_BUG_ON(fg != ZS_EMPTY);
 
        /* Free all deferred handles from zs_free */
-       free_handles(pool, zspage);
+       free_handles(pool, class, zspage);
 
        next = page = get_first_page(zspage);
        do {
@@ -1067,7 +1116,6 @@ static void init_zspage(struct size_class *class, struct zspage *zspage)
 #ifdef CONFIG_ZPOOL
        INIT_LIST_HEAD(&zspage->lru);
        zspage->under_reclaim = false;
-       zspage->deferred_handles = NULL;
 #endif
 
        set_freeobj(zspage, 0);
@@ -1568,7 +1616,7 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
 }
 EXPORT_SYMBOL_GPL(zs_malloc);
 
-static void obj_free(int class_size, unsigned long obj)
+static void obj_free(int class_size, unsigned long obj, unsigned long *handle)
 {
        struct link_free *link;
        struct zspage *zspage;
@@ -1582,15 +1630,29 @@ static void obj_free(int class_size, unsigned long obj)
        zspage = get_zspage(f_page);
 
        vaddr = kmap_atomic(f_page);
-
-       /* Insert this object in containing zspage's freelist */
        link = (struct link_free *)(vaddr + f_offset);
-       if (likely(!ZsHugePage(zspage)))
-               link->next = get_freeobj(zspage) << OBJ_TAG_BITS;
-       else
-               f_page->index = 0;
+
+       if (handle) {
+#ifdef CONFIG_ZPOOL
+               /* Stores the (deferred) handle in the object's header */
+               *handle |= OBJ_DEFERRED_HANDLE_TAG;
+               *handle &= ~OBJ_ALLOCATED_TAG;
+
+               if (likely(!ZsHugePage(zspage)))
+                       link->deferred_handle = *handle;
+               else
+                       f_page->index = *handle;
+#endif
+       } else {
+               /* Insert this object in containing zspage's freelist */
+               if (likely(!ZsHugePage(zspage)))
+                       link->next = get_freeobj(zspage) << OBJ_TAG_BITS;
+               else
+                       f_page->index = 0;
+               set_freeobj(zspage, f_objidx);
+       }
+
        kunmap_atomic(vaddr);
-       set_freeobj(zspage, f_objidx);
        mod_zspage_inuse(zspage, -1);
 }
 
@@ -1615,7 +1677,6 @@ void zs_free(struct zs_pool *pool, unsigned long handle)
        zspage = get_zspage(f_page);
        class = zspage_class(pool, zspage);
 
-       obj_free(class->size, obj);
        class_stat_dec(class, OBJ_USED, 1);
 
 #ifdef CONFIG_ZPOOL
@@ -1624,15 +1685,15 @@ void zs_free(struct zs_pool *pool, unsigned long handle)
                 * Reclaim needs the handles during writeback. It'll free
                 * them along with the zspage when it's done with them.
                 *
-                * Record current deferred handle at the memory location
-                * whose address is given by handle.
+                * Record current deferred handle in the object's header.
                 */
-               record_obj(handle, (unsigned long)zspage->deferred_handles);
-               zspage->deferred_handles = (unsigned long *)handle;
+               obj_free(class->size, obj, &handle);
                spin_unlock(&pool->lock);
                return;
        }
 #endif
+       obj_free(class->size, obj, NULL);
+
        fullness = fix_fullness_group(class, zspage);
        if (fullness == ZS_EMPTY)
                free_zspage(pool, class, zspage);
@@ -1713,11 +1774,11 @@ static void zs_object_copy(struct size_class *class, unsigned long dst,
 }
 
 /*
- * Find alloced object in zspage from index object and
+ * Find object with a certain tag in zspage from index object and
  * return handle.
  */
-static unsigned long find_alloced_obj(struct size_class *class,
-                                       struct page *page, int *obj_idx)
+static unsigned long find_tagged_obj(struct size_class *class,
+                                       struct page *page, int *obj_idx, int tag)
 {
        unsigned int offset;
        int index = *obj_idx;
@@ -1728,7 +1789,7 @@ static unsigned long find_alloced_obj(struct size_class *class,
        offset += class->size * index;
 
        while (offset < PAGE_SIZE) {
-               if (obj_allocated(page, addr + offset, &handle))
+               if (obj_tagged(page, addr + offset, &handle, tag))
                        break;
 
                offset += class->size;
@@ -1742,6 +1803,28 @@ static unsigned long find_alloced_obj(struct size_class *class,
        return handle;
 }
 
+/*
+ * Find alloced object in zspage from index object and
+ * return handle.
+ */
+static unsigned long find_alloced_obj(struct size_class *class,
+                                       struct page *page, int *obj_idx)
+{
+       return find_tagged_obj(class, page, obj_idx, OBJ_ALLOCATED_TAG);
+}
+
+#ifdef CONFIG_ZPOOL
+/*
+ * Find object storing a deferred handle in header in zspage from index object
+ * and return handle.
+ */
+static unsigned long find_deferred_handle_obj(struct size_class *class,
+               struct page *page, int *obj_idx)
+{
+       return find_tagged_obj(class, page, obj_idx, OBJ_DEFERRED_HANDLE_TAG);
+}
+#endif
+
 struct zs_compact_control {
        /* Source spage for migration which could be a subpage of zspage */
        struct page *s_page;
@@ -1784,7 +1867,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
                zs_object_copy(class, free_obj, used_obj);
                obj_idx++;
                record_obj(handle, free_obj);
-               obj_free(class->size, used_obj);
+               obj_free(class->size, used_obj, NULL);
        }
 
        /* Remember last position in this iteration */
@@ -2478,6 +2561,90 @@ void zs_destroy_pool(struct zs_pool *pool)
 EXPORT_SYMBOL_GPL(zs_destroy_pool);
 
 #ifdef CONFIG_ZPOOL
+static void restore_freelist(struct zs_pool *pool, struct size_class *class,
+               struct zspage *zspage)
+{
+       unsigned int obj_idx = 0;
+       unsigned long handle, off = 0; /* off is within-page offset */
+       struct page *page = get_first_page(zspage);
+       struct link_free *prev_free = NULL;
+       void *prev_page_vaddr = NULL;
+
+       /* in case no free object found */
+       set_freeobj(zspage, (unsigned int)(-1UL));
+
+       while (page) {
+               void *vaddr = kmap_atomic(page);
+               struct page *next_page;
+
+               while (off < PAGE_SIZE) {
+                       void *obj_addr = vaddr + off;
+
+                       /* skip allocated object */
+                       if (obj_allocated(page, obj_addr, &handle)) {
+                               obj_idx++;
+                               off += class->size;
+                               continue;
+                       }
+
+                       /* free deferred handle from reclaim attempt */
+                       if (obj_stores_deferred_handle(page, obj_addr, &handle))
+                               cache_free_handle(pool, handle);
+
+                       if (prev_free)
+                               prev_free->next = obj_idx << OBJ_TAG_BITS;
+                       else /* first free object found */
+                               set_freeobj(zspage, obj_idx);
+
+                       prev_free = (struct link_free *)vaddr + off / sizeof(*prev_free);
+                       /* if last free object in a previous page, need to unmap */
+                       if (prev_page_vaddr) {
+                               kunmap_atomic(prev_page_vaddr);
+                               prev_page_vaddr = NULL;
+                       }
+
+                       obj_idx++;
+                       off += class->size;
+               }
+
+               /*
+                * Handle the last (full or partial) object on this page.
+                */
+               next_page = get_next_page(page);
+               if (next_page) {
+                       if (!prev_free || prev_page_vaddr) {
+                               /*
+                                * There is no free object in this page, so we can safely
+                                * unmap it.
+                                */
+                               kunmap_atomic(vaddr);
+                       } else {
+                               /* update prev_page_vaddr since prev_free is on this page */
+                               prev_page_vaddr = vaddr;
+                       }
+               } else { /* this is the last page */
+                       if (prev_free) {
+                               /*
+                                * Reset OBJ_TAG_BITS bit to last link to tell
+                                * whether it's allocated object or not.
+                                */
+                               prev_free->next = -1UL << OBJ_TAG_BITS;
+                       }
+
+                       /* unmap previous page (if not done yet) */
+                       if (prev_page_vaddr) {
+                               kunmap_atomic(prev_page_vaddr);
+                               prev_page_vaddr = NULL;
+                       }
+
+                       kunmap_atomic(vaddr);
+               }
+
+               page = next_page;
+               off %= PAGE_SIZE;
+       }
+}
+
 static int zs_reclaim_page(struct zs_pool *pool, unsigned int retries)
 {
        int i, obj_idx, ret = 0;
@@ -2561,6 +2728,12 @@ next:
                        return 0;
                }
 
+               /*
+                * Eviction fails on one of the handles, so we need to restore zspage.
+                * We need to rebuild its freelist (and free stored deferred handles),
+                * put it back to the correct size class, and add it to the LRU list.
+                */
+               restore_freelist(pool, class, zspage);
                putback_zspage(class, zspage);
                list_add(&zspage->lru, &pool->lru);
                unlock_zspage(zspage);
index 9630b12..82c7005 100644 (file)
@@ -305,13 +305,12 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
        kfree(priv);
 }
 
-static int xen_9pfs_front_remove(struct xenbus_device *dev)
+static void xen_9pfs_front_remove(struct xenbus_device *dev)
 {
        struct xen_9pfs_front_priv *priv = dev_get_drvdata(&dev->dev);
 
        dev_set_drvdata(&dev->dev, NULL);
        xen_9pfs_front_free(priv);
-       return 0;
 }
 
 static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev,
index d3e542c..acf563f 100644 (file)
@@ -821,6 +821,7 @@ static void terminate_big_destroy(struct hci_dev *hdev, void *data, int err)
 static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis)
 {
        struct iso_list_data *d;
+       int ret;
 
        bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", big, bis);
 
@@ -831,8 +832,12 @@ static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis)
        d->big = big;
        d->bis = bis;
 
-       return hci_cmd_sync_queue(hdev, terminate_big_sync, d,
-                                 terminate_big_destroy);
+       ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d,
+                                terminate_big_destroy);
+       if (ret)
+               kfree(d);
+
+       return ret;
 }
 
 static int big_terminate_sync(struct hci_dev *hdev, void *data)
@@ -857,6 +862,7 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data)
 static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
 {
        struct iso_list_data *d;
+       int ret;
 
        bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle);
 
@@ -867,8 +873,12 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
        d->big = big;
        d->sync_handle = sync_handle;
 
-       return hci_cmd_sync_queue(hdev, big_terminate_sync, d,
-                                 terminate_big_destroy);
+       ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
+                                terminate_big_destroy);
+       if (ret)
+               kfree(d);
+
+       return ret;
 }
 
 /* Cleanup BIS connection
index 0594af4..ad92a4b 100644 (file)
@@ -3848,8 +3848,11 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
                           conn->handle, conn->link);
 
                /* Create CIS if LE is already connected */
-               if (conn->link && conn->link->state == BT_CONNECTED)
+               if (conn->link && conn->link->state == BT_CONNECTED) {
+                       rcu_read_unlock();
                        hci_le_create_cis(conn->link);
+                       rcu_read_lock();
+               }
 
                if (i == rp->num_handles)
                        break;
index 9e2d7e4..117eedb 100644 (file)
@@ -3572,7 +3572,7 @@ static const struct hci_init_stage hci_init2[] = {
 static int hci_le_read_buffer_size_sync(struct hci_dev *hdev)
 {
        /* Use Read LE Buffer Size V2 if supported */
-       if (hdev->commands[41] & 0x20)
+       if (iso_capable(hdev) && hdev->commands[41] & 0x20)
                return __hci_cmd_sync_status(hdev,
                                             HCI_OP_LE_READ_BUFFER_SIZE_V2,
                                             0, NULL, HCI_CMD_TIMEOUT);
@@ -3597,10 +3597,10 @@ static int hci_le_read_supported_states_sync(struct hci_dev *hdev)
 
 /* LE Controller init stage 2 command sequence */
 static const struct hci_init_stage le_init2[] = {
-       /* HCI_OP_LE_READ_BUFFER_SIZE */
-       HCI_INIT(hci_le_read_buffer_size_sync),
        /* HCI_OP_LE_READ_LOCAL_FEATURES */
        HCI_INIT(hci_le_read_local_features_sync),
+       /* HCI_OP_LE_READ_BUFFER_SIZE */
+       HCI_INIT(hci_le_read_buffer_size_sync),
        /* HCI_OP_LE_READ_SUPPORTED_STATES */
        HCI_INIT(hci_le_read_supported_states_sync),
        {}
@@ -6187,20 +6187,13 @@ int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
 
 static int _update_adv_data_sync(struct hci_dev *hdev, void *data)
 {
-       u8 instance = *(u8 *)data;
-
-       kfree(data);
+       u8 instance = PTR_ERR(data);
 
        return hci_update_adv_data_sync(hdev, instance);
 }
 
 int hci_update_adv_data(struct hci_dev *hdev, u8 instance)
 {
-       u8 *inst_ptr = kmalloc(1, GFP_KERNEL);
-
-       if (!inst_ptr)
-               return -ENOMEM;
-
-       *inst_ptr = instance;
-       return hci_cmd_sync_queue(hdev, _update_adv_data_sync, inst_ptr, NULL);
+       return hci_cmd_sync_queue(hdev, _update_adv_data_sync,
+                                 ERR_PTR(instance), NULL);
 }
index 035bb5d..24444b5 100644 (file)
@@ -289,15 +289,15 @@ static int iso_connect_bis(struct sock *sk)
        hci_dev_unlock(hdev);
        hci_dev_put(hdev);
 
+       err = iso_chan_add(conn, sk, NULL);
+       if (err)
+               return err;
+
        lock_sock(sk);
 
        /* Update source addr of the socket */
        bacpy(&iso_pi(sk)->src, &hcon->src);
 
-       err = iso_chan_add(conn, sk, NULL);
-       if (err)
-               goto release;
-
        if (hcon->state == BT_CONNECTED) {
                iso_sock_clear_timer(sk);
                sk->sk_state = BT_CONNECTED;
@@ -306,7 +306,6 @@ static int iso_connect_bis(struct sock *sk)
                iso_sock_set_timer(sk, sk->sk_sndtimeo);
        }
 
-release:
        release_sock(sk);
        return err;
 
@@ -372,15 +371,15 @@ static int iso_connect_cis(struct sock *sk)
        hci_dev_unlock(hdev);
        hci_dev_put(hdev);
 
+       err = iso_chan_add(conn, sk, NULL);
+       if (err)
+               return err;
+
        lock_sock(sk);
 
        /* Update source addr of the socket */
        bacpy(&iso_pi(sk)->src, &hcon->src);
 
-       err = iso_chan_add(conn, sk, NULL);
-       if (err)
-               goto release;
-
        if (hcon->state == BT_CONNECTED) {
                iso_sock_clear_timer(sk);
                sk->sk_state = BT_CONNECTED;
@@ -392,7 +391,6 @@ static int iso_connect_cis(struct sock *sk)
                iso_sock_set_timer(sk, sk->sk_sndtimeo);
        }
 
-release:
        release_sock(sk);
        return err;
 
@@ -895,13 +893,10 @@ static int iso_listen_bis(struct sock *sk)
        if (!hdev)
                return -EHOSTUNREACH;
 
-       hci_dev_lock(hdev);
-
        err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
                                 le_addr_type(iso_pi(sk)->dst_type),
                                 iso_pi(sk)->bc_sid);
 
-       hci_dev_unlock(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1432,33 +1427,29 @@ static void iso_conn_ready(struct iso_conn *conn)
        struct sock *parent;
        struct sock *sk = conn->sk;
        struct hci_ev_le_big_sync_estabilished *ev;
+       struct hci_conn *hcon;
 
        BT_DBG("conn %p", conn);
 
        if (sk) {
                iso_sock_ready(conn->sk);
        } else {
-               iso_conn_lock(conn);
-
-               if (!conn->hcon) {
-                       iso_conn_unlock(conn);
+               hcon = conn->hcon;
+               if (!hcon)
                        return;
-               }
 
-               ev = hci_recv_event_data(conn->hcon->hdev,
+               ev = hci_recv_event_data(hcon->hdev,
                                         HCI_EVT_LE_BIG_SYNC_ESTABILISHED);
                if (ev)
-                       parent = iso_get_sock_listen(&conn->hcon->src,
-                                                    &conn->hcon->dst,
+                       parent = iso_get_sock_listen(&hcon->src,
+                                                    &hcon->dst,
                                                     iso_match_big, ev);
                else
-                       parent = iso_get_sock_listen(&conn->hcon->src,
+                       parent = iso_get_sock_listen(&hcon->src,
                                                     BDADDR_ANY, NULL, NULL);
 
-               if (!parent) {
-                       iso_conn_unlock(conn);
+               if (!parent)
                        return;
-               }
 
                lock_sock(parent);
 
@@ -1466,30 +1457,29 @@ static void iso_conn_ready(struct iso_conn *conn)
                                    BTPROTO_ISO, GFP_ATOMIC, 0);
                if (!sk) {
                        release_sock(parent);
-                       iso_conn_unlock(conn);
                        return;
                }
 
                iso_sock_init(sk, parent);
 
-               bacpy(&iso_pi(sk)->src, &conn->hcon->src);
-               iso_pi(sk)->src_type = conn->hcon->src_type;
+               bacpy(&iso_pi(sk)->src, &hcon->src);
+               iso_pi(sk)->src_type = hcon->src_type;
 
                /* If hcon has no destination address (BDADDR_ANY) it means it
                 * was created by HCI_EV_LE_BIG_SYNC_ESTABILISHED so we need to
                 * initialize using the parent socket destination address.
                 */
-               if (!bacmp(&conn->hcon->dst, BDADDR_ANY)) {
-                       bacpy(&conn->hcon->dst, &iso_pi(parent)->dst);
-                       conn->hcon->dst_type = iso_pi(parent)->dst_type;
-                       conn->hcon->sync_handle = iso_pi(parent)->sync_handle;
+               if (!bacmp(&hcon->dst, BDADDR_ANY)) {
+                       bacpy(&hcon->dst, &iso_pi(parent)->dst);
+                       hcon->dst_type = iso_pi(parent)->dst_type;
+                       hcon->sync_handle = iso_pi(parent)->sync_handle;
                }
 
-               bacpy(&iso_pi(sk)->dst, &conn->hcon->dst);
-               iso_pi(sk)->dst_type = conn->hcon->dst_type;
+               bacpy(&iso_pi(sk)->dst, &hcon->dst);
+               iso_pi(sk)->dst_type = hcon->dst_type;
 
-               hci_conn_hold(conn->hcon);
-               __iso_chan_add(conn, sk, parent);
+               hci_conn_hold(hcon);
+               iso_chan_add(conn, sk, parent);
 
                if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
                        sk->sk_state = BT_CONNECT2;
@@ -1500,8 +1490,6 @@ static void iso_conn_ready(struct iso_conn *conn)
                parent->sk_data_ready(parent);
 
                release_sock(parent);
-
-               iso_conn_unlock(conn);
        }
 }
 
index 6a8b7e8..bdf9786 100644 (file)
@@ -27,7 +27,7 @@ struct mgmt_mesh_tx {
        struct sock *sk;
        u8 handle;
        u8 instance;
-       u8 param[sizeof(struct mgmt_cp_mesh_send) + 29];
+       u8 param[sizeof(struct mgmt_cp_mesh_send) + 31];
 };
 
 struct mgmt_pending_cmd {
index 21e24da..4397e14 100644 (file)
@@ -391,6 +391,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
            addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       sock_hold(sk);
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
@@ -410,14 +411,18 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
        d->sec_level = rfcomm_pi(sk)->sec_level;
        d->role_switch = rfcomm_pi(sk)->role_switch;
 
+       /* Drop sock lock to avoid potential deadlock with the RFCOMM lock */
+       release_sock(sk);
        err = rfcomm_dlc_open(d, &rfcomm_pi(sk)->src, &sa->rc_bdaddr,
                              sa->rc_channel);
-       if (!err)
+       lock_sock(sk);
+       if (!err && !sock_flag(sk, SOCK_ZAPPED))
                err = bt_sock_wait_state(sk, BT_CONNECTED,
                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
 done:
        release_sock(sk);
+       sock_put(sk);
        return err;
 }
 
index f20f437..9554abc 100644 (file)
@@ -871,6 +871,7 @@ static unsigned int ip_sabotage_in(void *priv,
        if (nf_bridge && !nf_bridge->in_prerouting &&
            !netif_is_l3_master(skb->dev) &&
            !netif_is_l3_slave(skb->dev)) {
+               nf_bridge_info_free(skb);
                state->okfn(state->net, state->sk, skb);
                return NF_STOLEN;
        }
index 608f8c2..fc81d77 100644 (file)
@@ -140,7 +140,7 @@ struct isotp_sock {
        canid_t rxid;
        ktime_t tx_gap;
        ktime_t lastrxcf_tstamp;
-       struct hrtimer rxtimer, txtimer;
+       struct hrtimer rxtimer, txtimer, txfrtimer;
        struct can_isotp_options opt;
        struct can_isotp_fc_options rxfc, txfc;
        struct can_isotp_ll_options ll;
@@ -871,7 +871,7 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
        }
 
        /* start timer to send next consecutive frame with correct delay */
-       hrtimer_start(&so->txtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
+       hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
 }
 
 static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
@@ -879,49 +879,39 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
        struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
                                             txtimer);
        struct sock *sk = &so->sk;
-       enum hrtimer_restart restart = HRTIMER_NORESTART;
 
-       switch (so->tx.state) {
-       case ISOTP_SENDING:
-
-               /* cfecho should be consumed by isotp_rcv_echo() here */
-               if (!so->cfecho) {
-                       /* start timeout for unlikely lost echo skb */
-                       hrtimer_set_expires(&so->txtimer,
-                                           ktime_add(ktime_get(),
-                                                     ktime_set(ISOTP_ECHO_TIMEOUT, 0)));
-                       restart = HRTIMER_RESTART;
+       /* don't handle timeouts in IDLE state */
+       if (so->tx.state == ISOTP_IDLE)
+               return HRTIMER_NORESTART;
 
-                       /* push out the next consecutive frame */
-                       isotp_send_cframe(so);
-                       break;
-               }
+       /* we did not get any flow control or echo frame in time */
 
-               /* cfecho has not been cleared in isotp_rcv_echo() */
-               pr_notice_once("can-isotp: cfecho %08X timeout\n", so->cfecho);
-               fallthrough;
+       /* report 'communication error on send' */
+       sk->sk_err = ECOMM;
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk_error_report(sk);
 
-       case ISOTP_WAIT_FC:
-       case ISOTP_WAIT_FIRST_FC:
+       /* reset tx state */
+       so->tx.state = ISOTP_IDLE;
+       wake_up_interruptible(&so->wait);
 
-               /* we did not get any flow control frame in time */
+       return HRTIMER_NORESTART;
+}
 
-               /* report 'communication error on send' */
-               sk->sk_err = ECOMM;
-               if (!sock_flag(sk, SOCK_DEAD))
-                       sk_error_report(sk);
+static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
+{
+       struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
+                                            txfrtimer);
 
-               /* reset tx state */
-               so->tx.state = ISOTP_IDLE;
-               wake_up_interruptible(&so->wait);
-               break;
+       /* start echo timeout handling and cover below protocol error */
+       hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
+                     HRTIMER_MODE_REL_SOFT);
 
-       default:
-               WARN_ONCE(1, "can-isotp: tx timer state %08X cfecho %08X\n",
-                         so->tx.state, so->cfecho);
-       }
+       /* cfecho should be consumed by isotp_rcv_echo() here */
+       if (so->tx.state == ISOTP_SENDING && !so->cfecho)
+               isotp_send_cframe(so);
 
-       return restart;
+       return HRTIMER_NORESTART;
 }
 
 static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
@@ -1162,6 +1152,10 @@ static int isotp_release(struct socket *sock)
        /* wait for complete transmission of current pdu */
        wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
 
+       /* force state machines to be idle also when a signal occurred */
+       so->tx.state = ISOTP_IDLE;
+       so->rx.state = ISOTP_IDLE;
+
        spin_lock(&isotp_notifier_lock);
        while (isotp_busy_notifier == so) {
                spin_unlock(&isotp_notifier_lock);
@@ -1194,6 +1188,7 @@ static int isotp_release(struct socket *sock)
                }
        }
 
+       hrtimer_cancel(&so->txfrtimer);
        hrtimer_cancel(&so->txtimer);
        hrtimer_cancel(&so->rxtimer);
 
@@ -1597,6 +1592,8 @@ static int isotp_init(struct sock *sk)
        so->rxtimer.function = isotp_rx_timer_handler;
        hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
        so->txtimer.function = isotp_tx_timer_handler;
+       hrtimer_init(&so->txfrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+       so->txfrtimer.function = isotp_txfr_timer_handler;
 
        init_waitqueue_head(&so->wait);
        spin_lock_init(&so->rx_lock);
index f33c473..ca4ad6c 100644 (file)
@@ -165,6 +165,46 @@ static void j1939_ac_process(struct j1939_priv *priv, struct sk_buff *skb)
         * leaving this function.
         */
        ecu = j1939_ecu_get_by_name_locked(priv, name);
+
+       if (ecu && ecu->addr == skcb->addr.sa) {
+               /* The ISO 11783-5 standard, in "4.5.2 - Address claim
+                * requirements", states:
+                *   d) No CF shall begin, or resume, transmission on the
+                *      network until 250 ms after it has successfully claimed
+                *      an address except when responding to a request for
+                *      address-claimed.
+                *
+                * But "Figure 6" and "Figure 7" in "4.5.4.2 - Address-claim
+                * prioritization" show that the CF begins the transmission
+                * after 250 ms from the first AC (address-claimed) message
+                * even if it sends another AC message during that time window
+                * to resolve the address contention with another CF.
+                *
+                * As stated in "4.4.2.3 - Address-claimed message":
+                *   In order to successfully claim an address, the CF sending
+                *   an address claimed message shall not receive a contending
+                *   claim from another CF for at least 250 ms.
+                *
+                * As stated in "4.4.3.2 - NAME management (NM) message":
+                *   1) A commanding CF can
+                *      d) request that a CF with a specified NAME transmit
+                *         the address-claimed message with its current NAME.
+                *   2) A target CF shall
+                *      d) send an address-claimed message in response to a
+                *         request for a matching NAME
+                *
+                * Taking the above arguments into account, the 250 ms wait is
+                * requested only during network initialization.
+                *
+                * Do not restart the timer on AC message if both the NAME and
+                * the address match and so if the address has already been
+                * claimed (timer has expired) or the AC message has been sent
+                * to resolve the contention with another CF (timer is still
+                * running).
+                */
+               goto out_ecu_put;
+       }
+
        if (!ecu && j1939_address_is_unicast(skcb->addr.sa))
                ecu = j1939_ecu_create_locked(priv, name);
 
index 5c722b5..fce9b9e 100644 (file)
@@ -1092,10 +1092,6 @@ static bool j1939_session_deactivate(struct j1939_session *session)
        bool active;
 
        j1939_session_list_lock(priv);
-       /* This function should be called with a session ref-count of at
-        * least 2.
-        */
-       WARN_ON_ONCE(kref_read(&session->kref) < 2);
        active = j1939_session_deactivate_locked(session);
        j1939_session_list_unlock(priv);
 
index 81071cd..ba86782 100644 (file)
@@ -132,8 +132,8 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
                return;
 
        /* make sure to not pass oversized frames to the socket */
-       if ((can_is_canfd_skb(oskb) && !ro->fd_frames && !ro->xl_frames) ||
-           (can_is_canxl_skb(oskb) && !ro->xl_frames))
+       if ((!ro->fd_frames && can_is_canfd_skb(oskb)) ||
+           (!ro->xl_frames && can_is_canxl_skb(oskb)))
                return;
 
        /* eliminate multiple filter matches for the same skb */
@@ -670,6 +670,11 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
                if (copy_from_sockptr(&ro->fd_frames, optval, optlen))
                        return -EFAULT;
 
+               /* Enabling CAN XL includes CAN FD */
+               if (ro->xl_frames && !ro->fd_frames) {
+                       ro->fd_frames = ro->xl_frames;
+                       return -EINVAL;
+               }
                break;
 
        case CAN_RAW_XL_FRAMES:
@@ -679,6 +684,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
                if (copy_from_sockptr(&ro->xl_frames, optval, optlen))
                        return -EFAULT;
 
+               /* Enabling CAN XL includes CAN FD */
+               if (ro->xl_frames)
+                       ro->fd_frames = ro->xl_frames;
                break;
 
        case CAN_RAW_JOIN_FILTERS:
@@ -786,6 +794,25 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
        return 0;
 }
 
+static bool raw_bad_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu)
+{
+       /* Classical CAN -> no checks for flags and device capabilities */
+       if (can_is_can_skb(skb))
+               return false;
+
+       /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */
+       if (ro->fd_frames && can_is_canfd_skb(skb) &&
+           (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu)))
+               return false;
+
+       /* CAN XL -> needs to be enabled and a CAN XL device */
+       if (ro->xl_frames && can_is_canxl_skb(skb) &&
+           can_is_canxl_dev_mtu(mtu))
+               return false;
+
+       return true;
+}
+
 static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 {
        struct sock *sk = sock->sk;
@@ -833,20 +860,8 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
                goto free_skb;
 
        err = -EINVAL;
-       if (ro->xl_frames && can_is_canxl_dev_mtu(dev->mtu)) {
-               /* CAN XL, CAN FD and Classical CAN */
-               if (!can_is_canxl_skb(skb) && !can_is_canfd_skb(skb) &&
-                   !can_is_can_skb(skb))
-                       goto free_skb;
-       } else if (ro->fd_frames && dev->mtu == CANFD_MTU) {
-               /* CAN FD and Classical CAN */
-               if (!can_is_canfd_skb(skb) && !can_is_can_skb(skb))
-                       goto free_skb;
-       } else {
-               /* Classical CAN */
-               if (!can_is_can_skb(skb))
-                       goto free_skb;
-       }
+       if (raw_bad_txframe(ro, skb, dev->mtu))
+               goto free_skb;
 
        sockcm_init(&sockc, sk);
        if (msg->msg_controllen) {
index 032d6d0..909a10e 100644 (file)
@@ -9979,7 +9979,7 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
                goto err_xa_alloc;
 
        devlink->netdevice_nb.notifier_call = devlink_netdevice_event;
-       ret = register_netdevice_notifier_net(net, &devlink->netdevice_nb);
+       ret = register_netdevice_notifier(&devlink->netdevice_nb);
        if (ret)
                goto err_register_netdevice_notifier;
 
@@ -10171,8 +10171,7 @@ void devlink_free(struct devlink *devlink)
        xa_destroy(&devlink->snapshot_ids);
        xa_destroy(&devlink->ports);
 
-       WARN_ON_ONCE(unregister_netdevice_notifier_net(devlink_net(devlink),
-                                                      &devlink->netdevice_nb));
+       WARN_ON_ONCE(unregister_netdevice_notifier(&devlink->netdevice_nb));
 
        xa_erase(&devlinks, devlink->index);
 
@@ -10503,6 +10502,8 @@ static int devlink_netdevice_event(struct notifier_block *nb,
                break;
        case NETDEV_REGISTER:
        case NETDEV_CHANGENAME:
+               if (devlink_net(devlink) != dev_net(netdev))
+                       return NOTIFY_OK;
                /* Set the netdev on top of previously set type. Note this
                 * event happens also during net namespace change so here
                 * we take into account netdev pointer appearing in this
@@ -10512,6 +10513,8 @@ static int devlink_netdevice_event(struct notifier_block *nb,
                                        netdev);
                break;
        case NETDEV_UNREGISTER:
+               if (devlink_net(devlink) != dev_net(netdev))
+                       return NOTIFY_OK;
                /* Clear netdev pointer, but not the type. This event happens
                 * also during net namespace change so we need to clear
                 * pointer to netdev that is going to another net namespace.
index fd8c6a7..4bac7ea 100644 (file)
@@ -162,6 +162,15 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
        struct sk_buff *lp;
        int segs;
 
+       /* Do not splice page pool based packets w/ non-page pool
+        * packets. This can result in reference count issues as page
+        * pool pages will not decrement the reference count and will
+        * instead be immediately returned to the pool or have frag
+        * count decremented.
+        */
+       if (p->pp_recycle != skb->pp_recycle)
+               return -ETOOMANYREFS;
+
        /* pairs with WRITE_ONCE() in netif_set_gro_max_size() */
        gro_max_size = READ_ONCE(p->dev->gro_max_size);
 
@@ -505,8 +514,9 @@ found_ptype:
        NAPI_GRO_CB(skb)->count = 1;
        if (unlikely(skb_is_gso(skb))) {
                NAPI_GRO_CB(skb)->count = skb_shinfo(skb)->gso_segs;
-               /* Only support TCP at the moment. */
-               if (!skb_is_gso_tcp(skb))
+               /* Only support TCP and non DODGY users. */
+               if (!skb_is_gso_tcp(skb) ||
+                   (skb_shinfo(skb)->gso_type & SKB_GSO_DODGY))
                        NAPI_GRO_CB(skb)->flush = 1;
        }
 
index f00a79f..4edd217 100644 (file)
@@ -269,7 +269,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
                            (n->nud_state == NUD_NOARP) ||
                            (tbl->is_multicast &&
                             tbl->is_multicast(n->primary_key)) ||
-                           time_after(tref, n->updated))
+                           !time_in_range(n->updated, tref, jiffies))
                                remove = true;
                        write_unlock(&n->lock);
 
@@ -289,7 +289,17 @@ static int neigh_forced_gc(struct neigh_table *tbl)
 
 static void neigh_add_timer(struct neighbour *n, unsigned long when)
 {
+       /* Use safe distance from the jiffies - LONG_MAX point while timer
+        * is running in DELAY/PROBE state but still show to user space
+        * large times in the past.
+        */
+       unsigned long mint = jiffies - (LONG_MAX - 86400 * HZ);
+
        neigh_hold(n);
+       if (!time_in_range(n->confirmed, mint, jiffies))
+               n->confirmed = mint;
+       if (time_before(n->used, n->confirmed))
+               n->used = n->confirmed;
        if (unlikely(mod_timer(&n->timer, when))) {
                printk("NEIGH: BUG, double timer add, state is %x\n",
                       n->nud_state);
@@ -1001,12 +1011,14 @@ static void neigh_periodic_work(struct work_struct *work)
                                goto next_elt;
                        }
 
-                       if (time_before(n->used, n->confirmed))
+                       if (time_before(n->used, n->confirmed) &&
+                           time_is_before_eq_jiffies(n->confirmed))
                                n->used = n->confirmed;
 
                        if (refcount_read(&n->refcnt) == 1 &&
                            (state == NUD_FAILED ||
-                            time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
+                            !time_in_range_open(jiffies, n->used,
+                                                n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
                                *np = n->next;
                                neigh_mark_dead(n);
                                write_unlock(&n->lock);
index 5581d22..078a0a4 100644 (file)
@@ -137,12 +137,12 @@ static int ops_init(const struct pernet_operations *ops, struct net *net)
                return 0;
 
        if (ops->id && ops->size) {
-cleanup:
                ng = rcu_dereference_protected(net->gen,
                                               lockdep_is_held(&pernet_ops_rwsem));
                ng->ptr[*ops->id] = NULL;
        }
 
+cleanup:
        kfree(data);
 
 out:
index 4a0eb55..a31ff4d 100644 (file)
@@ -4100,7 +4100,7 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
 
        skb_shinfo(skb)->frag_list = NULL;
 
-       do {
+       while (list_skb) {
                nskb = list_skb;
                list_skb = list_skb->next;
 
@@ -4146,8 +4146,7 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
                if (skb_needs_linearize(nskb, features) &&
                    __skb_linearize(nskb))
                        goto err_linearize;
-
-       } while (list_skb);
+       }
 
        skb->truesize = skb->truesize - delta_truesize;
        skb->data_len = skb->data_len - delta_len;
index f954d58..6f27c24 100644 (file)
@@ -1531,6 +1531,8 @@ set_sndbuf:
                        ret = -EINVAL;
                        break;
                }
+               if ((u8)val == SOCK_TXREHASH_DEFAULT)
+                       val = READ_ONCE(sock_net(sk)->core.sysctl_txrehash);
                /* Paired with READ_ONCE() in tcp_rtx_synack() */
                WRITE_ONCE(sk->sk_txrehash, (u8)val);
                break;
@@ -3451,7 +3453,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        sk->sk_pacing_rate = ~0UL;
        WRITE_ONCE(sk->sk_pacing_shift, 10);
        sk->sk_incoming_cpu = -1;
-       sk->sk_txrehash = SOCK_TXREHASH_DEFAULT;
 
        sk_rx_queue_clear(sk);
        /*
index 22fa2c5..a68a729 100644 (file)
@@ -1569,15 +1569,16 @@ void sock_map_unhash(struct sock *sk)
        psock = sk_psock(sk);
        if (unlikely(!psock)) {
                rcu_read_unlock();
-               if (sk->sk_prot->unhash)
-                       sk->sk_prot->unhash(sk);
-               return;
+               saved_unhash = READ_ONCE(sk->sk_prot)->unhash;
+       } else {
+               saved_unhash = psock->saved_unhash;
+               sock_map_remove_links(sk, psock);
+               rcu_read_unlock();
        }
-
-       saved_unhash = psock->saved_unhash;
-       sock_map_remove_links(sk, psock);
-       rcu_read_unlock();
-       saved_unhash(sk);
+       if (WARN_ON_ONCE(saved_unhash == sock_map_unhash))
+               return;
+       if (saved_unhash)
+               saved_unhash(sk);
 }
 EXPORT_SYMBOL_GPL(sock_map_unhash);
 
@@ -1590,17 +1591,18 @@ void sock_map_destroy(struct sock *sk)
        psock = sk_psock_get(sk);
        if (unlikely(!psock)) {
                rcu_read_unlock();
-               if (sk->sk_prot->destroy)
-                       sk->sk_prot->destroy(sk);
-               return;
+               saved_destroy = READ_ONCE(sk->sk_prot)->destroy;
+       } else {
+               saved_destroy = psock->saved_destroy;
+               sock_map_remove_links(sk, psock);
+               rcu_read_unlock();
+               sk_psock_stop(psock);
+               sk_psock_put(sk, psock);
        }
-
-       saved_destroy = psock->saved_destroy;
-       sock_map_remove_links(sk, psock);
-       rcu_read_unlock();
-       sk_psock_stop(psock);
-       sk_psock_put(sk, psock);
-       saved_destroy(sk);
+       if (WARN_ON_ONCE(saved_destroy == sock_map_destroy))
+               return;
+       if (saved_destroy)
+               saved_destroy(sk);
 }
 EXPORT_SYMBOL_GPL(sock_map_destroy);
 
@@ -1615,16 +1617,21 @@ void sock_map_close(struct sock *sk, long timeout)
        if (unlikely(!psock)) {
                rcu_read_unlock();
                release_sock(sk);
-               return sk->sk_prot->close(sk, timeout);
+               saved_close = READ_ONCE(sk->sk_prot)->close;
+       } else {
+               saved_close = psock->saved_close;
+               sock_map_remove_links(sk, psock);
+               rcu_read_unlock();
+               sk_psock_stop(psock);
+               release_sock(sk);
+               cancel_work_sync(&psock->work);
+               sk_psock_put(sk, psock);
        }
-
-       saved_close = psock->saved_close;
-       sock_map_remove_links(sk, psock);
-       rcu_read_unlock();
-       sk_psock_stop(psock);
-       release_sock(sk);
-       cancel_work_sync(&psock->work);
-       sk_psock_put(sk, psock);
+       /* Make sure we do not recurse. This is a bug.
+        * Leak the socket instead of crashing on a stack overflow.
+        */
+       if (WARN_ON_ONCE(saved_close == sock_map_close))
+               return;
        saved_close(sk, timeout);
 }
 EXPORT_SYMBOL_GPL(sock_map_close);
index ebe6145..be260ab 100644 (file)
@@ -122,10 +122,13 @@ rss_fill_reply(struct sk_buff *skb, const struct ethnl_req_info *req_base,
 {
        const struct rss_reply_data *data = RSS_REPDATA(reply_base);
 
-       if (nla_put_u32(skb, ETHTOOL_A_RSS_HFUNC, data->hfunc) ||
-           nla_put(skb, ETHTOOL_A_RSS_INDIR,
-                   sizeof(u32) * data->indir_size, data->indir_table) ||
-           nla_put(skb, ETHTOOL_A_RSS_HKEY, data->hkey_size, data->hkey))
+       if ((data->hfunc &&
+            nla_put_u32(skb, ETHTOOL_A_RSS_HFUNC, data->hfunc)) ||
+           (data->indir_size &&
+            nla_put(skb, ETHTOOL_A_RSS_INDIR,
+                    sizeof(u32) * data->indir_size, data->indir_table)) ||
+           (data->hkey_size &&
+            nla_put(skb, ETHTOOL_A_RSS_HKEY, data->hkey_size, data->hkey)))
                return -EMSGSIZE;
 
        return 0;
index 6c0ec27..cf11f10 100644 (file)
@@ -347,6 +347,7 @@ lookup_protocol:
        sk->sk_destruct    = inet_sock_destruct;
        sk->sk_protocol    = protocol;
        sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+       sk->sk_txrehash = READ_ONCE(net->core.sysctl_txrehash);
 
        inet->uc_ttl    = -1;
        inet->mc_loop   = 1;
index ce9ff3c..3bb890a 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/netlink.h>
 #include <linux/hash.h>
+#include <linux/nospec.h>
 
 #include <net/arp.h>
 #include <net/inet_dscp.h>
@@ -1022,6 +1023,7 @@ bool fib_metrics_match(struct fib_config *cfg, struct fib_info *fi)
                if (type > RTAX_MAX)
                        return false;
 
+               type = array_index_nospec(type, RTAX_MAX + 1);
                if (type == RTAX_CC_ALGO) {
                        char tmp[TCP_CA_NAME_MAX];
                        bool ecn_ca = false;
index d1f8375..f2c43f6 100644 (file)
@@ -1225,9 +1225,6 @@ int inet_csk_listen_start(struct sock *sk)
        sk->sk_ack_backlog = 0;
        inet_csk_delack_init(sk);
 
-       if (sk->sk_txrehash == SOCK_TXREHASH_DEFAULT)
-               sk->sk_txrehash = READ_ONCE(sock_net(sk)->core.sysctl_txrehash);
-
        /* There is race window here: we announce ourselves listening,
         * but this transition is still not validated by get_port().
         * It is OK, because this socket enters to hash table only
index 24a38b5..f58d738 100644 (file)
@@ -650,8 +650,20 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk)
        spin_lock(lock);
        if (osk) {
                WARN_ON_ONCE(sk->sk_hash != osk->sk_hash);
-               ret = sk_nulls_del_node_init_rcu(osk);
-       } else if (found_dup_sk) {
+               ret = sk_hashed(osk);
+               if (ret) {
+                       /* Before deleting the node, we insert a new one to make
+                        * sure that the look-up-sk process would not miss either
+                        * of them and that at least one node would exist in ehash
+                        * table all the time. Otherwise there's a tiny chance
+                        * that lookup process could find nothing in ehash table.
+                        */
+                       __sk_nulls_add_node_tail_rcu(sk, list);
+                       sk_nulls_del_node_init_rcu(osk);
+               }
+               goto unlock;
+       }
+       if (found_dup_sk) {
                *found_dup_sk = inet_ehash_lookup_by_sk(sk, list);
                if (*found_dup_sk)
                        ret = false;
@@ -660,6 +672,7 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk)
        if (ret)
                __sk_nulls_add_node_rcu(sk, list);
 
+unlock:
        spin_unlock(lock);
 
        return ret;
index 1d77d99..beed32f 100644 (file)
@@ -91,10 +91,10 @@ void inet_twsk_put(struct inet_timewait_sock *tw)
 }
 EXPORT_SYMBOL_GPL(inet_twsk_put);
 
-static void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw,
-                                  struct hlist_nulls_head *list)
+static void inet_twsk_add_node_tail_rcu(struct inet_timewait_sock *tw,
+                                       struct hlist_nulls_head *list)
 {
-       hlist_nulls_add_head_rcu(&tw->tw_node, list);
+       hlist_nulls_add_tail_rcu(&tw->tw_node, list);
 }
 
 static void inet_twsk_add_bind_node(struct inet_timewait_sock *tw,
@@ -147,7 +147,7 @@ void inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
 
        spin_lock(lock);
 
-       inet_twsk_add_node_rcu(tw, &ehead->chain);
+       inet_twsk_add_node_tail_rcu(tw, &ehead->chain);
 
        /* Step 3: Remove SK from hash chain */
        if (__sk_nulls_del_node_init_rcu(sk))
index 7fcfdfd..0e3ee15 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <linux/netlink.h>
+#include <linux/nospec.h>
 #include <linux/rtnetlink.h>
 #include <linux/types.h>
 #include <net/ip.h>
@@ -25,6 +26,7 @@ static int ip_metrics_convert(struct net *net, struct nlattr *fc_mx,
                        return -EINVAL;
                }
 
+               type = array_index_nospec(type, RTAX_MAX + 1);
                if (type == RTAX_CC_ALGO) {
                        char tmp[TCP_CA_NAME_MAX];
 
index c567d5e..33f559f 100644 (file)
@@ -435,6 +435,7 @@ void tcp_init_sock(struct sock *sk)
 
        /* There's a bubble in the pipe until at least the first ACK. */
        tp->app_limited = ~0U;
+       tp->rate_app_limited = 1;
 
        /* See draft-stevens-tcpca-spec-01 for discussion of the
         * initialization of these values.
@@ -3178,6 +3179,7 @@ int tcp_disconnect(struct sock *sk, int flags)
        tp->plb_rehash = 0;
        /* There's a bubble in the pipe until at least the first ACK. */
        tp->app_limited = ~0U;
+       tp->rate_app_limited = 1;
        tp->rack.mstamp = 0;
        tp->rack.advanced = 0;
        tp->rack.reo_wnd_steps = 1;
index 94aad38..cf26d65 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/bpf.h>
 #include <linux/init.h>
 #include <linux/wait.h>
+#include <linux/util_macros.h>
 
 #include <net/inet_common.h>
 #include <net/tls.h>
@@ -639,10 +640,9 @@ EXPORT_SYMBOL_GPL(tcp_bpf_update_proto);
  */
 void tcp_bpf_clone(const struct sock *sk, struct sock *newsk)
 {
-       int family = sk->sk_family == AF_INET6 ? TCP_BPF_IPV6 : TCP_BPF_IPV4;
        struct proto *prot = newsk->sk_prot;
 
-       if (prot == &tcp_bpf_prots[family][TCP_BPF_BASE])
+       if (is_insidevar(prot, tcp_bpf_prots))
                newsk->sk_prot = sk->sk_prot_creator;
 }
 #endif /* CONFIG_BPF_SYSCALL */
index 05b6077..2aa4421 100644 (file)
@@ -139,7 +139,7 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
        if (sk->sk_socket)
                clear_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags);
 
-       err = -EINVAL;
+       err = -ENOTCONN;
        if (!ulp_ops->clone && sk->sk_state == TCP_LISTEN)
                goto out_err;
 
index f7a84a4..faa47f9 100644 (file)
@@ -3127,17 +3127,17 @@ static void add_v4_addrs(struct inet6_dev *idev)
                offset = sizeof(struct in6_addr) - 4;
        memcpy(&addr.s6_addr32[3], idev->dev->dev_addr + offset, 4);
 
-       if (idev->dev->flags&IFF_POINTOPOINT) {
+       if (!(idev->dev->flags & IFF_POINTOPOINT) && idev->dev->type == ARPHRD_SIT) {
+               scope = IPV6_ADDR_COMPATv4;
+               plen = 96;
+               pflags |= RTF_NONEXTHOP;
+       } else {
                if (idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_NONE)
                        return;
 
                addr.s6_addr32[0] = htonl(0xfe800000);
                scope = IFA_LINK;
                plen = 64;
-       } else {
-               scope = IPV6_ADDR_COMPATv4;
-               plen = 96;
-               pflags |= RTF_NONEXTHOP;
        }
 
        if (addr.s6_addr32[3]) {
@@ -3447,6 +3447,30 @@ static void addrconf_gre_config(struct net_device *dev)
 }
 #endif
 
+static void addrconf_init_auto_addrs(struct net_device *dev)
+{
+       switch (dev->type) {
+#if IS_ENABLED(CONFIG_IPV6_SIT)
+       case ARPHRD_SIT:
+               addrconf_sit_config(dev);
+               break;
+#endif
+#if IS_ENABLED(CONFIG_NET_IPGRE) || IS_ENABLED(CONFIG_IPV6_GRE)
+       case ARPHRD_IP6GRE:
+       case ARPHRD_IPGRE:
+               addrconf_gre_config(dev);
+               break;
+#endif
+       case ARPHRD_LOOPBACK:
+               init_loopback(dev);
+               break;
+
+       default:
+               addrconf_dev_config(dev);
+               break;
+       }
+}
+
 static int fixup_permanent_addr(struct net *net,
                                struct inet6_dev *idev,
                                struct inet6_ifaddr *ifp)
@@ -3615,26 +3639,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        run_pending = 1;
                }
 
-               switch (dev->type) {
-#if IS_ENABLED(CONFIG_IPV6_SIT)
-               case ARPHRD_SIT:
-                       addrconf_sit_config(dev);
-                       break;
-#endif
-#if IS_ENABLED(CONFIG_NET_IPGRE) || IS_ENABLED(CONFIG_IPV6_GRE)
-               case ARPHRD_IP6GRE:
-               case ARPHRD_IPGRE:
-                       addrconf_gre_config(dev);
-                       break;
-#endif
-               case ARPHRD_LOOPBACK:
-                       init_loopback(dev);
-                       break;
-
-               default:
-                       addrconf_dev_config(dev);
-                       break;
-               }
+               addrconf_init_auto_addrs(dev);
 
                if (!IS_ERR_OR_NULL(idev)) {
                        if (run_pending)
@@ -6397,7 +6402,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
 
                        if (idev->cnf.addr_gen_mode != new_val) {
                                idev->cnf.addr_gen_mode = new_val;
-                               addrconf_dev_config(idev->dev);
+                               addrconf_init_auto_addrs(idev->dev);
                        }
                } else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) {
                        struct net_device *dev;
@@ -6408,7 +6413,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
                                if (idev &&
                                    idev->cnf.addr_gen_mode != new_val) {
                                        idev->cnf.addr_gen_mode = new_val;
-                                       addrconf_dev_config(idev->dev);
+                                       addrconf_init_auto_addrs(idev->dev);
                                }
                        }
                }
index fee9163..8479347 100644 (file)
@@ -222,6 +222,7 @@ lookup_protocol:
        np->pmtudisc    = IPV6_PMTUDISC_WANT;
        np->repflow     = net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ESTABLISHED;
        sk->sk_ipv6only = net->ipv6.sysctl.bindv6only;
+       sk->sk_txrehash = READ_ONCE(net->core.sysctl_txrehash);
 
        /* Init the ipv4 part of the socket since we can have sockets
         * using v6 API for ipv4.
index 60fd91b..c314fdd 100644 (file)
@@ -547,7 +547,20 @@ int ip6_forward(struct sk_buff *skb)
            pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
                int proxied = ip6_forward_proxy_check(skb);
                if (proxied > 0) {
-                       hdr->hop_limit--;
+                       /* It's tempting to decrease the hop limit
+                        * here by 1, as we do at the end of the
+                        * function too.
+                        *
+                        * But that would be incorrect, as proxying is
+                        * not forwarding.  The ip6_input function
+                        * will handle this packet locally, and it
+                        * depends on the hop limit being unchanged.
+                        *
+                        * One example is the NDP hop limit, that
+                        * always has to stay 255, but other would be
+                        * similar checks around RA packets, where the
+                        * user can even change the desired limit.
+                        */
                        return ip6_input(skb);
                } else if (proxied < 0) {
                        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
index a06a9f8..ada087b 100644 (file)
@@ -505,6 +505,7 @@ csum_copy_err:
 static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
                                     struct raw6_sock *rp)
 {
+       struct ipv6_txoptions *opt;
        struct sk_buff *skb;
        int err = 0;
        int offset;
@@ -522,6 +523,9 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
 
        offset = rp->offset;
        total_len = inet_sk(sk)->cork.base.length;
+       opt = inet6_sk(sk)->cork.opt;
+       total_len -= opt ? opt->opt_flen : 0;
+
        if (offset >= total_len - 1) {
                err = -EINVAL;
                ip6_flush_pending_frames(sk);
index 9a1415f..03608d3 100644 (file)
@@ -104,9 +104,9 @@ static struct workqueue_struct *l2tp_wq;
 /* per-net private data for this module */
 static unsigned int l2tp_net_id;
 struct l2tp_net {
-       struct list_head l2tp_tunnel_list;
-       /* Lock for write access to l2tp_tunnel_list */
-       spinlock_t l2tp_tunnel_list_lock;
+       /* Lock for write access to l2tp_tunnel_idr */
+       spinlock_t l2tp_tunnel_idr_lock;
+       struct idr l2tp_tunnel_idr;
        struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
        /* Lock for write access to l2tp_session_hlist */
        spinlock_t l2tp_session_hlist_lock;
@@ -208,13 +208,10 @@ struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
        struct l2tp_tunnel *tunnel;
 
        rcu_read_lock_bh();
-       list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
-               if (tunnel->tunnel_id == tunnel_id &&
-                   refcount_inc_not_zero(&tunnel->ref_count)) {
-                       rcu_read_unlock_bh();
-
-                       return tunnel;
-               }
+       tunnel = idr_find(&pn->l2tp_tunnel_idr, tunnel_id);
+       if (tunnel && refcount_inc_not_zero(&tunnel->ref_count)) {
+               rcu_read_unlock_bh();
+               return tunnel;
        }
        rcu_read_unlock_bh();
 
@@ -224,13 +221,14 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
 
 struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth)
 {
-       const struct l2tp_net *pn = l2tp_pernet(net);
+       struct l2tp_net *pn = l2tp_pernet(net);
+       unsigned long tunnel_id, tmp;
        struct l2tp_tunnel *tunnel;
        int count = 0;
 
        rcu_read_lock_bh();
-       list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
-               if (++count > nth &&
+       idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
+               if (tunnel && ++count > nth &&
                    refcount_inc_not_zero(&tunnel->ref_count)) {
                        rcu_read_unlock_bh();
                        return tunnel;
@@ -1043,7 +1041,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, uns
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
        nf_reset_ct(skb);
 
-       bh_lock_sock(sk);
+       bh_lock_sock_nested(sk);
        if (sock_owned_by_user(sk)) {
                kfree_skb(skb);
                ret = NET_XMIT_DROP;
@@ -1227,6 +1225,15 @@ static void l2tp_udp_encap_destroy(struct sock *sk)
                l2tp_tunnel_delete(tunnel);
 }
 
+static void l2tp_tunnel_remove(struct net *net, struct l2tp_tunnel *tunnel)
+{
+       struct l2tp_net *pn = l2tp_pernet(net);
+
+       spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
+       idr_remove(&pn->l2tp_tunnel_idr, tunnel->tunnel_id);
+       spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
+}
+
 /* Workqueue tunnel deletion function */
 static void l2tp_tunnel_del_work(struct work_struct *work)
 {
@@ -1234,7 +1241,6 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
                                                  del_work);
        struct sock *sk = tunnel->sock;
        struct socket *sock = sk->sk_socket;
-       struct l2tp_net *pn;
 
        l2tp_tunnel_closeall(tunnel);
 
@@ -1248,12 +1254,7 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
                }
        }
 
-       /* Remove the tunnel struct from the tunnel list */
-       pn = l2tp_pernet(tunnel->l2tp_net);
-       spin_lock_bh(&pn->l2tp_tunnel_list_lock);
-       list_del_rcu(&tunnel->list);
-       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
-
+       l2tp_tunnel_remove(tunnel->l2tp_net, tunnel);
        /* drop initial ref */
        l2tp_tunnel_dec_refcount(tunnel);
 
@@ -1384,8 +1385,6 @@ out:
        return err;
 }
 
-static struct lock_class_key l2tp_socket_class;
-
 int l2tp_tunnel_create(int fd, int version, u32 tunnel_id, u32 peer_tunnel_id,
                       struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
 {
@@ -1455,12 +1454,19 @@ static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
 int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
                         struct l2tp_tunnel_cfg *cfg)
 {
-       struct l2tp_tunnel *tunnel_walk;
-       struct l2tp_net *pn;
+       struct l2tp_net *pn = l2tp_pernet(net);
+       u32 tunnel_id = tunnel->tunnel_id;
        struct socket *sock;
        struct sock *sk;
        int ret;
 
+       spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
+       ret = idr_alloc_u32(&pn->l2tp_tunnel_idr, NULL, &tunnel_id, tunnel_id,
+                           GFP_ATOMIC);
+       spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
+       if (ret)
+               return ret == -ENOSPC ? -EEXIST : ret;
+
        if (tunnel->fd < 0) {
                ret = l2tp_tunnel_sock_create(net, tunnel->tunnel_id,
                                              tunnel->peer_tunnel_id, cfg,
@@ -1474,6 +1480,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
        }
 
        sk = sock->sk;
+       lock_sock(sk);
        write_lock_bh(&sk->sk_callback_lock);
        ret = l2tp_validate_socket(sk, net, tunnel->encap);
        if (ret < 0)
@@ -1481,24 +1488,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
        rcu_assign_sk_user_data(sk, tunnel);
        write_unlock_bh(&sk->sk_callback_lock);
 
-       tunnel->l2tp_net = net;
-       pn = l2tp_pernet(net);
-
-       sock_hold(sk);
-       tunnel->sock = sk;
-
-       spin_lock_bh(&pn->l2tp_tunnel_list_lock);
-       list_for_each_entry(tunnel_walk, &pn->l2tp_tunnel_list, list) {
-               if (tunnel_walk->tunnel_id == tunnel->tunnel_id) {
-                       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
-                       sock_put(sk);
-                       ret = -EEXIST;
-                       goto err_sock;
-               }
-       }
-       list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
-       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
-
        if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
                struct udp_tunnel_sock_cfg udp_cfg = {
                        .sk_user_data = tunnel,
@@ -1512,9 +1501,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
 
        tunnel->old_sk_destruct = sk->sk_destruct;
        sk->sk_destruct = &l2tp_tunnel_destruct;
-       lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class,
-                                  "l2tp_sock");
        sk->sk_allocation = GFP_ATOMIC;
+       release_sock(sk);
+
+       sock_hold(sk);
+       tunnel->sock = sk;
+       tunnel->l2tp_net = net;
+
+       spin_lock_bh(&pn->l2tp_tunnel_idr_lock);
+       idr_replace(&pn->l2tp_tunnel_idr, tunnel, tunnel->tunnel_id);
+       spin_unlock_bh(&pn->l2tp_tunnel_idr_lock);
 
        trace_register_tunnel(tunnel);
 
@@ -1523,17 +1519,16 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
 
        return 0;
 
-err_sock:
-       write_lock_bh(&sk->sk_callback_lock);
-       rcu_assign_sk_user_data(sk, NULL);
 err_inval_sock:
        write_unlock_bh(&sk->sk_callback_lock);
+       release_sock(sk);
 
        if (tunnel->fd < 0)
                sock_release(sock);
        else
                sockfd_put(sock);
 err:
+       l2tp_tunnel_remove(net, tunnel);
        return ret;
 }
 EXPORT_SYMBOL_GPL(l2tp_tunnel_register);
@@ -1647,8 +1642,8 @@ static __net_init int l2tp_init_net(struct net *net)
        struct l2tp_net *pn = net_generic(net, l2tp_net_id);
        int hash;
 
-       INIT_LIST_HEAD(&pn->l2tp_tunnel_list);
-       spin_lock_init(&pn->l2tp_tunnel_list_lock);
+       idr_init(&pn->l2tp_tunnel_idr);
+       spin_lock_init(&pn->l2tp_tunnel_idr_lock);
 
        for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
                INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]);
@@ -1662,11 +1657,13 @@ static __net_exit void l2tp_exit_net(struct net *net)
 {
        struct l2tp_net *pn = l2tp_pernet(net);
        struct l2tp_tunnel *tunnel = NULL;
+       unsigned long tunnel_id, tmp;
        int hash;
 
        rcu_read_lock_bh();
-       list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
-               l2tp_tunnel_delete(tunnel);
+       idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
+               if (tunnel)
+                       l2tp_tunnel_delete(tunnel);
        }
        rcu_read_unlock_bh();
 
@@ -1676,6 +1673,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
 
        for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
                WARN_ON_ONCE(!hlist_empty(&pn->l2tp_session_hlist[hash]));
+       idr_destroy(&pn->l2tp_tunnel_idr);
 }
 
 static struct pernet_operations l2tp_net_ops = {
index 9c40f8d..f9514ba 100644 (file)
@@ -491,7 +491,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
        struct tid_ampdu_tx *tid_tx;
        struct ieee80211_local *local = sta->local;
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_ampdu_params params = {
                .sta = &sta->sta,
                .action = IEEE80211_AMPDU_TX_START,
@@ -511,8 +511,6 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
         */
        clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
 
-       ieee80211_agg_stop_txq(sta, tid);
-
        /*
         * Make sure no packets are being processed. This ensures that
         * we have a valid starting sequence number and that in-flight
@@ -521,6 +519,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
         */
        synchronize_net();
 
+       sdata = sta->sdata;
        params.ssn = sta->tid_seq[tid] >> 4;
        ret = drv_ampdu_action(local, sdata, &params);
        tid_tx->ssn = params.ssn;
@@ -534,6 +533,9 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
                 */
                set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state);
        } else if (ret) {
+               if (!sdata)
+                       return;
+
                ht_dbg(sdata,
                       "BA request denied - HW unavailable for %pM tid %d\n",
                       sta->sta.addr, tid);
index 8f9a2ab..672eff6 100644 (file)
@@ -147,6 +147,7 @@ static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
        link_conf->bssid_index = 0;
        link_conf->nontransmitted = false;
        link_conf->ema_ap = false;
+       link_conf->bssid_indicator = 0;
 
        if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev)
                return -EINVAL;
@@ -1511,6 +1512,12 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
        kfree(link_conf->ftmr_params);
        link_conf->ftmr_params = NULL;
 
+       sdata->vif.mbssid_tx_vif = NULL;
+       link_conf->bssid_index = 0;
+       link_conf->nontransmitted = false;
+       link_conf->ema_ap = false;
+       link_conf->bssid_indicator = 0;
+
        __sta_info_flush(sdata, true);
        ieee80211_free_keys(sdata, true);
 
index 7a3d789..f1914bf 100644 (file)
@@ -167,7 +167,7 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
                        continue;
                txqi = to_txq_info(sta->sta.txq[i]);
                p += scnprintf(p, bufsz + buf - p,
-                              "%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s)\n",
+                              "%d %d %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s%s)\n",
                               txqi->txq.tid,
                               txqi->txq.ac,
                               txqi->tin.backlog_bytes,
@@ -182,7 +182,8 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
                               txqi->flags,
                               test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
                               test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
-                              test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "");
+                              test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "",
+                              test_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ? " DIRTY" : "");
        }
 
        rcu_read_unlock();
index d737db4..cfb09e4 100644 (file)
@@ -392,6 +392,9 @@ int drv_ampdu_action(struct ieee80211_local *local,
 
        might_sleep();
 
+       if (!sdata)
+               return -EIO;
+
        sdata = get_bss_sdata(sdata);
        if (!check_sdata_in_driver(sdata))
                return -EIO;
index 809bad5..5d13a3d 100644 (file)
@@ -1199,7 +1199,7 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
 
        /* In reconfig don't transmit now, but mark for waking later */
        if (local->in_reconfig) {
-               set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txq->flags);
+               set_bit(IEEE80211_TXQ_DIRTY, &txq->flags);
                return;
        }
 
index 83bc413..5315ab7 100644 (file)
@@ -391,6 +391,37 @@ void ieee80211_ba_session_work(struct work_struct *work)
 
                tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
                if (!blocked && tid_tx) {
+                       struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]);
+                       struct ieee80211_sub_if_data *sdata =
+                               vif_to_sdata(txqi->txq.vif);
+                       struct fq *fq = &sdata->local->fq;
+
+                       spin_lock_bh(&fq->lock);
+
+                       /* Allow only frags to be dequeued */
+                       set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
+
+                       if (!skb_queue_empty(&txqi->frags)) {
+                               /* Fragmented Tx is ongoing, wait for it to
+                                * finish. Reschedule worker to retry later.
+                                */
+
+                               spin_unlock_bh(&fq->lock);
+                               spin_unlock_bh(&sta->lock);
+
+                               /* Give the task working on the txq a chance
+                                * to send out the queued frags
+                                */
+                               synchronize_net();
+
+                               mutex_unlock(&sta->ampdu_mlme.mtx);
+
+                               ieee80211_queue_work(&sdata->local->hw, work);
+                               return;
+                       }
+
+                       spin_unlock_bh(&fq->lock);
+
                        /*
                         * Assign it over to the normal tid_tx array
                         * where it "goes live".
index 63ff0d2..d16606e 100644 (file)
@@ -838,7 +838,7 @@ enum txq_info_flags {
        IEEE80211_TXQ_STOP,
        IEEE80211_TXQ_AMPDU,
        IEEE80211_TXQ_NO_AMSDU,
-       IEEE80211_TXQ_STOP_NETIF_TX,
+       IEEE80211_TXQ_DIRTY,
 };
 
 /**
index d49a590..23ed13f 100644 (file)
@@ -364,7 +364,9 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 
                        /* No support for VLAN with MLO yet */
                        if (iftype == NL80211_IFTYPE_AP_VLAN &&
-                           nsdata->wdev.use_4addr)
+                           sdata->wdev.use_4addr &&
+                           nsdata->vif.type == NL80211_IFTYPE_AP &&
+                           nsdata->vif.valid_links)
                                return -EOPNOTSUPP;
 
                        /*
@@ -2195,7 +2197,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
                ret = cfg80211_register_netdevice(ndev);
                if (ret) {
-                       ieee80211_if_free(ndev);
                        free_netdev(ndev);
                        return ret;
                }
index 7e3ab6e..c6562a6 100644 (file)
@@ -4049,6 +4049,58 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
 #undef CALL_RXH
 }
 
+static bool
+ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
+{
+       if (!sta->mlo)
+               return false;
+
+       return !!(sta->valid_links & BIT(link_id));
+}
+
+static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
+                                      u8 link_id)
+{
+       rx->link_id = link_id;
+       rx->link = rcu_dereference(rx->sdata->link[link_id]);
+
+       if (!rx->sta)
+               return rx->link;
+
+       if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id))
+               return false;
+
+       rx->link_sta = rcu_dereference(rx->sta->link[link_id]);
+
+       return rx->link && rx->link_sta;
+}
+
+static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
+                                     struct ieee80211_sta *pubsta,
+                                     int link_id)
+{
+       struct sta_info *sta;
+
+       sta = container_of(pubsta, struct sta_info, sta);
+
+       rx->link_id = link_id;
+       rx->sta = sta;
+
+       if (sta) {
+               rx->local = sta->sdata->local;
+               if (!rx->sdata)
+                       rx->sdata = sta->sdata;
+               rx->link_sta = &sta->deflink;
+       }
+
+       if (link_id < 0)
+               rx->link = &rx->sdata->deflink;
+       else if (!ieee80211_rx_data_set_link(rx, link_id))
+               return false;
+
+       return true;
+}
+
 /*
  * This function makes calls into the RX path, therefore
  * it has to be invoked under RCU read lock.
@@ -4057,16 +4109,19 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
 {
        struct sk_buff_head frames;
        struct ieee80211_rx_data rx = {
-               .sta = sta,
-               .sdata = sta->sdata,
-               .local = sta->local,
                /* This is OK -- must be QoS data frame */
                .security_idx = tid,
                .seqno_idx = tid,
-               .link_id = -1,
        };
        struct tid_ampdu_rx *tid_agg_rx;
-       u8 link_id;
+       int link_id = -1;
+
+       /* FIXME: statistics won't be right with this */
+       if (sta->sta.valid_links)
+               link_id = ffs(sta->sta.valid_links) - 1;
+
+       if (!ieee80211_rx_data_set_sta(&rx, &sta->sta, link_id))
+               return;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
        if (!tid_agg_rx)
@@ -4086,10 +4141,6 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
                };
                drv_event_callback(rx.local, rx.sdata, &event);
        }
-       /* FIXME: statistics won't be right with this */
-       link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0;
-       rx.link = rcu_dereference(sta->sdata->link[link_id]);
-       rx.link_sta = rcu_dereference(sta->link[link_id]);
 
        ieee80211_rx_handlers(&rx, &frames);
 }
@@ -4105,7 +4156,6 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
                /* This is OK -- must be QoS data frame */
                .security_idx = tid,
                .seqno_idx = tid,
-               .link_id = -1,
        };
        int i, diff;
 
@@ -4116,10 +4166,8 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
 
        sta = container_of(pubsta, struct sta_info, sta);
 
-       rx.sta = sta;
-       rx.sdata = sta->sdata;
-       rx.link = &rx.sdata->deflink;
-       rx.local = sta->local;
+       if (!ieee80211_rx_data_set_sta(&rx, pubsta, -1))
+               return;
 
        rcu_read_lock();
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -4506,15 +4554,6 @@ void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&local->sta_mtx);
 }
 
-static bool
-ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
-{
-       if (!sta->mlo)
-               return false;
-
-       return !!(sta->valid_links & BIT(link_id));
-}
-
 static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
                              struct ieee80211_fast_rx *fast_rx,
                              int orig_len)
@@ -4625,7 +4664,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
        struct sk_buff *skb = rx->skb;
        struct ieee80211_hdr *hdr = (void *)skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct sta_info *sta = rx->sta;
        int orig_len = skb->len;
        int hdrlen = ieee80211_hdrlen(hdr->frame_control);
        int snap_offs = hdrlen;
@@ -4637,7 +4675,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
                u8 da[ETH_ALEN];
                u8 sa[ETH_ALEN];
        } addrs __aligned(2);
-       struct link_sta_info *link_sta;
        struct ieee80211_sta_rx_stats *stats;
 
        /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
@@ -4740,18 +4777,10 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
  drop:
        dev_kfree_skb(skb);
 
-       if (rx->link_id >= 0) {
-               link_sta = rcu_dereference(sta->link[rx->link_id]);
-               if (!link_sta)
-                       return true;
-       } else {
-               link_sta = &sta->deflink;
-       }
-
        if (fast_rx->uses_rss)
-               stats = this_cpu_ptr(link_sta->pcpu_rx_stats);
+               stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
        else
-               stats = &link_sta->rx_stats;
+               stats = &rx->link_sta->rx_stats;
 
        stats->dropped++;
        return true;
@@ -4769,8 +4798,8 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_hdr *hdr = (void *)skb->data;
-       struct link_sta_info *link_sta = NULL;
-       struct ieee80211_link_data *link;
+       struct link_sta_info *link_sta = rx->link_sta;
+       struct ieee80211_link_data *link = rx->link;
 
        rx->skb = skb;
 
@@ -4792,35 +4821,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
        if (!ieee80211_accept_frame(rx))
                return false;
 
-       if (rx->link_id >= 0) {
-               link = rcu_dereference(rx->sdata->link[rx->link_id]);
-
-               /* we might race link removal */
-               if (!link)
-                       return true;
-               rx->link = link;
-
-               if (rx->sta) {
-                       rx->link_sta =
-                               rcu_dereference(rx->sta->link[rx->link_id]);
-                       if (!rx->link_sta)
-                               return true;
-               }
-       } else {
-               if (rx->sta)
-                       rx->link_sta = &rx->sta->deflink;
-
-               rx->link = &sdata->deflink;
-       }
-
-       if (unlikely(!is_multicast_ether_addr(hdr->addr1) &&
-                    rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) {
-               link_sta = rcu_dereference(rx->sta->link[rx->link_id]);
-
-               if (WARN_ON_ONCE(!link_sta))
-                       return true;
-       }
-
        if (!consume) {
                struct skb_shared_hwtstamps *shwt;
 
@@ -4838,9 +4838,12 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
                 */
                shwt = skb_hwtstamps(rx->skb);
                shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
+
+               /* Update the hdr pointer to the new skb for translation below */
+               hdr = (struct ieee80211_hdr *)rx->skb->data;
        }
 
-       if (unlikely(link_sta)) {
+       if (unlikely(rx->sta && rx->sta->sta.mlo)) {
                /* translate to MLD addresses */
                if (ether_addr_equal(link->conf->addr, hdr->addr1))
                        ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
@@ -4870,6 +4873,7 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_fast_rx *fast_rx;
        struct ieee80211_rx_data rx;
+       int link_id = -1;
 
        memset(&rx, 0, sizeof(rx));
        rx.skb = skb;
@@ -4886,12 +4890,8 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
        if (!pubsta)
                goto drop;
 
-       rx.sta = container_of(pubsta, struct sta_info, sta);
-       rx.sdata = rx.sta->sdata;
-
-       if (status->link_valid &&
-           !ieee80211_rx_is_valid_sta_link_id(pubsta, status->link_id))
-               goto drop;
+       if (status->link_valid)
+               link_id = status->link_id;
 
        /*
         * TODO: Should the frame be dropped if the right link_id is not
@@ -4900,19 +4900,8 @@ static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw,
         * link_id is used only for stats purpose and updating the stats on
         * the deflink is fine?
         */
-       if (status->link_valid)
-               rx.link_id = status->link_id;
-
-       if (rx.link_id >= 0) {
-               struct ieee80211_link_data *link;
-
-               link =  rcu_dereference(rx.sdata->link[rx.link_id]);
-               if (!link)
-                       goto drop;
-               rx.link = link;
-       } else {
-               rx.link = &rx.sdata->deflink;
-       }
+       if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id))
+               goto drop;
 
        fast_rx = rcu_dereference(rx.sta->fast_rx);
        if (!fast_rx)
@@ -4930,6 +4919,8 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
 {
        struct link_sta_info *link_sta;
        struct ieee80211_hdr *hdr = (void *)skb->data;
+       struct sta_info *sta;
+       int link_id = -1;
 
        /*
         * Look up link station first, in case there's a
@@ -4939,24 +4930,19 @@ static bool ieee80211_rx_for_interface(struct ieee80211_rx_data *rx,
         */
        link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
        if (link_sta) {
-               rx->sta = link_sta->sta;
-               rx->link_id = link_sta->link_id;
+               sta = link_sta->sta;
+               link_id = link_sta->link_id;
        } else {
                struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
-               rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2);
-               if (rx->sta) {
-                       if (status->link_valid &&
-                           !ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta,
-                                                              status->link_id))
-                               return false;
-
-                       rx->link_id = status->link_valid ? status->link_id : -1;
-               } else {
-                       rx->link_id = -1;
-               }
+               sta = sta_info_get_bss(rx->sdata, hdr->addr2);
+               if (status->link_valid)
+                       link_id = status->link_id;
        }
 
+       if (!ieee80211_rx_data_set_sta(rx, &sta->sta, link_id))
+               return false;
+
        return ieee80211_prepare_and_rx_handle(rx, skb, consume);
 }
 
@@ -5015,19 +5001,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 
        if (ieee80211_is_data(fc)) {
                struct sta_info *sta, *prev_sta;
-               u8 link_id = status->link_id;
+               int link_id = -1;
 
-               if (pubsta) {
-                       rx.sta = container_of(pubsta, struct sta_info, sta);
-                       rx.sdata = rx.sta->sdata;
+               if (status->link_valid)
+                       link_id = status->link_id;
 
-                       if (status->link_valid &&
-                           !ieee80211_rx_is_valid_sta_link_id(pubsta, link_id))
+               if (pubsta) {
+                       if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id))
                                goto out;
 
-                       if (status->link_valid)
-                               rx.link_id = status->link_id;
-
                        /*
                         * In MLO connection, fetch the link_id using addr2
                         * when the driver does not pass link_id in status.
@@ -5045,7 +5027,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                if (!link_sta)
                                        goto out;
 
-                               rx.link_id = link_sta->link_id;
+                               ieee80211_rx_data_set_link(&rx, link_sta->link_id);
                        }
 
                        if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
@@ -5061,30 +5043,27 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                continue;
                        }
 
-                       if ((status->link_valid &&
-                            !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
-                                                               link_id)) ||
-                           (!status->link_valid && prev_sta->sta.mlo))
+                       rx.sdata = prev_sta->sdata;
+                       if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta,
+                                                      link_id))
+                               goto out;
+
+                       if (!status->link_valid && prev_sta->sta.mlo)
                                continue;
 
-                       rx.link_id = status->link_valid ? link_id : -1;
-                       rx.sta = prev_sta;
-                       rx.sdata = prev_sta->sdata;
                        ieee80211_prepare_and_rx_handle(&rx, skb, false);
 
                        prev_sta = sta;
                }
 
                if (prev_sta) {
-                       if ((status->link_valid &&
-                            !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
-                                                               link_id)) ||
-                           (!status->link_valid && prev_sta->sta.mlo))
+                       rx.sdata = prev_sta->sdata;
+                       if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta,
+                                                      link_id))
                                goto out;
 
-                       rx.link_id = status->link_valid ? link_id : -1;
-                       rx.sta = prev_sta;
-                       rx.sdata = prev_sta->sdata;
+                       if (!status->link_valid && prev_sta->sta.mlo)
+                               goto out;
 
                        if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
                                return;
index 2171cd1..defe97a 100644 (file)
@@ -1129,7 +1129,6 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
        struct sk_buff *purge_skb = NULL;
 
        if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
-               info->flags |= IEEE80211_TX_CTL_AMPDU;
                reset_agg_timer = true;
        } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
                /*
@@ -1161,7 +1160,6 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                if (!tid_tx) {
                        /* do nothing, let packet pass through */
                } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
-                       info->flags |= IEEE80211_TX_CTL_AMPDU;
                        reset_agg_timer = true;
                } else {
                        queued = true;
@@ -3677,8 +3675,7 @@ static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
        info->band = fast_tx->band;
        info->control.vif = &sdata->vif;
        info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
-                     IEEE80211_TX_CTL_DONTFRAG |
-                     (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
+                     IEEE80211_TX_CTL_DONTFRAG;
        info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT |
                              u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
                                              IEEE80211_TX_CTRL_MLO_LINK);
@@ -3783,6 +3780,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
        struct ieee80211_tx_data tx;
        ieee80211_tx_result r;
        struct ieee80211_vif *vif = txq->vif;
+       int q = vif->hw_queue[txq->ac];
+       bool q_stopped;
 
        WARN_ON_ONCE(softirq_count() == 0);
 
@@ -3790,17 +3789,18 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
                return NULL;
 
 begin:
-       spin_lock_bh(&fq->lock);
-
-       if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
-           test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
-               goto out;
+       spin_lock(&local->queue_stop_reason_lock);
+       q_stopped = local->queue_stop_reasons[q];
+       spin_unlock(&local->queue_stop_reason_lock);
 
-       if (vif->txqs_stopped[txq->ac]) {
-               set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
-               goto out;
+       if (unlikely(q_stopped)) {
+               /* mark for waking later */
+               set_bit(IEEE80211_TXQ_DIRTY, &txqi->flags);
+               return NULL;
        }
 
+       spin_lock_bh(&fq->lock);
+
        /* Make sure fragments stay together. */
        skb = __skb_dequeue(&txqi->frags);
        if (unlikely(skb)) {
@@ -3810,6 +3810,9 @@ begin:
                IEEE80211_SKB_CB(skb)->control.flags &=
                        ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
        } else {
+               if (unlikely(test_bit(IEEE80211_TXQ_STOP, &txqi->flags)))
+                       goto out;
+
                skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
        }
 
@@ -3860,9 +3863,8 @@ begin:
        }
 
        if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
-               info->flags |= IEEE80211_TX_CTL_AMPDU;
-       else
-               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= (IEEE80211_TX_CTL_AMPDU |
+                               IEEE80211_TX_CTL_DONTFRAG);
 
        if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
                if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
@@ -4596,8 +4598,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
 
        info = IEEE80211_SKB_CB(skb);
        memset(info, 0, sizeof(*info));
-       if (tid_tx)
-               info->flags |= IEEE80211_TX_CTL_AMPDU;
 
        info->hw_queue = sdata->vif.hw_queue[queue];
 
index 6f54070..261ac66 100644 (file)
@@ -292,22 +292,12 @@ static void wake_tx_push_queue(struct ieee80211_local *local,
                               struct ieee80211_sub_if_data *sdata,
                               struct ieee80211_txq *queue)
 {
-       int q = sdata->vif.hw_queue[queue->ac];
        struct ieee80211_tx_control control = {
                .sta = queue->sta,
        };
        struct sk_buff *skb;
-       unsigned long flags;
-       bool q_stopped;
 
        while (1) {
-               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-               q_stopped = local->queue_stop_reasons[q];
-               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
-               if (q_stopped)
-                       break;
-
                skb = ieee80211_tx_dequeue(&local->hw, queue);
                if (!skb)
                        break;
@@ -347,8 +337,6 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
        local_bh_disable();
        spin_lock(&fq->lock);
 
-       sdata->vif.txqs_stopped[ac] = false;
-
        if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
                goto out;
 
@@ -370,7 +358,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
                        if (ac != txq->ac)
                                continue;
 
-                       if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
+                       if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY,
                                                &txqi->flags))
                                continue;
 
@@ -385,7 +373,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
 
        txqi = to_txq_info(vif->txq);
 
-       if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
+       if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
            (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
                goto out;
 
@@ -517,8 +505,6 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
                                   bool refcounted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata;
-       int n_acs = IEEE80211_NUM_ACS;
 
        trace_stop_queue(local, queue, reason);
 
@@ -530,29 +516,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
        else
                local->q_stop_reasons[queue][reason]++;
 
-       if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
-               return;
-
-       if (local->hw.queues < IEEE80211_NUM_ACS)
-               n_acs = 1;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               int ac;
-
-               if (!sdata->dev)
-                       continue;
-
-               for (ac = 0; ac < n_acs; ac++) {
-                       if (sdata->vif.hw_queue[ac] == queue ||
-                           sdata->vif.cab_queue == queue) {
-                               spin_lock(&local->fq.lock);
-                               sdata->vif.txqs_stopped[ac] = true;
-                               spin_unlock(&local->fq.lock);
-                       }
-               }
-       }
-       rcu_read_unlock();
+       set_bit(reason, &local->queue_stop_reasons[queue]);
 }
 
 void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
index c2aae2a..97bb440 100644 (file)
@@ -213,7 +213,6 @@ __ieee802154_rx_handle_packet(struct ieee802154_local *local,
        ret = ieee802154_parse_frame_start(skb, &hdr);
        if (ret) {
                pr_debug("got invalid frame\n");
-               kfree_skb(skb);
                return;
        }
 
index fc9e728..3150f3f 100644 (file)
@@ -544,9 +544,6 @@ static int mctp_sk_init(struct sock *sk)
 
 static void mctp_sk_close(struct sock *sk, long timeout)
 {
-       struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
-
-       del_timer_sync(&msk->key_expiry);
        sk_common_release(sk);
 }
 
@@ -580,7 +577,19 @@ static void mctp_sk_unhash(struct sock *sk)
                spin_lock_irqsave(&key->lock, fl2);
                __mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_CLOSED);
        }
+       sock_set_flag(sk, SOCK_DEAD);
        spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
+
+       /* Since there are no more tag allocations (we have removed all of the
+        * keys), stop any pending expiry events. the timer cannot be re-queued
+        * as the sk is no longer observable
+        */
+       del_timer_sync(&msk->key_expiry);
+}
+
+static void mctp_sk_destruct(struct sock *sk)
+{
+       skb_queue_purge(&sk->sk_receive_queue);
 }
 
 static struct proto mctp_proto = {
@@ -619,6 +628,7 @@ static int mctp_pf_create(struct net *net, struct socket *sock,
                return -ENOMEM;
 
        sock_init_data(sock, sk);
+       sk->sk_destruct = mctp_sk_destruct;
 
        rc = 0;
        if (sk->sk_prot->init)
index f9a80b8..f51a05e 100644 (file)
@@ -147,6 +147,7 @@ static struct mctp_sk_key *mctp_key_alloc(struct mctp_sock *msk,
        key->valid = true;
        spin_lock_init(&key->lock);
        refcount_set(&key->refs, 1);
+       sock_hold(key->sk);
 
        return key;
 }
@@ -165,6 +166,7 @@ void mctp_key_unref(struct mctp_sk_key *key)
        mctp_dev_release_key(key->dev, key);
        spin_unlock_irqrestore(&key->lock, flags);
 
+       sock_put(key->sk);
        kfree(key);
 }
 
@@ -177,6 +179,11 @@ static int mctp_key_add(struct mctp_sk_key *key, struct mctp_sock *msk)
 
        spin_lock_irqsave(&net->mctp.keys_lock, flags);
 
+       if (sock_flag(&msk->sk, SOCK_DEAD)) {
+               rc = -EINVAL;
+               goto out_unlock;
+       }
+
        hlist_for_each_entry(tmp, &net->mctp.keys, hlist) {
                if (mctp_key_match(tmp, key->local_addr, key->peer_addr,
                                   key->tag)) {
@@ -198,6 +205,7 @@ static int mctp_key_add(struct mctp_sk_key *key, struct mctp_sock *msk)
                hlist_add_head(&key->sklist, &msk->keys);
        }
 
+out_unlock:
        spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
 
        return rc;
@@ -315,8 +323,8 @@ static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
 
 static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
 {
+       struct mctp_sk_key *key, *any_key = NULL;
        struct net *net = dev_net(skb->dev);
-       struct mctp_sk_key *key;
        struct mctp_sock *msk;
        struct mctp_hdr *mh;
        unsigned long f;
@@ -361,13 +369,11 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                         * key for reassembly - we'll create a more specific
                         * one for future packets if required (ie, !EOM).
                         */
-                       key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f);
-                       if (key) {
-                               msk = container_of(key->sk,
+                       any_key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f);
+                       if (any_key) {
+                               msk = container_of(any_key->sk,
                                                   struct mctp_sock, sk);
-                               spin_unlock_irqrestore(&key->lock, f);
-                               mctp_key_unref(key);
-                               key = NULL;
+                               spin_unlock_irqrestore(&any_key->lock, f);
                        }
                }
 
@@ -419,14 +425,14 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
                         * this function.
                         */
                        rc = mctp_key_add(key, msk);
-                       if (rc) {
-                               kfree(key);
-                       } else {
+                       if (!rc)
                                trace_mctp_key_acquire(key);
 
-                               /* we don't need to release key->lock on exit */
-                               mctp_key_unref(key);
-                       }
+                       /* we don't need to release key->lock on exit, so
+                        * clean up here and suppress the unlock via
+                        * setting to NULL
+                        */
+                       mctp_key_unref(key);
                        key = NULL;
 
                } else {
@@ -473,6 +479,8 @@ out_unlock:
                spin_unlock_irqrestore(&key->lock, f);
                mctp_key_unref(key);
        }
+       if (any_key)
+               mctp_key_unref(any_key);
 out:
        if (rc)
                kfree_skb(skb);
index 45e2a48..70f0ced 100644 (file)
@@ -420,6 +420,31 @@ void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk)
        }
 }
 
+/* if sk is ipv4 or ipv6_only allows only same-family local and remote addresses,
+ * otherwise allow any matching local/remote pair
+ */
+bool mptcp_pm_addr_families_match(const struct sock *sk,
+                                 const struct mptcp_addr_info *loc,
+                                 const struct mptcp_addr_info *rem)
+{
+       bool mptcp_is_v4 = sk->sk_family == AF_INET;
+
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+       bool loc_is_v4 = loc->family == AF_INET || ipv6_addr_v4mapped(&loc->addr6);
+       bool rem_is_v4 = rem->family == AF_INET || ipv6_addr_v4mapped(&rem->addr6);
+
+       if (mptcp_is_v4)
+               return loc_is_v4 && rem_is_v4;
+
+       if (ipv6_only_sock(sk))
+               return !loc_is_v4 && !rem_is_v4;
+
+       return loc_is_v4 == rem_is_v4;
+#else
+       return mptcp_is_v4 && loc->family == AF_INET && rem->family == AF_INET;
+#endif
+}
+
 void mptcp_pm_data_reset(struct mptcp_sock *msk)
 {
        u8 pm_type = mptcp_get_pm_type(sock_net((struct sock *)msk));
index 2ea7eae..10fe977 100644 (file)
@@ -998,8 +998,8 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
 {
        int addrlen = sizeof(struct sockaddr_in);
        struct sockaddr_storage addr;
-       struct mptcp_sock *msk;
        struct socket *ssock;
+       struct sock *newsk;
        int backlog = 1024;
        int err;
 
@@ -1008,11 +1008,13 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
        if (err)
                return err;
 
-       msk = mptcp_sk(entry->lsk->sk);
-       if (!msk)
+       newsk = entry->lsk->sk;
+       if (!newsk)
                return -EINVAL;
 
-       ssock = __mptcp_nmpc_socket(msk);
+       lock_sock(newsk);
+       ssock = __mptcp_nmpc_socket(mptcp_sk(newsk));
+       release_sock(newsk);
        if (!ssock)
                return -EINVAL;
 
index 65dcc55..ea6ad9d 100644 (file)
@@ -294,6 +294,13 @@ int mptcp_nl_cmd_sf_create(struct sk_buff *skb, struct genl_info *info)
        }
 
        sk = (struct sock *)msk;
+
+       if (!mptcp_pm_addr_families_match(sk, &addr_l, &addr_r)) {
+               GENL_SET_ERR_MSG(info, "families mismatch");
+               err = -EINVAL;
+               goto create_err;
+       }
+
        lock_sock(sk);
 
        err = __mptcp_subflow_connect(sk, &addr_l, &addr_r);
index b7ad030..bc6c1f6 100644 (file)
@@ -98,7 +98,7 @@ static int __mptcp_socket_create(struct mptcp_sock *msk)
        struct socket *ssock;
        int err;
 
-       err = mptcp_subflow_create_socket(sk, &ssock);
+       err = mptcp_subflow_create_socket(sk, sk->sk_family, &ssock);
        if (err)
                return err;
 
@@ -2897,6 +2897,7 @@ bool __mptcp_close(struct sock *sk, long timeout)
        struct mptcp_subflow_context *subflow;
        struct mptcp_sock *msk = mptcp_sk(sk);
        bool do_cancel_work = false;
+       int subflows_alive = 0;
 
        sk->sk_shutdown = SHUTDOWN_MASK;
 
@@ -2922,6 +2923,8 @@ cleanup:
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
                bool slow = lock_sock_fast_nested(ssk);
 
+               subflows_alive += ssk->sk_state != TCP_CLOSE;
+
                /* since the close timeout takes precedence on the fail one,
                 * cancel the latter
                 */
@@ -2937,6 +2940,12 @@ cleanup:
        }
        sock_orphan(sk);
 
+       /* all the subflows are closed, only timeout can change the msk
+        * state, let's not keep resources busy for no reasons
+        */
+       if (subflows_alive == 0)
+               inet_sk_state_store(sk, TCP_CLOSE);
+
        sock_hold(sk);
        pr_debug("msk=%p state=%d", sk, sk->sk_state);
        if (msk->token)
index a0d1658..6014692 100644 (file)
@@ -641,7 +641,8 @@ bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
 /* called with sk socket lock held */
 int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
                            const struct mptcp_addr_info *remote);
-int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock);
+int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
+                               struct socket **new_sock);
 void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
                         struct sockaddr_storage *addr,
                         unsigned short family);
@@ -776,6 +777,9 @@ int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info,
 int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info,
                         bool require_family,
                         struct mptcp_pm_addr_entry *entry);
+bool mptcp_pm_addr_families_match(const struct sock *sk,
+                                 const struct mptcp_addr_info *loc,
+                                 const struct mptcp_addr_info *rem);
 void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
 void mptcp_pm_nl_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
 void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int server_side);
index d4b1e6e..7f2c372 100644 (file)
@@ -760,14 +760,21 @@ static int mptcp_setsockopt_v4(struct mptcp_sock *msk, int optname,
 static int mptcp_setsockopt_first_sf_only(struct mptcp_sock *msk, int level, int optname,
                                          sockptr_t optval, unsigned int optlen)
 {
+       struct sock *sk = (struct sock *)msk;
        struct socket *sock;
+       int ret = -EINVAL;
 
        /* Limit to first subflow, before the connection establishment */
+       lock_sock(sk);
        sock = __mptcp_nmpc_socket(msk);
        if (!sock)
-               return -EINVAL;
+               goto unlock;
 
-       return tcp_setsockopt(sock->sk, level, optname, optval, optlen);
+       ret = tcp_setsockopt(sock->sk, level, optname, optval, optlen);
+
+unlock:
+       release_sock(sk);
+       return ret;
 }
 
 static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
index bd387d4..32904c7 100644 (file)
@@ -1399,6 +1399,7 @@ void __mptcp_error_report(struct sock *sk)
        mptcp_for_each_subflow(msk, subflow) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
                int err = sock_error(ssk);
+               int ssk_state;
 
                if (!err)
                        continue;
@@ -1409,7 +1410,14 @@ void __mptcp_error_report(struct sock *sk)
                if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(msk))
                        continue;
 
-               inet_sk_state_store(sk, inet_sk_state_load(ssk));
+               /* We need to propagate only transition to CLOSE state.
+                * Orphaned socket will see such state change via
+                * subflow_sched_work_if_closed() and that path will properly
+                * destroy the msk as needed.
+                */
+               ssk_state = inet_sk_state_load(ssk);
+               if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
+                       inet_sk_state_store(sk, ssk_state);
                sk->sk_err = -err;
 
                /* This barrier is coupled with smp_rmb() in mptcp_poll() */
@@ -1547,7 +1555,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
        if (!mptcp_is_fully_established(sk))
                goto err_out;
 
-       err = mptcp_subflow_create_socket(sk, &sf);
+       err = mptcp_subflow_create_socket(sk, loc->family, &sf);
        if (err)
                goto err_out;
 
@@ -1660,7 +1668,9 @@ static void mptcp_subflow_ops_undo_override(struct sock *ssk)
 #endif
                ssk->sk_prot = &tcp_prot;
 }
-int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
+
+int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
+                               struct socket **new_sock)
 {
        struct mptcp_subflow_context *subflow;
        struct net *net = sock_net(sk);
@@ -1673,12 +1683,11 @@ int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
        if (unlikely(!sk->sk_socket))
                return -EINVAL;
 
-       err = sock_create_kern(net, sk->sk_family, SOCK_STREAM, IPPROTO_TCP,
-                              &sf);
+       err = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, &sf);
        if (err)
                return err;
 
-       lock_sock(sf->sk);
+       lock_sock_nested(sf->sk, SINGLE_DEPTH_NESTING);
 
        /* the newly created socket has to be in the same cgroup as its parent */
        mptcp_attach_cgroup(sk, sf->sk);
index a8ce04a..e4fa00a 100644 (file)
@@ -308,8 +308,8 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
                        return -IPSET_ERR_BITMAP_RANGE;
 
                pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
-               hosts = 2 << (32 - netmask - 1);
-               elements = 2 << (netmask - mask_bits - 1);
+               hosts = 2U << (32 - netmask - 1);
+               elements = 2UL << (netmask - mask_bits - 1);
        }
        if (elements > IPSET_BITMAP_MAX_RANGE + 1)
                return -IPSET_ERR_BITMAP_RANGE_SIZE;
index d88b92a..011d414 100644 (file)
 #include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_conntrack_timeout.h>
 
-/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
-   closely.  They're more complex. --RR
-
-   And so for me for SCTP :D -Kiran */
-
 static const char *const sctp_conntrack_names[] = {
-       "NONE",
-       "CLOSED",
-       "COOKIE_WAIT",
-       "COOKIE_ECHOED",
-       "ESTABLISHED",
-       "SHUTDOWN_SENT",
-       "SHUTDOWN_RECD",
-       "SHUTDOWN_ACK_SENT",
-       "HEARTBEAT_SENT",
-       "HEARTBEAT_ACKED",
+       [SCTP_CONNTRACK_NONE]                   = "NONE",
+       [SCTP_CONNTRACK_CLOSED]                 = "CLOSED",
+       [SCTP_CONNTRACK_COOKIE_WAIT]            = "COOKIE_WAIT",
+       [SCTP_CONNTRACK_COOKIE_ECHOED]          = "COOKIE_ECHOED",
+       [SCTP_CONNTRACK_ESTABLISHED]            = "ESTABLISHED",
+       [SCTP_CONNTRACK_SHUTDOWN_SENT]          = "SHUTDOWN_SENT",
+       [SCTP_CONNTRACK_SHUTDOWN_RECD]          = "SHUTDOWN_RECD",
+       [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT]      = "SHUTDOWN_ACK_SENT",
+       [SCTP_CONNTRACK_HEARTBEAT_SENT]         = "HEARTBEAT_SENT",
 };
 
 #define SECS  * HZ
@@ -54,13 +48,11 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
        [SCTP_CONNTRACK_CLOSED]                 = 10 SECS,
        [SCTP_CONNTRACK_COOKIE_WAIT]            = 3 SECS,
        [SCTP_CONNTRACK_COOKIE_ECHOED]          = 3 SECS,
-       [SCTP_CONNTRACK_ESTABLISHED]            = 5 DAYS,
+       [SCTP_CONNTRACK_ESTABLISHED]            = 210 SECS,
        [SCTP_CONNTRACK_SHUTDOWN_SENT]          = 300 SECS / 1000,
        [SCTP_CONNTRACK_SHUTDOWN_RECD]          = 300 SECS / 1000,
        [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT]      = 3 SECS,
        [SCTP_CONNTRACK_HEARTBEAT_SENT]         = 30 SECS,
-       [SCTP_CONNTRACK_HEARTBEAT_ACKED]        = 210 SECS,
-       [SCTP_CONNTRACK_DATA_SENT]              = 30 SECS,
 };
 
 #define        SCTP_FLAG_HEARTBEAT_VTAG_FAILED 1
@@ -74,8 +66,6 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
 #define        sSR SCTP_CONNTRACK_SHUTDOWN_RECD
 #define        sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
 #define        sHS SCTP_CONNTRACK_HEARTBEAT_SENT
-#define        sHA SCTP_CONNTRACK_HEARTBEAT_ACKED
-#define        sDS SCTP_CONNTRACK_DATA_SENT
 #define        sIV SCTP_CONNTRACK_MAX
 
 /*
@@ -98,10 +88,6 @@ SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite
 CLOSED            - We have seen a SHUTDOWN_COMPLETE chunk in the direction of
                    the SHUTDOWN chunk. Connection is closed.
 HEARTBEAT_SENT    - We have seen a HEARTBEAT in a new flow.
-HEARTBEAT_ACKED   - We have seen a HEARTBEAT-ACK/DATA/SACK in the direction
-                   opposite to that of the HEARTBEAT/DATA chunk. Secondary connection
-                   is established.
-DATA_SENT         - We have seen a DATA/SACK in a new flow.
 */
 
 /* TODO
@@ -115,38 +101,36 @@ cookie echoed to closed.
 */
 
 /* SCTP conntrack state transitions */
-static const u8 sctp_conntracks[2][12][SCTP_CONNTRACK_MAX] = {
+static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = {
        {
 /*     ORIGINAL        */
-/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA, sDS */
-/* init         */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCW, sHA, sCW},
-/* init_ack     */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA, sCL},
-/* abort        */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
-/* shutdown     */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL, sSS, sCL},
-/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA, sHA, sSA},
-/* error        */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA, sCL},/* Can't have Stale cookie*/
-/* cookie_echo  */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL, sHA, sCL},/* 5.2.4 - Big TODO */
-/* cookie_ack   */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL, sHA, sCL},/* Can't come in orig dir */
-/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL, sHA, sCL},
-/* heartbeat    */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA, sDS},
-/* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA, sDS},
-/* data/sack    */ {sDS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA, sDS}
+/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS */
+/* init         */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCW},
+/* init_ack     */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},
+/* abort        */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
+/* shutdown     */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL},
+/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA},
+/* error        */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't have Stale cookie*/
+/* cookie_echo  */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL},/* 5.2.4 - Big TODO */
+/* cookie_ack   */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */
+/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL},
+/* heartbeat    */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS},
+/* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS},
        },
        {
 /*     REPLY   */
-/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA, sDS */
-/* init         */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA, sIV},/* INIT in sCL Big TODO */
-/* init_ack     */ {sIV, sCW, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA, sIV},
-/* abort        */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV, sCL, sIV},
-/* shutdown     */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV, sSR, sIV},
-/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV, sHA, sIV},
-/* error        */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV, sHA, sIV},
-/* cookie_echo  */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV, sHA, sIV},/* Can't come in reply dir */
-/* cookie_ack   */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV, sHA, sIV},
-/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV, sHA, sIV},
-/* heartbeat    */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS, sHA, sHA},
-/* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHA, sHA, sHA},
-/* data/sack    */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHA, sHA, sHA},
+/*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS */
+/* init         */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* INIT in sCL Big TODO */
+/* init_ack     */ {sIV, sCW, sCW, sCE, sES, sSS, sSR, sSA, sIV},
+/* abort        */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV},
+/* shutdown     */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV},
+/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV},
+/* error        */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV},
+/* cookie_echo  */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */
+/* cookie_ack   */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV},
+/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV},
+/* heartbeat    */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS},
+/* heartbeat_ack*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sES},
        }
 };
 
@@ -158,6 +142,7 @@ static void sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
 }
 #endif
 
+/* do_basic_checks ensures sch->length > 0, do not use before */
 #define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count)    \
 for ((offset) = (dataoff) + sizeof(struct sctphdr), (count) = 0;       \
        (offset) < (skb)->len &&                                        \
@@ -258,11 +243,6 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
                pr_debug("SCTP_CID_HEARTBEAT_ACK");
                i = 10;
                break;
-       case SCTP_CID_DATA:
-       case SCTP_CID_SACK:
-               pr_debug("SCTP_CID_DATA/SACK");
-               i = 11;
-               break;
        default:
                /* Other chunks like DATA or SACK do not change the state */
                pr_debug("Unknown chunk type, Will stay in %s\n",
@@ -316,9 +296,7 @@ sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
                                 ih->init_tag);
 
                        ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag;
-               } else if (sch->type == SCTP_CID_HEARTBEAT ||
-                          sch->type == SCTP_CID_DATA ||
-                          sch->type == SCTP_CID_SACK) {
+               } else if (sch->type == SCTP_CID_HEARTBEAT) {
                        pr_debug("Setting vtag %x for secondary conntrack\n",
                                 sh->vtag);
                        ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] = sh->vtag;
@@ -404,19 +382,19 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
 
                if (!sctp_new(ct, skb, sh, dataoff))
                        return -NF_ACCEPT;
-       } else {
-               /* Check the verification tag (Sec 8.5) */
-               if (!test_bit(SCTP_CID_INIT, map) &&
-                   !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) &&
-                   !test_bit(SCTP_CID_COOKIE_ECHO, map) &&
-                   !test_bit(SCTP_CID_ABORT, map) &&
-                   !test_bit(SCTP_CID_SHUTDOWN_ACK, map) &&
-                   !test_bit(SCTP_CID_HEARTBEAT, map) &&
-                   !test_bit(SCTP_CID_HEARTBEAT_ACK, map) &&
-                   sh->vtag != ct->proto.sctp.vtag[dir]) {
-                       pr_debug("Verification tag check failed\n");
-                       goto out;
-               }
+       }
+
+       /* Check the verification tag (Sec 8.5) */
+       if (!test_bit(SCTP_CID_INIT, map) &&
+           !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) &&
+           !test_bit(SCTP_CID_COOKIE_ECHO, map) &&
+           !test_bit(SCTP_CID_ABORT, map) &&
+           !test_bit(SCTP_CID_SHUTDOWN_ACK, map) &&
+           !test_bit(SCTP_CID_HEARTBEAT, map) &&
+           !test_bit(SCTP_CID_HEARTBEAT_ACK, map) &&
+           sh->vtag != ct->proto.sctp.vtag[dir]) {
+               pr_debug("Verification tag check failed\n");
+               goto out;
        }
 
        old_state = new_state = SCTP_CONNTRACK_NONE;
@@ -424,22 +402,29 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
        for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
                /* Special cases of Verification tag check (Sec 8.5.1) */
                if (sch->type == SCTP_CID_INIT) {
-                       /* Sec 8.5.1 (A) */
+                       /* (A) vtag MUST be zero */
                        if (sh->vtag != 0)
                                goto out_unlock;
                } else if (sch->type == SCTP_CID_ABORT) {
-                       /* Sec 8.5.1 (B) */
-                       if (sh->vtag != ct->proto.sctp.vtag[dir] &&
-                           sh->vtag != ct->proto.sctp.vtag[!dir])
+                       /* (B) vtag MUST match own vtag if T flag is unset OR
+                        * MUST match peer's vtag if T flag is set
+                        */
+                       if ((!(sch->flags & SCTP_CHUNK_FLAG_T) &&
+                            sh->vtag != ct->proto.sctp.vtag[dir]) ||
+                           ((sch->flags & SCTP_CHUNK_FLAG_T) &&
+                            sh->vtag != ct->proto.sctp.vtag[!dir]))
                                goto out_unlock;
                } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
-                       /* Sec 8.5.1 (C) */
-                       if (sh->vtag != ct->proto.sctp.vtag[dir] &&
-                           sh->vtag != ct->proto.sctp.vtag[!dir] &&
-                           sch->flags & SCTP_CHUNK_FLAG_T)
+                       /* (C) vtag MUST match own vtag if T flag is unset OR
+                        * MUST match peer's vtag if T flag is set
+                        */
+                       if ((!(sch->flags & SCTP_CHUNK_FLAG_T) &&
+                            sh->vtag != ct->proto.sctp.vtag[dir]) ||
+                           ((sch->flags & SCTP_CHUNK_FLAG_T) &&
+                            sh->vtag != ct->proto.sctp.vtag[!dir]))
                                goto out_unlock;
                } else if (sch->type == SCTP_CID_COOKIE_ECHO) {
-                       /* Sec 8.5.1 (D) */
+                       /* (D) vtag must be same as init_vtag as found in INIT_ACK */
                        if (sh->vtag != ct->proto.sctp.vtag[dir])
                                goto out_unlock;
                } else if (sch->type == SCTP_CID_HEARTBEAT) {
@@ -476,11 +461,6 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                        } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
                                ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
                        }
-               } else if (sch->type == SCTP_CID_DATA || sch->type == SCTP_CID_SACK) {
-                       if (ct->proto.sctp.vtag[dir] == 0) {
-                               pr_debug("Setting vtag %x for dir %d\n", sh->vtag, dir);
-                               ct->proto.sctp.vtag[dir] = sh->vtag;
-                       }
                }
 
                old_state = ct->proto.sctp.state;
@@ -518,8 +498,12 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
                }
 
                ct->proto.sctp.state = new_state;
-               if (old_state != new_state)
+               if (old_state != new_state) {
                        nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
+                       if (new_state == SCTP_CONNTRACK_ESTABLISHED &&
+                           !test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
+                               nf_conntrack_event_cache(IPCT_ASSURED, ct);
+               }
        }
        spin_unlock_bh(&ct->lock);
 
@@ -533,14 +517,6 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
 
        nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
 
-       if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED &&
-           dir == IP_CT_DIR_REPLY &&
-           new_state == SCTP_CONNTRACK_ESTABLISHED) {
-               pr_debug("Setting assured bit\n");
-               set_bit(IPS_ASSURED_BIT, &ct->status);
-               nf_conntrack_event_cache(IPCT_ASSURED, ct);
-       }
-
        return NF_ACCEPT;
 
 out_unlock:
@@ -701,7 +677,6 @@ sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = {
        [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT]    = { .type = NLA_U32 },
        [CTA_TIMEOUT_SCTP_HEARTBEAT_SENT]       = { .type = NLA_U32 },
        [CTA_TIMEOUT_SCTP_HEARTBEAT_ACKED]      = { .type = NLA_U32 },
-       [CTA_TIMEOUT_SCTP_DATA_SENT]            = { .type = NLA_U32 },
 };
 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
 
index 6566310..3ac1af6 100644 (file)
@@ -1068,6 +1068,13 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
                                ct->proto.tcp.last_flags |=
                                        IP_CT_EXP_CHALLENGE_ACK;
                }
+
+               /* possible challenge ack reply to syn */
+               if (old_state == TCP_CONNTRACK_SYN_SENT &&
+                   index == TCP_ACK_SET &&
+                   dir == IP_CT_DIR_REPLY)
+                       ct->proto.tcp.last_ack = ntohl(th->ack_seq);
+
                spin_unlock_bh(&ct->lock);
                nf_ct_l4proto_log_invalid(skb, ct, state,
                                          "packet (index %d) in dir %d ignored, state %s",
@@ -1193,6 +1200,14 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,
                         * segments we ignored. */
                        goto in_window;
                }
+
+               /* Reset in response to a challenge-ack we let through earlier */
+               if (old_state == TCP_CONNTRACK_SYN_SENT &&
+                   ct->proto.tcp.last_index == TCP_ACK_SET &&
+                   ct->proto.tcp.last_dir == IP_CT_DIR_REPLY &&
+                   ntohl(th->seq) == ct->proto.tcp.last_ack)
+                       goto in_window;
+
                break;
        default:
                /* Keep compilers happy. */
index 0250725..460294b 100644 (file)
@@ -601,8 +601,6 @@ enum nf_ct_sysctl_index {
        NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_RECD,
        NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT,
        NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_SENT,
-       NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_ACKED,
-       NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_DATA_SENT,
 #endif
 #ifdef CONFIG_NF_CT_PROTO_DCCP
        NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST,
@@ -887,18 +885,6 @@ static struct ctl_table nf_ct_sysctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_ACKED] = {
-               .procname       = "nf_conntrack_sctp_timeout_heartbeat_acked",
-               .maxlen         = sizeof(unsigned int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
-       [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_DATA_SENT] = {
-               .procname       = "nf_conntrack_sctp_timeout_data_sent",
-               .maxlen         = sizeof(unsigned int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
 #endif
 #ifdef CONFIG_NF_CT_PROTO_DCCP
        [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST] = {
@@ -1042,8 +1028,6 @@ static void nf_conntrack_standalone_init_sctp_sysctl(struct net *net,
        XASSIGN(SHUTDOWN_RECD, sn);
        XASSIGN(SHUTDOWN_ACK_SENT, sn);
        XASSIGN(HEARTBEAT_SENT, sn);
-       XASSIGN(HEARTBEAT_ACKED, sn);
-       XASSIGN(DATA_SENT, sn);
 #undef XASSIGN
 #endif
 }
index 17b418a..3a3c774 100644 (file)
@@ -63,7 +63,7 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
                        return false;
 
                if (offset + len > VLAN_ETH_HLEN + vlan_hlen)
-                       ethlen -= offset + len - VLAN_ETH_HLEN + vlan_hlen;
+                       ethlen -= offset + len - VLAN_ETH_HLEN - vlan_hlen;
 
                memcpy(dst_u8, vlanh + offset - vlan_hlen, ethlen);
 
index 7325bee..19ea4d3 100644 (file)
@@ -38,10 +38,12 @@ static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe)
        return !nft_rbtree_interval_end(rbe);
 }
 
-static bool nft_rbtree_equal(const struct nft_set *set, const void *this,
-                            const struct nft_rbtree_elem *interval)
+static int nft_rbtree_cmp(const struct nft_set *set,
+                         const struct nft_rbtree_elem *e1,
+                         const struct nft_rbtree_elem *e2)
 {
-       return memcmp(this, nft_set_ext_key(&interval->ext), set->klen) == 0;
+       return memcmp(nft_set_ext_key(&e1->ext), nft_set_ext_key(&e2->ext),
+                     set->klen);
 }
 
 static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
@@ -52,7 +54,6 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
        const struct nft_rbtree_elem *rbe, *interval = NULL;
        u8 genmask = nft_genmask_cur(net);
        const struct rb_node *parent;
-       const void *this;
        int d;
 
        parent = rcu_dereference_raw(priv->root.rb_node);
@@ -62,12 +63,11 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
 
                rbe = rb_entry(parent, struct nft_rbtree_elem, node);
 
-               this = nft_set_ext_key(&rbe->ext);
-               d = memcmp(this, key, set->klen);
+               d = memcmp(nft_set_ext_key(&rbe->ext), key, set->klen);
                if (d < 0) {
                        parent = rcu_dereference_raw(parent->rb_left);
                        if (interval &&
-                           nft_rbtree_equal(set, this, interval) &&
+                           !nft_rbtree_cmp(set, rbe, interval) &&
                            nft_rbtree_interval_end(rbe) &&
                            nft_rbtree_interval_start(interval))
                                continue;
@@ -215,154 +215,216 @@ static void *nft_rbtree_get(const struct net *net, const struct nft_set *set,
        return rbe;
 }
 
+static int nft_rbtree_gc_elem(const struct nft_set *__set,
+                             struct nft_rbtree *priv,
+                             struct nft_rbtree_elem *rbe)
+{
+       struct nft_set *set = (struct nft_set *)__set;
+       struct rb_node *prev = rb_prev(&rbe->node);
+       struct nft_rbtree_elem *rbe_prev;
+       struct nft_set_gc_batch *gcb;
+
+       gcb = nft_set_gc_batch_check(set, NULL, GFP_ATOMIC);
+       if (!gcb)
+               return -ENOMEM;
+
+       /* search for expired end interval coming before this element. */
+       do {
+               rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node);
+               if (nft_rbtree_interval_end(rbe_prev))
+                       break;
+
+               prev = rb_prev(prev);
+       } while (prev != NULL);
+
+       rb_erase(&rbe_prev->node, &priv->root);
+       rb_erase(&rbe->node, &priv->root);
+       atomic_sub(2, &set->nelems);
+
+       nft_set_gc_batch_add(gcb, rbe);
+       nft_set_gc_batch_complete(gcb);
+
+       return 0;
+}
+
+static bool nft_rbtree_update_first(const struct nft_set *set,
+                                   struct nft_rbtree_elem *rbe,
+                                   struct rb_node *first)
+{
+       struct nft_rbtree_elem *first_elem;
+
+       first_elem = rb_entry(first, struct nft_rbtree_elem, node);
+       /* this element is closest to where the new element is to be inserted:
+        * update the first element for the node list path.
+        */
+       if (nft_rbtree_cmp(set, rbe, first_elem) < 0)
+               return true;
+
+       return false;
+}
+
 static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                               struct nft_rbtree_elem *new,
                               struct nft_set_ext **ext)
 {
-       bool overlap = false, dup_end_left = false, dup_end_right = false;
+       struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL;
+       struct rb_node *node, *parent, **p, *first = NULL;
        struct nft_rbtree *priv = nft_set_priv(set);
        u8 genmask = nft_genmask_next(net);
-       struct nft_rbtree_elem *rbe;
-       struct rb_node *parent, **p;
-       int d;
+       int d, err;
 
-       /* Detect overlaps as we descend the tree. Set the flag in these cases:
-        *
-        * a1. _ _ __>|  ?_ _ __|  (insert end before existing end)
-        * a2. _ _ ___|  ?_ _ _>|  (insert end after existing end)
-        * a3. _ _ ___? >|_ _ __|  (insert start before existing end)
-        *
-        * and clear it later on, as we eventually reach the points indicated by
-        * '?' above, in the cases described below. We'll always meet these
-        * later, locally, due to tree ordering, and overlaps for the intervals
-        * that are the closest together are always evaluated last.
-        *
-        * b1. _ _ __>|  !_ _ __|  (insert end before existing start)
-        * b2. _ _ ___|  !_ _ _>|  (insert end after existing start)
-        * b3. _ _ ___! >|_ _ __|  (insert start after existing end, as a leaf)
-        *            '--' no nodes falling in this range
-        * b4.          >|_ _   !  (insert start before existing start)
-        *
-        * Case a3. resolves to b3.:
-        * - if the inserted start element is the leftmost, because the '0'
-        *   element in the tree serves as end element
-        * - otherwise, if an existing end is found immediately to the left. If
-        *   there are existing nodes in between, we need to further descend the
-        *   tree before we can conclude the new start isn't causing an overlap
-        *
-        * or to b4., which, preceded by a3., means we already traversed one or
-        * more existing intervals entirely, from the right.
-        *
-        * For a new, rightmost pair of elements, we'll hit cases b3. and b2.,
-        * in that order.
-        *
-        * The flag is also cleared in two special cases:
-        *
-        * b5. |__ _ _!|<_ _ _   (insert start right before existing end)
-        * b6. |__ _ >|!__ _ _   (insert end right after existing start)
-        *
-        * which always happen as last step and imply that no further
-        * overlapping is possible.
-        *
-        * Another special case comes from the fact that start elements matching
-        * an already existing start element are allowed: insertion is not
-        * performed but we return -EEXIST in that case, and the error will be
-        * cleared by the caller if NLM_F_EXCL is not present in the request.
-        * This way, request for insertion of an exact overlap isn't reported as
-        * error to userspace if not desired.
-        *
-        * However, if the existing start matches a pre-existing start, but the
-        * end element doesn't match the corresponding pre-existing end element,
-        * we need to report a partial overlap. This is a local condition that
-        * can be noticed without need for a tracking flag, by checking for a
-        * local duplicated end for a corresponding start, from left and right,
-        * separately.
+       /* Descend the tree to search for an existing element greater than the
+        * key value to insert that is greater than the new element. This is the
+        * first element to walk the ordered elements to find possible overlap.
         */
-
        parent = NULL;
        p = &priv->root.rb_node;
        while (*p != NULL) {
                parent = *p;
                rbe = rb_entry(parent, struct nft_rbtree_elem, node);
-               d = memcmp(nft_set_ext_key(&rbe->ext),
-                          nft_set_ext_key(&new->ext),
-                          set->klen);
+               d = nft_rbtree_cmp(set, rbe, new);
+
                if (d < 0) {
                        p = &parent->rb_left;
-
-                       if (nft_rbtree_interval_start(new)) {
-                               if (nft_rbtree_interval_end(rbe) &&
-                                   nft_set_elem_active(&rbe->ext, genmask) &&
-                                   !nft_set_elem_expired(&rbe->ext) && !*p)
-                                       overlap = false;
-                       } else {
-                               if (dup_end_left && !*p)
-                                       return -ENOTEMPTY;
-
-                               overlap = nft_rbtree_interval_end(rbe) &&
-                                         nft_set_elem_active(&rbe->ext,
-                                                             genmask) &&
-                                         !nft_set_elem_expired(&rbe->ext);
-
-                               if (overlap) {
-                                       dup_end_right = true;
-                                       continue;
-                               }
-                       }
                } else if (d > 0) {
-                       p = &parent->rb_right;
+                       if (!first ||
+                           nft_rbtree_update_first(set, rbe, first))
+                               first = &rbe->node;
 
-                       if (nft_rbtree_interval_end(new)) {
-                               if (dup_end_right && !*p)
-                                       return -ENOTEMPTY;
-
-                               overlap = nft_rbtree_interval_end(rbe) &&
-                                         nft_set_elem_active(&rbe->ext,
-                                                             genmask) &&
-                                         !nft_set_elem_expired(&rbe->ext);
-
-                               if (overlap) {
-                                       dup_end_left = true;
-                                       continue;
-                               }
-                       } else if (nft_set_elem_active(&rbe->ext, genmask) &&
-                                  !nft_set_elem_expired(&rbe->ext)) {
-                               overlap = nft_rbtree_interval_end(rbe);
-                       }
+                       p = &parent->rb_right;
                } else {
-                       if (nft_rbtree_interval_end(rbe) &&
-                           nft_rbtree_interval_start(new)) {
+                       if (nft_rbtree_interval_end(rbe))
                                p = &parent->rb_left;
-
-                               if (nft_set_elem_active(&rbe->ext, genmask) &&
-                                   !nft_set_elem_expired(&rbe->ext))
-                                       overlap = false;
-                       } else if (nft_rbtree_interval_start(rbe) &&
-                                  nft_rbtree_interval_end(new)) {
+                       else
                                p = &parent->rb_right;
+               }
+       }
+
+       if (!first)
+               first = rb_first(&priv->root);
+
+       /* Detect overlap by going through the list of valid tree nodes.
+        * Values stored in the tree are in reversed order, starting from
+        * highest to lowest value.
+        */
+       for (node = first; node != NULL; node = rb_next(node)) {
+               rbe = rb_entry(node, struct nft_rbtree_elem, node);
 
-                               if (nft_set_elem_active(&rbe->ext, genmask) &&
-                                   !nft_set_elem_expired(&rbe->ext))
-                                       overlap = false;
-                       } else if (nft_set_elem_active(&rbe->ext, genmask) &&
-                                  !nft_set_elem_expired(&rbe->ext)) {
-                               *ext = &rbe->ext;
-                               return -EEXIST;
-                       } else {
-                               overlap = false;
-                               if (nft_rbtree_interval_end(rbe))
-                                       p = &parent->rb_left;
-                               else
-                                       p = &parent->rb_right;
+               if (!nft_set_elem_active(&rbe->ext, genmask))
+                       continue;
+
+               /* perform garbage collection to avoid bogus overlap reports. */
+               if (nft_set_elem_expired(&rbe->ext)) {
+                       err = nft_rbtree_gc_elem(set, priv, rbe);
+                       if (err < 0)
+                               return err;
+
+                       continue;
+               }
+
+               d = nft_rbtree_cmp(set, rbe, new);
+               if (d == 0) {
+                       /* Matching end element: no need to look for an
+                        * overlapping greater or equal element.
+                        */
+                       if (nft_rbtree_interval_end(rbe)) {
+                               rbe_le = rbe;
+                               break;
+                       }
+
+                       /* first element that is greater or equal to key value. */
+                       if (!rbe_ge) {
+                               rbe_ge = rbe;
+                               continue;
+                       }
+
+                       /* this is a closer more or equal element, update it. */
+                       if (nft_rbtree_cmp(set, rbe_ge, new) != 0) {
+                               rbe_ge = rbe;
+                               continue;
+                       }
+
+                       /* element is equal to key value, make sure flags are
+                        * the same, an existing more or equal start element
+                        * must not be replaced by more or equal end element.
+                        */
+                       if ((nft_rbtree_interval_start(new) &&
+                            nft_rbtree_interval_start(rbe_ge)) ||
+                           (nft_rbtree_interval_end(new) &&
+                            nft_rbtree_interval_end(rbe_ge))) {
+                               rbe_ge = rbe;
+                               continue;
                        }
+               } else if (d > 0) {
+                       /* annotate element greater than the new element. */
+                       rbe_ge = rbe;
+                       continue;
+               } else if (d < 0) {
+                       /* annotate element less than the new element. */
+                       rbe_le = rbe;
+                       break;
                }
+       }
 
-               dup_end_left = dup_end_right = false;
+       /* - new start element matching existing start element: full overlap
+        *   reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
+        */
+       if (rbe_ge && !nft_rbtree_cmp(set, new, rbe_ge) &&
+           nft_rbtree_interval_start(rbe_ge) == nft_rbtree_interval_start(new)) {
+               *ext = &rbe_ge->ext;
+               return -EEXIST;
        }
 
-       if (overlap)
+       /* - new end element matching existing end element: full overlap
+        *   reported as -EEXIST, cleared by caller if NLM_F_EXCL is not given.
+        */
+       if (rbe_le && !nft_rbtree_cmp(set, new, rbe_le) &&
+           nft_rbtree_interval_end(rbe_le) == nft_rbtree_interval_end(new)) {
+               *ext = &rbe_le->ext;
+               return -EEXIST;
+       }
+
+       /* - new start element with existing closest, less or equal key value
+        *   being a start element: partial overlap, reported as -ENOTEMPTY.
+        *   Anonymous sets allow for two consecutive start element since they
+        *   are constant, skip them to avoid bogus overlap reports.
+        */
+       if (!nft_set_is_anonymous(set) && rbe_le &&
+           nft_rbtree_interval_start(rbe_le) && nft_rbtree_interval_start(new))
+               return -ENOTEMPTY;
+
+       /* - new end element with existing closest, less or equal key value
+        *   being a end element: partial overlap, reported as -ENOTEMPTY.
+        */
+       if (rbe_le &&
+           nft_rbtree_interval_end(rbe_le) && nft_rbtree_interval_end(new))
                return -ENOTEMPTY;
 
+       /* - new end element with existing closest, greater or equal key value
+        *   being an end element: partial overlap, reported as -ENOTEMPTY
+        */
+       if (rbe_ge &&
+           nft_rbtree_interval_end(rbe_ge) && nft_rbtree_interval_end(new))
+               return -ENOTEMPTY;
+
+       /* Accepted element: pick insertion point depending on key value */
+       parent = NULL;
+       p = &priv->root.rb_node;
+       while (*p != NULL) {
+               parent = *p;
+               rbe = rb_entry(parent, struct nft_rbtree_elem, node);
+               d = nft_rbtree_cmp(set, rbe, new);
+
+               if (d < 0)
+                       p = &parent->rb_left;
+               else if (d > 0)
+                       p = &parent->rb_right;
+               else if (nft_rbtree_interval_end(rbe))
+                       p = &parent->rb_left;
+               else
+                       p = &parent->rb_right;
+       }
+
        rb_link_node_rcu(&new->node, parent, p);
        rb_insert_color(&new->node, &priv->root);
        return 0;
@@ -501,23 +563,37 @@ static void nft_rbtree_gc(struct work_struct *work)
        struct nft_rbtree *priv;
        struct rb_node *node;
        struct nft_set *set;
+       struct net *net;
+       u8 genmask;
 
        priv = container_of(work, struct nft_rbtree, gc_work.work);
        set  = nft_set_container_of(priv);
+       net  = read_pnet(&set->net);
+       genmask = nft_genmask_cur(net);
 
        write_lock_bh(&priv->lock);
        write_seqcount_begin(&priv->count);
        for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
                rbe = rb_entry(node, struct nft_rbtree_elem, node);
 
+               if (!nft_set_elem_active(&rbe->ext, genmask))
+                       continue;
+
+               /* elements are reversed in the rbtree for historical reasons,
+                * from highest to lowest value, that is why end element is
+                * always visited before the start element.
+                */
                if (nft_rbtree_interval_end(rbe)) {
                        rbe_end = rbe;
                        continue;
                }
                if (!nft_set_elem_expired(&rbe->ext))
                        continue;
-               if (nft_set_elem_mark_busy(&rbe->ext))
+
+               if (nft_set_elem_mark_busy(&rbe->ext)) {
+                       rbe_end = NULL;
                        continue;
+               }
 
                if (rbe_prev) {
                        rb_erase(&rbe_prev->node, &priv->root);
index bca2a47..c642776 100644 (file)
@@ -580,7 +580,9 @@ static int netlink_insert(struct sock *sk, u32 portid)
        if (nlk_sk(sk)->bound)
                goto err;
 
-       nlk_sk(sk)->portid = portid;
+       /* portid can be read locklessly from netlink_getname(). */
+       WRITE_ONCE(nlk_sk(sk)->portid, portid);
+
        sock_hold(sk);
 
        err = __netlink_insert(table, sk);
@@ -1096,9 +1098,11 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
                return -EINVAL;
 
        if (addr->sa_family == AF_UNSPEC) {
-               sk->sk_state    = NETLINK_UNCONNECTED;
-               nlk->dst_portid = 0;
-               nlk->dst_group  = 0;
+               /* paired with READ_ONCE() in netlink_getsockbyportid() */
+               WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED);
+               /* dst_portid and dst_group can be read locklessly */
+               WRITE_ONCE(nlk->dst_portid, 0);
+               WRITE_ONCE(nlk->dst_group, 0);
                return 0;
        }
        if (addr->sa_family != AF_NETLINK)
@@ -1119,9 +1123,11 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
                err = netlink_autobind(sock);
 
        if (err == 0) {
-               sk->sk_state    = NETLINK_CONNECTED;
-               nlk->dst_portid = nladdr->nl_pid;
-               nlk->dst_group  = ffs(nladdr->nl_groups);
+               /* paired with READ_ONCE() in netlink_getsockbyportid() */
+               WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED);
+               /* dst_portid and dst_group can be read locklessly */
+               WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid);
+               WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups));
        }
 
        return err;
@@ -1138,10 +1144,12 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr,
        nladdr->nl_pad = 0;
 
        if (peer) {
-               nladdr->nl_pid = nlk->dst_portid;
-               nladdr->nl_groups = netlink_group_mask(nlk->dst_group);
+               /* Paired with WRITE_ONCE() in netlink_connect() */
+               nladdr->nl_pid = READ_ONCE(nlk->dst_portid);
+               nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group));
        } else {
-               nladdr->nl_pid = nlk->portid;
+               /* Paired with WRITE_ONCE() in netlink_insert() */
+               nladdr->nl_pid = READ_ONCE(nlk->portid);
                netlink_lock_table();
                nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
                netlink_unlock_table();
@@ -1168,8 +1176,9 @@ static struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid)
 
        /* Don't bother queuing skb if kernel socket has no input function */
        nlk = nlk_sk(sock);
-       if (sock->sk_state == NETLINK_CONNECTED &&
-           nlk->dst_portid != nlk_sk(ssk)->portid) {
+       /* dst_portid and sk_state can be changed in netlink_connect() */
+       if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED &&
+           READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) {
                sock_put(sock);
                return ERR_PTR(-ECONNREFUSED);
        }
@@ -1886,8 +1895,9 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
                        goto out;
                netlink_skb_flags |= NETLINK_SKB_DST;
        } else {
-               dst_portid = nlk->dst_portid;
-               dst_group = nlk->dst_group;
+               /* Paired with WRITE_ONCE() in netlink_connect() */
+               dst_portid = READ_ONCE(nlk->dst_portid);
+               dst_group = READ_ONCE(nlk->dst_group);
        }
 
        /* Paired with WRITE_ONCE() in netlink_insert() */
index 6f7f439..5a4cb79 100644 (file)
@@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
        struct sock *sk = sock->sk;
 
        lock_sock(sk);
+       if (sock->state != SS_UNCONNECTED) {
+               release_sock(sk);
+               return -EINVAL;
+       }
+
        if (sk->sk_state != TCP_LISTEN) {
                memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
                sk->sk_max_ack_backlog = backlog;
index a8da88d..4e7c968 100644 (file)
@@ -121,6 +121,7 @@ static void nr_heartbeat_expiry(struct timer_list *t)
                   is accepted() it isn't 'dead' so doesn't get removed. */
                if (sock_flag(sk, SOCK_DESTROY) ||
                    (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
+                       sock_hold(sk);
                        bh_unlock_sock(sk);
                        nr_destroy_socket(sk);
                        goto out;
index 3364caa..a27e184 100644 (file)
@@ -157,6 +157,7 @@ static void local_cleanup(struct nfc_llcp_local *local)
        cancel_work_sync(&local->rx_work);
        cancel_work_sync(&local->timeout_work);
        kfree_skb(local->rx_pending);
+       local->rx_pending = NULL;
        del_timer_sync(&local->sdreq_timer);
        cancel_work_sync(&local->sdreq_timeout_work);
        nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
index a717953..fcee601 100644 (file)
@@ -1004,14 +1004,14 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        key = kzalloc(sizeof(*key), GFP_KERNEL);
        if (!key) {
                error = -ENOMEM;
-               goto err_kfree_key;
+               goto err_kfree_flow;
        }
 
        ovs_match_init(&match, key, false, &mask);
        error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
                                  a[OVS_FLOW_ATTR_MASK], log);
        if (error)
-               goto err_kfree_flow;
+               goto err_kfree_key;
 
        ovs_flow_mask_key(&new_flow->key, key, true, &mask);
 
@@ -1019,14 +1019,14 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
                                       key, log);
        if (error)
-               goto err_kfree_flow;
+               goto err_kfree_key;
 
        /* Validate actions. */
        error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
                                     &new_flow->key, &acts, log);
        if (error) {
                OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
-               goto err_kfree_flow;
+               goto err_kfree_key;
        }
 
        reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,
@@ -1126,10 +1126,10 @@ err_unlock_ovs:
        kfree_skb(reply);
 err_kfree_acts:
        ovs_nla_free_flow_actions(acts);
-err_kfree_flow:
-       ovs_flow_free(new_flow, false);
 err_kfree_key:
        kfree(key);
+err_kfree_flow:
+       ovs_flow_free(new_flow, false);
 error:
        return error;
 }
index 1990d49..e595079 100644 (file)
@@ -83,7 +83,10 @@ static struct qrtr_node *node_get(unsigned int node_id)
 
        node->id = node_id;
 
-       radix_tree_insert(&nodes, node_id, node);
+       if (radix_tree_insert(&nodes, node_id, node)) {
+               kfree(node);
+               return NULL;
+       }
 
        return node;
 }
index b47e4f0..c19c935 100644 (file)
@@ -104,9 +104,9 @@ static void rds_rm_zerocopy_callback(struct rds_sock *rs,
        spin_lock_irqsave(&q->lock, flags);
        head = &q->zcookie_head;
        if (!list_empty(head)) {
-               info = list_entry(head, struct rds_msg_zcopy_info,
-                                 rs_zcookie_next);
-               if (info && rds_zcookie_add(info, cookie)) {
+               info = list_first_entry(head, struct rds_msg_zcopy_info,
+                                       rs_zcookie_next);
+               if (rds_zcookie_add(info, cookie)) {
                        spin_unlock_irqrestore(&q->lock, flags);
                        kfree(rds_info_from_znotifier(znotif));
                        /* caller invokes rds_wake_sk_sleep() */
index 36fefc3..ca2b17f 100644 (file)
@@ -488,6 +488,12 @@ static int rose_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
 
+       lock_sock(sk);
+       if (sock->state != SS_UNCONNECTED) {
+               release_sock(sk);
+               return -EINVAL;
+       }
+
        if (sk->sk_state != TCP_LISTEN) {
                struct rose_sock *rose = rose_sk(sk);
 
@@ -497,8 +503,10 @@ static int rose_listen(struct socket *sock, int backlog)
                memset(rose->dest_digis, 0, AX25_ADDR_LEN * ROSE_MAX_DIGIS);
                sk->sk_max_ack_backlog = backlog;
                sk->sk_state           = TCP_LISTEN;
+               release_sock(sk);
                return 0;
        }
+       release_sock(sk);
 
        return -EOPNOTSUPP;
 }
index e76d345..ac5caf5 100644 (file)
@@ -10,6 +10,7 @@ rxrpc-y := \
        call_accept.o \
        call_event.o \
        call_object.o \
+       call_state.o \
        conn_client.o \
        conn_event.o \
        conn_object.o \
index 7ea576f..ebbd4a1 100644 (file)
@@ -155,10 +155,10 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
 
                if (service_id) {
                        write_lock(&local->services_lock);
-                       if (rcu_access_pointer(local->service))
+                       if (local->service)
                                goto service_in_use;
                        rx->local = local;
-                       rcu_assign_pointer(local->service, rx);
+                       local->service = rx;
                        write_unlock(&local->services_lock);
 
                        rx->sk.sk_state = RXRPC_SERVER_BOUND;
@@ -328,7 +328,6 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
                mutex_unlock(&call->user_mutex);
        }
 
-       rxrpc_put_peer(cp.peer, rxrpc_peer_put_discard_tmp);
        _leave(" = %p", call);
        return call;
 }
@@ -374,13 +373,17 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call);
  * @sock: The socket the call is on
  * @call: The call to check
  *
- * Allow a kernel service to find out whether a call is still alive -
- * ie. whether it has completed.
+ * Allow a kernel service to find out whether a call is still alive - whether
+ * it has completed successfully and all received data has been consumed.
  */
 bool rxrpc_kernel_check_life(const struct socket *sock,
                             const struct rxrpc_call *call)
 {
-       return call->state != RXRPC_CALL_COMPLETE;
+       if (!rxrpc_call_is_complete(call))
+               return true;
+       if (call->completion != RXRPC_CALL_SUCCEEDED)
+               return false;
+       return !skb_queue_empty(&call->recvmsg_queue);
 }
 EXPORT_SYMBOL(rxrpc_kernel_check_life);
 
@@ -872,9 +875,9 @@ static int rxrpc_release_sock(struct sock *sk)
 
        sk->sk_state = RXRPC_CLOSE;
 
-       if (rx->local && rcu_access_pointer(rx->local->service) == rx) {
+       if (rx->local && rx->local->service == rx) {
                write_lock(&rx->local->services_lock);
-               rcu_assign_pointer(rx->local->service, NULL);
+               rx->local->service = NULL;
                write_unlock(&rx->local->services_lock);
        }
 
@@ -957,16 +960,9 @@ static const struct net_proto_family rxrpc_family_ops = {
 static int __init af_rxrpc_init(void)
 {
        int ret = -1;
-       unsigned int tmp;
 
        BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));
 
-       get_random_bytes(&tmp, sizeof(tmp));
-       tmp &= 0x3fffffff;
-       if (tmp == 0)
-               tmp = 1;
-       idr_set_cursor(&rxrpc_client_conn_ids, tmp);
-
        ret = -ENOMEM;
        rxrpc_call_jar = kmem_cache_create(
                "rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
@@ -1062,7 +1058,6 @@ static void __exit af_rxrpc_exit(void)
         * are released.
         */
        rcu_barrier();
-       rxrpc_destroy_client_conn_ids();
 
        destroy_workqueue(rxrpc_workqueue);
        rxrpc_exit_security();
index 1809252..433060c 100644 (file)
@@ -38,6 +38,7 @@ struct rxrpc_txbuf;
 enum rxrpc_skb_mark {
        RXRPC_SKB_MARK_PACKET,          /* Received packet */
        RXRPC_SKB_MARK_ERROR,           /* Error notification */
+       RXRPC_SKB_MARK_SERVICE_CONN_SECURED, /* Service connection response has been verified */
        RXRPC_SKB_MARK_REJECT_BUSY,     /* Reject with BUSY */
        RXRPC_SKB_MARK_REJECT_ABORT,    /* Reject with ABORT (code in skb->priority) */
 };
@@ -75,13 +76,7 @@ struct rxrpc_net {
 
        bool                    live;
 
-       bool                    kill_all_client_conns;
        atomic_t                nr_client_conns;
-       spinlock_t              client_conn_cache_lock; /* Lock for ->*_client_conns */
-       struct mutex            client_conn_discard_lock; /* Prevent multiple discarders */
-       struct list_head        idle_client_conns;
-       struct work_struct      client_conn_reaper;
-       struct timer_list       client_conn_reap_timer;
 
        struct hlist_head       local_endpoints;
        struct mutex            local_mutex;    /* Lock for ->local_endpoints */
@@ -202,6 +197,7 @@ struct rxrpc_host_header {
  * - max 48 bytes (struct sk_buff::cb)
  */
 struct rxrpc_skb_priv {
+       struct rxrpc_connection *conn;  /* Connection referred to (poke packet) */
        u16             offset;         /* Offset of data */
        u16             len;            /* Length of data */
        u8              flags;
@@ -262,13 +258,11 @@ struct rxrpc_security {
 
        /* respond to a challenge */
        int (*respond_to_challenge)(struct rxrpc_connection *,
-                                   struct sk_buff *,
-                                   u32 *);
+                                   struct sk_buff *);
 
        /* verify a response */
        int (*verify_response)(struct rxrpc_connection *,
-                              struct sk_buff *,
-                              u32 *);
+                              struct sk_buff *);
 
        /* clear connection security */
        void (*clear)(struct rxrpc_connection *);
@@ -283,22 +277,34 @@ struct rxrpc_local {
        struct rcu_head         rcu;
        atomic_t                active_users;   /* Number of users of the local endpoint */
        refcount_t              ref;            /* Number of references to the structure */
-       struct rxrpc_net        *rxnet;         /* The network ns in which this resides */
+       struct net              *net;           /* The network namespace */
+       struct rxrpc_net        *rxnet;         /* Our bits in the network namespace */
        struct hlist_node       link;
        struct socket           *socket;        /* my UDP socket */
        struct task_struct      *io_thread;
        struct completion       io_thread_ready; /* Indication that the I/O thread started */
-       struct rxrpc_sock __rcu *service;       /* Service(s) listening on this endpoint */
+       struct rxrpc_sock       *service;       /* Service(s) listening on this endpoint */
        struct rw_semaphore     defrag_sem;     /* control re-enablement of IP DF bit */
        struct sk_buff_head     rx_queue;       /* Received packets */
+       struct list_head        conn_attend_q;  /* Conns requiring immediate attention */
        struct list_head        call_attend_q;  /* Calls requiring immediate attention */
+
        struct rb_root          client_bundles; /* Client connection bundles by socket params */
        spinlock_t              client_bundles_lock; /* Lock for client_bundles */
+       bool                    kill_all_client_conns;
+       struct list_head        idle_client_conns;
+       struct timer_list       client_conn_reap_timer;
+       unsigned long           client_conn_flags;
+#define RXRPC_CLIENT_CONN_REAP_TIMER   0       /* The client conn reap timer expired */
+
        spinlock_t              lock;           /* access lock */
        rwlock_t                services_lock;  /* lock for services list */
        int                     debug_id;       /* debug ID for printks */
        bool                    dead;
        bool                    service_closed; /* Service socket closed */
+       struct idr              conn_ids;       /* List of connection IDs */
+       struct list_head        new_client_calls; /* Newly created client calls need connection */
+       spinlock_t              client_call_lock; /* Lock for ->new_client_calls */
        struct sockaddr_rxrpc   srx;            /* local address */
 };
 
@@ -356,7 +362,6 @@ struct rxrpc_conn_proto {
 
 struct rxrpc_conn_parameters {
        struct rxrpc_local      *local;         /* Representation of local endpoint */
-       struct rxrpc_peer       *peer;          /* Remote endpoint */
        struct key              *key;           /* Security details */
        bool                    exclusive;      /* T if conn is exclusive */
        bool                    upgrade;        /* T if service ID can be upgraded */
@@ -364,11 +369,22 @@ struct rxrpc_conn_parameters {
        u32                     security_level; /* Security level selected */
 };
 
+/*
+ * Call completion condition (state == RXRPC_CALL_COMPLETE).
+ */
+enum rxrpc_call_completion {
+       RXRPC_CALL_SUCCEEDED,           /* - Normal termination */
+       RXRPC_CALL_REMOTELY_ABORTED,    /* - call aborted by peer */
+       RXRPC_CALL_LOCALLY_ABORTED,     /* - call aborted locally on error or close */
+       RXRPC_CALL_LOCAL_ERROR,         /* - call failed due to local error */
+       RXRPC_CALL_NETWORK_ERROR,       /* - call terminated by network error */
+       NR__RXRPC_CALL_COMPLETIONS
+};
+
 /*
  * Bits in the connection flags.
  */
 enum rxrpc_conn_flag {
-       RXRPC_CONN_HAS_IDR,             /* Has a client conn ID assigned */
        RXRPC_CONN_IN_SERVICE_CONNS,    /* Conn is in peer->service_conns */
        RXRPC_CONN_DONT_REUSE,          /* Don't reuse this connection */
        RXRPC_CONN_PROBING_FOR_UPGRADE, /* Probing for service upgrade */
@@ -388,6 +404,7 @@ enum rxrpc_conn_flag {
  */
 enum rxrpc_conn_event {
        RXRPC_CONN_EV_CHALLENGE,        /* Send challenge packet */
+       RXRPC_CONN_EV_ABORT_CALLS,      /* Abort attached calls */
 };
 
 /*
@@ -395,13 +412,13 @@ enum rxrpc_conn_event {
  */
 enum rxrpc_conn_proto_state {
        RXRPC_CONN_UNUSED,              /* Connection not yet attempted */
+       RXRPC_CONN_CLIENT_UNSECURED,    /* Client connection needs security init */
        RXRPC_CONN_CLIENT,              /* Client connection */
        RXRPC_CONN_SERVICE_PREALLOC,    /* Service connection preallocation */
        RXRPC_CONN_SERVICE_UNSECURED,   /* Service unsecured connection */
        RXRPC_CONN_SERVICE_CHALLENGING, /* Service challenging for security */
        RXRPC_CONN_SERVICE,             /* Service secured connection */
-       RXRPC_CONN_REMOTELY_ABORTED,    /* Conn aborted by peer */
-       RXRPC_CONN_LOCALLY_ABORTED,     /* Conn aborted locally */
+       RXRPC_CONN_ABORTED,             /* Conn aborted */
        RXRPC_CONN__NR_STATES
 };
 
@@ -412,17 +429,16 @@ struct rxrpc_bundle {
        struct rxrpc_local      *local;         /* Representation of local endpoint */
        struct rxrpc_peer       *peer;          /* Remote endpoint */
        struct key              *key;           /* Security details */
+       const struct rxrpc_security *security;  /* applied security module */
        refcount_t              ref;
        atomic_t                active;         /* Number of active users */
        unsigned int            debug_id;
        u32                     security_level; /* Security level selected */
        u16                     service_id;     /* Service ID for this connection */
        bool                    try_upgrade;    /* True if the bundle is attempting upgrade */
-       bool                    alloc_conn;     /* True if someone's getting a conn */
        bool                    exclusive;      /* T if conn is exclusive */
        bool                    upgrade;        /* T if service ID can be upgraded */
-       short                   alloc_error;    /* Error from last conn allocation */
-       spinlock_t              channel_lock;
+       unsigned short          alloc_error;    /* Error from last conn allocation */
        struct rb_node          local_node;     /* Node in local->client_conns */
        struct list_head        waiting_calls;  /* Calls waiting for channels */
        unsigned long           avail_chans;    /* Mask of available channels */
@@ -440,6 +456,7 @@ struct rxrpc_connection {
        struct rxrpc_peer       *peer;          /* Remote endpoint */
        struct rxrpc_net        *rxnet;         /* Network namespace to which call belongs */
        struct key              *key;           /* Security details */
+       struct list_head        attend_link;    /* Link in local->conn_attend_q */
 
        refcount_t              ref;
        atomic_t                active;         /* Active count for service conns */
@@ -449,7 +466,7 @@ struct rxrpc_connection {
        unsigned char           act_chans;      /* Mask of active channels */
        struct rxrpc_channel {
                unsigned long           final_ack_at;   /* Time at which to issue final ACK */
-               struct rxrpc_call __rcu *call;          /* Active call */
+               struct rxrpc_call       *call;          /* Active call */
                unsigned int            call_debug_id;  /* call->debug_id */
                u32                     call_id;        /* ID of current call */
                u32                     call_counter;   /* Call ID counter */
@@ -470,6 +487,7 @@ struct rxrpc_connection {
        struct list_head        link;           /* link in master connection list */
        struct sk_buff_head     rx_queue;       /* received conn-level packets */
 
+       struct mutex            security_lock;  /* Lock for security management */
        const struct rxrpc_security *security;  /* applied security module */
        union {
                struct {
@@ -483,7 +501,8 @@ struct rxrpc_connection {
        unsigned long           idle_timestamp; /* Time at which last became idle */
        spinlock_t              state_lock;     /* state-change lock */
        enum rxrpc_conn_proto_state state;      /* current state of connection */
-       u32                     abort_code;     /* Abort code of connection abort */
+       enum rxrpc_call_completion completion;  /* Completion condition */
+       s32                     abort_code;     /* Abort code of connection abort */
        int                     debug_id;       /* debug ID for printks */
        atomic_t                serial;         /* packet serial number counter */
        unsigned int            hi_serial;      /* highest serial number received */
@@ -527,7 +546,8 @@ enum rxrpc_call_flag {
        RXRPC_CALL_KERNEL,              /* The call was made by the kernel */
        RXRPC_CALL_UPGRADE,             /* Service upgrade was requested for the call */
        RXRPC_CALL_EXCLUSIVE,           /* The call uses a once-only connection */
-       RXRPC_CALL_RX_IS_IDLE,          /* Reception is idle - send an ACK */
+       RXRPC_CALL_RX_IS_IDLE,          /* recvmsg() is idle - send an ACK */
+       RXRPC_CALL_RECVMSG_READ_ALL,    /* recvmsg() read all of the received data */
 };
 
 /*
@@ -557,18 +577,6 @@ enum rxrpc_call_state {
        NR__RXRPC_CALL_STATES
 };
 
-/*
- * Call completion condition (state == RXRPC_CALL_COMPLETE).
- */
-enum rxrpc_call_completion {
-       RXRPC_CALL_SUCCEEDED,           /* - Normal termination */
-       RXRPC_CALL_REMOTELY_ABORTED,    /* - call aborted by peer */
-       RXRPC_CALL_LOCALLY_ABORTED,     /* - call aborted locally on error or close */
-       RXRPC_CALL_LOCAL_ERROR,         /* - call failed due to local error */
-       RXRPC_CALL_NETWORK_ERROR,       /* - call terminated by network error */
-       NR__RXRPC_CALL_COMPLETIONS
-};
-
 /*
  * Call Tx congestion management modes.
  */
@@ -587,6 +595,7 @@ enum rxrpc_congest_mode {
 struct rxrpc_call {
        struct rcu_head         rcu;
        struct rxrpc_connection *conn;          /* connection carrying call */
+       struct rxrpc_bundle     *bundle;        /* Connection bundle to use */
        struct rxrpc_peer       *peer;          /* Peer record for remote address */
        struct rxrpc_local      *local;         /* Representation of local endpoint */
        struct rxrpc_sock __rcu *socket;        /* socket responsible */
@@ -609,7 +618,7 @@ struct rxrpc_call {
        struct work_struct      destroyer;      /* In-process-context destroyer */
        rxrpc_notify_rx_t       notify_rx;      /* kernel service Rx notification function */
        struct list_head        link;           /* link in master call list */
-       struct list_head        chan_wait_link; /* Link in conn->bundle->waiting_calls */
+       struct list_head        wait_link;      /* Link in local->new_client_calls */
        struct hlist_node       error_link;     /* link in error distribution list */
        struct list_head        accept_link;    /* Link in rx->acceptq */
        struct list_head        recvmsg_link;   /* Link in rx->recvmsg_q */
@@ -623,10 +632,13 @@ struct rxrpc_call {
        unsigned long           flags;
        unsigned long           events;
        spinlock_t              notify_lock;    /* Kernel notification lock */
-       rwlock_t                state_lock;     /* lock for state transition */
-       u32                     abort_code;     /* Local/remote abort code */
+       unsigned int            send_abort_why; /* Why the abort [enum rxrpc_abort_reason] */
+       s32                     send_abort;     /* Abort code to be sent */
+       short                   send_abort_err; /* Error to be associated with the abort */
+       rxrpc_seq_t             send_abort_seq; /* DATA packet that incurred the abort (or 0) */
+       s32                     abort_code;     /* Local/remote abort code */
        int                     error;          /* Local error incurred */
-       enum rxrpc_call_state   state;          /* current state of call */
+       enum rxrpc_call_state   _state;         /* Current state of call (needs barrier) */
        enum rxrpc_call_completion completion;  /* Call completion condition */
        refcount_t              ref;
        u8                      security_ix;    /* Security type */
@@ -812,9 +824,11 @@ extern struct workqueue_struct *rxrpc_workqueue;
  */
 int rxrpc_service_prealloc(struct rxrpc_sock *, gfp_t);
 void rxrpc_discard_prealloc(struct rxrpc_sock *);
-int rxrpc_new_incoming_call(struct rxrpc_local *, struct rxrpc_peer *,
-                           struct rxrpc_connection *, struct sockaddr_rxrpc *,
-                           struct sk_buff *);
+bool rxrpc_new_incoming_call(struct rxrpc_local *local,
+                            struct rxrpc_peer *peer,
+                            struct rxrpc_connection *conn,
+                            struct sockaddr_rxrpc *peer_srx,
+                            struct sk_buff *skb);
 void rxrpc_accept_incoming_calls(struct rxrpc_local *);
 int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long);
 
@@ -834,7 +848,7 @@ void rxrpc_reduce_call_timer(struct rxrpc_call *call,
                             unsigned long now,
                             enum rxrpc_timer_trace why);
 
-void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb);
+bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb);
 
 /*
  * call_object.c
@@ -851,6 +865,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *,
                                         struct sockaddr_rxrpc *,
                                         struct rxrpc_call_params *, gfp_t,
                                         unsigned int);
+void rxrpc_start_call_timer(struct rxrpc_call *call);
 void rxrpc_incoming_call(struct rxrpc_sock *, struct rxrpc_call *,
                         struct sk_buff *);
 void rxrpc_release_call(struct rxrpc_sock *, struct rxrpc_call *);
@@ -872,33 +887,89 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
        return !rxrpc_is_service_call(call);
 }
 
+/*
+ * call_state.c
+ */
+bool rxrpc_set_call_completion(struct rxrpc_call *call,
+                              enum rxrpc_call_completion compl,
+                              u32 abort_code,
+                              int error);
+bool rxrpc_call_completed(struct rxrpc_call *call);
+bool rxrpc_abort_call(struct rxrpc_call *call, rxrpc_seq_t seq,
+                     u32 abort_code, int error, enum rxrpc_abort_reason why);
+void rxrpc_prefail_call(struct rxrpc_call *call, enum rxrpc_call_completion compl,
+                       int error);
+
+static inline void rxrpc_set_call_state(struct rxrpc_call *call,
+                                       enum rxrpc_call_state state)
+{
+       /* Order write of completion info before write of ->state. */
+       smp_store_release(&call->_state, state);
+       wake_up(&call->waitq);
+}
+
+static inline enum rxrpc_call_state __rxrpc_call_state(const struct rxrpc_call *call)
+{
+       return call->_state; /* Only inside I/O thread */
+}
+
+static inline bool __rxrpc_call_is_complete(const struct rxrpc_call *call)
+{
+       return __rxrpc_call_state(call) == RXRPC_CALL_COMPLETE;
+}
+
+static inline enum rxrpc_call_state rxrpc_call_state(const struct rxrpc_call *call)
+{
+       /* Order read ->state before read of completion info. */
+       return smp_load_acquire(&call->_state);
+}
+
+static inline bool rxrpc_call_is_complete(const struct rxrpc_call *call)
+{
+       return rxrpc_call_state(call) == RXRPC_CALL_COMPLETE;
+}
+
+static inline bool rxrpc_call_has_failed(const struct rxrpc_call *call)
+{
+       return rxrpc_call_is_complete(call) && call->completion != RXRPC_CALL_SUCCEEDED;
+}
+
 /*
  * conn_client.c
  */
 extern unsigned int rxrpc_reap_client_connections;
 extern unsigned long rxrpc_conn_idle_client_expiry;
 extern unsigned long rxrpc_conn_idle_client_fast_expiry;
-extern struct idr rxrpc_client_conn_ids;
 
-void rxrpc_destroy_client_conn_ids(void);
+void rxrpc_purge_client_connections(struct rxrpc_local *local);
 struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
 void rxrpc_put_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
-int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_call *,
-                      struct rxrpc_conn_parameters *, struct sockaddr_rxrpc *,
-                      gfp_t);
+int rxrpc_look_up_bundle(struct rxrpc_call *call, gfp_t gfp);
+void rxrpc_connect_client_calls(struct rxrpc_local *local);
 void rxrpc_expose_client_call(struct rxrpc_call *);
 void rxrpc_disconnect_client_call(struct rxrpc_bundle *, struct rxrpc_call *);
+void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
 void rxrpc_put_client_conn(struct rxrpc_connection *, enum rxrpc_conn_trace);
-void rxrpc_discard_expired_client_conns(struct work_struct *);
-void rxrpc_destroy_all_client_connections(struct rxrpc_net *);
+void rxrpc_discard_expired_client_conns(struct rxrpc_local *local);
 void rxrpc_clean_up_local_conns(struct rxrpc_local *);
 
 /*
  * conn_event.c
  */
+void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, struct sk_buff *skb,
+                               unsigned int channel);
+int rxrpc_abort_conn(struct rxrpc_connection *conn, struct sk_buff *skb,
+                    s32 abort_code, int err, enum rxrpc_abort_reason why);
 void rxrpc_process_connection(struct work_struct *);
 void rxrpc_process_delayed_final_acks(struct rxrpc_connection *, bool);
-int rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb);
+bool rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb);
+void rxrpc_input_conn_event(struct rxrpc_connection *conn, struct sk_buff *skb);
+
+static inline bool rxrpc_is_conn_aborted(const struct rxrpc_connection *conn)
+{
+       /* Order reading the abort info after the state check. */
+       return smp_load_acquire(&conn->state) == RXRPC_CONN_ABORTED;
+}
 
 /*
  * conn_object.c
@@ -906,6 +977,7 @@ int rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb);
 extern unsigned int rxrpc_connection_expiry;
 extern unsigned int rxrpc_closed_conn_expiry;
 
+void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why);
 struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *, gfp_t);
 struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *,
                                                          struct sockaddr_rxrpc *,
@@ -961,12 +1033,19 @@ void rxrpc_implicit_end_call(struct rxrpc_call *, struct sk_buff *);
  */
 int rxrpc_encap_rcv(struct sock *, struct sk_buff *);
 void rxrpc_error_report(struct sock *);
+bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
+                       s32 abort_code, int err);
 int rxrpc_io_thread(void *data);
 static inline void rxrpc_wake_up_io_thread(struct rxrpc_local *local)
 {
        wake_up_process(local->io_thread);
 }
 
+static inline bool rxrpc_protocol_error(struct sk_buff *skb, enum rxrpc_abort_reason why)
+{
+       return rxrpc_direct_abort(skb, why, RX_PROTOCOL_ERROR, -EPROTO);
+}
+
 /*
  * insecure.c
  */
@@ -1048,6 +1127,7 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net)
 int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb);
 int rxrpc_send_abort_packet(struct rxrpc_call *);
 int rxrpc_send_data_packet(struct rxrpc_call *, struct rxrpc_txbuf *);
+void rxrpc_send_conn_abort(struct rxrpc_connection *conn);
 void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb);
 void rxrpc_send_keepalive(struct rxrpc_peer *);
 void rxrpc_transmit_one(struct rxrpc_call *call, struct rxrpc_txbuf *txb);
@@ -1063,12 +1143,11 @@ void rxrpc_peer_keepalive_worker(struct work_struct *);
  */
 struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *,
                                         const struct sockaddr_rxrpc *);
-struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *, struct rxrpc_local *,
-                                    struct sockaddr_rxrpc *, gfp_t);
+struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
+                                    struct sockaddr_rxrpc *srx, gfp_t gfp);
 struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t,
                                    enum rxrpc_peer_trace);
-void rxrpc_new_incoming_peer(struct rxrpc_sock *, struct rxrpc_local *,
-                            struct rxrpc_peer *);
+void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer);
 void rxrpc_destroy_all_peers(struct rxrpc_net *);
 struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *, enum rxrpc_peer_trace);
 struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *, enum rxrpc_peer_trace);
@@ -1086,33 +1165,22 @@ extern const struct seq_operations rxrpc_local_seq_ops;
  * recvmsg.c
  */
 void rxrpc_notify_socket(struct rxrpc_call *);
-bool __rxrpc_set_call_completion(struct rxrpc_call *, enum rxrpc_call_completion, u32, int);
-bool rxrpc_set_call_completion(struct rxrpc_call *, enum rxrpc_call_completion, u32, int);
-bool __rxrpc_call_completed(struct rxrpc_call *);
-bool rxrpc_call_completed(struct rxrpc_call *);
-bool __rxrpc_abort_call(const char *, struct rxrpc_call *, rxrpc_seq_t, u32, int);
-bool rxrpc_abort_call(const char *, struct rxrpc_call *, rxrpc_seq_t, u32, int);
 int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
 
 /*
  * Abort a call due to a protocol error.
  */
-static inline bool __rxrpc_abort_eproto(struct rxrpc_call *call,
-                                       struct sk_buff *skb,
-                                       const char *eproto_why,
-                                       const char *why,
-                                       u32 abort_code)
+static inline int rxrpc_abort_eproto(struct rxrpc_call *call,
+                                    struct sk_buff *skb,
+                                    s32 abort_code,
+                                    enum rxrpc_abort_reason why)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
 
-       trace_rxrpc_rx_eproto(call, sp->hdr.serial, eproto_why);
-       return rxrpc_abort_call(why, call, sp->hdr.seq, abort_code, -EPROTO);
+       rxrpc_abort_call(call, sp->hdr.seq, abort_code, -EPROTO, why);
+       return -EPROTO;
 }
 
-#define rxrpc_abort_eproto(call, skb, eproto_why, abort_why, abort_code) \
-       __rxrpc_abort_eproto((call), (skb), tracepoint_string(eproto_why), \
-                            (abort_why), (abort_code))
-
 /*
  * rtt.c
  */
@@ -1144,6 +1212,8 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *,
 /*
  * sendmsg.c
  */
+bool rxrpc_propose_abort(struct rxrpc_call *call, s32 abort_code, int error,
+                        enum rxrpc_abort_reason why);
 int rxrpc_do_sendmsg(struct rxrpc_sock *, struct msghdr *, size_t);
 
 /*
index c024016..3e8689f 100644 (file)
@@ -99,7 +99,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
        if (!call)
                return -ENOMEM;
        call->flags |= (1 << RXRPC_CALL_IS_SERVICE);
-       call->state = RXRPC_CALL_SERVER_PREALLOC;
+       rxrpc_set_call_state(call, RXRPC_CALL_SERVER_PREALLOC);
        __set_bit(RXRPC_CALL_EV_INITIAL_PING, &call->events);
 
        trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
@@ -280,7 +280,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
                                          (peer_tail + 1) &
                                          (RXRPC_BACKLOG_MAX - 1));
 
-                       rxrpc_new_incoming_peer(rx, local, peer);
+                       rxrpc_new_incoming_peer(local, peer);
                }
 
                /* Now allocate and set up the connection */
@@ -326,11 +326,11 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
  * If we want to report an error, we mark the skb with the packet type and
  * abort code and return false.
  */
-int rxrpc_new_incoming_call(struct rxrpc_local *local,
-                           struct rxrpc_peer *peer,
-                           struct rxrpc_connection *conn,
-                           struct sockaddr_rxrpc *peer_srx,
-                           struct sk_buff *skb)
+bool rxrpc_new_incoming_call(struct rxrpc_local *local,
+                            struct rxrpc_peer *peer,
+                            struct rxrpc_connection *conn,
+                            struct sockaddr_rxrpc *peer_srx,
+                            struct sk_buff *skb)
 {
        const struct rxrpc_security *sec = NULL;
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
@@ -339,18 +339,17 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
 
        _enter("");
 
-       /* Don't set up a call for anything other than the first DATA packet. */
-       if (sp->hdr.seq != 1 ||
-           sp->hdr.type != RXRPC_PACKET_TYPE_DATA)
-               return 0; /* Just discard */
+       /* Don't set up a call for anything other than a DATA packet. */
+       if (sp->hdr.type != RXRPC_PACKET_TYPE_DATA)
+               return rxrpc_protocol_error(skb, rxrpc_eproto_no_service_call);
 
-       rcu_read_lock();
+       read_lock(&local->services_lock);
 
        /* Weed out packets to services we're not offering.  Packets that would
         * begin a call are explicitly rejected and the rest are just
         * discarded.
         */
-       rx = rcu_dereference(local->service);
+       rx = local->service;
        if (!rx || (sp->hdr.serviceId != rx->srx.srx_service &&
                    sp->hdr.serviceId != rx->second_service)
            ) {
@@ -363,16 +362,14 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
        if (!conn) {
                sec = rxrpc_get_incoming_security(rx, skb);
                if (!sec)
-                       goto reject;
+                       goto unsupported_security;
        }
 
        spin_lock(&rx->incoming_lock);
        if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED ||
            rx->sk.sk_state == RXRPC_CLOSE) {
-               trace_rxrpc_abort(0, "CLS", sp->hdr.cid, sp->hdr.callNumber,
-                                 sp->hdr.seq, RX_INVALID_OPERATION, ESHUTDOWN);
-               skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
-               skb->priority = RX_INVALID_OPERATION;
+               rxrpc_direct_abort(skb, rxrpc_abort_shut_down,
+                                  RX_INVALID_OPERATION, -ESHUTDOWN);
                goto no_call;
        }
 
@@ -402,7 +399,7 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
        spin_unlock(&conn->state_lock);
 
        spin_unlock(&rx->incoming_lock);
-       rcu_read_unlock();
+       read_unlock(&local->services_lock);
 
        if (hlist_unhashed(&call->error_link)) {
                spin_lock(&call->peer->lock);
@@ -413,22 +410,24 @@ int rxrpc_new_incoming_call(struct rxrpc_local *local,
        _leave(" = %p{%d}", call, call->debug_id);
        rxrpc_input_call_event(call, skb);
        rxrpc_put_call(call, rxrpc_call_put_input);
-       return 0;
+       return true;
 
 unsupported_service:
-       trace_rxrpc_abort(0, "INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                         RX_INVALID_OPERATION, EOPNOTSUPP);
-       skb->priority = RX_INVALID_OPERATION;
-       goto reject;
+       read_unlock(&local->services_lock);
+       return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
+                                 RX_INVALID_OPERATION, -EOPNOTSUPP);
+unsupported_security:
+       read_unlock(&local->services_lock);
+       return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
+                                 RX_INVALID_OPERATION, -EKEYREJECTED);
 no_call:
        spin_unlock(&rx->incoming_lock);
-reject:
-       rcu_read_unlock();
+       read_unlock(&local->services_lock);
        _leave(" = f [%u]", skb->mark);
-       return -EPROTO;
+       return false;
 discard:
-       rcu_read_unlock();
-       return 0;
+       read_unlock(&local->services_lock);
+       return true;
 }
 
 /*
index b2cf448..1abdef1 100644 (file)
@@ -251,6 +251,41 @@ out:
        _leave("");
 }
 
+/*
+ * Start transmitting the reply to a service.  This cancels the need to ACK the
+ * request if we haven't yet done so.
+ */
+static void rxrpc_begin_service_reply(struct rxrpc_call *call)
+{
+       unsigned long now = jiffies;
+
+       rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SEND_REPLY);
+       WRITE_ONCE(call->delay_ack_at, now + MAX_JIFFY_OFFSET);
+       if (call->ackr_reason == RXRPC_ACK_DELAY)
+               call->ackr_reason = 0;
+       trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now);
+}
+
+/*
+ * Close the transmission phase.  After this point there is no more data to be
+ * transmitted in the call.
+ */
+static void rxrpc_close_tx_phase(struct rxrpc_call *call)
+{
+       _debug("________awaiting reply/ACK__________");
+
+       switch (__rxrpc_call_state(call)) {
+       case RXRPC_CALL_CLIENT_SEND_REQUEST:
+               rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY);
+               break;
+       case RXRPC_CALL_SERVER_SEND_REPLY:
+               rxrpc_set_call_state(call, RXRPC_CALL_SERVER_AWAIT_ACK);
+               break;
+       default:
+               break;
+       }
+}
+
 static bool rxrpc_tx_window_has_space(struct rxrpc_call *call)
 {
        unsigned int winsize = min_t(unsigned int, call->tx_winsize,
@@ -270,9 +305,11 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call)
 {
        struct rxrpc_txbuf *txb;
 
-       if (rxrpc_is_client_call(call) &&
-           !test_bit(RXRPC_CALL_EXPOSED, &call->flags))
+       if (!test_bit(RXRPC_CALL_EXPOSED, &call->flags)) {
+               if (list_empty(&call->tx_sendmsg))
+                       return;
                rxrpc_expose_client_call(call);
+       }
 
        while ((txb = list_first_entry_or_null(&call->tx_sendmsg,
                                               struct rxrpc_txbuf, call_link))) {
@@ -283,6 +320,9 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call)
                call->tx_top = txb->seq;
                list_add_tail(&txb->call_link, &call->tx_buffer);
 
+               if (txb->wire.flags & RXRPC_LAST_PACKET)
+                       rxrpc_close_tx_phase(call);
+
                rxrpc_transmit_one(call, txb);
 
                if (!rxrpc_tx_window_has_space(call))
@@ -292,16 +332,15 @@ static void rxrpc_decant_prepared_tx(struct rxrpc_call *call)
 
 static void rxrpc_transmit_some_data(struct rxrpc_call *call)
 {
-       switch (call->state) {
+       switch (__rxrpc_call_state(call)) {
        case RXRPC_CALL_SERVER_ACK_REQUEST:
                if (list_empty(&call->tx_sendmsg))
                        return;
+               rxrpc_begin_service_reply(call);
                fallthrough;
 
        case RXRPC_CALL_SERVER_SEND_REPLY:
-       case RXRPC_CALL_SERVER_AWAIT_ACK:
        case RXRPC_CALL_CLIENT_SEND_REQUEST:
-       case RXRPC_CALL_CLIENT_AWAIT_REPLY:
                if (!rxrpc_tx_window_has_space(call))
                        return;
                if (list_empty(&call->tx_sendmsg)) {
@@ -331,21 +370,31 @@ static void rxrpc_send_initial_ping(struct rxrpc_call *call)
 /*
  * Handle retransmission and deferred ACK/abort generation.
  */
-void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
+bool rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
 {
        unsigned long now, next, t;
        rxrpc_serial_t ackr_serial;
        bool resend = false, expired = false;
+       s32 abort_code;
 
        rxrpc_see_call(call, rxrpc_call_see_input);
 
        //printk("\n--------------------\n");
        _enter("{%d,%s,%lx}",
-              call->debug_id, rxrpc_call_states[call->state], call->events);
+              call->debug_id, rxrpc_call_states[__rxrpc_call_state(call)],
+              call->events);
 
-       if (call->state == RXRPC_CALL_COMPLETE)
+       if (__rxrpc_call_is_complete(call))
                goto out;
 
+       /* Handle abort request locklessly, vs rxrpc_propose_abort(). */
+       abort_code = smp_load_acquire(&call->send_abort);
+       if (abort_code) {
+               rxrpc_abort_call(call, 0, call->send_abort, call->send_abort_err,
+                                call->send_abort_why);
+               goto out;
+       }
+
        if (skb && skb->mark == RXRPC_SKB_MARK_ERROR)
                goto out;
 
@@ -358,7 +407,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
        }
 
        t = READ_ONCE(call->expect_req_by);
-       if (call->state == RXRPC_CALL_SERVER_RECV_REQUEST &&
+       if (__rxrpc_call_state(call) == RXRPC_CALL_SERVER_RECV_REQUEST &&
            time_after_eq(now, t)) {
                trace_rxrpc_timer(call, rxrpc_timer_exp_idle, now);
                expired = true;
@@ -429,11 +478,12 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
                if (test_bit(RXRPC_CALL_RX_HEARD, &call->flags) &&
                    (int)call->conn->hi_serial - (int)call->rx_serial > 0) {
                        trace_rxrpc_call_reset(call);
-                       rxrpc_abort_call("EXP", call, 0, RX_CALL_DEAD, -ECONNRESET);
+                       rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ECONNRESET,
+                                        rxrpc_abort_call_reset);
                } else {
-                       rxrpc_abort_call("EXP", call, 0, RX_CALL_TIMEOUT, -ETIME);
+                       rxrpc_abort_call(call, 0, RX_CALL_TIMEOUT, -ETIME,
+                                        rxrpc_abort_call_timeout);
                }
-               rxrpc_send_abort_packet(call);
                goto out;
        }
 
@@ -441,7 +491,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
                rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
                               rxrpc_propose_ack_ping_for_lost_ack);
 
-       if (resend && call->state != RXRPC_CALL_CLIENT_RECV_REPLY)
+       if (resend && __rxrpc_call_state(call) != RXRPC_CALL_CLIENT_RECV_REPLY)
                rxrpc_resend(call, NULL);
 
        if (test_and_clear_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags))
@@ -453,7 +503,7 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
                               rxrpc_propose_ack_input_data);
 
        /* Make sure the timer is restarted */
-       if (call->state != RXRPC_CALL_COMPLETE) {
+       if (!__rxrpc_call_is_complete(call)) {
                next = call->expect_rx_by;
 
 #define set(T) { t = READ_ONCE(T); if (time_before(t, next)) next = t; }
@@ -474,9 +524,15 @@ void rxrpc_input_call_event(struct rxrpc_call *call, struct sk_buff *skb)
        }
 
 out:
-       if (call->state == RXRPC_CALL_COMPLETE)
+       if (__rxrpc_call_is_complete(call)) {
                del_timer_sync(&call->timer);
+               if (!test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
+                       rxrpc_disconnect_call(call);
+               if (call->security)
+                       call->security->free_call_crypto(call);
+       }
        if (call->acks_hard_ack != call->tx_bottom)
                rxrpc_shrink_call_tx_buffer(call);
        _leave("");
+       return true;
 }
index 89dcf60..f3c9f02 100644 (file)
@@ -50,7 +50,7 @@ void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what)
        struct rxrpc_local *local = call->local;
        bool busy;
 
-       if (call->state < RXRPC_CALL_COMPLETE) {
+       if (!test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) {
                spin_lock_bh(&local->lock);
                busy = !list_empty(&call->attend_link);
                trace_rxrpc_poke_call(call, busy, what);
@@ -69,7 +69,7 @@ static void rxrpc_call_timer_expired(struct timer_list *t)
 
        _enter("%d", call->debug_id);
 
-       if (call->state < RXRPC_CALL_COMPLETE) {
+       if (!__rxrpc_call_is_complete(call)) {
                trace_rxrpc_timer_expired(call, jiffies);
                rxrpc_poke_call(call, rxrpc_call_poke_timer);
        }
@@ -150,7 +150,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
        timer_setup(&call->timer, rxrpc_call_timer_expired, 0);
        INIT_WORK(&call->destroyer, rxrpc_destroy_call);
        INIT_LIST_HEAD(&call->link);
-       INIT_LIST_HEAD(&call->chan_wait_link);
+       INIT_LIST_HEAD(&call->wait_link);
        INIT_LIST_HEAD(&call->accept_link);
        INIT_LIST_HEAD(&call->recvmsg_link);
        INIT_LIST_HEAD(&call->sock_link);
@@ -162,7 +162,6 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
        init_waitqueue_head(&call->waitq);
        spin_lock_init(&call->notify_lock);
        spin_lock_init(&call->tx_lock);
-       rwlock_init(&call->state_lock);
        refcount_set(&call->ref, 1);
        call->debug_id = debug_id;
        call->tx_total_len = -1;
@@ -211,7 +210,6 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
        now = ktime_get_real();
        call->acks_latest_ts    = now;
        call->cong_tstamp       = now;
-       call->state             = RXRPC_CALL_CLIENT_AWAIT_CONN;
        call->dest_srx          = *srx;
        call->interruptibility  = p->interruptibility;
        call->tx_total_len      = p->tx_total_len;
@@ -227,11 +225,13 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
 
        ret = rxrpc_init_client_call_security(call);
        if (ret < 0) {
-               __rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret);
+               rxrpc_prefail_call(call, RXRPC_CALL_LOCAL_ERROR, ret);
                rxrpc_put_call(call, rxrpc_call_put_discard_error);
                return ERR_PTR(ret);
        }
 
+       rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_CONN);
+
        trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
                         p->user_call_ID, rxrpc_call_new_client);
 
@@ -242,7 +242,7 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
 /*
  * Initiate the call ack/resend/expiry timer.
  */
-static void rxrpc_start_call_timer(struct rxrpc_call *call)
+void rxrpc_start_call_timer(struct rxrpc_call *call)
 {
        unsigned long now = jiffies;
        unsigned long j = now + MAX_JIFFY_OFFSET;
@@ -286,6 +286,39 @@ static void rxrpc_put_call_slot(struct rxrpc_call *call)
        up(limiter);
 }
 
+/*
+ * Start the process of connecting a call.  We obtain a peer and a connection
+ * bundle, but the actual association of a call with a connection is offloaded
+ * to the I/O thread to simplify locking.
+ */
+static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp)
+{
+       struct rxrpc_local *local = call->local;
+       int ret = -ENOMEM;
+
+       _enter("{%d,%lx},", call->debug_id, call->user_call_ID);
+
+       call->peer = rxrpc_lookup_peer(local, &call->dest_srx, gfp);
+       if (!call->peer)
+               goto error;
+
+       ret = rxrpc_look_up_bundle(call, gfp);
+       if (ret < 0)
+               goto error;
+
+       trace_rxrpc_client(NULL, -1, rxrpc_client_queue_new_call);
+       rxrpc_get_call(call, rxrpc_call_get_io_thread);
+       spin_lock(&local->client_call_lock);
+       list_add_tail(&call->wait_link, &local->new_client_calls);
+       spin_unlock(&local->client_call_lock);
+       rxrpc_wake_up_io_thread(local);
+       return 0;
+
+error:
+       __set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
+       return ret;
+}
+
 /*
  * Set up a call for the given parameters.
  * - Called with the socket lock held, which it must release.
@@ -365,14 +398,10 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
        /* Set up or get a connection record and set the protocol parameters,
         * including channel number and call ID.
         */
-       ret = rxrpc_connect_call(rx, call, cp, srx, gfp);
+       ret = rxrpc_connect_call(call, gfp);
        if (ret < 0)
                goto error_attached_to_socket;
 
-       rxrpc_see_call(call, rxrpc_call_see_connected);
-
-       rxrpc_start_call_timer(call);
-
        _leave(" = %p [new]", call);
        return call;
 
@@ -384,27 +413,23 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
 error_dup_user_ID:
        write_unlock(&rx->call_lock);
        release_sock(&rx->sk);
-       __rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
-                                   RX_CALL_DEAD, -EEXIST);
+       rxrpc_prefail_call(call, RXRPC_CALL_LOCAL_ERROR, -EEXIST);
        trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), 0,
                         rxrpc_call_see_userid_exists);
-       rxrpc_release_call(rx, call);
        mutex_unlock(&call->user_mutex);
        rxrpc_put_call(call, rxrpc_call_put_userid_exists);
        _leave(" = -EEXIST");
        return ERR_PTR(-EEXIST);
 
        /* We got an error, but the call is attached to the socket and is in
-        * need of release.  However, we might now race with recvmsg() when
-        * completing the call queues it.  Return 0 from sys_sendmsg() and
+        * need of release.  However, we might now race with recvmsg() when it
+        * completion notifies the socket.  Return 0 from sys_sendmsg() and
         * leave the error to recvmsg() to deal with.
         */
 error_attached_to_socket:
        trace_rxrpc_call(call->debug_id, refcount_read(&call->ref), ret,
                         rxrpc_call_see_connect_failed);
-       set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
-       __rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
-                                   RX_CALL_DEAD, ret);
+       rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret);
        _leave(" = c=%08x [err]", call->debug_id);
        return call;
 }
@@ -427,32 +452,32 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
        call->call_id           = sp->hdr.callNumber;
        call->dest_srx.srx_service = sp->hdr.serviceId;
        call->cid               = sp->hdr.cid;
-       call->state             = RXRPC_CALL_SERVER_SECURING;
        call->cong_tstamp       = skb->tstamp;
 
+       __set_bit(RXRPC_CALL_EXPOSED, &call->flags);
+       rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SECURING);
+
        spin_lock(&conn->state_lock);
 
        switch (conn->state) {
        case RXRPC_CONN_SERVICE_UNSECURED:
        case RXRPC_CONN_SERVICE_CHALLENGING:
-               call->state = RXRPC_CALL_SERVER_SECURING;
+               rxrpc_set_call_state(call, RXRPC_CALL_SERVER_SECURING);
                break;
        case RXRPC_CONN_SERVICE:
-               call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
+               rxrpc_set_call_state(call, RXRPC_CALL_SERVER_RECV_REQUEST);
                break;
 
-       case RXRPC_CONN_REMOTELY_ABORTED:
-               __rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
-                                           conn->abort_code, conn->error);
-               break;
-       case RXRPC_CONN_LOCALLY_ABORTED:
-               __rxrpc_abort_call("CON", call, 1,
-                                  conn->abort_code, conn->error);
+       case RXRPC_CONN_ABORTED:
+               rxrpc_set_call_completion(call, conn->completion,
+                                         conn->abort_code, conn->error);
                break;
        default:
                BUG();
        }
 
+       rxrpc_get_call(call, rxrpc_call_get_io_thread);
+
        /* Set the channel for this call.  We don't get channel_lock as we're
         * only defending against the data_ready handler (which we're called
         * from) and the RESPONSE packet parser (which is only really
@@ -462,7 +487,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
        chan = sp->hdr.cid & RXRPC_CHANNELMASK;
        conn->channels[chan].call_counter = call->call_id;
        conn->channels[chan].call_id = call->call_id;
-       rcu_assign_pointer(conn->channels[chan].call, call);
+       conn->channels[chan].call = call;
        spin_unlock(&conn->state_lock);
 
        spin_lock(&conn->peer->lock);
@@ -522,20 +547,17 @@ static void rxrpc_cleanup_ring(struct rxrpc_call *call)
 void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
 {
        struct rxrpc_connection *conn = call->conn;
-       bool put = false;
+       bool put = false, putu = false;
 
        _enter("{%d,%d}", call->debug_id, refcount_read(&call->ref));
 
        trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
                         call->flags, rxrpc_call_see_release);
 
-       ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
-
        if (test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags))
                BUG();
 
        rxrpc_put_call_slot(call);
-       del_timer_sync(&call->timer);
 
        /* Make sure we don't get any more notifications */
        write_lock(&rx->recvmsg_lock);
@@ -560,7 +582,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
        if (test_and_clear_bit(RXRPC_CALL_HAS_USERID, &call->flags)) {
                rb_erase(&call->sock_node, &rx->calls);
                memset(&call->sock_node, 0xdd, sizeof(call->sock_node));
-               rxrpc_put_call(call, rxrpc_call_put_userid_exists);
+               putu = true;
        }
 
        list_del(&call->sock_link);
@@ -568,10 +590,9 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
 
        _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn);
 
-       if (conn && !test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
-               rxrpc_disconnect_call(call);
-       if (call->security)
-               call->security->free_call_crypto(call);
+       if (putu)
+               rxrpc_put_call(call, rxrpc_call_put_userid);
+
        _leave("");
 }
 
@@ -588,7 +609,8 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
                call = list_entry(rx->to_be_accepted.next,
                                  struct rxrpc_call, accept_link);
                list_del(&call->accept_link);
-               rxrpc_abort_call("SKR", call, 0, RX_CALL_DEAD, -ECONNRESET);
+               rxrpc_propose_abort(call, RX_CALL_DEAD, -ECONNRESET,
+                                   rxrpc_abort_call_sock_release_tba);
                rxrpc_put_call(call, rxrpc_call_put_release_sock_tba);
        }
 
@@ -596,8 +618,8 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
                call = list_entry(rx->sock_calls.next,
                                  struct rxrpc_call, sock_link);
                rxrpc_get_call(call, rxrpc_call_get_release_sock);
-               rxrpc_abort_call("SKT", call, 0, RX_CALL_DEAD, -ECONNRESET);
-               rxrpc_send_abort_packet(call);
+               rxrpc_propose_abort(call, RX_CALL_DEAD, -ECONNRESET,
+                                   rxrpc_abort_call_sock_release);
                rxrpc_release_call(rx, call);
                rxrpc_put_call(call, rxrpc_call_put_release_sock);
        }
@@ -620,7 +642,7 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace why)
        dead = __refcount_dec_and_test(&call->ref, &r);
        trace_rxrpc_call(debug_id, r - 1, 0, why);
        if (dead) {
-               ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
+               ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
 
                if (!list_empty(&call->link)) {
                        spin_lock(&rxnet->call_lock);
@@ -669,6 +691,8 @@ static void rxrpc_destroy_call(struct work_struct *work)
 
        rxrpc_put_txbuf(call->tx_pending, rxrpc_txbuf_put_cleaned);
        rxrpc_put_connection(call->conn, rxrpc_conn_put_call);
+       rxrpc_deactivate_bundle(call->bundle);
+       rxrpc_put_bundle(call->bundle, rxrpc_bundle_put_call);
        rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
        rxrpc_put_local(call->local, rxrpc_local_put_call);
        call_rcu(&call->rcu, rxrpc_rcu_free_call);
@@ -681,7 +705,7 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
 {
        memset(&call->sock_node, 0xcd, sizeof(call->sock_node));
 
-       ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
+       ASSERTCMP(__rxrpc_call_state(call), ==, RXRPC_CALL_COMPLETE);
        ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
 
        del_timer(&call->timer);
@@ -719,7 +743,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet)
 
                        pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n",
                               call, refcount_read(&call->ref),
-                              rxrpc_call_states[call->state],
+                              rxrpc_call_states[__rxrpc_call_state(call)],
                               call->flags, call->events);
 
                        spin_unlock(&rxnet->call_lock);
diff --git a/net/rxrpc/call_state.c b/net/rxrpc/call_state.c
new file mode 100644 (file)
index 0000000..6afb543
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Call state changing functions.
+ *
+ * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ */
+
+#include "ar-internal.h"
+
+/*
+ * Transition a call to the complete state.
+ */
+bool rxrpc_set_call_completion(struct rxrpc_call *call,
+                                enum rxrpc_call_completion compl,
+                                u32 abort_code,
+                                int error)
+{
+       if (__rxrpc_call_state(call) == RXRPC_CALL_COMPLETE)
+               return false;
+
+       call->abort_code = abort_code;
+       call->error = error;
+       call->completion = compl;
+       /* Allow reader of completion state to operate locklessly */
+       rxrpc_set_call_state(call, RXRPC_CALL_COMPLETE);
+       trace_rxrpc_call_complete(call);
+       wake_up(&call->waitq);
+       rxrpc_notify_socket(call);
+       return true;
+}
+
+/*
+ * Record that a call successfully completed.
+ */
+bool rxrpc_call_completed(struct rxrpc_call *call)
+{
+       return rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
+}
+
+/*
+ * Record that a call is locally aborted.
+ */
+bool rxrpc_abort_call(struct rxrpc_call *call, rxrpc_seq_t seq,
+                     u32 abort_code, int error, enum rxrpc_abort_reason why)
+{
+       trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
+                         abort_code, error);
+       if (!rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
+                                      abort_code, error))
+               return false;
+       if (test_bit(RXRPC_CALL_EXPOSED, &call->flags))
+               rxrpc_send_abort_packet(call);
+       return true;
+}
+
+/*
+ * Record that a call errored out before even getting off the ground, thereby
+ * setting the state to allow it to be destroyed.
+ */
+void rxrpc_prefail_call(struct rxrpc_call *call, enum rxrpc_call_completion compl,
+                       int error)
+{
+       call->abort_code        = RX_CALL_DEAD;
+       call->error             = error;
+       call->completion        = compl;
+       call->_state            = RXRPC_CALL_COMPLETE;
+       trace_rxrpc_call_complete(call);
+       WARN_ON_ONCE(__test_and_set_bit(RXRPC_CALL_RELEASED, &call->flags));
+}
index 87efa03..981ca5b 100644 (file)
@@ -34,104 +34,59 @@ __read_mostly unsigned int rxrpc_reap_client_connections = 900;
 __read_mostly unsigned long rxrpc_conn_idle_client_expiry = 2 * 60 * HZ;
 __read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ;
 
-/*
- * We use machine-unique IDs for our client connections.
- */
-DEFINE_IDR(rxrpc_client_conn_ids);
-static DEFINE_SPINLOCK(rxrpc_conn_id_lock);
-
-static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
-
-/*
- * Get a connection ID and epoch for a client connection from the global pool.
- * The connection struct pointer is then recorded in the idr radix tree.  The
- * epoch doesn't change until the client is rebooted (or, at least, unless the
- * module is unloaded).
- */
-static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn,
-                                         gfp_t gfp)
+static void rxrpc_activate_bundle(struct rxrpc_bundle *bundle)
 {
-       struct rxrpc_net *rxnet = conn->rxnet;
-       int id;
-
-       _enter("");
-
-       idr_preload(gfp);
-       spin_lock(&rxrpc_conn_id_lock);
-
-       id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn,
-                             1, 0x40000000, GFP_NOWAIT);
-       if (id < 0)
-               goto error;
-
-       spin_unlock(&rxrpc_conn_id_lock);
-       idr_preload_end();
-
-       conn->proto.epoch = rxnet->epoch;
-       conn->proto.cid = id << RXRPC_CIDSHIFT;
-       set_bit(RXRPC_CONN_HAS_IDR, &conn->flags);
-       _leave(" [CID %x]", conn->proto.cid);
-       return 0;
-
-error:
-       spin_unlock(&rxrpc_conn_id_lock);
-       idr_preload_end();
-       _leave(" = %d", id);
-       return id;
+       atomic_inc(&bundle->active);
 }
 
 /*
- * Release a connection ID for a client connection from the global pool.
+ * Release a connection ID for a client connection.
  */
-static void rxrpc_put_client_connection_id(struct rxrpc_connection *conn)
+static void rxrpc_put_client_connection_id(struct rxrpc_local *local,
+                                          struct rxrpc_connection *conn)
 {
-       if (test_bit(RXRPC_CONN_HAS_IDR, &conn->flags)) {
-               spin_lock(&rxrpc_conn_id_lock);
-               idr_remove(&rxrpc_client_conn_ids,
-                          conn->proto.cid >> RXRPC_CIDSHIFT);
-               spin_unlock(&rxrpc_conn_id_lock);
-       }
+       idr_remove(&local->conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT);
 }
 
 /*
  * Destroy the client connection ID tree.
  */
-void rxrpc_destroy_client_conn_ids(void)
+static void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local)
 {
        struct rxrpc_connection *conn;
        int id;
 
-       if (!idr_is_empty(&rxrpc_client_conn_ids)) {
-               idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) {
+       if (!idr_is_empty(&local->conn_ids)) {
+               idr_for_each_entry(&local->conn_ids, conn, id) {
                        pr_err("AF_RXRPC: Leaked client conn %p {%d}\n",
                               conn, refcount_read(&conn->ref));
                }
                BUG();
        }
 
-       idr_destroy(&rxrpc_client_conn_ids);
+       idr_destroy(&local->conn_ids);
 }
 
 /*
  * Allocate a connection bundle.
  */
-static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp,
+static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call,
                                               gfp_t gfp)
 {
        struct rxrpc_bundle *bundle;
 
        bundle = kzalloc(sizeof(*bundle), gfp);
        if (bundle) {
-               bundle->local           = cp->local;
-               bundle->peer            = rxrpc_get_peer(cp->peer, rxrpc_peer_get_bundle);
-               bundle->key             = cp->key;
-               bundle->exclusive       = cp->exclusive;
-               bundle->upgrade         = cp->upgrade;
-               bundle->service_id      = cp->service_id;
-               bundle->security_level  = cp->security_level;
+               bundle->local           = call->local;
+               bundle->peer            = rxrpc_get_peer(call->peer, rxrpc_peer_get_bundle);
+               bundle->key             = key_get(call->key);
+               bundle->security        = call->security;
+               bundle->exclusive       = test_bit(RXRPC_CALL_EXCLUSIVE, &call->flags);
+               bundle->upgrade         = test_bit(RXRPC_CALL_UPGRADE, &call->flags);
+               bundle->service_id      = call->dest_srx.srx_service;
+               bundle->security_level  = call->security_level;
                refcount_set(&bundle->ref, 1);
                atomic_set(&bundle->active, 1);
-               spin_lock_init(&bundle->channel_lock);
                INIT_LIST_HEAD(&bundle->waiting_calls);
                trace_rxrpc_bundle(bundle->debug_id, 1, rxrpc_bundle_new);
        }
@@ -152,84 +107,87 @@ static void rxrpc_free_bundle(struct rxrpc_bundle *bundle)
 {
        trace_rxrpc_bundle(bundle->debug_id, 1, rxrpc_bundle_free);
        rxrpc_put_peer(bundle->peer, rxrpc_peer_put_bundle);
+       key_put(bundle->key);
        kfree(bundle);
 }
 
 void rxrpc_put_bundle(struct rxrpc_bundle *bundle, enum rxrpc_bundle_trace why)
 {
-       unsigned int id = bundle->debug_id;
+       unsigned int id;
        bool dead;
        int r;
 
-       dead = __refcount_dec_and_test(&bundle->ref, &r);
-       trace_rxrpc_bundle(id, r - 1, why);
-       if (dead)
-               rxrpc_free_bundle(bundle);
+       if (bundle) {
+               id = bundle->debug_id;
+               dead = __refcount_dec_and_test(&bundle->ref, &r);
+               trace_rxrpc_bundle(id, r - 1, why);
+               if (dead)
+                       rxrpc_free_bundle(bundle);
+       }
+}
+
+/*
+ * Get rid of outstanding client connection preallocations when a local
+ * endpoint is destroyed.
+ */
+void rxrpc_purge_client_connections(struct rxrpc_local *local)
+{
+       rxrpc_destroy_client_conn_ids(local);
 }
 
 /*
  * Allocate a client connection.
  */
 static struct rxrpc_connection *
-rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp)
+rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle)
 {
        struct rxrpc_connection *conn;
-       struct rxrpc_net *rxnet = bundle->local->rxnet;
-       int ret;
+       struct rxrpc_local *local = bundle->local;
+       struct rxrpc_net *rxnet = local->rxnet;
+       int id;
 
        _enter("");
 
-       conn = rxrpc_alloc_connection(rxnet, gfp);
-       if (!conn) {
-               _leave(" = -ENOMEM");
+       conn = rxrpc_alloc_connection(rxnet, GFP_ATOMIC | __GFP_NOWARN);
+       if (!conn)
                return ERR_PTR(-ENOMEM);
+
+       id = idr_alloc_cyclic(&local->conn_ids, conn, 1, 0x40000000,
+                             GFP_ATOMIC | __GFP_NOWARN);
+       if (id < 0) {
+               kfree(conn);
+               return ERR_PTR(id);
        }
 
        refcount_set(&conn->ref, 1);
-       conn->bundle            = bundle;
-       conn->local             = bundle->local;
-       conn->peer              = bundle->peer;
-       conn->key               = bundle->key;
+       conn->proto.cid         = id << RXRPC_CIDSHIFT;
+       conn->proto.epoch       = local->rxnet->epoch;
+       conn->out_clientflag    = RXRPC_CLIENT_INITIATED;
+       conn->bundle            = rxrpc_get_bundle(bundle, rxrpc_bundle_get_client_conn);
+       conn->local             = rxrpc_get_local(bundle->local, rxrpc_local_get_client_conn);
+       conn->peer              = rxrpc_get_peer(bundle->peer, rxrpc_peer_get_client_conn);
+       conn->key               = key_get(bundle->key);
+       conn->security          = bundle->security;
        conn->exclusive         = bundle->exclusive;
        conn->upgrade           = bundle->upgrade;
        conn->orig_service_id   = bundle->service_id;
        conn->security_level    = bundle->security_level;
-       conn->out_clientflag    = RXRPC_CLIENT_INITIATED;
-       conn->state             = RXRPC_CONN_CLIENT;
+       conn->state             = RXRPC_CONN_CLIENT_UNSECURED;
        conn->service_id        = conn->orig_service_id;
 
-       ret = rxrpc_get_client_connection_id(conn, gfp);
-       if (ret < 0)
-               goto error_0;
-
-       ret = rxrpc_init_client_conn_security(conn);
-       if (ret < 0)
-               goto error_1;
+       if (conn->security == &rxrpc_no_security)
+               conn->state     = RXRPC_CONN_CLIENT;
 
        atomic_inc(&rxnet->nr_conns);
        write_lock(&rxnet->conn_lock);
        list_add_tail(&conn->proc_link, &rxnet->conn_proc_list);
        write_unlock(&rxnet->conn_lock);
 
-       rxrpc_get_bundle(bundle, rxrpc_bundle_get_client_conn);
-       rxrpc_get_peer(conn->peer, rxrpc_peer_get_client_conn);
-       rxrpc_get_local(conn->local, rxrpc_local_get_client_conn);
-       key_get(conn->key);
-
-       trace_rxrpc_conn(conn->debug_id, refcount_read(&conn->ref),
-                        rxrpc_conn_new_client);
+       rxrpc_see_connection(conn, rxrpc_conn_new_client);
 
        atomic_inc(&rxnet->nr_client_conns);
        trace_rxrpc_client(conn, -1, rxrpc_client_alloc);
-       _leave(" = %p", conn);
        return conn;
-
-error_1:
-       rxrpc_put_client_connection_id(conn);
-error_0:
-       kfree(conn);
-       _leave(" = %d", ret);
-       return ERR_PTR(ret);
 }
 
 /*
@@ -247,7 +205,8 @@ static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn)
        if (test_bit(RXRPC_CONN_DONT_REUSE, &conn->flags))
                goto dont_reuse;
 
-       if (conn->state != RXRPC_CONN_CLIENT ||
+       if ((conn->state != RXRPC_CONN_CLIENT_UNSECURED &&
+            conn->state != RXRPC_CONN_CLIENT) ||
            conn->proto.epoch != rxnet->epoch)
                goto mark_dont_reuse;
 
@@ -257,7 +216,7 @@ static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn)
         * times the maximum number of client conns away from the current
         * allocation point to try and keep the IDs concentrated.
         */
-       id_cursor = idr_get_cursor(&rxrpc_client_conn_ids);
+       id_cursor = idr_get_cursor(&conn->local->conn_ids);
        id = conn->proto.cid >> RXRPC_CIDSHIFT;
        distance = id - id_cursor;
        if (distance < 0)
@@ -278,20 +237,23 @@ dont_reuse:
  * Look up the conn bundle that matches the connection parameters, adding it if
  * it doesn't yet exist.
  */
-static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *cp,
-                                                gfp_t gfp)
+int rxrpc_look_up_bundle(struct rxrpc_call *call, gfp_t gfp)
 {
        static atomic_t rxrpc_bundle_id;
        struct rxrpc_bundle *bundle, *candidate;
-       struct rxrpc_local *local = cp->local;
+       struct rxrpc_local *local = call->local;
        struct rb_node *p, **pp, *parent;
        long diff;
+       bool upgrade = test_bit(RXRPC_CALL_UPGRADE, &call->flags);
 
        _enter("{%px,%x,%u,%u}",
-              cp->peer, key_serial(cp->key), cp->security_level, cp->upgrade);
+              call->peer, key_serial(call->key), call->security_level,
+              upgrade);
 
-       if (cp->exclusive)
-               return rxrpc_alloc_bundle(cp, gfp);
+       if (test_bit(RXRPC_CALL_EXCLUSIVE, &call->flags)) {
+               call->bundle = rxrpc_alloc_bundle(call, gfp);
+               return call->bundle ? 0 : -ENOMEM;
+       }
 
        /* First, see if the bundle is already there. */
        _debug("search 1");
@@ -300,11 +262,11 @@ static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *c
        while (p) {
                bundle = rb_entry(p, struct rxrpc_bundle, local_node);
 
-#define cmp(X) ((long)bundle->X - (long)cp->X)
-               diff = (cmp(peer) ?:
-                       cmp(key) ?:
-                       cmp(security_level) ?:
-                       cmp(upgrade));
+#define cmp(X, Y) ((long)(X) - (long)(Y))
+               diff = (cmp(bundle->peer, call->peer) ?:
+                       cmp(bundle->key, call->key) ?:
+                       cmp(bundle->security_level, call->security_level) ?:
+                       cmp(bundle->upgrade, upgrade));
 #undef cmp
                if (diff < 0)
                        p = p->rb_left;
@@ -317,9 +279,9 @@ static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *c
        _debug("not found");
 
        /* It wasn't.  We need to add one. */
-       candidate = rxrpc_alloc_bundle(cp, gfp);
+       candidate = rxrpc_alloc_bundle(call, gfp);
        if (!candidate)
-               return NULL;
+               return -ENOMEM;
 
        _debug("search 2");
        spin_lock(&local->client_bundles_lock);
@@ -329,11 +291,11 @@ static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *c
                parent = *pp;
                bundle = rb_entry(parent, struct rxrpc_bundle, local_node);
 
-#define cmp(X) ((long)bundle->X - (long)cp->X)
-               diff = (cmp(peer) ?:
-                       cmp(key) ?:
-                       cmp(security_level) ?:
-                       cmp(upgrade));
+#define cmp(X, Y) ((long)(X) - (long)(Y))
+               diff = (cmp(bundle->peer, call->peer) ?:
+                       cmp(bundle->key, call->key) ?:
+                       cmp(bundle->security_level, call->security_level) ?:
+                       cmp(bundle->upgrade, upgrade));
 #undef cmp
                if (diff < 0)
                        pp = &(*pp)->rb_left;
@@ -347,178 +309,89 @@ static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *c
        candidate->debug_id = atomic_inc_return(&rxrpc_bundle_id);
        rb_link_node(&candidate->local_node, parent, pp);
        rb_insert_color(&candidate->local_node, &local->client_bundles);
-       rxrpc_get_bundle(candidate, rxrpc_bundle_get_client_call);
+       call->bundle = rxrpc_get_bundle(candidate, rxrpc_bundle_get_client_call);
        spin_unlock(&local->client_bundles_lock);
-       _leave(" = %u [new]", candidate->debug_id);
-       return candidate;
+       _leave(" = B=%u [new]", call->bundle->debug_id);
+       return 0;
 
 found_bundle_free:
        rxrpc_free_bundle(candidate);
 found_bundle:
-       rxrpc_get_bundle(bundle, rxrpc_bundle_get_client_call);
-       atomic_inc(&bundle->active);
+       call->bundle = rxrpc_get_bundle(bundle, rxrpc_bundle_get_client_call);
+       rxrpc_activate_bundle(bundle);
        spin_unlock(&local->client_bundles_lock);
-       _leave(" = %u [found]", bundle->debug_id);
-       return bundle;
-}
-
-/*
- * Create or find a client bundle to use for a call.
- *
- * If we return with a connection, the call will be on its waiting list.  It's
- * left to the caller to assign a channel and wake up the call.
- */
-static struct rxrpc_bundle *rxrpc_prep_call(struct rxrpc_sock *rx,
-                                           struct rxrpc_call *call,
-                                           struct rxrpc_conn_parameters *cp,
-                                           struct sockaddr_rxrpc *srx,
-                                           gfp_t gfp)
-{
-       struct rxrpc_bundle *bundle;
-
-       _enter("{%d,%lx},", call->debug_id, call->user_call_ID);
-
-       cp->peer = rxrpc_lookup_peer(rx, cp->local, srx, gfp);
-       if (!cp->peer)
-               goto error;
-
-       call->tx_last_sent = ktime_get_real();
-       call->cong_ssthresh = cp->peer->cong_ssthresh;
-       if (call->cong_cwnd >= call->cong_ssthresh)
-               call->cong_mode = RXRPC_CALL_CONGEST_AVOIDANCE;
-       else
-               call->cong_mode = RXRPC_CALL_SLOW_START;
-       if (cp->upgrade)
-               __set_bit(RXRPC_CALL_UPGRADE, &call->flags);
-
-       /* Find the client connection bundle. */
-       bundle = rxrpc_look_up_bundle(cp, gfp);
-       if (!bundle)
-               goto error;
-
-       /* Get this call queued.  Someone else may activate it whilst we're
-        * lining up a new connection, but that's fine.
-        */
-       spin_lock(&bundle->channel_lock);
-       list_add_tail(&call->chan_wait_link, &bundle->waiting_calls);
-       spin_unlock(&bundle->channel_lock);
-
-       _leave(" = [B=%x]", bundle->debug_id);
-       return bundle;
-
-error:
-       _leave(" = -ENOMEM");
-       return ERR_PTR(-ENOMEM);
+       _leave(" = B=%u [found]", call->bundle->debug_id);
+       return 0;
 }
 
 /*
  * Allocate a new connection and add it into a bundle.
  */
-static void rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle, gfp_t gfp)
-       __releases(bundle->channel_lock)
+static bool rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle,
+                                    unsigned int slot)
 {
-       struct rxrpc_connection *candidate = NULL, *old = NULL;
-       bool conflict;
-       int i;
-
-       _enter("");
-
-       conflict = bundle->alloc_conn;
-       if (!conflict)
-               bundle->alloc_conn = true;
-       spin_unlock(&bundle->channel_lock);
-       if (conflict) {
-               _leave(" [conf]");
-               return;
-       }
-
-       candidate = rxrpc_alloc_client_connection(bundle, gfp);
-
-       spin_lock(&bundle->channel_lock);
-       bundle->alloc_conn = false;
-
-       if (IS_ERR(candidate)) {
-               bundle->alloc_error = PTR_ERR(candidate);
-               spin_unlock(&bundle->channel_lock);
-               _leave(" [err %ld]", PTR_ERR(candidate));
-               return;
-       }
-
-       bundle->alloc_error = 0;
-
-       for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) {
-               unsigned int shift = i * RXRPC_MAXCALLS;
-               int j;
-
-               old = bundle->conns[i];
-               if (!rxrpc_may_reuse_conn(old)) {
-                       if (old)
-                               trace_rxrpc_client(old, -1, rxrpc_client_replace);
-                       candidate->bundle_shift = shift;
-                       atomic_inc(&bundle->active);
-                       bundle->conns[i] = candidate;
-                       for (j = 0; j < RXRPC_MAXCALLS; j++)
-                               set_bit(shift + j, &bundle->avail_chans);
-                       candidate = NULL;
-                       break;
-               }
+       struct rxrpc_connection *conn, *old;
+       unsigned int shift = slot * RXRPC_MAXCALLS;
+       unsigned int i;
 
-               old = NULL;
+       old = bundle->conns[slot];
+       if (old) {
+               bundle->conns[slot] = NULL;
+               trace_rxrpc_client(old, -1, rxrpc_client_replace);
+               rxrpc_put_connection(old, rxrpc_conn_put_noreuse);
        }
 
-       spin_unlock(&bundle->channel_lock);
-
-       if (candidate) {
-               _debug("discard C=%x", candidate->debug_id);
-               trace_rxrpc_client(candidate, -1, rxrpc_client_duplicate);
-               rxrpc_put_connection(candidate, rxrpc_conn_put_discard);
+       conn = rxrpc_alloc_client_connection(bundle);
+       if (IS_ERR(conn)) {
+               bundle->alloc_error = PTR_ERR(conn);
+               return false;
        }
 
-       rxrpc_put_connection(old, rxrpc_conn_put_noreuse);
-       _leave("");
+       rxrpc_activate_bundle(bundle);
+       conn->bundle_shift = shift;
+       bundle->conns[slot] = conn;
+       for (i = 0; i < RXRPC_MAXCALLS; i++)
+               set_bit(shift + i, &bundle->avail_chans);
+       return true;
 }
 
 /*
  * Add a connection to a bundle if there are no usable connections or we have
  * connections waiting for extra capacity.
  */
-static void rxrpc_maybe_add_conn(struct rxrpc_bundle *bundle, gfp_t gfp)
+static bool rxrpc_bundle_has_space(struct rxrpc_bundle *bundle)
 {
-       struct rxrpc_call *call;
-       int i, usable;
+       int slot = -1, i, usable;
 
        _enter("");
 
-       spin_lock(&bundle->channel_lock);
+       bundle->alloc_error = 0;
 
        /* See if there are any usable connections. */
        usable = 0;
-       for (i = 0; i < ARRAY_SIZE(bundle->conns); i++)
+       for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) {
                if (rxrpc_may_reuse_conn(bundle->conns[i]))
                        usable++;
-
-       if (!usable && !list_empty(&bundle->waiting_calls)) {
-               call = list_first_entry(&bundle->waiting_calls,
-                                       struct rxrpc_call, chan_wait_link);
-               if (test_bit(RXRPC_CALL_UPGRADE, &call->flags))
-                       bundle->try_upgrade = true;
+               else if (slot == -1)
+                       slot = i;
        }
 
+       if (!usable && bundle->upgrade)
+               bundle->try_upgrade = true;
+
        if (!usable)
                goto alloc_conn;
 
        if (!bundle->avail_chans &&
            !bundle->try_upgrade &&
-           !list_empty(&bundle->waiting_calls) &&
            usable < ARRAY_SIZE(bundle->conns))
                goto alloc_conn;
 
-       spin_unlock(&bundle->channel_lock);
        _leave("");
-       return;
+       return usable;
 
 alloc_conn:
-       return rxrpc_add_conn_to_bundle(bundle, gfp);
+       return slot >= 0 ? rxrpc_add_conn_to_bundle(bundle, slot) : false;
 }
 
 /*
@@ -532,11 +405,13 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,
        struct rxrpc_channel *chan = &conn->channels[channel];
        struct rxrpc_bundle *bundle = conn->bundle;
        struct rxrpc_call *call = list_entry(bundle->waiting_calls.next,
-                                            struct rxrpc_call, chan_wait_link);
+                                            struct rxrpc_call, wait_link);
        u32 call_id = chan->call_counter + 1;
 
        _enter("C=%x,%u", conn->debug_id, channel);
 
+       list_del_init(&call->wait_link);
+
        trace_rxrpc_client(conn, channel, rxrpc_client_chan_activate);
 
        /* Cancel the final ACK on the previous call if it hasn't been sent yet
@@ -546,68 +421,50 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,
        clear_bit(conn->bundle_shift + channel, &bundle->avail_chans);
 
        rxrpc_see_call(call, rxrpc_call_see_activate_client);
-       list_del_init(&call->chan_wait_link);
-       call->peer      = rxrpc_get_peer(conn->peer, rxrpc_peer_get_activate_call);
        call->conn      = rxrpc_get_connection(conn, rxrpc_conn_get_activate_call);
        call->cid       = conn->proto.cid | channel;
        call->call_id   = call_id;
        call->dest_srx.srx_service = conn->service_id;
-
-       trace_rxrpc_connect_call(call);
-
-       write_lock(&call->state_lock);
-       call->state = RXRPC_CALL_CLIENT_SEND_REQUEST;
-       write_unlock(&call->state_lock);
-
-       /* Paired with the read barrier in rxrpc_connect_call().  This orders
-        * cid and epoch in the connection wrt to call_id without the need to
-        * take the channel_lock.
-        *
-        * We provisionally assign a callNumber at this point, but we don't
-        * confirm it until the call is about to be exposed.
-        *
-        * TODO: Pair with a barrier in the data_ready handler when that looks
-        * at the call ID through a connection channel.
-        */
-       smp_wmb();
+       call->cong_ssthresh = call->peer->cong_ssthresh;
+       if (call->cong_cwnd >= call->cong_ssthresh)
+               call->cong_mode = RXRPC_CALL_CONGEST_AVOIDANCE;
+       else
+               call->cong_mode = RXRPC_CALL_SLOW_START;
 
        chan->call_id           = call_id;
        chan->call_debug_id     = call->debug_id;
-       rcu_assign_pointer(chan->call, call);
+       chan->call              = call;
+
+       rxrpc_see_call(call, rxrpc_call_see_connected);
+       trace_rxrpc_connect_call(call);
+       call->tx_last_sent = ktime_get_real();
+       rxrpc_start_call_timer(call);
+       rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_SEND_REQUEST);
        wake_up(&call->waitq);
 }
 
 /*
  * Remove a connection from the idle list if it's on it.
  */
-static void rxrpc_unidle_conn(struct rxrpc_bundle *bundle, struct rxrpc_connection *conn)
+static void rxrpc_unidle_conn(struct rxrpc_connection *conn)
 {
-       struct rxrpc_net *rxnet = bundle->local->rxnet;
-       bool drop_ref;
-
        if (!list_empty(&conn->cache_link)) {
-               drop_ref = false;
-               spin_lock(&rxnet->client_conn_cache_lock);
-               if (!list_empty(&conn->cache_link)) {
-                       list_del_init(&conn->cache_link);
-                       drop_ref = true;
-               }
-               spin_unlock(&rxnet->client_conn_cache_lock);
-               if (drop_ref)
-                       rxrpc_put_connection(conn, rxrpc_conn_put_unidle);
+               list_del_init(&conn->cache_link);
+               rxrpc_put_connection(conn, rxrpc_conn_put_unidle);
        }
 }
 
 /*
- * Assign channels and callNumbers to waiting calls with channel_lock
- * held by caller.
+ * Assign channels and callNumbers to waiting calls.
  */
-static void rxrpc_activate_channels_locked(struct rxrpc_bundle *bundle)
+static void rxrpc_activate_channels(struct rxrpc_bundle *bundle)
 {
        struct rxrpc_connection *conn;
        unsigned long avail, mask;
        unsigned int channel, slot;
 
+       trace_rxrpc_client(NULL, -1, rxrpc_client_activate_chans);
+
        if (bundle->try_upgrade)
                mask = 1;
        else
@@ -627,7 +484,7 @@ static void rxrpc_activate_channels_locked(struct rxrpc_bundle *bundle)
 
                if (bundle->try_upgrade)
                        set_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags);
-               rxrpc_unidle_conn(bundle, conn);
+               rxrpc_unidle_conn(conn);
 
                channel &= (RXRPC_MAXCALLS - 1);
                conn->act_chans |= 1 << channel;
@@ -636,132 +493,24 @@ static void rxrpc_activate_channels_locked(struct rxrpc_bundle *bundle)
 }
 
 /*
- * Assign channels and callNumbers to waiting calls.
- */
-static void rxrpc_activate_channels(struct rxrpc_bundle *bundle)
-{
-       _enter("B=%x", bundle->debug_id);
-
-       trace_rxrpc_client(NULL, -1, rxrpc_client_activate_chans);
-
-       if (!bundle->avail_chans)
-               return;
-
-       spin_lock(&bundle->channel_lock);
-       rxrpc_activate_channels_locked(bundle);
-       spin_unlock(&bundle->channel_lock);
-       _leave("");
-}
-
-/*
- * Wait for a callNumber and a channel to be granted to a call.
- */
-static int rxrpc_wait_for_channel(struct rxrpc_bundle *bundle,
-                                 struct rxrpc_call *call, gfp_t gfp)
-{
-       DECLARE_WAITQUEUE(myself, current);
-       int ret = 0;
-
-       _enter("%d", call->debug_id);
-
-       if (!gfpflags_allow_blocking(gfp)) {
-               rxrpc_maybe_add_conn(bundle, gfp);
-               rxrpc_activate_channels(bundle);
-               ret = bundle->alloc_error ?: -EAGAIN;
-               goto out;
-       }
-
-       add_wait_queue_exclusive(&call->waitq, &myself);
-       for (;;) {
-               rxrpc_maybe_add_conn(bundle, gfp);
-               rxrpc_activate_channels(bundle);
-               ret = bundle->alloc_error;
-               if (ret < 0)
-                       break;
-
-               switch (call->interruptibility) {
-               case RXRPC_INTERRUPTIBLE:
-               case RXRPC_PREINTERRUPTIBLE:
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       break;
-               case RXRPC_UNINTERRUPTIBLE:
-               default:
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       break;
-               }
-               if (READ_ONCE(call->state) != RXRPC_CALL_CLIENT_AWAIT_CONN)
-                       break;
-               if ((call->interruptibility == RXRPC_INTERRUPTIBLE ||
-                    call->interruptibility == RXRPC_PREINTERRUPTIBLE) &&
-                   signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       remove_wait_queue(&call->waitq, &myself);
-       __set_current_state(TASK_RUNNING);
-
-out:
-       _leave(" = %d", ret);
-       return ret;
-}
-
-/*
- * find a connection for a call
- * - called in process context with IRQs enabled
+ * Connect waiting channels (called from the I/O thread).
  */
-int rxrpc_connect_call(struct rxrpc_sock *rx,
-                      struct rxrpc_call *call,
-                      struct rxrpc_conn_parameters *cp,
-                      struct sockaddr_rxrpc *srx,
-                      gfp_t gfp)
+void rxrpc_connect_client_calls(struct rxrpc_local *local)
 {
-       struct rxrpc_bundle *bundle;
-       struct rxrpc_net *rxnet = cp->local->rxnet;
-       int ret = 0;
-
-       _enter("{%d,%lx},", call->debug_id, call->user_call_ID);
-
-       rxrpc_discard_expired_client_conns(&rxnet->client_conn_reaper);
+       struct rxrpc_call *call;
 
-       bundle = rxrpc_prep_call(rx, call, cp, srx, gfp);
-       if (IS_ERR(bundle)) {
-               ret = PTR_ERR(bundle);
-               goto out;
-       }
+       while ((call = list_first_entry_or_null(&local->new_client_calls,
+                                               struct rxrpc_call, wait_link))
+              ) {
+               struct rxrpc_bundle *bundle = call->bundle;
 
-       if (call->state == RXRPC_CALL_CLIENT_AWAIT_CONN) {
-               ret = rxrpc_wait_for_channel(bundle, call, gfp);
-               if (ret < 0)
-                       goto wait_failed;
-       }
+               spin_lock(&local->client_call_lock);
+               list_move_tail(&call->wait_link, &bundle->waiting_calls);
+               spin_unlock(&local->client_call_lock);
 
-granted_channel:
-       /* Paired with the write barrier in rxrpc_activate_one_channel(). */
-       smp_rmb();
-
-out_put_bundle:
-       rxrpc_deactivate_bundle(bundle);
-       rxrpc_put_bundle(bundle, rxrpc_bundle_get_client_call);
-out:
-       _leave(" = %d", ret);
-       return ret;
-
-wait_failed:
-       spin_lock(&bundle->channel_lock);
-       list_del_init(&call->chan_wait_link);
-       spin_unlock(&bundle->channel_lock);
-
-       if (call->state != RXRPC_CALL_CLIENT_AWAIT_CONN) {
-               ret = 0;
-               goto granted_channel;
+               if (rxrpc_bundle_has_space(bundle))
+                       rxrpc_activate_channels(bundle);
        }
-
-       trace_rxrpc_client(call->conn, ret, rxrpc_client_chan_wait_failed);
-       rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret);
-       rxrpc_disconnect_client_call(bundle, call);
-       goto out_put_bundle;
 }
 
 /*
@@ -794,14 +543,14 @@ void rxrpc_expose_client_call(struct rxrpc_call *call)
 /*
  * Set the reap timer.
  */
-static void rxrpc_set_client_reap_timer(struct rxrpc_net *rxnet)
+static void rxrpc_set_client_reap_timer(struct rxrpc_local *local)
 {
-       if (!rxnet->kill_all_client_conns) {
+       if (!local->kill_all_client_conns) {
                unsigned long now = jiffies;
                unsigned long reap_at = now + rxrpc_conn_idle_client_expiry;
 
-               if (rxnet->live)
-                       timer_reduce(&rxnet->client_conn_reap_timer, reap_at);
+               if (local->rxnet->live)
+                       timer_reduce(&local->client_conn_reap_timer, reap_at);
        }
 }
 
@@ -812,16 +561,13 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
 {
        struct rxrpc_connection *conn;
        struct rxrpc_channel *chan = NULL;
-       struct rxrpc_net *rxnet = bundle->local->rxnet;
+       struct rxrpc_local *local = bundle->local;
        unsigned int channel;
        bool may_reuse;
        u32 cid;
 
        _enter("c=%x", call->debug_id);
 
-       spin_lock(&bundle->channel_lock);
-       set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
-
        /* Calls that have never actually been assigned a channel can simply be
         * discarded.
         */
@@ -830,8 +576,8 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
                _debug("call is waiting");
                ASSERTCMP(call->call_id, ==, 0);
                ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags));
-               list_del_init(&call->chan_wait_link);
-               goto out;
+               list_del_init(&call->wait_link);
+               return;
        }
 
        cid = call->cid;
@@ -839,10 +585,8 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
        chan = &conn->channels[channel];
        trace_rxrpc_client(conn, channel, rxrpc_client_chan_disconnect);
 
-       if (rcu_access_pointer(chan->call) != call) {
-               spin_unlock(&bundle->channel_lock);
-               BUG();
-       }
+       if (WARN_ON(chan->call != call))
+               return;
 
        may_reuse = rxrpc_may_reuse_conn(conn);
 
@@ -863,16 +607,15 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
                        trace_rxrpc_client(conn, channel, rxrpc_client_to_active);
                        bundle->try_upgrade = false;
                        if (may_reuse)
-                               rxrpc_activate_channels_locked(bundle);
+                               rxrpc_activate_channels(bundle);
                }
-
        }
 
        /* See if we can pass the channel directly to another call. */
        if (may_reuse && !list_empty(&bundle->waiting_calls)) {
                trace_rxrpc_client(conn, channel, rxrpc_client_chan_pass);
                rxrpc_activate_one_channel(conn, channel);
-               goto out;
+               return;
        }
 
        /* Schedule the final ACK to be transmitted in a short while so that it
@@ -890,7 +633,7 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
        }
 
        /* Deactivate the channel. */
-       rcu_assign_pointer(chan->call, NULL);
+       chan->call = NULL;
        set_bit(conn->bundle_shift + channel, &conn->bundle->avail_chans);
        conn->act_chans &= ~(1 << channel);
 
@@ -903,17 +646,10 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
                conn->idle_timestamp = jiffies;
 
                rxrpc_get_connection(conn, rxrpc_conn_get_idle);
-               spin_lock(&rxnet->client_conn_cache_lock);
-               list_move_tail(&conn->cache_link, &rxnet->idle_client_conns);
-               spin_unlock(&rxnet->client_conn_cache_lock);
+               list_move_tail(&conn->cache_link, &local->idle_client_conns);
 
-               rxrpc_set_client_reap_timer(rxnet);
+               rxrpc_set_client_reap_timer(local);
        }
-
-out:
-       spin_unlock(&bundle->channel_lock);
-       _leave("");
-       return;
 }
 
 /*
@@ -923,7 +659,6 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
 {
        struct rxrpc_bundle *bundle = conn->bundle;
        unsigned int bindex;
-       bool need_drop = false;
        int i;
 
        _enter("C=%x", conn->debug_id);
@@ -931,18 +666,13 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
        if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
                rxrpc_process_delayed_final_acks(conn, true);
 
-       spin_lock(&bundle->channel_lock);
        bindex = conn->bundle_shift / RXRPC_MAXCALLS;
        if (bundle->conns[bindex] == conn) {
                _debug("clear slot %u", bindex);
                bundle->conns[bindex] = NULL;
                for (i = 0; i < RXRPC_MAXCALLS; i++)
                        clear_bit(conn->bundle_shift + i, &bundle->avail_chans);
-               need_drop = true;
-       }
-       spin_unlock(&bundle->channel_lock);
-
-       if (need_drop) {
+               rxrpc_put_client_connection_id(bundle->local, conn);
                rxrpc_deactivate_bundle(bundle);
                rxrpc_put_connection(conn, rxrpc_conn_put_unbundle);
        }
@@ -951,11 +681,15 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
 /*
  * Drop the active count on a bundle.
  */
-static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle)
+void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle)
 {
-       struct rxrpc_local *local = bundle->local;
+       struct rxrpc_local *local;
        bool need_put = false;
 
+       if (!bundle)
+               return;
+
+       local = bundle->local;
        if (atomic_dec_and_lock(&bundle->active, &local->client_bundles_lock)) {
                if (!bundle->exclusive) {
                        _debug("erase bundle");
@@ -982,7 +716,7 @@ void rxrpc_kill_client_conn(struct rxrpc_connection *conn)
        trace_rxrpc_client(conn, -1, rxrpc_client_cleanup);
        atomic_dec(&rxnet->nr_client_conns);
 
-       rxrpc_put_client_connection_id(conn);
+       rxrpc_put_client_connection_id(local, conn);
 }
 
 /*
@@ -992,42 +726,26 @@ void rxrpc_kill_client_conn(struct rxrpc_connection *conn)
  * This may be called from conn setup or from a work item so cannot be
  * considered non-reentrant.
  */
-void rxrpc_discard_expired_client_conns(struct work_struct *work)
+void rxrpc_discard_expired_client_conns(struct rxrpc_local *local)
 {
        struct rxrpc_connection *conn;
-       struct rxrpc_net *rxnet =
-               container_of(work, struct rxrpc_net, client_conn_reaper);
        unsigned long expiry, conn_expires_at, now;
        unsigned int nr_conns;
 
        _enter("");
 
-       if (list_empty(&rxnet->idle_client_conns)) {
-               _leave(" [empty]");
-               return;
-       }
-
-       /* Don't double up on the discarding */
-       if (!mutex_trylock(&rxnet->client_conn_discard_lock)) {
-               _leave(" [already]");
-               return;
-       }
-
        /* We keep an estimate of what the number of conns ought to be after
         * we've discarded some so that we don't overdo the discarding.
         */
-       nr_conns = atomic_read(&rxnet->nr_client_conns);
+       nr_conns = atomic_read(&local->rxnet->nr_client_conns);
 
 next:
-       spin_lock(&rxnet->client_conn_cache_lock);
-
-       if (list_empty(&rxnet->idle_client_conns))
-               goto out;
-
-       conn = list_entry(rxnet->idle_client_conns.next,
-                         struct rxrpc_connection, cache_link);
+       conn = list_first_entry_or_null(&local->idle_client_conns,
+                                       struct rxrpc_connection, cache_link);
+       if (!conn)
+               return;
 
-       if (!rxnet->kill_all_client_conns) {
+       if (!local->kill_all_client_conns) {
                /* If the number of connections is over the reap limit, we
                 * expedite discard by reducing the expiry timeout.  We must,
                 * however, have at least a short grace period to be able to do
@@ -1050,8 +768,6 @@ next:
        trace_rxrpc_client(conn, -1, rxrpc_client_discard);
        list_del_init(&conn->cache_link);
 
-       spin_unlock(&rxnet->client_conn_cache_lock);
-
        rxrpc_unbundle_conn(conn);
        /* Drop the ->cache_link ref */
        rxrpc_put_connection(conn, rxrpc_conn_put_discard_idle);
@@ -1068,31 +784,8 @@ not_yet_expired:
         * then things get messier.
         */
        _debug("not yet");
-       if (!rxnet->kill_all_client_conns)
-               timer_reduce(&rxnet->client_conn_reap_timer, conn_expires_at);
-
-out:
-       spin_unlock(&rxnet->client_conn_cache_lock);
-       mutex_unlock(&rxnet->client_conn_discard_lock);
-       _leave("");
-}
-
-/*
- * Preemptively destroy all the client connection records rather than waiting
- * for them to time out
- */
-void rxrpc_destroy_all_client_connections(struct rxrpc_net *rxnet)
-{
-       _enter("");
-
-       spin_lock(&rxnet->client_conn_cache_lock);
-       rxnet->kill_all_client_conns = true;
-       spin_unlock(&rxnet->client_conn_cache_lock);
-
-       del_timer_sync(&rxnet->client_conn_reap_timer);
-
-       if (!rxrpc_queue_work(&rxnet->client_conn_reaper))
-               _debug("destroy: queue failed");
+       if (!local->kill_all_client_conns)
+               timer_reduce(&local->client_conn_reap_timer, conn_expires_at);
 
        _leave("");
 }
@@ -1102,29 +795,19 @@ void rxrpc_destroy_all_client_connections(struct rxrpc_net *rxnet)
  */
 void rxrpc_clean_up_local_conns(struct rxrpc_local *local)
 {
-       struct rxrpc_connection *conn, *tmp;
-       struct rxrpc_net *rxnet = local->rxnet;
-       LIST_HEAD(graveyard);
+       struct rxrpc_connection *conn;
 
        _enter("");
 
-       spin_lock(&rxnet->client_conn_cache_lock);
-
-       list_for_each_entry_safe(conn, tmp, &rxnet->idle_client_conns,
-                                cache_link) {
-               if (conn->local == local) {
-                       atomic_dec(&conn->active);
-                       trace_rxrpc_client(conn, -1, rxrpc_client_discard);
-                       list_move(&conn->cache_link, &graveyard);
-               }
-       }
+       local->kill_all_client_conns = true;
 
-       spin_unlock(&rxnet->client_conn_cache_lock);
+       del_timer_sync(&local->client_conn_reap_timer);
 
-       while (!list_empty(&graveyard)) {
-               conn = list_entry(graveyard.next,
-                                 struct rxrpc_connection, cache_link);
+       while ((conn = list_first_entry_or_null(&local->idle_client_conns,
+                                               struct rxrpc_connection, cache_link))) {
                list_del_init(&conn->cache_link);
+               atomic_dec(&conn->active);
+               trace_rxrpc_client(conn, -1, rxrpc_client_discard);
                rxrpc_unbundle_conn(conn);
                rxrpc_put_connection(conn, rxrpc_conn_put_local_dead);
        }
index 480364b..44414e7 100644 (file)
 #include <net/ip.h>
 #include "ar-internal.h"
 
+/*
+ * Set the completion state on an aborted connection.
+ */
+static bool rxrpc_set_conn_aborted(struct rxrpc_connection *conn, struct sk_buff *skb,
+                                  s32 abort_code, int err,
+                                  enum rxrpc_call_completion compl)
+{
+       bool aborted = false;
+
+       if (conn->state != RXRPC_CONN_ABORTED) {
+               spin_lock(&conn->state_lock);
+               if (conn->state != RXRPC_CONN_ABORTED) {
+                       conn->abort_code = abort_code;
+                       conn->error      = err;
+                       conn->completion = compl;
+                       /* Order the abort info before the state change. */
+                       smp_store_release(&conn->state, RXRPC_CONN_ABORTED);
+                       set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
+                       set_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events);
+                       aborted = true;
+               }
+               spin_unlock(&conn->state_lock);
+       }
+
+       return aborted;
+}
+
+/*
+ * Mark a socket buffer to indicate that the connection it's on should be aborted.
+ */
+int rxrpc_abort_conn(struct rxrpc_connection *conn, struct sk_buff *skb,
+                    s32 abort_code, int err, enum rxrpc_abort_reason why)
+{
+       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+       if (rxrpc_set_conn_aborted(conn, skb, abort_code, err,
+                                  RXRPC_CALL_LOCALLY_ABORTED)) {
+               trace_rxrpc_abort(0, why, sp->hdr.cid, sp->hdr.callNumber,
+                                 sp->hdr.seq, abort_code, err);
+               rxrpc_poke_conn(conn, rxrpc_conn_get_poke_abort);
+       }
+       return -EPROTO;
+}
+
+/*
+ * Mark a connection as being remotely aborted.
+ */
+static bool rxrpc_input_conn_abort(struct rxrpc_connection *conn,
+                                  struct sk_buff *skb)
+{
+       return rxrpc_set_conn_aborted(conn, skb, skb->priority, -ECONNABORTED,
+                                     RXRPC_CALL_REMOTELY_ABORTED);
+}
+
 /*
  * Retransmit terminal ACK or ABORT of the previous call.
  */
-static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
-                                      struct sk_buff *skb,
-                                      unsigned int channel)
+void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
+                               struct sk_buff *skb,
+                               unsigned int channel)
 {
        struct rxrpc_skb_priv *sp = skb ? rxrpc_skb(skb) : NULL;
        struct rxrpc_channel *chan;
@@ -46,9 +100,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
        /* If the last call got moved on whilst we were waiting to run, just
         * ignore this packet.
         */
-       call_id = READ_ONCE(chan->last_call);
-       /* Sync with __rxrpc_disconnect_call() */
-       smp_rmb();
+       call_id = chan->last_call;
        if (skb && call_id != sp->hdr.callNumber)
                return;
 
@@ -65,9 +117,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
        iov[2].iov_base = &ack_info;
        iov[2].iov_len  = sizeof(ack_info);
 
+       serial = atomic_inc_return(&conn->serial);
+
        pkt.whdr.epoch          = htonl(conn->proto.epoch);
        pkt.whdr.cid            = htonl(conn->proto.cid | channel);
        pkt.whdr.callNumber     = htonl(call_id);
+       pkt.whdr.serial         = htonl(serial);
        pkt.whdr.seq            = 0;
        pkt.whdr.type           = chan->last_type;
        pkt.whdr.flags          = conn->out_clientflag;
@@ -104,31 +159,15 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
                iov[0].iov_len += sizeof(pkt.ack);
                len += sizeof(pkt.ack) + 3 + sizeof(ack_info);
                ioc = 3;
-               break;
-
-       default:
-               return;
-       }
-
-       /* Resync with __rxrpc_disconnect_call() and check that the last call
-        * didn't get advanced whilst we were filling out the packets.
-        */
-       smp_rmb();
-       if (READ_ONCE(chan->last_call) != call_id)
-               return;
-
-       serial = atomic_inc_return(&conn->serial);
-       pkt.whdr.serial = htonl(serial);
 
-       switch (chan->last_type) {
-       case RXRPC_PACKET_TYPE_ABORT:
-               break;
-       case RXRPC_PACKET_TYPE_ACK:
                trace_rxrpc_tx_ack(chan->call_debug_id, serial,
                                   ntohl(pkt.ack.firstPacket),
                                   ntohl(pkt.ack.serial),
                                   pkt.ack.reason, 0);
                break;
+
+       default:
+               return;
        }
 
        ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len);
@@ -146,131 +185,34 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
 /*
  * pass a connection-level abort onto all calls on that connection
  */
-static void rxrpc_abort_calls(struct rxrpc_connection *conn,
-                             enum rxrpc_call_completion compl,
-                             rxrpc_serial_t serial)
+static void rxrpc_abort_calls(struct rxrpc_connection *conn)
 {
        struct rxrpc_call *call;
        int i;
 
        _enter("{%d},%x", conn->debug_id, conn->abort_code);
 
-       spin_lock(&conn->bundle->channel_lock);
-
        for (i = 0; i < RXRPC_MAXCALLS; i++) {
-               call = rcu_dereference_protected(
-                       conn->channels[i].call,
-                       lockdep_is_held(&conn->bundle->channel_lock));
-               if (call) {
-                       if (compl == RXRPC_CALL_LOCALLY_ABORTED)
-                               trace_rxrpc_abort(call->debug_id,
-                                                 "CON", call->cid,
-                                                 call->call_id, 0,
+               call = conn->channels[i].call;
+               if (call)
+                       rxrpc_set_call_completion(call,
+                                                 conn->completion,
                                                  conn->abort_code,
                                                  conn->error);
-                       else
-                               trace_rxrpc_rx_abort(call, serial,
-                                                    conn->abort_code);
-                       rxrpc_set_call_completion(call, compl,
-                                                 conn->abort_code,
-                                                 conn->error);
-               }
        }
 
-       spin_unlock(&conn->bundle->channel_lock);
        _leave("");
 }
 
-/*
- * generate a connection-level abort
- */
-static int rxrpc_abort_connection(struct rxrpc_connection *conn,
-                                 int error, u32 abort_code)
-{
-       struct rxrpc_wire_header whdr;
-       struct msghdr msg;
-       struct kvec iov[2];
-       __be32 word;
-       size_t len;
-       u32 serial;
-       int ret;
-
-       _enter("%d,,%u,%u", conn->debug_id, error, abort_code);
-
-       /* generate a connection-level abort */
-       spin_lock(&conn->state_lock);
-       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
-               spin_unlock(&conn->state_lock);
-               _leave(" = 0 [already dead]");
-               return 0;
-       }
-
-       conn->error = error;
-       conn->abort_code = abort_code;
-       conn->state = RXRPC_CONN_LOCALLY_ABORTED;
-       set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
-       spin_unlock(&conn->state_lock);
-
-       msg.msg_name    = &conn->peer->srx.transport;
-       msg.msg_namelen = conn->peer->srx.transport_len;
-       msg.msg_control = NULL;
-       msg.msg_controllen = 0;
-       msg.msg_flags   = 0;
-
-       whdr.epoch      = htonl(conn->proto.epoch);
-       whdr.cid        = htonl(conn->proto.cid);
-       whdr.callNumber = 0;
-       whdr.seq        = 0;
-       whdr.type       = RXRPC_PACKET_TYPE_ABORT;
-       whdr.flags      = conn->out_clientflag;
-       whdr.userStatus = 0;
-       whdr.securityIndex = conn->security_ix;
-       whdr._rsvd      = 0;
-       whdr.serviceId  = htons(conn->service_id);
-
-       word            = htonl(conn->abort_code);
-
-       iov[0].iov_base = &whdr;
-       iov[0].iov_len  = sizeof(whdr);
-       iov[1].iov_base = &word;
-       iov[1].iov_len  = sizeof(word);
-
-       len = iov[0].iov_len + iov[1].iov_len;
-
-       serial = atomic_inc_return(&conn->serial);
-       rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, serial);
-       whdr.serial = htonl(serial);
-
-       ret = kernel_sendmsg(conn->local->socket, &msg, iov, 2, len);
-       if (ret < 0) {
-               trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
-                                   rxrpc_tx_point_conn_abort);
-               _debug("sendmsg failed: %d", ret);
-               return -EAGAIN;
-       }
-
-       trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort);
-
-       conn->peer->last_tx_at = ktime_get_seconds();
-
-       _leave(" = 0");
-       return 0;
-}
-
 /*
  * mark a call as being on a now-secured channel
  * - must be called with BH's disabled.
  */
 static void rxrpc_call_is_secure(struct rxrpc_call *call)
 {
-       _enter("%p", call);
-       if (call) {
-               write_lock(&call->state_lock);
-               if (call->state == RXRPC_CALL_SERVER_SECURING) {
-                       call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
-                       rxrpc_notify_socket(call);
-               }
-               write_unlock(&call->state_lock);
+       if (call && __rxrpc_call_state(call) == RXRPC_CALL_SERVER_SECURING) {
+               rxrpc_set_call_state(call, RXRPC_CALL_SERVER_RECV_REQUEST);
+               rxrpc_notify_socket(call);
        }
 }
 
@@ -278,44 +220,22 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
  * connection-level Rx packet processor
  */
 static int rxrpc_process_event(struct rxrpc_connection *conn,
-                              struct sk_buff *skb,
-                              u32 *_abort_code)
+                              struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       int loop, ret;
+       int ret;
 
-       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
-               _leave(" = -ECONNABORTED [%u]", conn->state);
+       if (conn->state == RXRPC_CONN_ABORTED)
                return -ECONNABORTED;
-       }
 
        _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
 
        switch (sp->hdr.type) {
-       case RXRPC_PACKET_TYPE_DATA:
-       case RXRPC_PACKET_TYPE_ACK:
-               rxrpc_conn_retransmit_call(conn, skb,
-                                          sp->hdr.cid & RXRPC_CHANNELMASK);
-               return 0;
-
-       case RXRPC_PACKET_TYPE_BUSY:
-               /* Just ignore BUSY packets for now. */
-               return 0;
-
-       case RXRPC_PACKET_TYPE_ABORT:
-               conn->error = -ECONNABORTED;
-               conn->abort_code = skb->priority;
-               conn->state = RXRPC_CONN_REMOTELY_ABORTED;
-               set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
-               rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, sp->hdr.serial);
-               return -ECONNABORTED;
-
        case RXRPC_PACKET_TYPE_CHALLENGE:
-               return conn->security->respond_to_challenge(conn, skb,
-                                                           _abort_code);
+               return conn->security->respond_to_challenge(conn, skb);
 
        case RXRPC_PACKET_TYPE_RESPONSE:
-               ret = conn->security->verify_response(conn, skb, _abort_code);
+               ret = conn->security->verify_response(conn, skb);
                if (ret < 0)
                        return ret;
 
@@ -324,27 +244,25 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
                if (ret < 0)
                        return ret;
 
-               spin_lock(&conn->bundle->channel_lock);
                spin_lock(&conn->state_lock);
-
-               if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
+               if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
                        conn->state = RXRPC_CONN_SERVICE;
-                       spin_unlock(&conn->state_lock);
-                       for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
-                               rxrpc_call_is_secure(
-                                       rcu_dereference_protected(
-                                               conn->channels[loop].call,
-                                               lockdep_is_held(&conn->bundle->channel_lock)));
-               } else {
-                       spin_unlock(&conn->state_lock);
-               }
+               spin_unlock(&conn->state_lock);
 
-               spin_unlock(&conn->bundle->channel_lock);
+               if (conn->state == RXRPC_CONN_SERVICE) {
+                       /* Offload call state flipping to the I/O thread.  As
+                        * we've already received the packet, put it on the
+                        * front of the queue.
+                        */
+                       skb->mark = RXRPC_SKB_MARK_SERVICE_CONN_SECURED;
+                       rxrpc_get_skb(skb, rxrpc_skb_get_conn_secured);
+                       skb_queue_head(&conn->local->rx_queue, skb);
+                       rxrpc_wake_up_io_thread(conn->local);
+               }
                return 0;
 
        default:
-               trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
-                                     tracepoint_string("bad_conn_pkt"));
+               WARN_ON_ONCE(1);
                return -EPROTO;
        }
 }
@@ -354,26 +272,9 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
  */
 static void rxrpc_secure_connection(struct rxrpc_connection *conn)
 {
-       u32 abort_code;
-       int ret;
-
-       _enter("{%d}", conn->debug_id);
-
-       ASSERT(conn->security_ix != 0);
-
-       if (conn->security->issue_challenge(conn) < 0) {
-               abort_code = RX_CALL_DEAD;
-               ret = -ENOMEM;
-               goto abort;
-       }
-
-       _leave("");
-       return;
-
-abort:
-       _debug("abort %d, %d", ret, abort_code);
-       rxrpc_abort_connection(conn, ret, abort_code);
-       _leave(" [aborted]");
+       if (conn->security->issue_challenge(conn) < 0)
+               rxrpc_abort_conn(conn, NULL, RX_CALL_DEAD, -ENOMEM,
+                                rxrpc_abort_nomem);
 }
 
 /*
@@ -395,9 +296,7 @@ again:
                if (!test_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags))
                        continue;
 
-               smp_rmb(); /* vs rxrpc_disconnect_client_call */
-               ack_at = READ_ONCE(chan->final_ack_at);
-
+               ack_at = chan->final_ack_at;
                if (time_before(j, ack_at) && !force) {
                        if (time_before(ack_at, next_j)) {
                                next_j = ack_at;
@@ -424,47 +323,27 @@ again:
 static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
 {
        struct sk_buff *skb;
-       u32 abort_code = RX_PROTOCOL_ERROR;
        int ret;
 
        if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
                rxrpc_secure_connection(conn);
 
-       /* Process delayed ACKs whose time has come. */
-       if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
-               rxrpc_process_delayed_final_acks(conn, false);
-
        /* go through the conn-level event packets, releasing the ref on this
         * connection that each one has when we've finished with it */
        while ((skb = skb_dequeue(&conn->rx_queue))) {
                rxrpc_see_skb(skb, rxrpc_skb_see_conn_work);
-               ret = rxrpc_process_event(conn, skb, &abort_code);
+               ret = rxrpc_process_event(conn, skb);
                switch (ret) {
-               case -EPROTO:
-               case -EKEYEXPIRED:
-               case -EKEYREJECTED:
-                       goto protocol_error;
                case -ENOMEM:
                case -EAGAIN:
-                       goto requeue_and_leave;
-               case -ECONNABORTED:
+                       skb_queue_head(&conn->rx_queue, skb);
+                       rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work);
+                       break;
                default:
                        rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
                        break;
                }
        }
-
-       return;
-
-requeue_and_leave:
-       skb_queue_head(&conn->rx_queue, skb);
-       return;
-
-protocol_error:
-       if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
-               goto requeue_and_leave;
-       rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
-       return;
 }
 
 void rxrpc_process_connection(struct work_struct *work)
@@ -498,44 +377,59 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
 /*
  * Input a connection-level packet.
  */
-int rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
+bool rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
 
-       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
-               _leave(" = -ECONNABORTED [%u]", conn->state);
-               return -ECONNABORTED;
-       }
-
-       _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
-
        switch (sp->hdr.type) {
-       case RXRPC_PACKET_TYPE_DATA:
-       case RXRPC_PACKET_TYPE_ACK:
-               rxrpc_conn_retransmit_call(conn, skb,
-                                          sp->hdr.cid & RXRPC_CHANNELMASK);
-               return 0;
-
        case RXRPC_PACKET_TYPE_BUSY:
                /* Just ignore BUSY packets for now. */
-               return 0;
+               return true;
 
        case RXRPC_PACKET_TYPE_ABORT:
-               conn->error = -ECONNABORTED;
-               conn->abort_code = skb->priority;
-               conn->state = RXRPC_CONN_REMOTELY_ABORTED;
-               set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
-               rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, sp->hdr.serial);
-               return -ECONNABORTED;
+               if (rxrpc_is_conn_aborted(conn))
+                       return true;
+               rxrpc_input_conn_abort(conn, skb);
+               rxrpc_abort_calls(conn);
+               return true;
 
        case RXRPC_PACKET_TYPE_CHALLENGE:
        case RXRPC_PACKET_TYPE_RESPONSE:
+               if (rxrpc_is_conn_aborted(conn)) {
+                       if (conn->completion == RXRPC_CALL_LOCALLY_ABORTED)
+                               rxrpc_send_conn_abort(conn);
+                       return true;
+               }
                rxrpc_post_packet_to_conn(conn, skb);
-               return 0;
+               return true;
 
        default:
-               trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
-                                     tracepoint_string("bad_conn_pkt"));
-               return -EPROTO;
+               WARN_ON_ONCE(1);
+               return true;
        }
 }
+
+/*
+ * Input a connection event.
+ */
+void rxrpc_input_conn_event(struct rxrpc_connection *conn, struct sk_buff *skb)
+{
+       unsigned int loop;
+
+       if (test_and_clear_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events))
+               rxrpc_abort_calls(conn);
+
+       switch (skb->mark) {
+       case RXRPC_SKB_MARK_SERVICE_CONN_SECURED:
+               if (conn->state != RXRPC_CONN_SERVICE)
+                       break;
+
+               for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
+                       rxrpc_call_is_secure(conn->channels[loop].call);
+               break;
+       }
+
+       /* Process delayed ACKs whose time has come. */
+       if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
+               rxrpc_process_delayed_final_acks(conn, false);
+}
index 3c8f83d..ac85d46 100644 (file)
@@ -23,12 +23,30 @@ static void rxrpc_clean_up_connection(struct work_struct *work);
 static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet,
                                         unsigned long reap_at);
 
+void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
+{
+       struct rxrpc_local *local = conn->local;
+       bool busy;
+
+       if (WARN_ON_ONCE(!local))
+               return;
+
+       spin_lock_bh(&local->lock);
+       busy = !list_empty(&conn->attend_link);
+       if (!busy) {
+               rxrpc_get_connection(conn, why);
+               list_add_tail(&conn->attend_link, &local->conn_attend_q);
+       }
+       spin_unlock_bh(&local->lock);
+       rxrpc_wake_up_io_thread(local);
+}
+
 static void rxrpc_connection_timer(struct timer_list *timer)
 {
        struct rxrpc_connection *conn =
                container_of(timer, struct rxrpc_connection, timer);
 
-       rxrpc_queue_conn(conn, rxrpc_conn_queue_timer);
+       rxrpc_poke_conn(conn, rxrpc_conn_get_poke_timer);
 }
 
 /*
@@ -49,6 +67,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet,
                INIT_WORK(&conn->destructor, rxrpc_clean_up_connection);
                INIT_LIST_HEAD(&conn->proc_link);
                INIT_LIST_HEAD(&conn->link);
+               mutex_init(&conn->security_lock);
                skb_queue_head_init(&conn->rx_queue);
                conn->rxnet = rxnet;
                conn->security = &rxrpc_no_security;
@@ -82,10 +101,10 @@ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *lo
 
        _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
 
-       /* Look up client connections by connection ID alone as their IDs are
-        * unique for this machine.
+       /* Look up client connections by connection ID alone as their
+        * IDs are unique for this machine.
         */
-       conn = idr_find(&rxrpc_client_conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
+       conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
        if (!conn || refcount_read(&conn->ref) == 0) {
                _debug("no conn");
                goto not_found;
@@ -139,7 +158,7 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
 
        _enter("%d,%x", conn->debug_id, call->cid);
 
-       if (rcu_access_pointer(chan->call) == call) {
+       if (chan->call == call) {
                /* Save the result of the call so that we can repeat it if necessary
                 * through the channel, whilst disposing of the actual call record.
                 */
@@ -159,12 +178,9 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
                        break;
                }
 
-               /* Sync with rxrpc_conn_retransmit(). */
-               smp_wmb();
                chan->last_call = chan->call_id;
                chan->call_id = chan->call_counter;
-
-               rcu_assign_pointer(chan->call, NULL);
+               chan->call = NULL;
        }
 
        _leave("");
@@ -178,6 +194,9 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
 {
        struct rxrpc_connection *conn = call->conn;
 
+       set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
+       rxrpc_see_call(call, rxrpc_call_see_disconnected);
+
        call->peer->cong_ssthresh = call->cong_ssthresh;
 
        if (!hlist_unhashed(&call->error_link)) {
@@ -186,18 +205,17 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
                spin_unlock(&call->peer->lock);
        }
 
-       if (rxrpc_is_client_call(call))
-               return rxrpc_disconnect_client_call(conn->bundle, call);
-
-       spin_lock(&conn->bundle->channel_lock);
-       __rxrpc_disconnect_call(conn, call);
-       spin_unlock(&conn->bundle->channel_lock);
+       if (rxrpc_is_client_call(call)) {
+               rxrpc_disconnect_client_call(call->bundle, call);
+       } else {
+               __rxrpc_disconnect_call(conn, call);
+               conn->idle_timestamp = jiffies;
+               if (atomic_dec_and_test(&conn->active))
+                       rxrpc_set_service_reap_timer(conn->rxnet,
+                                                    jiffies + rxrpc_connection_expiry);
+       }
 
-       set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
-       conn->idle_timestamp = jiffies;
-       if (atomic_dec_and_test(&conn->active))
-               rxrpc_set_service_reap_timer(conn->rxnet,
-                                            jiffies + rxrpc_connection_expiry);
+       rxrpc_put_call(call, rxrpc_call_put_io_thread);
 }
 
 /*
@@ -293,10 +311,10 @@ static void rxrpc_clean_up_connection(struct work_struct *work)
                container_of(work, struct rxrpc_connection, destructor);
        struct rxrpc_net *rxnet = conn->rxnet;
 
-       ASSERT(!rcu_access_pointer(conn->channels[0].call) &&
-              !rcu_access_pointer(conn->channels[1].call) &&
-              !rcu_access_pointer(conn->channels[2].call) &&
-              !rcu_access_pointer(conn->channels[3].call));
+       ASSERT(!conn->channels[0].call &&
+              !conn->channels[1].call &&
+              !conn->channels[2].call &&
+              !conn->channels[3].call);
        ASSERT(list_empty(&conn->cache_link));
 
        del_timer_sync(&conn->timer);
@@ -447,7 +465,6 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
        _enter("");
 
        atomic_dec(&rxnet->nr_conns);
-       rxrpc_destroy_all_client_connections(rxnet);
 
        del_timer_sync(&rxnet->service_conn_reap_timer);
        rxrpc_queue_work(&rxnet->service_conn_reaper);
index 2a55a88..f30323d 100644 (file)
@@ -11,7 +11,6 @@
 static struct rxrpc_bundle rxrpc_service_dummy_bundle = {
        .ref            = REFCOUNT_INIT(1),
        .debug_id       = UINT_MAX,
-       .channel_lock   = __SPIN_LOCK_UNLOCKED(&rxrpc_service_dummy_bundle.channel_lock),
 };
 
 /*
index d0e20e9..367927a 100644 (file)
@@ -9,11 +9,10 @@
 
 #include "ar-internal.h"
 
-static void rxrpc_proto_abort(const char *why,
-                             struct rxrpc_call *call, rxrpc_seq_t seq)
+static void rxrpc_proto_abort(struct rxrpc_call *call, rxrpc_seq_t seq,
+                             enum rxrpc_abort_reason why)
 {
-       if (rxrpc_abort_call(why, call, seq, RX_PROTOCOL_ERROR, -EBADMSG))
-               rxrpc_send_abort_packet(call);
+       rxrpc_abort_call(call, seq, RX_PROTOCOL_ERROR, -EBADMSG, why);
 }
 
 /*
@@ -185,7 +184,7 @@ void rxrpc_congestion_degrade(struct rxrpc_call *call)
        if (call->cong_mode != RXRPC_CALL_SLOW_START &&
            call->cong_mode != RXRPC_CALL_CONGEST_AVOIDANCE)
                return;
-       if (call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY)
+       if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_REPLY)
                return;
 
        rtt = ns_to_ktime(call->peer->srtt_us * (1000 / 8));
@@ -250,47 +249,34 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to,
  * This occurs when we get an ACKALL packet, the first DATA packet of a reply,
  * or a final ACK packet.
  */
-static bool rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
-                              const char *abort_why)
+static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
+                              enum rxrpc_abort_reason abort_why)
 {
-       unsigned int state;
-
        ASSERT(test_bit(RXRPC_CALL_TX_LAST, &call->flags));
 
-       write_lock(&call->state_lock);
-
-       state = call->state;
-       switch (state) {
+       switch (__rxrpc_call_state(call)) {
        case RXRPC_CALL_CLIENT_SEND_REQUEST:
        case RXRPC_CALL_CLIENT_AWAIT_REPLY:
-               if (reply_begun)
-                       call->state = state = RXRPC_CALL_CLIENT_RECV_REPLY;
-               else
-                       call->state = state = RXRPC_CALL_CLIENT_AWAIT_REPLY;
+               if (reply_begun) {
+                       rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_RECV_REPLY);
+                       trace_rxrpc_txqueue(call, rxrpc_txqueue_end);
+                       break;
+               }
+
+               rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY);
+               trace_rxrpc_txqueue(call, rxrpc_txqueue_await_reply);
                break;
 
        case RXRPC_CALL_SERVER_AWAIT_ACK:
-               __rxrpc_call_completed(call);
-               state = call->state;
+               rxrpc_call_completed(call);
+               trace_rxrpc_txqueue(call, rxrpc_txqueue_end);
                break;
 
        default:
-               goto bad_state;
+               kdebug("end_tx %s", rxrpc_call_states[__rxrpc_call_state(call)]);
+               rxrpc_proto_abort(call, call->tx_top, abort_why);
+               break;
        }
-
-       write_unlock(&call->state_lock);
-       if (state == RXRPC_CALL_CLIENT_AWAIT_REPLY)
-               trace_rxrpc_txqueue(call, rxrpc_txqueue_await_reply);
-       else
-               trace_rxrpc_txqueue(call, rxrpc_txqueue_end);
-       _leave(" = ok");
-       return true;
-
-bad_state:
-       write_unlock(&call->state_lock);
-       kdebug("end_tx %s", rxrpc_call_states[call->state]);
-       rxrpc_proto_abort(abort_why, call, call->tx_top);
-       return false;
 }
 
 /*
@@ -305,18 +291,48 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call)
        if (call->ackr_reason) {
                now = jiffies;
                timo = now + MAX_JIFFY_OFFSET;
-               WRITE_ONCE(call->resend_at, timo);
+
                WRITE_ONCE(call->delay_ack_at, timo);
                trace_rxrpc_timer(call, rxrpc_timer_init_for_reply, now);
        }
 
        if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) {
                if (!rxrpc_rotate_tx_window(call, top, &summary)) {
-                       rxrpc_proto_abort("TXL", call, top);
+                       rxrpc_proto_abort(call, top, rxrpc_eproto_early_reply);
                        return false;
                }
        }
-       return rxrpc_end_tx_phase(call, true, "ETD");
+
+       rxrpc_end_tx_phase(call, true, rxrpc_eproto_unexpected_reply);
+       return true;
+}
+
+/*
+ * End the packet reception phase.
+ */
+static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
+{
+       rxrpc_seq_t whigh = READ_ONCE(call->rx_highest_seq);
+
+       _enter("%d,%s", call->debug_id, rxrpc_call_states[__rxrpc_call_state(call)]);
+
+       trace_rxrpc_receive(call, rxrpc_receive_end, 0, whigh);
+
+       switch (__rxrpc_call_state(call)) {
+       case RXRPC_CALL_CLIENT_RECV_REPLY:
+               rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_terminal_ack);
+               rxrpc_call_completed(call);
+               break;
+
+       case RXRPC_CALL_SERVER_RECV_REQUEST:
+               rxrpc_set_call_state(call, RXRPC_CALL_SERVER_ACK_REQUEST);
+               call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
+               rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_processing_op);
+               break;
+
+       default:
+               break;
+       }
 }
 
 static void rxrpc_input_update_ack_window(struct rxrpc_call *call,
@@ -337,8 +353,9 @@ static void rxrpc_input_queue_data(struct rxrpc_call *call, struct sk_buff *skb,
 
        __skb_queue_tail(&call->recvmsg_queue, skb);
        rxrpc_input_update_ack_window(call, window, wtop);
-
        trace_rxrpc_receive(call, last ? why + 1 : why, sp->hdr.serial, sp->hdr.seq);
+       if (last)
+               rxrpc_end_rx_phase(call, sp->hdr.serial);
 }
 
 /*
@@ -366,17 +383,14 @@ static void rxrpc_input_data_one(struct rxrpc_call *call, struct sk_buff *skb,
 
        if (last) {
                if (test_and_set_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
-                   seq + 1 != wtop) {
-                       rxrpc_proto_abort("LSN", call, seq);
-                       return;
-               }
+                   seq + 1 != wtop)
+                       return rxrpc_proto_abort(call, seq, rxrpc_eproto_different_last);
        } else {
                if (test_bit(RXRPC_CALL_RX_LAST, &call->flags) &&
                    after_eq(seq, wtop)) {
                        pr_warn("Packet beyond last: c=%x q=%x window=%x-%x wlimit=%x\n",
                                call->debug_id, seq, window, wtop, wlimit);
-                       rxrpc_proto_abort("LSA", call, seq);
-                       return;
+                       return rxrpc_proto_abort(call, seq, rxrpc_eproto_data_after_last);
                }
        }
 
@@ -550,7 +564,6 @@ protocol_error:
 static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       enum rxrpc_call_state state;
        rxrpc_serial_t serial = sp->hdr.serial;
        rxrpc_seq_t seq0 = sp->hdr.seq;
 
@@ -558,11 +571,20 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
               atomic64_read(&call->ackr_window), call->rx_highest_seq,
               skb->len, seq0);
 
-       state = READ_ONCE(call->state);
-       if (state >= RXRPC_CALL_COMPLETE)
+       if (__rxrpc_call_is_complete(call))
                return;
 
-       if (state == RXRPC_CALL_SERVER_RECV_REQUEST) {
+       switch (__rxrpc_call_state(call)) {
+       case RXRPC_CALL_CLIENT_SEND_REQUEST:
+       case RXRPC_CALL_CLIENT_AWAIT_REPLY:
+               /* Received data implicitly ACKs all of the request
+                * packets we sent when we're acting as a client.
+                */
+               if (!rxrpc_receiving_reply(call))
+                       goto out_notify;
+               break;
+
+       case RXRPC_CALL_SERVER_RECV_REQUEST: {
                unsigned long timo = READ_ONCE(call->next_req_timo);
                unsigned long now, expect_req_by;
 
@@ -573,18 +595,15 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
                        rxrpc_reduce_call_timer(call, expect_req_by, now,
                                                rxrpc_timer_set_for_idle);
                }
+               break;
        }
 
-       /* Received data implicitly ACKs all of the request packets we sent
-        * when we're acting as a client.
-        */
-       if ((state == RXRPC_CALL_CLIENT_SEND_REQUEST ||
-            state == RXRPC_CALL_CLIENT_AWAIT_REPLY) &&
-           !rxrpc_receiving_reply(call))
-               goto out_notify;
+       default:
+               break;
+       }
 
        if (!rxrpc_input_split_jumbo(call, skb)) {
-               rxrpc_proto_abort("VLD", call, sp->hdr.seq);
+               rxrpc_proto_abort(call, sp->hdr.seq, rxrpc_badmsg_bad_jumbo);
                goto out_notify;
        }
        skb = NULL;
@@ -765,7 +784,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
 
        offset = sizeof(struct rxrpc_wire_header);
        if (skb_copy_bits(skb, offset, &ack, sizeof(ack)) < 0)
-               return rxrpc_proto_abort("XAK", call, 0);
+               return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack);
        offset += sizeof(ack);
 
        ack_serial = sp->hdr.serial;
@@ -845,7 +864,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
        ioffset = offset + nr_acks + 3;
        if (skb->len >= ioffset + sizeof(info) &&
            skb_copy_bits(skb, ioffset, &info, sizeof(info)) < 0)
-               return rxrpc_proto_abort("XAI", call, 0);
+               return rxrpc_proto_abort(call, 0, rxrpc_badmsg_short_ack_info);
 
        if (nr_acks > 0)
                skb_condense(skb);
@@ -868,10 +887,10 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
                rxrpc_input_ackinfo(call, skb, &info);
 
        if (first_soft_ack == 0)
-               return rxrpc_proto_abort("AK0", call, 0);
+               return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero);
 
        /* Ignore ACKs unless we are or have just been transmitting. */
-       switch (READ_ONCE(call->state)) {
+       switch (__rxrpc_call_state(call)) {
        case RXRPC_CALL_CLIENT_SEND_REQUEST:
        case RXRPC_CALL_CLIENT_AWAIT_REPLY:
        case RXRPC_CALL_SERVER_SEND_REPLY:
@@ -883,20 +902,20 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
 
        if (before(hard_ack, call->acks_hard_ack) ||
            after(hard_ack, call->tx_top))
-               return rxrpc_proto_abort("AKW", call, 0);
+               return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_outside_window);
        if (nr_acks > call->tx_top - hard_ack)
-               return rxrpc_proto_abort("AKN", call, 0);
+               return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_sack_overflow);
 
        if (after(hard_ack, call->acks_hard_ack)) {
                if (rxrpc_rotate_tx_window(call, hard_ack, &summary)) {
-                       rxrpc_end_tx_phase(call, false, "ETA");
+                       rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ack);
                        return;
                }
        }
 
        if (nr_acks > 0) {
                if (offset > (int)skb->len - nr_acks)
-                       return rxrpc_proto_abort("XSA", call, 0);
+                       return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_short_sack);
                rxrpc_input_soft_acks(call, skb->data + offset, first_soft_ack,
                                      nr_acks, &summary);
        }
@@ -918,7 +937,7 @@ static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb)
        struct rxrpc_ack_summary summary = { 0 };
 
        if (rxrpc_rotate_tx_window(call, call->tx_top, &summary))
-               rxrpc_end_tx_phase(call, false, "ETL");
+               rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ackall);
 }
 
 /*
@@ -963,27 +982,23 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb)
 
        switch (sp->hdr.type) {
        case RXRPC_PACKET_TYPE_DATA:
-               rxrpc_input_data(call, skb);
-               break;
+               return rxrpc_input_data(call, skb);
 
        case RXRPC_PACKET_TYPE_ACK:
-               rxrpc_input_ack(call, skb);
-               break;
+               return rxrpc_input_ack(call, skb);
 
        case RXRPC_PACKET_TYPE_BUSY:
                /* Just ignore BUSY packets from the server; the retry and
                 * lifespan timers will take care of business.  BUSY packets
                 * from the client don't make sense.
                 */
-               break;
+               return;
 
        case RXRPC_PACKET_TYPE_ABORT:
-               rxrpc_input_abort(call, skb);
-               break;
+               return rxrpc_input_abort(call, skb);
 
        case RXRPC_PACKET_TYPE_ACKALL:
-               rxrpc_input_ackall(call, skb);
-               break;
+               return rxrpc_input_ackall(call, skb);
 
        default:
                break;
@@ -998,24 +1013,18 @@ void rxrpc_input_call_packet(struct rxrpc_call *call, struct sk_buff *skb)
  */
 void rxrpc_implicit_end_call(struct rxrpc_call *call, struct sk_buff *skb)
 {
-       struct rxrpc_connection *conn = call->conn;
-
-       switch (READ_ONCE(call->state)) {
+       switch (__rxrpc_call_state(call)) {
        case RXRPC_CALL_SERVER_AWAIT_ACK:
                rxrpc_call_completed(call);
                fallthrough;
        case RXRPC_CALL_COMPLETE:
                break;
        default:
-               if (rxrpc_abort_call("IMP", call, 0, RX_CALL_DEAD, -ESHUTDOWN))
-                       rxrpc_send_abort_packet(call);
+               rxrpc_abort_call(call, 0, RX_CALL_DEAD, -ESHUTDOWN,
+                                rxrpc_eproto_improper_term);
                trace_rxrpc_improper_term(call);
                break;
        }
 
        rxrpc_input_call_event(call, skb);
-
-       spin_lock(&conn->bundle->channel_lock);
-       __rxrpc_disconnect_call(conn, call);
-       spin_unlock(&conn->bundle->channel_lock);
 }
index 0eb8471..34353b6 100644 (file)
@@ -43,25 +43,17 @@ static void none_free_call_crypto(struct rxrpc_call *call)
 }
 
 static int none_respond_to_challenge(struct rxrpc_connection *conn,
-                                    struct sk_buff *skb,
-                                    u32 *_abort_code)
+                                    struct sk_buff *skb)
 {
-       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-
-       trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
-                             tracepoint_string("chall_none"));
-       return -EPROTO;
+       return rxrpc_abort_conn(conn, skb, RX_PROTOCOL_ERROR, -EPROTO,
+                               rxrpc_eproto_rxnull_challenge);
 }
 
 static int none_verify_response(struct rxrpc_connection *conn,
-                               struct sk_buff *skb,
-                               u32 *_abort_code)
+                               struct sk_buff *skb)
 {
-       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-
-       trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
-                             tracepoint_string("resp_none"));
-       return -EPROTO;
+       return rxrpc_abort_conn(conn, skb, RX_PROTOCOL_ERROR, -EPROTO,
+                               rxrpc_eproto_rxnull_response);
 }
 
 static void none_clear(struct rxrpc_connection *conn)
index 1ad067d..9e9dfb2 100644 (file)
@@ -66,10 +66,32 @@ void rxrpc_error_report(struct sock *sk)
        rcu_read_unlock();
 }
 
+/*
+ * Directly produce an abort from a packet.
+ */
+bool rxrpc_direct_abort(struct sk_buff *skb, enum rxrpc_abort_reason why,
+                       s32 abort_code, int err)
+{
+       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+       trace_rxrpc_abort(0, why, sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
+                         abort_code, err);
+       skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
+       skb->priority = abort_code;
+       return false;
+}
+
+static bool rxrpc_bad_message(struct sk_buff *skb, enum rxrpc_abort_reason why)
+{
+       return rxrpc_direct_abort(skb, why, RX_PROTOCOL_ERROR, -EBADMSG);
+}
+
+#define just_discard true
+
 /*
  * Process event packets targeted at a local endpoint.
  */
-static void rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb)
+static bool rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        char v;
@@ -81,22 +103,21 @@ static void rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb)
                if (v == 0)
                        rxrpc_send_version_request(local, &sp->hdr, skb);
        }
+
+       return true;
 }
 
 /*
  * Extract the wire header from a packet and translate the byte order.
  */
-static noinline
-int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
+static bool rxrpc_extract_header(struct rxrpc_skb_priv *sp,
+                                struct sk_buff *skb)
 {
        struct rxrpc_wire_header whdr;
 
        /* dig out the RxRPC connection details */
-       if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0) {
-               trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
-                                     tracepoint_string("bad_hdr"));
-               return -EBADMSG;
-       }
+       if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0)
+               return rxrpc_bad_message(skb, rxrpc_badmsg_short_hdr);
 
        memset(sp, 0, sizeof(*sp));
        sp->hdr.epoch           = ntohl(whdr.epoch);
@@ -110,7 +131,7 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
        sp->hdr.securityIndex   = whdr.securityIndex;
        sp->hdr._rsvd           = ntohs(whdr._rsvd);
        sp->hdr.serviceId       = ntohs(whdr.serviceId);
-       return 0;
+       return true;
 }
 
 /*
@@ -130,28 +151,28 @@ static bool rxrpc_extract_abort(struct sk_buff *skb)
 /*
  * Process packets received on the local endpoint
  */
-static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
+static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
 {
        struct rxrpc_connection *conn;
        struct sockaddr_rxrpc peer_srx;
        struct rxrpc_skb_priv *sp;
        struct rxrpc_peer *peer = NULL;
        struct sk_buff *skb = *_skb;
-       int ret = 0;
+       bool ret = false;
 
        skb_pull(skb, sizeof(struct udphdr));
 
        sp = rxrpc_skb(skb);
 
        /* dig out the RxRPC connection details */
-       if (rxrpc_extract_header(sp, skb) < 0)
-               goto bad_message;
+       if (!rxrpc_extract_header(sp, skb))
+               return just_discard;
 
        if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) {
                static int lose;
                if ((lose++ & 7) == 7) {
                        trace_rxrpc_rx_lose(sp);
-                       return 0;
+                       return just_discard;
                }
        }
 
@@ -160,28 +181,28 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
        switch (sp->hdr.type) {
        case RXRPC_PACKET_TYPE_VERSION:
                if (rxrpc_to_client(sp))
-                       return 0;
-               rxrpc_input_version(local, skb);
-               return 0;
+                       return just_discard;
+               return rxrpc_input_version(local, skb);
 
        case RXRPC_PACKET_TYPE_BUSY:
                if (rxrpc_to_server(sp))
-                       return 0;
+                       return just_discard;
                fallthrough;
        case RXRPC_PACKET_TYPE_ACK:
        case RXRPC_PACKET_TYPE_ACKALL:
                if (sp->hdr.callNumber == 0)
-                       goto bad_message;
+                       return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
                break;
        case RXRPC_PACKET_TYPE_ABORT:
                if (!rxrpc_extract_abort(skb))
-                       return 0; /* Just discard if malformed */
+                       return just_discard; /* Just discard if malformed */
                break;
 
        case RXRPC_PACKET_TYPE_DATA:
-               if (sp->hdr.callNumber == 0 ||
-                   sp->hdr.seq == 0)
-                       goto bad_message;
+               if (sp->hdr.callNumber == 0)
+                       return rxrpc_bad_message(skb, rxrpc_badmsg_zero_call);
+               if (sp->hdr.seq == 0)
+                       return rxrpc_bad_message(skb, rxrpc_badmsg_zero_seq);
 
                /* Unshare the packet so that it can be modified for in-place
                 * decryption.
@@ -191,7 +212,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
                        if (!skb) {
                                rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem);
                                *_skb = NULL;
-                               return 0;
+                               return just_discard;
                        }
 
                        if (skb != *_skb) {
@@ -205,28 +226,28 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
 
        case RXRPC_PACKET_TYPE_CHALLENGE:
                if (rxrpc_to_server(sp))
-                       return 0;
+                       return just_discard;
                break;
        case RXRPC_PACKET_TYPE_RESPONSE:
                if (rxrpc_to_client(sp))
-                       return 0;
+                       return just_discard;
                break;
 
                /* Packet types 9-11 should just be ignored. */
        case RXRPC_PACKET_TYPE_PARAMS:
        case RXRPC_PACKET_TYPE_10:
        case RXRPC_PACKET_TYPE_11:
-               return 0;
+               return just_discard;
 
        default:
-               goto bad_message;
+               return rxrpc_bad_message(skb, rxrpc_badmsg_unsupported_packet);
        }
 
        if (sp->hdr.serviceId == 0)
-               goto bad_message;
+               return rxrpc_bad_message(skb, rxrpc_badmsg_zero_service);
 
        if (WARN_ON_ONCE(rxrpc_extract_addr_from_skb(&peer_srx, skb) < 0))
-               return true; /* Unsupported address type - discard. */
+               return just_discard; /* Unsupported address type. */
 
        if (peer_srx.transport.family != local->srx.transport.family &&
            (peer_srx.transport.family == AF_INET &&
@@ -234,7 +255,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
                pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n",
                                    peer_srx.transport.family,
                                    local->srx.transport.family);
-               return true; /* Wrong address type - discard. */
+               return just_discard; /* Wrong address type. */
        }
 
        if (rxrpc_to_client(sp)) {
@@ -242,12 +263,8 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
                conn = rxrpc_find_client_connection_rcu(local, &peer_srx, skb);
                conn = rxrpc_get_connection_maybe(conn, rxrpc_conn_get_call_input);
                rcu_read_unlock();
-               if (!conn) {
-                       trace_rxrpc_abort(0, "NCC", sp->hdr.cid,
-                                         sp->hdr.callNumber, sp->hdr.seq,
-                                         RXKADINCONSISTENCY, EBADMSG);
-                       goto protocol_error;
-               }
+               if (!conn)
+                       return rxrpc_protocol_error(skb, rxrpc_eproto_no_client_conn);
 
                ret = rxrpc_input_packet_on_conn(conn, &peer_srx, skb);
                rxrpc_put_connection(conn, rxrpc_conn_put_call_input);
@@ -280,19 +297,7 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb)
 
        ret = rxrpc_new_incoming_call(local, peer, NULL, &peer_srx, skb);
        rxrpc_put_peer(peer, rxrpc_peer_put_input);
-       if (ret < 0)
-               goto reject_packet;
-       return 0;
-
-bad_message:
-       trace_rxrpc_abort(0, "BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                         RX_PROTOCOL_ERROR, EBADMSG);
-protocol_error:
-       skb->priority = RX_PROTOCOL_ERROR;
-       skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
-reject_packet:
-       rxrpc_reject_packet(local, skb);
-       return 0;
+       return ret;
 }
 
 /*
@@ -306,21 +311,23 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
        struct rxrpc_channel *chan;
        struct rxrpc_call *call = NULL;
        unsigned int channel;
+       bool ret;
 
        if (sp->hdr.securityIndex != conn->security_ix)
-               goto wrong_security;
+               return rxrpc_direct_abort(skb, rxrpc_eproto_wrong_security,
+                                         RXKADINCONSISTENCY, -EBADMSG);
 
        if (sp->hdr.serviceId != conn->service_id) {
                int old_id;
 
                if (!test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags))
-                       goto reupgrade;
+                       return rxrpc_protocol_error(skb, rxrpc_eproto_reupgrade);
+
                old_id = cmpxchg(&conn->service_id, conn->orig_service_id,
                                 sp->hdr.serviceId);
-
                if (old_id != conn->orig_service_id &&
                    old_id != sp->hdr.serviceId)
-                       goto reupgrade;
+                       return rxrpc_protocol_error(skb, rxrpc_eproto_bad_upgrade);
        }
 
        if (after(sp->hdr.serial, conn->hi_serial))
@@ -336,19 +343,19 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
 
        /* Ignore really old calls */
        if (sp->hdr.callNumber < chan->last_call)
-               return 0;
+               return just_discard;
 
        if (sp->hdr.callNumber == chan->last_call) {
                if (chan->call ||
                    sp->hdr.type == RXRPC_PACKET_TYPE_ABORT)
-                       return 0;
+                       return just_discard;
 
                /* For the previous service call, if completed successfully, we
                 * discard all further packets.
                 */
                if (rxrpc_conn_is_service(conn) &&
                    chan->last_type == RXRPC_PACKET_TYPE_ACK)
-                       return 0;
+                       return just_discard;
 
                /* But otherwise we need to retransmit the final packet from
                 * data cached in the connection record.
@@ -358,19 +365,17 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
                                            sp->hdr.seq,
                                            sp->hdr.serial,
                                            sp->hdr.flags);
-               rxrpc_input_conn_packet(conn, skb);
-               return 0;
+               rxrpc_conn_retransmit_call(conn, skb, channel);
+               return just_discard;
        }
 
-       rcu_read_lock();
-       call = rxrpc_try_get_call(rcu_dereference(chan->call),
-                                 rxrpc_call_get_input);
-       rcu_read_unlock();
+       call = rxrpc_try_get_call(chan->call, rxrpc_call_get_input);
 
        if (sp->hdr.callNumber > chan->call_id) {
                if (rxrpc_to_client(sp)) {
                        rxrpc_put_call(call, rxrpc_call_put_input);
-                       goto reject_packet;
+                       return rxrpc_protocol_error(skb,
+                                                   rxrpc_eproto_unexpected_implicit_end);
                }
 
                if (call) {
@@ -382,38 +387,14 @@ static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn,
 
        if (!call) {
                if (rxrpc_to_client(sp))
-                       goto bad_message;
-               if (rxrpc_new_incoming_call(conn->local, conn->peer, conn,
-                                           peer_srx, skb) == 0)
-                       return 0;
-               goto reject_packet;
+                       return rxrpc_protocol_error(skb, rxrpc_eproto_no_client_call);
+               return rxrpc_new_incoming_call(conn->local, conn->peer, conn,
+                                              peer_srx, skb);
        }
 
-       rxrpc_input_call_event(call, skb);
+       ret = rxrpc_input_call_event(call, skb);
        rxrpc_put_call(call, rxrpc_call_put_input);
-       return 0;
-
-wrong_security:
-       trace_rxrpc_abort(0, "SEC", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                         RXKADINCONSISTENCY, EBADMSG);
-       skb->priority = RXKADINCONSISTENCY;
-       goto post_abort;
-
-reupgrade:
-       trace_rxrpc_abort(0, "UPG", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                         RX_PROTOCOL_ERROR, EBADMSG);
-       goto protocol_error;
-
-bad_message:
-       trace_rxrpc_abort(0, "BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                         RX_PROTOCOL_ERROR, EBADMSG);
-protocol_error:
-       skb->priority = RX_PROTOCOL_ERROR;
-post_abort:
-       skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
-reject_packet:
-       rxrpc_reject_packet(conn->local, skb);
-       return 0;
+       return ret;
 }
 
 /*
@@ -421,6 +402,7 @@ reject_packet:
  */
 int rxrpc_io_thread(void *data)
 {
+       struct rxrpc_connection *conn;
        struct sk_buff_head rx_queue;
        struct rxrpc_local *local = data;
        struct rxrpc_call *call;
@@ -436,6 +418,24 @@ int rxrpc_io_thread(void *data)
        for (;;) {
                rxrpc_inc_stat(local->rxnet, stat_io_loop);
 
+               /* Deal with connections that want immediate attention. */
+               conn = list_first_entry_or_null(&local->conn_attend_q,
+                                               struct rxrpc_connection,
+                                               attend_link);
+               if (conn) {
+                       spin_lock_bh(&local->lock);
+                       list_del_init(&conn->attend_link);
+                       spin_unlock_bh(&local->lock);
+
+                       rxrpc_input_conn_event(conn, NULL);
+                       rxrpc_put_connection(conn, rxrpc_conn_put_poke);
+                       continue;
+               }
+
+               if (test_and_clear_bit(RXRPC_CLIENT_CONN_REAP_TIMER,
+                                      &local->client_conn_flags))
+                       rxrpc_discard_expired_client_conns(local);
+
                /* Deal with calls that want immediate attention. */
                if ((call = list_first_entry_or_null(&local->call_attend_q,
                                                     struct rxrpc_call,
@@ -450,12 +450,17 @@ int rxrpc_io_thread(void *data)
                        continue;
                }
 
+               if (!list_empty(&local->new_client_calls))
+                       rxrpc_connect_client_calls(local);
+
                /* Process received packets and errors. */
                if ((skb = __skb_dequeue(&rx_queue))) {
+                       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
                        switch (skb->mark) {
                        case RXRPC_SKB_MARK_PACKET:
                                skb->priority = 0;
-                               rxrpc_input_packet(local, &skb);
+                               if (!rxrpc_input_packet(local, &skb))
+                                       rxrpc_reject_packet(local, skb);
                                trace_rxrpc_rx_done(skb->mark, skb->priority);
                                rxrpc_free_skb(skb, rxrpc_skb_put_input);
                                break;
@@ -463,6 +468,11 @@ int rxrpc_io_thread(void *data)
                                rxrpc_input_error(local, skb);
                                rxrpc_free_skb(skb, rxrpc_skb_put_error_report);
                                break;
+                       case RXRPC_SKB_MARK_SERVICE_CONN_SECURED:
+                               rxrpc_input_conn_event(sp->conn, skb);
+                               rxrpc_put_connection(sp->conn, rxrpc_conn_put_poke);
+                               rxrpc_free_skb(skb, rxrpc_skb_put_conn_secured);
+                               break;
                        default:
                                WARN_ON_ONCE(1);
                                rxrpc_free_skb(skb, rxrpc_skb_put_unknown);
@@ -481,7 +491,11 @@ int rxrpc_io_thread(void *data)
                set_current_state(TASK_INTERRUPTIBLE);
                should_stop = kthread_should_stop();
                if (!skb_queue_empty(&local->rx_queue) ||
-                   !list_empty(&local->call_attend_q)) {
+                   !list_empty(&local->call_attend_q) ||
+                   !list_empty(&local->conn_attend_q) ||
+                   !list_empty(&local->new_client_calls) ||
+                   test_bit(RXRPC_CLIENT_CONN_REAP_TIMER,
+                            &local->client_conn_flags)) {
                        __set_current_state(TASK_RUNNING);
                        continue;
                }
index 270b63d..b8eaca5 100644 (file)
@@ -82,31 +82,59 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local,
        }
 }
 
+static void rxrpc_client_conn_reap_timeout(struct timer_list *timer)
+{
+       struct rxrpc_local *local =
+               container_of(timer, struct rxrpc_local, client_conn_reap_timer);
+
+       if (local->kill_all_client_conns &&
+           test_and_set_bit(RXRPC_CLIENT_CONN_REAP_TIMER, &local->client_conn_flags))
+               rxrpc_wake_up_io_thread(local);
+}
+
 /*
  * Allocate a new local endpoint.
  */
-static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
+static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
                                             const struct sockaddr_rxrpc *srx)
 {
        struct rxrpc_local *local;
+       u32 tmp;
 
        local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
        if (local) {
                refcount_set(&local->ref, 1);
                atomic_set(&local->active_users, 1);
-               local->rxnet = rxnet;
+               local->net = net;
+               local->rxnet = rxrpc_net(net);
                INIT_HLIST_NODE(&local->link);
                init_rwsem(&local->defrag_sem);
                init_completion(&local->io_thread_ready);
                skb_queue_head_init(&local->rx_queue);
+               INIT_LIST_HEAD(&local->conn_attend_q);
                INIT_LIST_HEAD(&local->call_attend_q);
+
                local->client_bundles = RB_ROOT;
                spin_lock_init(&local->client_bundles_lock);
+               local->kill_all_client_conns = false;
+               INIT_LIST_HEAD(&local->idle_client_conns);
+               timer_setup(&local->client_conn_reap_timer,
+                           rxrpc_client_conn_reap_timeout, 0);
+
                spin_lock_init(&local->lock);
                rwlock_init(&local->services_lock);
                local->debug_id = atomic_inc_return(&rxrpc_debug_id);
                memcpy(&local->srx, srx, sizeof(*srx));
                local->srx.srx_service = 0;
+               idr_init(&local->conn_ids);
+               get_random_bytes(&tmp, sizeof(tmp));
+               tmp &= 0x3fffffff;
+               if (tmp == 0)
+                       tmp = 1;
+               idr_set_cursor(&local->conn_ids, tmp);
+               INIT_LIST_HEAD(&local->new_client_calls);
+               spin_lock_init(&local->client_call_lock);
+
                trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1);
        }
 
@@ -248,7 +276,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
                goto found;
        }
 
-       local = rxrpc_alloc_local(rxnet, srx);
+       local = rxrpc_alloc_local(net, srx);
        if (!local)
                goto nomem;
 
@@ -407,6 +435,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
         * local endpoint.
         */
        rxrpc_purge_queue(&local->rx_queue);
+       rxrpc_purge_client_connections(local);
 }
 
 /*
index 5905530..a0319c0 100644 (file)
 
 unsigned int rxrpc_net_id;
 
-static void rxrpc_client_conn_reap_timeout(struct timer_list *timer)
-{
-       struct rxrpc_net *rxnet =
-               container_of(timer, struct rxrpc_net, client_conn_reap_timer);
-
-       if (rxnet->live)
-               rxrpc_queue_work(&rxnet->client_conn_reaper);
-}
-
 static void rxrpc_service_conn_reap_timeout(struct timer_list *timer)
 {
        struct rxrpc_net *rxnet =
@@ -63,14 +54,6 @@ static __net_init int rxrpc_init_net(struct net *net)
                    rxrpc_service_conn_reap_timeout, 0);
 
        atomic_set(&rxnet->nr_client_conns, 0);
-       rxnet->kill_all_client_conns = false;
-       spin_lock_init(&rxnet->client_conn_cache_lock);
-       mutex_init(&rxnet->client_conn_discard_lock);
-       INIT_LIST_HEAD(&rxnet->idle_client_conns);
-       INIT_WORK(&rxnet->client_conn_reaper,
-                 rxrpc_discard_expired_client_conns);
-       timer_setup(&rxnet->client_conn_reap_timer,
-                   rxrpc_client_conn_reap_timeout, 0);
 
        INIT_HLIST_HEAD(&rxnet->local_endpoints);
        mutex_init(&rxnet->local_mutex);
index 3d8c9f8..a9746be 100644 (file)
@@ -261,7 +261,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, struct rxrpc_txbuf *txb)
                                      rxrpc_tx_point_call_ack);
        rxrpc_tx_backoff(call, ret);
 
-       if (call->state < RXRPC_CALL_COMPLETE) {
+       if (!__rxrpc_call_is_complete(call)) {
                if (ret < 0)
                        rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
                rxrpc_set_keepalive(call);
@@ -544,6 +544,62 @@ send_fragmentable:
        goto done;
 }
 
+/*
+ * Transmit a connection-level abort.
+ */
+void rxrpc_send_conn_abort(struct rxrpc_connection *conn)
+{
+       struct rxrpc_wire_header whdr;
+       struct msghdr msg;
+       struct kvec iov[2];
+       __be32 word;
+       size_t len;
+       u32 serial;
+       int ret;
+
+       msg.msg_name    = &conn->peer->srx.transport;
+       msg.msg_namelen = conn->peer->srx.transport_len;
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+       msg.msg_flags   = 0;
+
+       whdr.epoch      = htonl(conn->proto.epoch);
+       whdr.cid        = htonl(conn->proto.cid);
+       whdr.callNumber = 0;
+       whdr.seq        = 0;
+       whdr.type       = RXRPC_PACKET_TYPE_ABORT;
+       whdr.flags      = conn->out_clientflag;
+       whdr.userStatus = 0;
+       whdr.securityIndex = conn->security_ix;
+       whdr._rsvd      = 0;
+       whdr.serviceId  = htons(conn->service_id);
+
+       word            = htonl(conn->abort_code);
+
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len  = sizeof(whdr);
+       iov[1].iov_base = &word;
+       iov[1].iov_len  = sizeof(word);
+
+       len = iov[0].iov_len + iov[1].iov_len;
+
+       serial = atomic_inc_return(&conn->serial);
+       whdr.serial = htonl(serial);
+
+       iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len);
+       ret = do_udp_sendmsg(conn->local->socket, &msg, len);
+       if (ret < 0) {
+               trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
+                                   rxrpc_tx_point_conn_abort);
+               _debug("sendmsg failed: %d", ret);
+               return;
+       }
+
+       trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort);
+
+       conn->peer->last_tx_at = ktime_get_seconds();
+}
+
 /*
  * Reject a packet through the local endpoint.
  */
@@ -667,7 +723,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *peer)
 static inline void rxrpc_instant_resend(struct rxrpc_call *call,
                                        struct rxrpc_txbuf *txb)
 {
-       if (call->state < RXRPC_CALL_COMPLETE)
+       if (!__rxrpc_call_is_complete(call))
                kdebug("resend");
 }
 
index 4eecea2..8d7a715 100644 (file)
@@ -147,10 +147,10 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
  * assess the MTU size for the network interface through which this peer is
  * reached
  */
-static void rxrpc_assess_MTU_size(struct rxrpc_sock *rx,
+static void rxrpc_assess_MTU_size(struct rxrpc_local *local,
                                  struct rxrpc_peer *peer)
 {
-       struct net *net = sock_net(&rx->sk);
+       struct net *net = local->net;
        struct dst_entry *dst;
        struct rtable *rt;
        struct flowi fl;
@@ -236,11 +236,11 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp,
 /*
  * Initialise peer record.
  */
-static void rxrpc_init_peer(struct rxrpc_sock *rx, struct rxrpc_peer *peer,
+static void rxrpc_init_peer(struct rxrpc_local *local, struct rxrpc_peer *peer,
                            unsigned long hash_key)
 {
        peer->hash_key = hash_key;
-       rxrpc_assess_MTU_size(rx, peer);
+       rxrpc_assess_MTU_size(local, peer);
        peer->mtu = peer->if_mtu;
        peer->rtt_last_req = ktime_get_real();
 
@@ -272,8 +272,7 @@ static void rxrpc_init_peer(struct rxrpc_sock *rx, struct rxrpc_peer *peer,
 /*
  * Set up a new peer.
  */
-static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx,
-                                           struct rxrpc_local *local,
+static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local,
                                            struct sockaddr_rxrpc *srx,
                                            unsigned long hash_key,
                                            gfp_t gfp)
@@ -285,7 +284,7 @@ static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx,
        peer = rxrpc_alloc_peer(local, gfp, rxrpc_peer_new_client);
        if (peer) {
                memcpy(&peer->srx, srx, sizeof(*srx));
-               rxrpc_init_peer(rx, peer, hash_key);
+               rxrpc_init_peer(local, peer, hash_key);
        }
 
        _leave(" = %p", peer);
@@ -304,14 +303,13 @@ static void rxrpc_free_peer(struct rxrpc_peer *peer)
  * since we've already done a search in the list from the non-reentrant context
  * (the data_ready handler) that is the only place we can add new peers.
  */
-void rxrpc_new_incoming_peer(struct rxrpc_sock *rx, struct rxrpc_local *local,
-                            struct rxrpc_peer *peer)
+void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer)
 {
        struct rxrpc_net *rxnet = local->rxnet;
        unsigned long hash_key;
 
        hash_key = rxrpc_peer_hash_key(local, &peer->srx);
-       rxrpc_init_peer(rx, peer, hash_key);
+       rxrpc_init_peer(local, peer, hash_key);
 
        spin_lock(&rxnet->peer_hash_lock);
        hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key);
@@ -322,8 +320,7 @@ void rxrpc_new_incoming_peer(struct rxrpc_sock *rx, struct rxrpc_local *local,
 /*
  * obtain a remote transport endpoint for the specified address
  */
-struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx,
-                                    struct rxrpc_local *local,
+struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
                                     struct sockaddr_rxrpc *srx, gfp_t gfp)
 {
        struct rxrpc_peer *peer, *candidate;
@@ -343,7 +340,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx,
                /* The peer is not yet present in hash - create a candidate
                 * for a new record and then redo the search.
                 */
-               candidate = rxrpc_create_peer(rx, local, srx, hash_key, gfp);
+               candidate = rxrpc_create_peer(local, srx, hash_key, gfp);
                if (!candidate) {
                        _leave(" = NULL [nomem]");
                        return NULL;
index 3a59591..750158a 100644 (file)
 
 static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
        [RXRPC_CONN_UNUSED]                     = "Unused  ",
+       [RXRPC_CONN_CLIENT_UNSECURED]           = "ClUnsec ",
        [RXRPC_CONN_CLIENT]                     = "Client  ",
        [RXRPC_CONN_SERVICE_PREALLOC]           = "SvPrealc",
        [RXRPC_CONN_SERVICE_UNSECURED]          = "SvUnsec ",
        [RXRPC_CONN_SERVICE_CHALLENGING]        = "SvChall ",
        [RXRPC_CONN_SERVICE]                    = "SvSecure",
-       [RXRPC_CONN_REMOTELY_ABORTED]           = "RmtAbort",
-       [RXRPC_CONN_LOCALLY_ABORTED]            = "LocAbort",
+       [RXRPC_CONN_ABORTED]                    = "Aborted ",
 };
 
 /*
@@ -51,6 +51,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
        struct rxrpc_local *local;
        struct rxrpc_call *call;
        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+       enum rxrpc_call_state state;
        unsigned long timeout = 0;
        rxrpc_seq_t acks_hard_ack;
        char lbuff[50], rbuff[50];
@@ -75,7 +76,8 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
 
        sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
 
-       if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
+       state = rxrpc_call_state(call);
+       if (state != RXRPC_CALL_SERVER_PREALLOC) {
                timeout = READ_ONCE(call->expect_rx_by);
                timeout -= jiffies;
        }
@@ -92,7 +94,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
                   call->call_id,
                   rxrpc_is_service_call(call) ? "Svc" : "Clt",
                   refcount_read(&call->ref),
-                  rxrpc_call_states[call->state],
+                  rxrpc_call_states[state],
                   call->abort_code,
                   call->debug_id,
                   acks_hard_ack, READ_ONCE(call->tx_top) - acks_hard_ack,
@@ -143,6 +145,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
 {
        struct rxrpc_connection *conn;
        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+       const char *state;
        char lbuff[50], rbuff[50];
 
        if (v == &rxnet->conn_proc_list) {
@@ -163,9 +166,11 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
        }
 
        sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
-
        sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
 print:
+       state = rxrpc_is_conn_aborted(conn) ?
+               rxrpc_call_completions[conn->completion] :
+               rxrpc_conn_states[conn->state];
        seq_printf(seq,
                   "UDP   %-47.47s %-47.47s %4x %08x %s %3u %3d"
                   " %s %08x %08x %08x %08x %08x %08x %08x\n",
@@ -176,7 +181,7 @@ print:
                   rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
                   refcount_read(&conn->ref),
                   atomic_read(&conn->active),
-                  rxrpc_conn_states[conn->state],
+                  state,
                   key_serial(conn->key),
                   atomic_read(&conn->serial),
                   conn->hi_serial,
index 6ebd644..dd54cee 100644 (file)
@@ -58,85 +58,6 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
        _leave("");
 }
 
-/*
- * Transition a call to the complete state.
- */
-bool __rxrpc_set_call_completion(struct rxrpc_call *call,
-                                enum rxrpc_call_completion compl,
-                                u32 abort_code,
-                                int error)
-{
-       if (call->state < RXRPC_CALL_COMPLETE) {
-               call->abort_code = abort_code;
-               call->error = error;
-               call->completion = compl;
-               call->state = RXRPC_CALL_COMPLETE;
-               trace_rxrpc_call_complete(call);
-               wake_up(&call->waitq);
-               rxrpc_notify_socket(call);
-               return true;
-       }
-       return false;
-}
-
-bool rxrpc_set_call_completion(struct rxrpc_call *call,
-                              enum rxrpc_call_completion compl,
-                              u32 abort_code,
-                              int error)
-{
-       bool ret = false;
-
-       if (call->state < RXRPC_CALL_COMPLETE) {
-               write_lock(&call->state_lock);
-               ret = __rxrpc_set_call_completion(call, compl, abort_code, error);
-               write_unlock(&call->state_lock);
-       }
-       return ret;
-}
-
-/*
- * Record that a call successfully completed.
- */
-bool __rxrpc_call_completed(struct rxrpc_call *call)
-{
-       return __rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
-}
-
-bool rxrpc_call_completed(struct rxrpc_call *call)
-{
-       bool ret = false;
-
-       if (call->state < RXRPC_CALL_COMPLETE) {
-               write_lock(&call->state_lock);
-               ret = __rxrpc_call_completed(call);
-               write_unlock(&call->state_lock);
-       }
-       return ret;
-}
-
-/*
- * Record that a call is locally aborted.
- */
-bool __rxrpc_abort_call(const char *why, struct rxrpc_call *call,
-                       rxrpc_seq_t seq, u32 abort_code, int error)
-{
-       trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
-                         abort_code, error);
-       return __rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
-                                          abort_code, error);
-}
-
-bool rxrpc_abort_call(const char *why, struct rxrpc_call *call,
-                     rxrpc_seq_t seq, u32 abort_code, int error)
-{
-       bool ret;
-
-       write_lock(&call->state_lock);
-       ret = __rxrpc_abort_call(why, call, seq, abort_code, error);
-       write_unlock(&call->state_lock);
-       return ret;
-}
-
 /*
  * Pass a call terminating message to userspace.
  */
@@ -168,7 +89,7 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
                ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp);
                break;
        default:
-               pr_err("Invalid terminal call state %u\n", call->state);
+               pr_err("Invalid terminal call state %u\n", call->completion);
                BUG();
                break;
        }
@@ -179,41 +100,6 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
        return ret;
 }
 
-/*
- * End the packet reception phase.
- */
-static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
-{
-       rxrpc_seq_t whigh = READ_ONCE(call->rx_highest_seq);
-
-       _enter("%d,%s", call->debug_id, rxrpc_call_states[call->state]);
-
-       trace_rxrpc_receive(call, rxrpc_receive_end, 0, whigh);
-
-       if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY)
-               rxrpc_propose_delay_ACK(call, serial, rxrpc_propose_ack_terminal_ack);
-
-       write_lock(&call->state_lock);
-
-       switch (call->state) {
-       case RXRPC_CALL_CLIENT_RECV_REPLY:
-               __rxrpc_call_completed(call);
-               write_unlock(&call->state_lock);
-               break;
-
-       case RXRPC_CALL_SERVER_RECV_REQUEST:
-               call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
-               call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
-               write_unlock(&call->state_lock);
-               rxrpc_propose_delay_ACK(call, serial,
-                                       rxrpc_propose_ack_processing_op);
-               break;
-       default:
-               write_unlock(&call->state_lock);
-               break;
-       }
-}
-
 /*
  * Discard a packet we've used up and advance the Rx window by one.
  */
@@ -244,10 +130,9 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
 
        trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate,
                            serial, call->rx_consumed);
-       if (last) {
-               rxrpc_end_rx_phase(call, serial);
-               return;
-       }
+
+       if (last)
+               set_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags);
 
        /* Check to see if there's an ACK that needs sending. */
        acked = atomic_add_return(call->rx_consumed - old_consumed,
@@ -272,7 +157,8 @@ static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb)
 /*
  * Deliver messages to a call.  This keeps processing packets until the buffer
  * is filled and we find either more DATA (returns 0) or the end of the DATA
- * (returns 1).  If more packets are required, it returns -EAGAIN.
+ * (returns 1).  If more packets are required, it returns -EAGAIN and if the
+ * call has failed it returns -EIO.
  */
 static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
                              struct msghdr *msg, struct iov_iter *iter,
@@ -288,7 +174,13 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
        rx_pkt_offset = call->rx_pkt_offset;
        rx_pkt_len = call->rx_pkt_len;
 
-       if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) {
+       if (rxrpc_call_has_failed(call)) {
+               seq = lower_32_bits(atomic64_read(&call->ackr_window)) - 1;
+               ret = -EIO;
+               goto done;
+       }
+
+       if (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags)) {
                seq = lower_32_bits(atomic64_read(&call->ackr_window)) - 1;
                ret = 1;
                goto done;
@@ -312,14 +204,15 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
 
                if (rx_pkt_offset == 0) {
                        ret2 = rxrpc_verify_data(call, skb);
-                       rx_pkt_offset = sp->offset;
-                       rx_pkt_len = sp->len;
                        trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq,
-                                            rx_pkt_offset, rx_pkt_len, ret2);
+                                            sp->offset, sp->len, ret2);
                        if (ret2 < 0) {
+                               kdebug("verify = %d", ret2);
                                ret = ret2;
                                goto out;
                        }
+                       rx_pkt_offset = sp->offset;
+                       rx_pkt_len = sp->len;
                } else {
                        trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq,
                                             rx_pkt_offset, rx_pkt_len, 0);
@@ -494,36 +387,36 @@ try_again:
                msg->msg_namelen = len;
        }
 
-       switch (READ_ONCE(call->state)) {
-       case RXRPC_CALL_CLIENT_RECV_REPLY:
-       case RXRPC_CALL_SERVER_RECV_REQUEST:
-       case RXRPC_CALL_SERVER_ACK_REQUEST:
-               ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len,
-                                        flags, &copied);
-               if (ret == -EAGAIN)
-                       ret = 0;
-
-               if (!skb_queue_empty(&call->recvmsg_queue))
-                       rxrpc_notify_socket(call);
-               break;
-       default:
+       ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len,
+                                flags, &copied);
+       if (ret == -EAGAIN)
                ret = 0;
-               break;
-       }
-
+       if (ret == -EIO)
+               goto call_failed;
        if (ret < 0)
                goto error_unlock_call;
 
-       if (call->state == RXRPC_CALL_COMPLETE) {
-               ret = rxrpc_recvmsg_term(call, msg);
-               if (ret < 0)
-                       goto error_unlock_call;
-               if (!(flags & MSG_PEEK))
-                       rxrpc_release_call(rx, call);
-               msg->msg_flags |= MSG_EOR;
-               ret = 1;
-       }
+       if (rxrpc_call_is_complete(call) &&
+           skb_queue_empty(&call->recvmsg_queue))
+               goto call_complete;
+       if (rxrpc_call_has_failed(call))
+               goto call_failed;
 
+       rxrpc_notify_socket(call);
+       goto not_yet_complete;
+
+call_failed:
+       rxrpc_purge_queue(&call->recvmsg_queue);
+call_complete:
+       ret = rxrpc_recvmsg_term(call, msg);
+       if (ret < 0)
+               goto error_unlock_call;
+       if (!(flags & MSG_PEEK))
+               rxrpc_release_call(rx, call);
+       msg->msg_flags |= MSG_EOR;
+       ret = 1;
+
+not_yet_complete:
        if (ret == 0)
                msg->msg_flags |= MSG_MORE;
        else
@@ -586,49 +479,34 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
        size_t offset = 0;
        int ret;
 
-       _enter("{%d,%s},%zu,%d",
-              call->debug_id, rxrpc_call_states[call->state],
-              *_len, want_more);
-
-       ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_SECURING);
+       _enter("{%d},%zu,%d", call->debug_id, *_len, want_more);
 
        mutex_lock(&call->user_mutex);
 
-       switch (READ_ONCE(call->state)) {
-       case RXRPC_CALL_CLIENT_RECV_REPLY:
-       case RXRPC_CALL_SERVER_RECV_REQUEST:
-       case RXRPC_CALL_SERVER_ACK_REQUEST:
-               ret = rxrpc_recvmsg_data(sock, call, NULL, iter,
-                                        *_len, 0, &offset);
-               *_len -= offset;
-               if (ret < 0)
-                       goto out;
-
-               /* We can only reach here with a partially full buffer if we
-                * have reached the end of the data.  We must otherwise have a
-                * full buffer or have been given -EAGAIN.
-                */
-               if (ret == 1) {
-                       if (iov_iter_count(iter) > 0)
-                               goto short_data;
-                       if (!want_more)
-                               goto read_phase_complete;
-                       ret = 0;
-                       goto out;
-               }
-
-               if (!want_more)
-                       goto excess_data;
+       ret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, &offset);
+       *_len -= offset;
+       if (ret == -EIO)
+               goto call_failed;
+       if (ret < 0)
                goto out;
 
-       case RXRPC_CALL_COMPLETE:
-               goto call_complete;
-
-       default:
-               ret = -EINPROGRESS;
+       /* We can only reach here with a partially full buffer if we have
+        * reached the end of the data.  We must otherwise have a full buffer
+        * or have been given -EAGAIN.
+        */
+       if (ret == 1) {
+               if (iov_iter_count(iter) > 0)
+                       goto short_data;
+               if (!want_more)
+                       goto read_phase_complete;
+               ret = 0;
                goto out;
        }
 
+       if (!want_more)
+               goto excess_data;
+       goto out;
+
 read_phase_complete:
        ret = 1;
 out:
@@ -639,14 +517,18 @@ out:
        return ret;
 
 short_data:
-       trace_rxrpc_rx_eproto(call, 0, tracepoint_string("short_data"));
+       trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_short_data,
+                         call->cid, call->call_id, call->rx_consumed,
+                         0, -EBADMSG);
        ret = -EBADMSG;
        goto out;
 excess_data:
-       trace_rxrpc_rx_eproto(call, 0, tracepoint_string("excess_data"));
+       trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_excess_data,
+                         call->cid, call->call_id, call->rx_consumed,
+                         0, -EMSGSIZE);
        ret = -EMSGSIZE;
        goto out;
-call_complete:
+call_failed:
        *_abort = call->abort_code;
        ret = call->error;
        if (call->completion == RXRPC_CALL_SUCCEEDED) {
index d123372..1bf571a 100644 (file)
@@ -411,18 +411,15 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        struct rxrpc_crypt iv;
        struct scatterlist sg[16];
-       bool aborted;
        u32 data_size, buf;
        u16 check;
        int ret;
 
        _enter("");
 
-       if (sp->len < 8) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_hdr", "V1H",
-                                            RXKADSEALEDINCON);
-               goto protocol_error;
-       }
+       if (sp->len < 8)
+               return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+                                         rxkad_abort_1_short_header);
 
        /* Decrypt the skbuff in-place.  TODO: We really want to decrypt
         * directly into the target buffer.
@@ -442,11 +439,9 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
        skcipher_request_zero(req);
 
        /* Extract the decrypted packet length */
-       if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_len", "XV1",
-                                            RXKADDATALEN);
-               goto protocol_error;
-       }
+       if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
+               return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
+                                         rxkad_abort_1_short_encdata);
        sp->offset += sizeof(sechdr);
        sp->len    -= sizeof(sechdr);
 
@@ -456,26 +451,16 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
        check = buf >> 16;
        check ^= seq ^ call->call_id;
        check &= 0xffff;
-       if (check != 0) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_check", "V1C",
-                                            RXKADSEALEDINCON);
-               goto protocol_error;
-       }
-
-       if (data_size > sp->len) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_datalen", "V1L",
-                                            RXKADDATALEN);
-               goto protocol_error;
-       }
+       if (check != 0)
+               return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+                                         rxkad_abort_1_short_check);
+       if (data_size > sp->len)
+               return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
+                                         rxkad_abort_1_short_data);
        sp->len = data_size;
 
        _leave(" = 0 [dlen=%x]", data_size);
        return 0;
-
-protocol_error:
-       if (aborted)
-               rxrpc_send_abort_packet(call);
-       return -EPROTO;
 }
 
 /*
@@ -490,18 +475,15 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        struct rxrpc_crypt iv;
        struct scatterlist _sg[4], *sg;
-       bool aborted;
        u32 data_size, buf;
        u16 check;
        int nsg, ret;
 
        _enter(",{%d}", sp->len);
 
-       if (sp->len < 8) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_hdr", "V2H",
-                                            RXKADSEALEDINCON);
-               goto protocol_error;
-       }
+       if (sp->len < 8)
+               return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+                                         rxkad_abort_2_short_header);
 
        /* Decrypt the skbuff in-place.  TODO: We really want to decrypt
         * directly into the target buffer.
@@ -513,7 +495,7 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
        } else {
                sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
                if (!sg)
-                       goto nomem;
+                       return -ENOMEM;
        }
 
        sg_init_table(sg, nsg);
@@ -537,11 +519,9 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
                kfree(sg);
 
        /* Extract the decrypted packet length */
-       if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_len", "XV2",
-                                            RXKADDATALEN);
-               goto protocol_error;
-       }
+       if (skb_copy_bits(skb, sp->offset, &sechdr, sizeof(sechdr)) < 0)
+               return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
+                                         rxkad_abort_2_short_len);
        sp->offset += sizeof(sechdr);
        sp->len    -= sizeof(sechdr);
 
@@ -551,30 +531,17 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
        check = buf >> 16;
        check ^= seq ^ call->call_id;
        check &= 0xffff;
-       if (check != 0) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_check", "V2C",
-                                            RXKADSEALEDINCON);
-               goto protocol_error;
-       }
+       if (check != 0)
+               return rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+                                         rxkad_abort_2_short_check);
 
-       if (data_size > sp->len) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_datalen", "V2L",
-                                            RXKADDATALEN);
-               goto protocol_error;
-       }
+       if (data_size > sp->len)
+               return rxrpc_abort_eproto(call, skb, RXKADDATALEN,
+                                         rxkad_abort_2_short_data);
 
        sp->len = data_size;
        _leave(" = 0 [dlen=%x]", data_size);
        return 0;
-
-protocol_error:
-       if (aborted)
-               rxrpc_send_abort_packet(call);
-       return -EPROTO;
-
-nomem:
-       _leave(" = -ENOMEM");
-       return -ENOMEM;
 }
 
 /*
@@ -590,7 +557,6 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
                __be32 buf[2];
        } crypto __aligned(8);
        rxrpc_seq_t seq = sp->hdr.seq;
-       bool aborted;
        int ret;
        u16 cksum;
        u32 x, y;
@@ -627,9 +593,9 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
                cksum = 1; /* zero checksums are not permitted */
 
        if (cksum != sp->hdr.cksum) {
-               aborted = rxrpc_abort_eproto(call, skb, "rxkad_csum", "VCK",
-                                            RXKADSEALEDINCON);
-               goto protocol_error;
+               ret = rxrpc_abort_eproto(call, skb, RXKADSEALEDINCON,
+                                        rxkad_abort_bad_checksum);
+               goto out;
        }
 
        switch (call->conn->security_level) {
@@ -647,13 +613,9 @@ static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb)
                break;
        }
 
+out:
        skcipher_request_free(req);
        return ret;
-
-protocol_error:
-       if (aborted)
-               rxrpc_send_abort_packet(call);
-       return -EPROTO;
 }
 
 /*
@@ -821,34 +783,30 @@ static int rxkad_encrypt_response(struct rxrpc_connection *conn,
  * respond to a challenge packet
  */
 static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
-                                     struct sk_buff *skb,
-                                     u32 *_abort_code)
+                                     struct sk_buff *skb)
 {
        const struct rxrpc_key_token *token;
        struct rxkad_challenge challenge;
        struct rxkad_response *resp;
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       const char *eproto;
-       u32 version, nonce, min_level, abort_code;
-       int ret;
+       u32 version, nonce, min_level;
+       int ret = -EPROTO;
 
        _enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
 
-       eproto = tracepoint_string("chall_no_key");
-       abort_code = RX_PROTOCOL_ERROR;
        if (!conn->key)
-               goto protocol_error;
+               return rxrpc_abort_conn(conn, skb, RX_PROTOCOL_ERROR, -EPROTO,
+                                       rxkad_abort_chall_no_key);
 
-       abort_code = RXKADEXPIRED;
        ret = key_validate(conn->key);
        if (ret < 0)
-               goto other_error;
+               return rxrpc_abort_conn(conn, skb, RXKADEXPIRED, ret,
+                                       rxkad_abort_chall_key_expired);
 
-       eproto = tracepoint_string("chall_short");
-       abort_code = RXKADPACKETSHORT;
        if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
                          &challenge, sizeof(challenge)) < 0)
-               goto protocol_error;
+               return rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
+                                       rxkad_abort_chall_short);
 
        version = ntohl(challenge.version);
        nonce = ntohl(challenge.nonce);
@@ -856,15 +814,13 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
 
        trace_rxrpc_rx_challenge(conn, sp->hdr.serial, version, nonce, min_level);
 
-       eproto = tracepoint_string("chall_ver");
-       abort_code = RXKADINCONSISTENCY;
        if (version != RXKAD_VERSION)
-               goto protocol_error;
+               return rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
+                                       rxkad_abort_chall_version);
 
-       abort_code = RXKADLEVELFAIL;
-       ret = -EACCES;
        if (conn->security_level < min_level)
-               goto other_error;
+               return rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EACCES,
+                                       rxkad_abort_chall_level);
 
        token = conn->key->payload.data[0];
 
@@ -893,13 +849,6 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
                ret = rxkad_send_response(conn, &sp->hdr, resp, token->kad);
        kfree(resp);
        return ret;
-
-protocol_error:
-       trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
-       ret = -EPROTO;
-other_error:
-       *_abort_code = abort_code;
-       return ret;
 }
 
 /*
@@ -910,20 +859,15 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
                                struct sk_buff *skb,
                                void *ticket, size_t ticket_len,
                                struct rxrpc_crypt *_session_key,
-                               time64_t *_expiry,
-                               u32 *_abort_code)
+                               time64_t *_expiry)
 {
        struct skcipher_request *req;
-       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        struct rxrpc_crypt iv, key;
        struct scatterlist sg[1];
        struct in_addr addr;
        unsigned int life;
-       const char *eproto;
        time64_t issue, now;
        bool little_endian;
-       int ret;
-       u32 abort_code;
        u8 *p, *q, *name, *end;
 
        _enter("{%d},{%x}", conn->debug_id, key_serial(server_key));
@@ -935,10 +879,9 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
 
        memcpy(&iv, &server_key->payload.data[2], sizeof(iv));
 
-       ret = -ENOMEM;
        req = skcipher_request_alloc(server_key->payload.data[0], GFP_NOFS);
        if (!req)
-               goto temporary_error;
+               return -ENOMEM;
 
        sg_init_one(&sg[0], ticket, ticket_len);
        skcipher_request_set_callback(req, 0, NULL, NULL);
@@ -949,18 +892,21 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
        p = ticket;
        end = p + ticket_len;
 
-#define Z(field)                                       \
-       ({                                              \
-               u8 *__str = p;                          \
-               eproto = tracepoint_string("rxkad_bad_"#field); \
-               q = memchr(p, 0, end - p);              \
-               if (!q || q - p > (field##_SZ))         \
-                       goto bad_ticket;                \
-               for (; p < q; p++)                      \
-                       if (!isprint(*p))               \
-                               goto bad_ticket;        \
-               p++;                                    \
-               __str;                                  \
+#define Z(field, fieldl)                                               \
+       ({                                                              \
+               u8 *__str = p;                                          \
+               q = memchr(p, 0, end - p);                              \
+               if (!q || q - p > field##_SZ)                           \
+                       return rxrpc_abort_conn(                        \
+                               conn, skb, RXKADBADTICKET, -EPROTO,     \
+                               rxkad_abort_resp_tkt_##fieldl);         \
+               for (; p < q; p++)                                      \
+                       if (!isprint(*p))                               \
+                               return rxrpc_abort_conn(                \
+                                       conn, skb, RXKADBADTICKET, -EPROTO, \
+                                       rxkad_abort_resp_tkt_##fieldl); \
+               p++;                                                    \
+               __str;                                                  \
        })
 
        /* extract the ticket flags */
@@ -969,20 +915,20 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
        p++;
 
        /* extract the authentication name */
-       name = Z(ANAME);
+       name = Z(ANAME, aname);
        _debug("KIV ANAME: %s", name);
 
        /* extract the principal's instance */
-       name = Z(INST);
+       name = Z(INST, inst);
        _debug("KIV INST : %s", name);
 
        /* extract the principal's authentication domain */
-       name = Z(REALM);
+       name = Z(REALM, realm);
        _debug("KIV REALM: %s", name);
 
-       eproto = tracepoint_string("rxkad_bad_len");
        if (end - p < 4 + 8 + 4 + 2)
-               goto bad_ticket;
+               return rxrpc_abort_conn(conn, skb, RXKADBADTICKET, -EPROTO,
+                                       rxkad_abort_resp_tkt_short);
 
        /* get the IPv4 address of the entity that requested the ticket */
        memcpy(&addr, p, sizeof(addr));
@@ -1014,38 +960,23 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
        _debug("KIV ISSUE: %llx [%llx]", issue, now);
 
        /* check the ticket is in date */
-       if (issue > now) {
-               abort_code = RXKADNOAUTH;
-               ret = -EKEYREJECTED;
-               goto other_error;
-       }
-
-       if (issue < now - life) {
-               abort_code = RXKADEXPIRED;
-               ret = -EKEYEXPIRED;
-               goto other_error;
-       }
+       if (issue > now)
+               return rxrpc_abort_conn(conn, skb, RXKADNOAUTH, -EKEYREJECTED,
+                                       rxkad_abort_resp_tkt_future);
+       if (issue < now - life)
+               return rxrpc_abort_conn(conn, skb, RXKADEXPIRED, -EKEYEXPIRED,
+                                       rxkad_abort_resp_tkt_expired);
 
        *_expiry = issue + life;
 
        /* get the service name */
-       name = Z(SNAME);
+       name = Z(SNAME, sname);
        _debug("KIV SNAME: %s", name);
 
        /* get the service instance name */
-       name = Z(INST);
+       name = Z(INST, sinst);
        _debug("KIV SINST: %s", name);
        return 0;
-
-bad_ticket:
-       trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
-       abort_code = RXKADBADTICKET;
-       ret = -EPROTO;
-other_error:
-       *_abort_code = abort_code;
-       return ret;
-temporary_error:
-       return ret;
 }
 
 /*
@@ -1086,17 +1017,15 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn,
  * verify a response
  */
 static int rxkad_verify_response(struct rxrpc_connection *conn,
-                                struct sk_buff *skb,
-                                u32 *_abort_code)
+                                struct sk_buff *skb)
 {
        struct rxkad_response *response;
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        struct rxrpc_crypt session_key;
        struct key *server_key;
-       const char *eproto;
        time64_t expiry;
        void *ticket;
-       u32 abort_code, version, kvno, ticket_len, level;
+       u32 version, kvno, ticket_len, level;
        __be32 csum;
        int ret, i;
 
@@ -1104,22 +1033,18 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
 
        server_key = rxrpc_look_up_server_security(conn, skb, 0, 0);
        if (IS_ERR(server_key)) {
-               switch (PTR_ERR(server_key)) {
+               ret = PTR_ERR(server_key);
+               switch (ret) {
                case -ENOKEY:
-                       abort_code = RXKADUNKNOWNKEY;
-                       break;
+                       return rxrpc_abort_conn(conn, skb, RXKADUNKNOWNKEY, ret,
+                                               rxkad_abort_resp_nokey);
                case -EKEYEXPIRED:
-                       abort_code = RXKADEXPIRED;
-                       break;
+                       return rxrpc_abort_conn(conn, skb, RXKADEXPIRED, ret,
+                                               rxkad_abort_resp_key_expired);
                default:
-                       abort_code = RXKADNOAUTH;
-                       break;
+                       return rxrpc_abort_conn(conn, skb, RXKADNOAUTH, ret,
+                                               rxkad_abort_resp_key_rejected);
                }
-               trace_rxrpc_abort(0, "SVK",
-                                 sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                                 abort_code, PTR_ERR(server_key));
-               *_abort_code = abort_code;
-               return -EPROTO;
        }
 
        ret = -ENOMEM;
@@ -1127,11 +1052,12 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        if (!response)
                goto temporary_error;
 
-       eproto = tracepoint_string("rxkad_rsp_short");
-       abort_code = RXKADPACKETSHORT;
        if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
-                         response, sizeof(*response)) < 0)
+                         response, sizeof(*response)) < 0) {
+               rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
+                                rxkad_abort_resp_short);
                goto protocol_error;
+       }
 
        version = ntohl(response->version);
        ticket_len = ntohl(response->ticket_len);
@@ -1139,20 +1065,23 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
 
        trace_rxrpc_rx_response(conn, sp->hdr.serial, version, kvno, ticket_len);
 
-       eproto = tracepoint_string("rxkad_rsp_ver");
-       abort_code = RXKADINCONSISTENCY;
-       if (version != RXKAD_VERSION)
+       if (version != RXKAD_VERSION) {
+               rxrpc_abort_conn(conn, skb, RXKADINCONSISTENCY, -EPROTO,
+                                rxkad_abort_resp_version);
                goto protocol_error;
+       }
 
-       eproto = tracepoint_string("rxkad_rsp_tktlen");
-       abort_code = RXKADTICKETLEN;
-       if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN)
+       if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN) {
+               rxrpc_abort_conn(conn, skb, RXKADTICKETLEN, -EPROTO,
+                                rxkad_abort_resp_tkt_len);
                goto protocol_error;
+       }
 
-       eproto = tracepoint_string("rxkad_rsp_unkkey");
-       abort_code = RXKADUNKNOWNKEY;
-       if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5)
+       if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5) {
+               rxrpc_abort_conn(conn, skb, RXKADUNKNOWNKEY, -EPROTO,
+                                rxkad_abort_resp_unknown_tkt);
                goto protocol_error;
+       }
 
        /* extract the kerberos ticket and decrypt and decode it */
        ret = -ENOMEM;
@@ -1160,15 +1089,15 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        if (!ticket)
                goto temporary_error_free_resp;
 
-       eproto = tracepoint_string("rxkad_tkt_short");
-       abort_code = RXKADPACKETSHORT;
-       ret = skb_copy_bits(skb, sizeof(struct rxrpc_wire_header) + sizeof(*response),
-                           ticket, ticket_len);
-       if (ret < 0)
-               goto temporary_error_free_ticket;
+       if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header) + sizeof(*response),
+                         ticket, ticket_len) < 0) {
+               rxrpc_abort_conn(conn, skb, RXKADPACKETSHORT, -EPROTO,
+                                rxkad_abort_resp_short_tkt);
+               goto protocol_error;
+       }
 
        ret = rxkad_decrypt_ticket(conn, server_key, skb, ticket, ticket_len,
-                                  &session_key, &expiry, _abort_code);
+                                  &session_key, &expiry);
        if (ret < 0)
                goto temporary_error_free_ticket;
 
@@ -1176,56 +1105,61 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
         * response */
        rxkad_decrypt_response(conn, response, &session_key);
 
-       eproto = tracepoint_string("rxkad_rsp_param");
-       abort_code = RXKADSEALEDINCON;
-       if (ntohl(response->encrypted.epoch) != conn->proto.epoch)
-               goto protocol_error_free;
-       if (ntohl(response->encrypted.cid) != conn->proto.cid)
-               goto protocol_error_free;
-       if (ntohl(response->encrypted.securityIndex) != conn->security_ix)
+       if (ntohl(response->encrypted.epoch) != conn->proto.epoch ||
+           ntohl(response->encrypted.cid) != conn->proto.cid ||
+           ntohl(response->encrypted.securityIndex) != conn->security_ix) {
+               rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+                                rxkad_abort_resp_bad_param);
                goto protocol_error_free;
+       }
+
        csum = response->encrypted.checksum;
        response->encrypted.checksum = 0;
        rxkad_calc_response_checksum(response);
-       eproto = tracepoint_string("rxkad_rsp_csum");
-       if (response->encrypted.checksum != csum)
+       if (response->encrypted.checksum != csum) {
+               rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+                                rxkad_abort_resp_bad_checksum);
                goto protocol_error_free;
+       }
 
-       spin_lock(&conn->bundle->channel_lock);
        for (i = 0; i < RXRPC_MAXCALLS; i++) {
-               struct rxrpc_call *call;
                u32 call_id = ntohl(response->encrypted.call_id[i]);
+               u32 counter = READ_ONCE(conn->channels[i].call_counter);
+
+               if (call_id > INT_MAX) {
+                       rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+                                        rxkad_abort_resp_bad_callid);
+                       goto protocol_error_free;
+               }
 
-               eproto = tracepoint_string("rxkad_rsp_callid");
-               if (call_id > INT_MAX)
-                       goto protocol_error_unlock;
-
-               eproto = tracepoint_string("rxkad_rsp_callctr");
-               if (call_id < conn->channels[i].call_counter)
-                       goto protocol_error_unlock;
-
-               eproto = tracepoint_string("rxkad_rsp_callst");
-               if (call_id > conn->channels[i].call_counter) {
-                       call = rcu_dereference_protected(
-                               conn->channels[i].call,
-                               lockdep_is_held(&conn->bundle->channel_lock));
-                       if (call && call->state < RXRPC_CALL_COMPLETE)
-                               goto protocol_error_unlock;
+               if (call_id < counter) {
+                       rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+                                        rxkad_abort_resp_call_ctr);
+                       goto protocol_error_free;
+               }
+
+               if (call_id > counter) {
+                       if (conn->channels[i].call) {
+                               rxrpc_abort_conn(conn, skb, RXKADSEALEDINCON, -EPROTO,
+                                                rxkad_abort_resp_call_state);
+                               goto protocol_error_free;
+                       }
                        conn->channels[i].call_counter = call_id;
                }
        }
-       spin_unlock(&conn->bundle->channel_lock);
 
-       eproto = tracepoint_string("rxkad_rsp_seq");
-       abort_code = RXKADOUTOFSEQUENCE;
-       if (ntohl(response->encrypted.inc_nonce) != conn->rxkad.nonce + 1)
+       if (ntohl(response->encrypted.inc_nonce) != conn->rxkad.nonce + 1) {
+               rxrpc_abort_conn(conn, skb, RXKADOUTOFSEQUENCE, -EPROTO,
+                                rxkad_abort_resp_ooseq);
                goto protocol_error_free;
+       }
 
-       eproto = tracepoint_string("rxkad_rsp_level");
-       abort_code = RXKADLEVELFAIL;
        level = ntohl(response->encrypted.level);
-       if (level > RXRPC_SECURITY_ENCRYPT)
+       if (level > RXRPC_SECURITY_ENCRYPT) {
+               rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EPROTO,
+                                rxkad_abort_resp_level);
                goto protocol_error_free;
+       }
        conn->security_level = level;
 
        /* create a key to hold the security data and expiration time - after
@@ -1240,15 +1174,11 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        _leave(" = 0");
        return 0;
 
-protocol_error_unlock:
-       spin_unlock(&conn->bundle->channel_lock);
 protocol_error_free:
        kfree(ticket);
 protocol_error:
        kfree(response);
-       trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
        key_put(server_key);
-       *_abort_code = abort_code;
        return -EPROTO;
 
 temporary_error_free_ticket:
index d33a109..16dcabb 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
+#define RXRPC_TRACE_ONLY_DEFINE_ENUMS
+#include <trace/events/rxrpc.h>
 
 MODULE_DESCRIPTION("rxperf test server (afs)");
 MODULE_AUTHOR("Red Hat, Inc.");
@@ -307,12 +309,14 @@ static void rxperf_deliver_to_call(struct work_struct *work)
                case -EOPNOTSUPP:
                        abort_code = RXGEN_OPCODE;
                        rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-                                               abort_code, ret, "GOP");
+                                               abort_code, ret,
+                                               rxperf_abort_op_not_supported);
                        goto call_complete;
                case -ENOTSUPP:
                        abort_code = RX_USER_ABORT;
                        rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-                                               abort_code, ret, "GUA");
+                                               abort_code, ret,
+                                               rxperf_abort_op_not_supported);
                        goto call_complete;
                case -EIO:
                        pr_err("Call %u in bad state %u\n",
@@ -324,11 +328,13 @@ static void rxperf_deliver_to_call(struct work_struct *work)
                case -ENOMEM:
                case -EFAULT:
                        rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-                                               RXGEN_SS_UNMARSHAL, ret, "GUM");
+                                               RXGEN_SS_UNMARSHAL, ret,
+                                               rxperf_abort_unmarshal_error);
                        goto call_complete;
                default:
                        rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-                                               RX_CALL_DEAD, ret, "GER");
+                                               RX_CALL_DEAD, ret,
+                                               rxperf_abort_general_error);
                        goto call_complete;
                }
        }
@@ -523,7 +529,8 @@ static int rxperf_process_call(struct rxperf_call *call)
 
        if (n == -ENOMEM)
                rxrpc_kernel_abort_call(rxperf_socket, call->rxcall,
-                                       RXGEN_SS_MARSHAL, -ENOMEM, "GOM");
+                                       RXGEN_SS_MARSHAL, -ENOMEM,
+                                       rxperf_abort_oom);
        return n;
 }
 
index ab968f6..cb8dd1d 100644 (file)
@@ -97,38 +97,31 @@ found:
  */
 int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
 {
-       const struct rxrpc_security *sec;
        struct rxrpc_key_token *token;
        struct key *key = conn->key;
-       int ret;
+       int ret = 0;
 
        _enter("{%d},{%x}", conn->debug_id, key_serial(key));
 
-       if (!key)
-               return 0;
-
-       ret = key_validate(key);
-       if (ret < 0)
-               return ret;
-
        for (token = key->payload.data[0]; token; token = token->next) {
-               sec = rxrpc_security_lookup(token->security_index);
-               if (sec)
+               if (token->security_index == conn->security->security_index)
                        goto found;
        }
        return -EKEYREJECTED;
 
 found:
-       conn->security = sec;
-
-       ret = conn->security->init_connection_security(conn, token);
-       if (ret < 0) {
-               conn->security = &rxrpc_no_security;
-               return ret;
+       mutex_lock(&conn->security_lock);
+       if (conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
+               ret = conn->security->init_connection_security(conn, token);
+               if (ret == 0) {
+                       spin_lock(&conn->state_lock);
+                       if (conn->state == RXRPC_CONN_CLIENT_UNSECURED)
+                               conn->state = RXRPC_CONN_CLIENT;
+                       spin_unlock(&conn->state_lock);
+               }
        }
-
-       _leave(" = 0");
-       return 0;
+       mutex_unlock(&conn->security_lock);
+       return ret;
 }
 
 /*
@@ -144,21 +137,15 @@ const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx,
 
        sec = rxrpc_security_lookup(sp->hdr.securityIndex);
        if (!sec) {
-               trace_rxrpc_abort(0, "SVS",
-                                 sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                                 RX_INVALID_OPERATION, EKEYREJECTED);
-               skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
-               skb->priority = RX_INVALID_OPERATION;
+               rxrpc_direct_abort(skb, rxrpc_abort_unsupported_security,
+                                  RX_INVALID_OPERATION, -EKEYREJECTED);
                return NULL;
        }
 
        if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
            !rx->securities) {
-               trace_rxrpc_abort(0, "SVR",
-                                 sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
-                                 RX_INVALID_OPERATION, EKEYREJECTED);
-               skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
-               skb->priority = sec->no_key_abort;
+               rxrpc_direct_abort(skb, rxrpc_abort_no_service_key,
+                                  sec->no_key_abort, -EKEYREJECTED);
                return NULL;
        }
 
@@ -191,9 +178,9 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
                sprintf(kdesc, "%u:%u",
                        sp->hdr.serviceId, sp->hdr.securityIndex);
 
-       rcu_read_lock();
+       read_lock(&conn->local->services_lock);
 
-       rx = rcu_dereference(conn->local->service);
+       rx = conn->local->service;
        if (!rx)
                goto out;
 
@@ -215,6 +202,6 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
        }
 
 out:
-       rcu_read_unlock();
+       read_unlock(&conn->local->services_lock);
        return key;
 }
index cde1e65..da49fcf 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Propose an abort to be made in the I/O thread.
+ */
+bool rxrpc_propose_abort(struct rxrpc_call *call, s32 abort_code, int error,
+                        enum rxrpc_abort_reason why)
+{
+       _enter("{%d},%d,%d,%u", call->debug_id, abort_code, error, why);
+
+       if (!call->send_abort && !rxrpc_call_is_complete(call)) {
+               call->send_abort_why = why;
+               call->send_abort_err = error;
+               call->send_abort_seq = 0;
+               /* Request abort locklessly vs rxrpc_input_call_event(). */
+               smp_store_release(&call->send_abort, abort_code);
+               rxrpc_poke_call(call, rxrpc_call_poke_abort);
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Wait for a call to become connected.  Interruption here doesn't cause the
+ * call to be aborted.
+ */
+static int rxrpc_wait_to_be_connected(struct rxrpc_call *call, long *timeo)
+{
+       DECLARE_WAITQUEUE(myself, current);
+       int ret = 0;
+
+       _enter("%d", call->debug_id);
+
+       if (rxrpc_call_state(call) != RXRPC_CALL_CLIENT_AWAIT_CONN)
+               return call->error;
+
+       add_wait_queue_exclusive(&call->waitq, &myself);
+
+       for (;;) {
+               ret = call->error;
+               if (ret < 0)
+                       break;
+
+               switch (call->interruptibility) {
+               case RXRPC_INTERRUPTIBLE:
+               case RXRPC_PREINTERRUPTIBLE:
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       break;
+               case RXRPC_UNINTERRUPTIBLE:
+               default:
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       break;
+               }
+               if (rxrpc_call_state(call) != RXRPC_CALL_CLIENT_AWAIT_CONN) {
+                       ret = call->error;
+                       break;
+               }
+               if ((call->interruptibility == RXRPC_INTERRUPTIBLE ||
+                    call->interruptibility == RXRPC_PREINTERRUPTIBLE) &&
+                   signal_pending(current)) {
+                       ret = sock_intr_errno(*timeo);
+                       break;
+               }
+               *timeo = schedule_timeout(*timeo);
+       }
+
+       remove_wait_queue(&call->waitq, &myself);
+       __set_current_state(TASK_RUNNING);
+
+       if (ret == 0 && rxrpc_call_is_complete(call))
+               ret = call->error;
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
 /*
  * Return true if there's sufficient Tx queue space.
  */
@@ -39,7 +114,7 @@ static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
                if (rxrpc_check_tx_space(call, NULL))
                        return 0;
 
-               if (call->state >= RXRPC_CALL_COMPLETE)
+               if (rxrpc_call_is_complete(call))
                        return call->error;
 
                if (signal_pending(current))
@@ -74,7 +149,7 @@ static int rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock *rx,
                if (rxrpc_check_tx_space(call, &tx_win))
                        return 0;
 
-               if (call->state >= RXRPC_CALL_COMPLETE)
+               if (rxrpc_call_is_complete(call))
                        return call->error;
 
                if (timeout == 0 &&
@@ -103,7 +178,7 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
                if (rxrpc_check_tx_space(call, NULL))
                        return 0;
 
-               if (call->state >= RXRPC_CALL_COMPLETE)
+               if (rxrpc_call_is_complete(call))
                        return call->error;
 
                trace_rxrpc_txqueue(call, rxrpc_txqueue_wait);
@@ -168,7 +243,6 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
                               struct rxrpc_txbuf *txb,
                               rxrpc_notify_end_tx_t notify_end_tx)
 {
-       unsigned long now;
        rxrpc_seq_t seq = txb->seq;
        bool last = test_bit(RXRPC_TXBUF_LAST, &txb->flags), poke;
 
@@ -191,36 +265,10 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
        poke = list_empty(&call->tx_sendmsg);
        list_add_tail(&txb->call_link, &call->tx_sendmsg);
        call->tx_prepared = seq;
+       if (last)
+               rxrpc_notify_end_tx(rx, call, notify_end_tx);
        spin_unlock(&call->tx_lock);
 
-       if (last || call->state == RXRPC_CALL_SERVER_ACK_REQUEST) {
-               _debug("________awaiting reply/ACK__________");
-               write_lock(&call->state_lock);
-               switch (call->state) {
-               case RXRPC_CALL_CLIENT_SEND_REQUEST:
-                       call->state = RXRPC_CALL_CLIENT_AWAIT_REPLY;
-                       rxrpc_notify_end_tx(rx, call, notify_end_tx);
-                       break;
-               case RXRPC_CALL_SERVER_ACK_REQUEST:
-                       call->state = RXRPC_CALL_SERVER_SEND_REPLY;
-                       now = jiffies;
-                       WRITE_ONCE(call->delay_ack_at, now + MAX_JIFFY_OFFSET);
-                       if (call->ackr_reason == RXRPC_ACK_DELAY)
-                               call->ackr_reason = 0;
-                       trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now);
-                       if (!last)
-                               break;
-                       fallthrough;
-               case RXRPC_CALL_SERVER_SEND_REPLY:
-                       call->state = RXRPC_CALL_SERVER_AWAIT_ACK;
-                       rxrpc_notify_end_tx(rx, call, notify_end_tx);
-                       break;
-               default:
-                       break;
-               }
-               write_unlock(&call->state_lock);
-       }
-
        if (poke)
                rxrpc_poke_call(call, rxrpc_call_poke_start);
 }
@@ -245,6 +293,16 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
        timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
 
+       ret = rxrpc_wait_to_be_connected(call, &timeo);
+       if (ret < 0)
+               return ret;
+
+       if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
+               ret = rxrpc_init_client_conn_security(call->conn);
+               if (ret < 0)
+                       return ret;
+       }
+
        /* this should be in poll */
        sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
 
@@ -252,15 +310,20 @@ reload:
        ret = -EPIPE;
        if (sk->sk_shutdown & SEND_SHUTDOWN)
                goto maybe_error;
-       state = READ_ONCE(call->state);
+       state = rxrpc_call_state(call);
        ret = -ESHUTDOWN;
        if (state >= RXRPC_CALL_COMPLETE)
                goto maybe_error;
        ret = -EPROTO;
        if (state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
            state != RXRPC_CALL_SERVER_ACK_REQUEST &&
-           state != RXRPC_CALL_SERVER_SEND_REPLY)
+           state != RXRPC_CALL_SERVER_SEND_REPLY) {
+               /* Request phase complete for this client call */
+               trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
+                                 call->cid, call->call_id, call->rx_consumed,
+                                 0, -EPROTO);
                goto maybe_error;
+       }
 
        ret = -EMSGSIZE;
        if (call->tx_total_len != -1) {
@@ -329,7 +392,7 @@ reload:
 
                /* check for the far side aborting the call or a network error
                 * occurring */
-               if (call->state == RXRPC_CALL_COMPLETE)
+               if (rxrpc_call_is_complete(call))
                        goto call_terminated;
 
                /* add the packet to the send queue if it's now full */
@@ -354,12 +417,9 @@ reload:
 
 success:
        ret = copied;
-       if (READ_ONCE(call->state) == RXRPC_CALL_COMPLETE) {
-               read_lock(&call->state_lock);
-               if (call->error < 0)
-                       ret = call->error;
-               read_unlock(&call->state_lock);
-       }
+       if (rxrpc_call_is_complete(call) &&
+           call->error < 0)
+               ret = call->error;
 out:
        call->tx_pending = txb;
        _leave(" = %d", ret);
@@ -543,7 +603,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
                                     atomic_inc_return(&rxrpc_debug_id));
        /* The socket is now unlocked */
 
-       rxrpc_put_peer(cp.peer, rxrpc_peer_put_discard_tmp);
        _leave(" = %p\n", call);
        return call;
 }
@@ -556,7 +615,6 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
 int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
        __releases(&rx->sk.sk_lock.slock)
 {
-       enum rxrpc_call_state state;
        struct rxrpc_call *call;
        unsigned long now, j;
        bool dropped_lock = false;
@@ -598,10 +656,10 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                        return PTR_ERR(call);
                /* ... and we have the call lock. */
                ret = 0;
-               if (READ_ONCE(call->state) == RXRPC_CALL_COMPLETE)
+               if (rxrpc_call_is_complete(call))
                        goto out_put_unlock;
        } else {
-               switch (READ_ONCE(call->state)) {
+               switch (rxrpc_call_state(call)) {
                case RXRPC_CALL_UNINITIALISED:
                case RXRPC_CALL_CLIENT_AWAIT_CONN:
                case RXRPC_CALL_SERVER_PREALLOC:
@@ -655,17 +713,13 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                break;
        }
 
-       state = READ_ONCE(call->state);
-       _debug("CALL %d USR %lx ST %d on CONN %p",
-              call->debug_id, call->user_call_ID, state, call->conn);
-
-       if (state >= RXRPC_CALL_COMPLETE) {
+       if (rxrpc_call_is_complete(call)) {
                /* it's too late for this call */
                ret = -ESHUTDOWN;
        } else if (p.command == RXRPC_CMD_SEND_ABORT) {
+               rxrpc_propose_abort(call, p.abort_code, -ECONNABORTED,
+                                   rxrpc_abort_call_sendmsg);
                ret = 0;
-               if (rxrpc_abort_call("CMD", call, 0, p.abort_code, -ECONNABORTED))
-                       ret = rxrpc_send_abort_packet(call);
        } else if (p.command != RXRPC_CMD_SEND_DATA) {
                ret = -EINVAL;
        } else {
@@ -705,34 +759,17 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
        bool dropped_lock = false;
        int ret;
 
-       _enter("{%d,%s},", call->debug_id, rxrpc_call_states[call->state]);
+       _enter("{%d},", call->debug_id);
 
        ASSERTCMP(msg->msg_name, ==, NULL);
        ASSERTCMP(msg->msg_control, ==, NULL);
 
        mutex_lock(&call->user_mutex);
 
-       _debug("CALL %d USR %lx ST %d on CONN %p",
-              call->debug_id, call->user_call_ID, call->state, call->conn);
-
-       switch (READ_ONCE(call->state)) {
-       case RXRPC_CALL_CLIENT_SEND_REQUEST:
-       case RXRPC_CALL_SERVER_ACK_REQUEST:
-       case RXRPC_CALL_SERVER_SEND_REPLY:
-               ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
-                                     notify_end_tx, &dropped_lock);
-               break;
-       case RXRPC_CALL_COMPLETE:
-               read_lock(&call->state_lock);
+       ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
+                             notify_end_tx, &dropped_lock);
+       if (ret == -ESHUTDOWN)
                ret = call->error;
-               read_unlock(&call->state_lock);
-               break;
-       default:
-               /* Request phase complete for this client call */
-               trace_rxrpc_rx_eproto(call, 0, tracepoint_string("late_send"));
-               ret = -EPROTO;
-               break;
-       }
 
        if (!dropped_lock)
                mutex_unlock(&call->user_mutex);
@@ -747,24 +784,20 @@ EXPORT_SYMBOL(rxrpc_kernel_send_data);
  * @call: The call to be aborted
  * @abort_code: The abort code to stick into the ABORT packet
  * @error: Local error value
- * @why: 3-char string indicating why.
+ * @why: Indication as to why.
  *
  * Allow a kernel service to abort a call, if it's still in an abortable state
  * and return true if the call was aborted, false if it was already complete.
  */
 bool rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call,
-                            u32 abort_code, int error, const char *why)
+                            u32 abort_code, int error, enum rxrpc_abort_reason why)
 {
        bool aborted;
 
-       _enter("{%d},%d,%d,%s", call->debug_id, abort_code, error, why);
+       _enter("{%d},%d,%d,%u", call->debug_id, abort_code, error, why);
 
        mutex_lock(&call->user_mutex);
-
-       aborted = rxrpc_abort_call(why, call, 0, abort_code, error);
-       if (aborted)
-               rxrpc_send_abort_packet(call);
-
+       aborted = rxrpc_propose_abort(call, abort_code, error, why);
        mutex_unlock(&call->user_mutex);
        return aborted;
 }
index ff47ce4..6b26bdb 100644 (file)
@@ -134,6 +134,11 @@ static int valid_label(const struct nlattr *attr,
 {
        const u32 *label = nla_data(attr);
 
+       if (nla_len(attr) != sizeof(*label)) {
+               NL_SET_ERR_MSG_MOD(extack, "Invalid MPLS label length");
+               return -EINVAL;
+       }
+
        if (*label & ~MPLS_LABEL_MASK || *label == MPLS_LABEL_IMPLNULL) {
                NL_SET_ERR_MSG_MOD(extack, "MPLS label out of range");
                return -EINVAL;
@@ -145,7 +150,8 @@ static int valid_label(const struct nlattr *attr,
 static const struct nla_policy mpls_policy[TCA_MPLS_MAX + 1] = {
        [TCA_MPLS_PARMS]        = NLA_POLICY_EXACT_LEN(sizeof(struct tc_mpls)),
        [TCA_MPLS_PROTO]        = { .type = NLA_U16 },
-       [TCA_MPLS_LABEL]        = NLA_POLICY_VALIDATE_FN(NLA_U32, valid_label),
+       [TCA_MPLS_LABEL]        = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
+                                                        valid_label),
        [TCA_MPLS_TC]           = NLA_POLICY_RANGE(NLA_U8, 0, 7),
        [TCA_MPLS_TTL]          = NLA_POLICY_MIN(NLA_U8, 1),
        [TCA_MPLS_BOS]          = NLA_POLICY_RANGE(NLA_U8, 0, 1),
index 2317db0..72d2c20 100644 (file)
@@ -1133,6 +1133,11 @@ skip:
                        return -ENOENT;
                }
 
+               if (new && new->ops == &noqueue_qdisc_ops) {
+                       NL_SET_ERR_MSG(extack, "Cannot assign noqueue to a class");
+                       return -EINVAL;
+               }
+
                err = cops->graft(parent, cl, new, &old, extack);
                if (err)
                        return err;
index a661b06..872d127 100644 (file)
@@ -377,6 +377,7 @@ static int gred_offload_dump_stats(struct Qdisc *sch)
        /* Even if driver returns failure adjust the stats - in case offload
         * ended but driver still wants to adjust the values.
         */
+       sch_tree_lock(sch);
        for (i = 0; i < MAX_DPs; i++) {
                if (!table->tab[i])
                        continue;
@@ -393,6 +394,7 @@ static int gred_offload_dump_stats(struct Qdisc *sch)
                sch->qstats.overlimits += hw_stats->stats.qstats[i].overlimits;
        }
        _bstats_update(&sch->bstats, bytes, packets);
+       sch_tree_unlock(sch);
 
        kfree(hw_stats);
        return ret;
index 2238ede..92f2975 100644 (file)
@@ -431,7 +431,10 @@ static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl)
        while (cl->cmode == HTB_MAY_BORROW && p && mask) {
                m = mask;
                while (m) {
-                       int prio = ffz(~m);
+                       unsigned int prio = ffz(~m);
+
+                       if (WARN_ON_ONCE(prio >= ARRAY_SIZE(p->inner.clprio)))
+                               break;
                        m &= ~(1 << prio);
 
                        if (p->inner.clprio[prio].feed.rb_node)
@@ -1549,7 +1552,7 @@ static int htb_destroy_class_offload(struct Qdisc *sch, struct htb_class *cl,
        struct tc_htb_qopt_offload offload_opt;
        struct netdev_queue *dev_queue;
        struct Qdisc *q = cl->leaf.q;
-       struct Qdisc *old = NULL;
+       struct Qdisc *old;
        int err;
 
        if (cl->level)
@@ -1557,14 +1560,17 @@ static int htb_destroy_class_offload(struct Qdisc *sch, struct htb_class *cl,
 
        WARN_ON(!q);
        dev_queue = htb_offload_get_queue(cl);
-       old = htb_graft_helper(dev_queue, NULL);
-       if (destroying)
-               /* Before HTB is destroyed, the kernel grafts noop_qdisc to
-                * all queues.
+       /* When destroying, caller qdisc_graft grafts the new qdisc and invokes
+        * qdisc_put for the qdisc being destroyed. htb_destroy_class_offload
+        * does not need to graft or qdisc_put the qdisc being destroyed.
+        */
+       if (!destroying) {
+               old = htb_graft_helper(dev_queue, NULL);
+               /* Last qdisc grafted should be the same as cl->leaf.q when
+                * calling htb_delete.
                 */
-               WARN_ON(!(old->flags & TCQ_F_BUILTIN));
-       else
                WARN_ON(old != q);
+       }
 
        if (cl->parent) {
                _bstats_update(&cl->parent->bstats_bias,
@@ -1581,10 +1587,12 @@ static int htb_destroy_class_offload(struct Qdisc *sch, struct htb_class *cl,
        };
        err = htb_offload(qdisc_dev(sch), &offload_opt);
 
-       if (!err || destroying)
-               qdisc_put(old);
-       else
-               htb_graft_helper(dev_queue, old);
+       if (!destroying) {
+               if (!err)
+                       qdisc_put(old);
+               else
+                       htb_graft_helper(dev_queue, old);
+       }
 
        if (last_child)
                return err;
index 570389f..c322a61 100644 (file)
@@ -1700,6 +1700,7 @@ static void taprio_reset(struct Qdisc *sch)
        int i;
 
        hrtimer_cancel(&q->advance_timer);
+
        if (q->qdiscs) {
                for (i = 0; i < dev->num_tx_queues; i++)
                        if (q->qdiscs[i])
@@ -1720,6 +1721,7 @@ static void taprio_destroy(struct Qdisc *sch)
         * happens in qdisc_create(), after taprio_init() has been called.
         */
        hrtimer_cancel(&q->advance_timer);
+       qdisc_synchronize(sch);
 
        taprio_disable_offload(dev, q, NULL);
 
index 59e653b..6b95d3b 100644 (file)
@@ -73,6 +73,12 @@ int sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest,
                }
        }
 
+       /* If somehow no addresses were found that can be used with this
+        * scope, it's an error.
+        */
+       if (list_empty(&dest->address_list))
+               error = -ENETUNREACH;
+
 out:
        if (error)
                sctp_bind_addr_clean(dest);
index ca1eba9..2f66a20 100644 (file)
@@ -196,9 +196,7 @@ void sctp_transport_reset_hb_timer(struct sctp_transport *transport)
 
        /* When a data chunk is sent, reset the heartbeat interval.  */
        expires = jiffies + sctp_transport_timeout(transport);
-       if ((time_before(transport->hb_timer.expires, expires) ||
-            !timer_pending(&transport->hb_timer)) &&
-           !mod_timer(&transport->hb_timer,
+       if (!mod_timer(&transport->hb_timer,
                       expires + get_random_u32_below(transport->rto)))
                sctp_transport_hold(transport);
 }
index 148bb0a..acb822b 100644 (file)
@@ -923,7 +923,7 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g
         * rejecting the server-computed MIC in this somewhat rare case,
         * do not use splice with the GSS integrity service.
         */
-       __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
+       clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
 
        /* Did we already verify the signature on the original pass through? */
        if (rqstp->rq_deferred)
@@ -990,7 +990,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs
        int pad, remaining_len, offset;
        u32 rseqno;
 
-       __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
+       clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
 
        priv_len = svc_getnl(&buf->head[0]);
        if (rqstp->rq_deferred) {
index 85f0c3c..f066228 100644 (file)
@@ -1243,10 +1243,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
                goto err_short_len;
 
        /* Will be turned off by GSS integrity and privacy services */
-       __set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
+       set_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
        /* Will be turned off only when NFSv4 Sessions are used */
-       __set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
-       __clear_bit(RQ_DROPME, &rqstp->rq_flags);
+       set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
+       clear_bit(RQ_DROPME, &rqstp->rq_flags);
 
        svc_putu32(resv, rqstp->rq_xid);
 
index 2106003..c2ce125 100644 (file)
@@ -1238,7 +1238,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
        trace_svc_defer(rqstp);
        svc_xprt_get(rqstp->rq_xprt);
        dr->xprt = rqstp->rq_xprt;
-       __set_bit(RQ_DROPME, &rqstp->rq_flags);
+       set_bit(RQ_DROPME, &rqstp->rq_flags);
 
        dr->handle.revisit = svc_revisit;
        return &dr->handle;
index 0157143..815baf3 100644 (file)
@@ -298,9 +298,9 @@ static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs)
 static void svc_sock_secure_port(struct svc_rqst *rqstp)
 {
        if (svc_port_is_privileged(svc_addr(rqstp)))
-               __set_bit(RQ_SECURE, &rqstp->rq_flags);
+               set_bit(RQ_SECURE, &rqstp->rq_flags);
        else
-               __clear_bit(RQ_SECURE, &rqstp->rq_flags);
+               clear_bit(RQ_SECURE, &rqstp->rq_flags);
 }
 
 /*
@@ -1008,9 +1008,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
        rqstp->rq_xprt_ctxt   = NULL;
        rqstp->rq_prot        = IPPROTO_TCP;
        if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags))
-               __set_bit(RQ_LOCAL, &rqstp->rq_flags);
+               set_bit(RQ_LOCAL, &rqstp->rq_flags);
        else
-               __clear_bit(RQ_LOCAL, &rqstp->rq_flags);
+               clear_bit(RQ_LOCAL, &rqstp->rq_flags);
 
        p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
        calldir = p[1];
index 199fa01..94b20fb 100644 (file)
@@ -602,7 +602,7 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt)
 
 static void svc_rdma_secure_port(struct svc_rqst *rqstp)
 {
-       __set_bit(RQ_SECURE, &rqstp->rq_flags);
+       set_bit(RQ_SECURE, &rqstp->rq_flags);
 }
 
 static void svc_rdma_kill_temp_xprt(struct svc_xprt *xprt)
index 49ddc48..5e000fd 100644 (file)
@@ -1179,8 +1179,9 @@ void tipc_node_check_dest(struct net *net, u32 addr,
        bool addr_match = false;
        bool sign_match = false;
        bool link_up = false;
+       bool link_is_reset = false;
        bool accept_addr = false;
-       bool reset = true;
+       bool reset = false;
        char *if_name;
        unsigned long intv;
        u16 session;
@@ -1200,14 +1201,14 @@ void tipc_node_check_dest(struct net *net, u32 addr,
        /* Prepare to validate requesting node's signature and media address */
        l = le->link;
        link_up = l && tipc_link_is_up(l);
+       link_is_reset = l && tipc_link_is_reset(l);
        addr_match = l && !memcmp(&le->maddr, maddr, sizeof(*maddr));
        sign_match = (signature == n->signature);
 
        /* These three flags give us eight permutations: */
 
        if (sign_match && addr_match && link_up) {
-               /* All is fine. Do nothing. */
-               reset = false;
+               /* All is fine. Ignore requests. */
                /* Peer node is not a container/local namespace */
                if (!n->peer_hash_mix)
                        n->peer_hash_mix = hash_mixes;
@@ -1232,6 +1233,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
                 */
                accept_addr = true;
                *respond = true;
+               reset = true;
        } else if (!sign_match && addr_match && link_up) {
                /* Peer node rebooted. Two possibilities:
                 *  - Delayed re-discovery; this link endpoint has already
@@ -1263,6 +1265,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
                n->signature = signature;
                accept_addr = true;
                *respond = true;
+               reset = true;
        }
 
        if (!accept_addr)
@@ -1291,6 +1294,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
                tipc_link_fsm_evt(l, LINK_RESET_EVT);
                if (n->state == NODE_FAILINGOVER)
                        tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT);
+               link_is_reset = tipc_link_is_reset(l);
                le->link = l;
                n->link_cnt++;
                tipc_node_calculate_timer(n, l);
@@ -1303,7 +1307,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
        memcpy(&le->maddr, maddr, sizeof(*maddr));
 exit:
        tipc_node_write_unlock(n);
-       if (reset && l && !tipc_link_is_reset(l))
+       if (reset && !link_is_reset)
                tipc_node_link_down(n, b->identity, false);
        tipc_node_put(n);
 }
index 9ed9786..a83d2b4 100644 (file)
@@ -2427,7 +2427,7 @@ static bool tls_is_tx_ready(struct tls_sw_context_tx *ctx)
 {
        struct tls_rec *rec;
 
-       rec = list_first_entry(&ctx->tx_list, struct tls_rec, list);
+       rec = list_first_entry_or_null(&ctx->tx_list, struct tls_rec, list);
        if (!rec)
                return false;
 
index 3b55502..5c7ad30 100644 (file)
@@ -482,6 +482,12 @@ static int x25_listen(struct socket *sock, int backlog)
        int rc = -EOPNOTSUPP;
 
        lock_sock(sk);
+       if (sock->state != SS_UNCONNECTED) {
+               rc = -EINVAL;
+               release_sock(sk);
+               return rc;
+       }
+
        if (sk->sk_state != TCP_LISTEN) {
                memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
                sk->sk_max_ack_backlog = backlog;
index a0f62fa..8cbf45a 100644 (file)
@@ -5,6 +5,7 @@
  * Based on code and translator idea by: Florian Westphal <fw@strlen.de>
  */
 #include <linux/compat.h>
+#include <linux/nospec.h>
 #include <linux/xfrm.h>
 #include <net/xfrm.h>
 
@@ -302,7 +303,7 @@ static int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src)
        nla_for_each_attr(nla, attrs, len, remaining) {
                int err;
 
-               switch (type) {
+               switch (nlh_src->nlmsg_type) {
                case XFRM_MSG_NEWSPDINFO:
                        err = xfrm_nla_cpy(dst, nla, nla_len(nla));
                        break;
@@ -437,6 +438,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
                NL_SET_ERR_MSG(extack, "Bad attribute");
                return -EOPNOTSUPP;
        }
+       type = array_index_nospec(type, XFRMA_MAX + 1);
        if (nla_len(nla) < compat_policy[type].len) {
                NL_SET_ERR_MSG(extack, "Attribute bad length");
                return -EOPNOTSUPP;
index c06e54a..436d296 100644 (file)
@@ -279,8 +279,7 @@ static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
                goto out;
 
        if (x->props.flags & XFRM_STATE_DECAP_DSCP)
-               ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)),
-                              ipipv6_hdr(skb));
+               ipv6_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipipv6_hdr(skb));
        if (!(x->props.flags & XFRM_STATE_NOECN))
                ipip6_ecn_decapsulate(skb);
 
index 1f99dc4..35279c2 100644 (file)
@@ -310,6 +310,52 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->mark = 0;
 }
 
+static int xfrmi_input(struct sk_buff *skb, int nexthdr, __be32 spi,
+                      int encap_type, unsigned short family)
+{
+       struct sec_path *sp;
+
+       sp = skb_sec_path(skb);
+       if (sp && (sp->len || sp->olen) &&
+           !xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
+               goto discard;
+
+       XFRM_SPI_SKB_CB(skb)->family = family;
+       if (family == AF_INET) {
+               XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
+               XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
+       } else {
+               XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
+               XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
+       }
+
+       return xfrm_input(skb, nexthdr, spi, encap_type);
+discard:
+       kfree_skb(skb);
+       return 0;
+}
+
+static int xfrmi4_rcv(struct sk_buff *skb)
+{
+       return xfrmi_input(skb, ip_hdr(skb)->protocol, 0, 0, AF_INET);
+}
+
+static int xfrmi6_rcv(struct sk_buff *skb)
+{
+       return xfrmi_input(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
+                          0, 0, AF_INET6);
+}
+
+static int xfrmi4_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+{
+       return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET);
+}
+
+static int xfrmi6_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
+{
+       return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET6);
+}
+
 static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
 {
        const struct xfrm_mode *inner_mode;
@@ -945,8 +991,8 @@ static struct pernet_operations xfrmi_net_ops = {
 };
 
 static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
-       .handler        =       xfrm6_rcv,
-       .input_handler  =       xfrm_input,
+       .handler        =       xfrmi6_rcv,
+       .input_handler  =       xfrmi6_input,
        .cb_handler     =       xfrmi_rcv_cb,
        .err_handler    =       xfrmi6_err,
        .priority       =       10,
@@ -996,8 +1042,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
 #endif
 
 static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
-       .handler        =       xfrm4_rcv,
-       .input_handler  =       xfrm_input,
+       .handler        =       xfrmi4_rcv,
+       .input_handler  =       xfrmi4_input,
        .cb_handler     =       xfrmi_rcv_cb,
        .err_handler    =       xfrmi4_err,
        .priority       =       10,
index e9eb82c..5c61ec0 100644 (file)
@@ -336,7 +336,7 @@ static void xfrm_policy_timer(struct timer_list *t)
        }
        if (xp->lft.hard_use_expires_seconds) {
                time64_t tmo = xp->lft.hard_use_expires_seconds +
-                       (xp->curlft.use_time ? : xp->curlft.add_time) - now;
+                       (READ_ONCE(xp->curlft.use_time) ? : xp->curlft.add_time) - now;
                if (tmo <= 0)
                        goto expired;
                if (tmo < next)
@@ -354,7 +354,7 @@ static void xfrm_policy_timer(struct timer_list *t)
        }
        if (xp->lft.soft_use_expires_seconds) {
                time64_t tmo = xp->lft.soft_use_expires_seconds +
-                       (xp->curlft.use_time ? : xp->curlft.add_time) - now;
+                       (READ_ONCE(xp->curlft.use_time) ? : xp->curlft.add_time) - now;
                if (tmo <= 0) {
                        warn = 1;
                        tmo = XFRM_KM_TIMEOUT;
@@ -3661,7 +3661,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                return 1;
        }
 
-       pol->curlft.use_time = ktime_get_real_seconds();
+       /* This lockless write can happen from different cpus. */
+       WRITE_ONCE(pol->curlft.use_time, ktime_get_real_seconds());
 
        pols[0] = pol;
        npols++;
@@ -3676,7 +3677,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                                xfrm_pol_put(pols[0]);
                                return 0;
                        }
-                       pols[1]->curlft.use_time = ktime_get_real_seconds();
+                       /* This write can happen from different cpus. */
+                       WRITE_ONCE(pols[1]->curlft.use_time,
+                                  ktime_get_real_seconds());
                        npols++;
                }
        }
@@ -3742,6 +3745,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                        goto reject;
                }
 
+               if (if_id)
+                       secpath_reset(skb);
+
                xfrm_pols_put(pols, npols);
                return 1;
        }
index 89c731f..00afe83 100644 (file)
@@ -577,7 +577,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
        if (x->km.state == XFRM_STATE_EXPIRED)
                goto expired;
        if (x->lft.hard_add_expires_seconds) {
-               long tmo = x->lft.hard_add_expires_seconds +
+               time64_t tmo = x->lft.hard_add_expires_seconds +
                        x->curlft.add_time - now;
                if (tmo <= 0) {
                        if (x->xflags & XFRM_SOFT_EXPIRE) {
@@ -594,8 +594,8 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
                        next = tmo;
        }
        if (x->lft.hard_use_expires_seconds) {
-               long tmo = x->lft.hard_use_expires_seconds +
-                       (x->curlft.use_time ? : now) - now;
+               time64_t tmo = x->lft.hard_use_expires_seconds +
+                       (READ_ONCE(x->curlft.use_time) ? : now) - now;
                if (tmo <= 0)
                        goto expired;
                if (tmo < next)
@@ -604,7 +604,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
        if (x->km.dying)
                goto resched;
        if (x->lft.soft_add_expires_seconds) {
-               long tmo = x->lft.soft_add_expires_seconds +
+               time64_t tmo = x->lft.soft_add_expires_seconds +
                        x->curlft.add_time - now;
                if (tmo <= 0) {
                        warn = 1;
@@ -616,8 +616,8 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
                }
        }
        if (x->lft.soft_use_expires_seconds) {
-               long tmo = x->lft.soft_use_expires_seconds +
-                       (x->curlft.use_time ? : now) - now;
+               time64_t tmo = x->lft.soft_use_expires_seconds +
+                       (READ_ONCE(x->curlft.use_time) ? : now) - now;
                if (tmo <= 0)
                        warn = 1;
                else if (tmo < next)
@@ -1906,7 +1906,7 @@ out:
 
                hrtimer_start(&x1->mtimer, ktime_set(1, 0),
                              HRTIMER_MODE_REL_SOFT);
-               if (x1->curlft.use_time)
+               if (READ_ONCE(x1->curlft.use_time))
                        xfrm_state_check_expire(x1);
 
                if (x->props.smark.m || x->props.smark.v || x->if_id) {
@@ -1940,8 +1940,8 @@ int xfrm_state_check_expire(struct xfrm_state *x)
 {
        xfrm_dev_state_update_curlft(x);
 
-       if (!x->curlft.use_time)
-               x->curlft.use_time = ktime_get_real_seconds();
+       if (!READ_ONCE(x->curlft.use_time))
+               WRITE_ONCE(x->curlft.use_time, ktime_get_real_seconds());
 
        if (x->curlft.bytes >= x->lft.hard_byte_limit ||
            x->curlft.packets >= x->lft.hard_packet_limit) {
index 29bf9c2..3010332 100644 (file)
@@ -142,17 +142,24 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) {
 macro_rules! print_macro (
     // The non-continuation cases (most of them, e.g. `INFO`).
     ($format_string:path, false, $($arg:tt)+) => (
-        // SAFETY: This hidden macro should only be called by the documented
-        // printing macros which ensure the format string is one of the fixed
-        // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
-        // by the `module!` proc macro or fixed values defined in a kernel
-        // crate.
-        unsafe {
-            $crate::print::call_printk(
-                &$format_string,
-                crate::__LOG_PREFIX,
-                format_args!($($arg)+),
-            );
+        // To remain sound, `arg`s must be expanded outside the `unsafe` block.
+        // Typically one would use a `let` binding for that; however, `format_args!`
+        // takes borrows on the arguments, but does not extend the scope of temporaries.
+        // Therefore, a `match` expression is used to keep them around, since
+        // the scrutinee is kept until the end of the `match`.
+        match format_args!($($arg)+) {
+            // SAFETY: This hidden macro should only be called by the documented
+            // printing macros which ensure the format string is one of the fixed
+            // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
+            // by the `module!` proc macro or fixed values defined in a kernel
+            // crate.
+            args => unsafe {
+                $crate::print::call_printk(
+                    &$format_string,
+                    crate::__LOG_PREFIX,
+                    args,
+                );
+            }
         }
     );
 
index d52370c..a825dbd 100644 (file)
@@ -152,6 +152,7 @@ static void __exit ftrace_direct_multi_exit(void)
 {
        kthread_stop(simple_tsk);
        unregister_ftrace_direct_multi(&direct, my_tramp);
+       ftrace_free_filter(&direct);
 }
 
 module_init(ftrace_direct_multi_init);
index ec10889..d955a26 100644 (file)
@@ -79,6 +79,7 @@ static int __init ftrace_direct_multi_init(void)
 static void __exit ftrace_direct_multi_exit(void)
 {
        unregister_ftrace_direct_multi(&direct, (unsigned long) my_tramp);
+       ftrace_free_filter(&direct);
 }
 
 module_init(ftrace_direct_multi_init);
index 836391e..4815a8e 100644 (file)
@@ -66,9 +66,13 @@ endif
 # Don't stop modules_install even if we can't sign external modules.
 #
 ifeq ($(CONFIG_MODULE_SIG_ALL),y)
+ifeq ($(filter pkcs11:%, $(CONFIG_MODULE_SIG_KEY)),)
 sig-key := $(if $(wildcard $(CONFIG_MODULE_SIG_KEY)),,$(srctree)/)$(CONFIG_MODULE_SIG_KEY)
+else
+sig-key := $(CONFIG_MODULE_SIG_KEY)
+endif
 quiet_cmd_sign = SIGN    $@
-      cmd_sign = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(sig-key) certs/signing_key.x509 $@ \
+      cmd_sign = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) "$(sig-key)" certs/signing_key.x509 $@ \
                  $(if $(KBUILD_EXTMOD),|| true)
 else
 quiet_cmd_sign :=
index 49946cb..10176de 100644 (file)
@@ -18,6 +18,7 @@ quiet_cmd_cc_o_c = CC      $@
        $(call if_changed_dep,cc_o_c)
 
 ifdef CONFIG_MODULES
+KASAN_SANITIZE_.vmlinux.export.o := n
 targets += .vmlinux.export.o
 vmlinux: .vmlinux.export.o
 endif
old mode 100755 (executable)
new mode 100644 (file)
index 9a18957..84c730d 100644 (file)
@@ -71,7 +71,9 @@
 #include "varasm.h"
 #include "stor-layout.h"
 #include "internal-fn.h"
+#include "gimple.h"
 #include "gimple-expr.h"
+#include "gimple-iterator.h"
 #include "gimple-fold.h"
 #include "context.h"
 #include "tree-ssa-alias.h"
 #include "tree-eh.h"
 #include "stmt.h"
 #include "gimplify.h"
-#include "gimple.h"
 #include "tree-phinodes.h"
 #include "tree-cfg.h"
-#include "gimple-iterator.h"
 #include "gimple-ssa.h"
 #include "ssa-iterators.h"
 
index 4192855..7eca035 100755 (executable)
@@ -26,11 +26,20 @@ try:
        # If the MAKEFLAGS variable contains multiple instances of the
        # --jobserver-auth= option, the last one is relevant.
        fds = opts[-1].split("=", 1)[1]
-       reader, writer = [int(x) for x in fds.split(",", 1)]
-       # Open a private copy of reader to avoid setting nonblocking
-       # on an unexpecting process with the same reader fd.
-       reader = os.open("/proc/self/fd/%d" % (reader),
-                        os.O_RDONLY | os.O_NONBLOCK)
+
+       # Starting with GNU Make 4.4, named pipes are used for reader and writer.
+       # Example argument: --jobserver-auth=fifo:/tmp/GMfifo8134
+       _, _, path = fds.partition('fifo:')
+
+       if path:
+               reader = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
+               writer = os.open(path, os.O_WRONLY)
+       else:
+               reader, writer = [int(x) for x in fds.split(",", 1)]
+               # Open a private copy of reader to avoid setting nonblocking
+               # on an unexpecting process with the same reader fd.
+               reader = os.open("/proc/self/fd/%d" % (reader),
+                                os.O_RDONLY | os.O_NONBLOCK)
 
        # Read out as many jobserver slots as possible.
        while True:
index c8a3f9c..0b2ff77 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 /conf
 /[gmnq]conf
+/[gmnq]conf-bin
 /[gmnq]conf-cflags
 /[gmnq]conf-libs
-/qconf-bin
 /qconf-moc.cc
index 0b1d15e..af1c961 100644 (file)
@@ -209,7 +209,7 @@ $(obj)/gconf: | $(obj)/gconf-libs
 $(obj)/gconf.o: | $(obj)/gconf-cflags
 
 # check if necessary packages are available, and configure build flags
-cmd_conf_cfg = $< $(addprefix $(obj)/$*conf-, cflags libs bin)
+cmd_conf_cfg = $< $(addprefix $(obj)/$*conf-, cflags libs bin); touch $(obj)/$*conf-bin
 
 $(obj)/%conf-cflags $(obj)/%conf-libs $(obj)/%conf-bin: $(src)/%conf-cfg.sh
        $(call cmd,conf_cfg)
index adab28f..094e52c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 #      Output a simple RPM spec file.
-#      This version assumes a minimum of RPM 4.0.3.
+#      This version assumes a minimum of RPM 4.13
 #
 #      The only gothic bit here is redefining install_post to avoid
 #      stripping the symbols from files in the kernel which we want
index 9267011..bb4f592 100755 (executable)
@@ -12,7 +12,7 @@
 #   (note, if this is a problem with function_graph tracing, then simply
 #    replace "function" with "function_graph" in the following steps).
 #
-#  # cd /sys/kernel/debug/tracing
+#  # cd /sys/kernel/tracing
 #  # echo schedule > set_ftrace_filter
 #  # echo function > current_tracer
 #
 #
 #  # echo nop > current_tracer
 #
-#  # cat available_filter_functions > ~/full-file
+# Starting with v5.1 this can be done with numbers, making it much faster:
+#
+# The old (slow) way, for kernels before v5.1.
+#
+# [old-way] # cat available_filter_functions > ~/full-file
+#
+# [old-way] *** Note ***  this process will take several minutes to update the
+# [old-way] filters. Setting multiple functions is an O(n^2) operation, and we
+# [old-way] are dealing with thousands of functions. So go have coffee, talk
+# [old-way] with your coworkers, read facebook. And eventually, this operation
+# [old-way] will end.
+#
+# The new way (using numbers) is an O(n) operation, and usually takes less than a second.
+#
+# seq `wc -l available_filter_functions | cut -d' ' -f1` > ~/full-file
+#
+# This will create a sequence of numbers that match the functions in
+# available_filter_functions, and when echoing in a number into the
+# set_ftrace_filter file, it will enable the corresponding function in
+# O(1) time. Making enabling all functions O(n) where n is the number of
+# functions to enable.
+#
+# For either the new or old way, the rest of the operations remain the same.
+#
 #  # ftrace-bisect ~/full-file ~/test-file ~/non-test-file
 #  # cat ~/test-file > set_ftrace_filter
 #
-# *** Note *** this will take several minutes. Setting multiple functions is
-# an O(n^2) operation, and we are dealing with thousands of functions. So go
-# have  coffee, talk with your coworkers, read facebook. And eventually, this
-# operation will end.
-#
 #  # echo function > current_tracer
 #
 # If it crashes, we know that ~/test-file has a bad function.
 #
 #   Reboot back to test kernel.
 #
-#     # cd /sys/kernel/debug/tracing
+#     # cd /sys/kernel/tracing
 #     # mv ~/test-file ~/full-file
 #
 # If it didn't crash.
index b9f8671..fad75be 100644 (file)
@@ -6,13 +6,11 @@ config SECURITY_TOMOYO
        select SECURITYFS
        select SECURITY_PATH
        select SECURITY_NETWORK
-       select SRCU
-       select BUILD_BIN2C
        default n
        help
          This selects TOMOYO Linux, pathname-based access control.
          Required userspace tools and further information may be
-         found at <http://tomoyo.sourceforge.jp/>.
+         found at <https://tomoyo.osdn.jp/>.
          If you are unsure how to answer this question, answer N.
 
 config SECURITY_TOMOYO_MAX_ACCEPT_ENTRY
index cca5a30..884ff15 100644 (file)
@@ -2,15 +2,18 @@
 obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o
 
 targets += builtin-policy.h
-define do_policy
-echo "static char tomoyo_builtin_$(1)[] __initdata ="; \
-$(objtree)/scripts/bin2c <$(firstword $(wildcard $(obj)/policy/$(1).conf $(srctree)/$(src)/policy/$(1).conf.default) /dev/null); \
-echo ";"
-endef
-quiet_cmd_policy  = POLICY  $@
-      cmd_policy  = ($(call do_policy,profile); $(call do_policy,exception_policy); $(call do_policy,domain_policy); $(call do_policy,manager); $(call do_policy,stat)) >$@
 
-$(obj)/builtin-policy.h: $(wildcard $(obj)/policy/*.conf $(src)/policy/*.conf.default) FORCE
+quiet_cmd_policy = POLICY  $@
+      cmd_policy = { \
+       $(foreach x, profile exception_policy domain_policy manager stat, \
+       printf 'static char tomoyo_builtin_$x[] __initdata =\n'; \
+       sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/\t"\1\\n"/' -- $(firstword $(filter %/$x.conf %/$x.conf.default, $^) /dev/null);  \
+       printf '\t"";\n';) \
+       } > $@
+
+$(obj)/builtin-policy.h: $(wildcard $(obj)/policy/*.conf $(srctree)/$(src)/policy/*.conf.default) FORCE
        $(call if_changed,policy)
 
+ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
 $(obj)/common.o: $(obj)/builtin-policy.h
+endif
index 50e7ba6..82aa1af 100644 (file)
@@ -1203,14 +1203,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
        const u32 pattern = 0xdeadbeef;
        int ret;
 
+       down_read(&card->controls_rwsem);
        kctl = snd_ctl_find_id(card, &control->id);
-       if (kctl == NULL)
-               return -ENOENT;
+       if (kctl == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
 
        index_offset = snd_ctl_get_ioff(kctl, &control->id);
        vd = &kctl->vd[index_offset];
-       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)
-               return -EPERM;
+       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
+               ret = -EPERM;
+               goto unlock;
+       }
 
        snd_ctl_build_ioff(&control->id, kctl, index_offset);
 
@@ -1220,7 +1225,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
        info.id = control->id;
        ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
        if (ret < 0)
-               return ret;
+               goto unlock;
 #endif
 
        if (!snd_ctl_skip_validation(&info))
@@ -1230,7 +1235,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
                ret = kctl->get(kctl, control);
        snd_power_unref(card);
        if (ret < 0)
-               return ret;
+               goto unlock;
        if (!snd_ctl_skip_validation(&info) &&
            sanity_check_elem_value(card, control, &info, pattern) < 0) {
                dev_err(card->dev,
@@ -1238,8 +1243,11 @@ static int snd_ctl_elem_read(struct snd_card *card,
                        control->id.iface, control->id.device,
                        control->id.subdevice, control->id.name,
                        control->id.index);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto unlock;
        }
+unlock:
+       up_read(&card->controls_rwsem);
        return ret;
 }
 
@@ -1253,9 +1261,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
        if (IS_ERR(control))
                return PTR_ERR(control);
 
-       down_read(&card->controls_rwsem);
        result = snd_ctl_elem_read(card, control);
-       up_read(&card->controls_rwsem);
        if (result < 0)
                goto error;
 
index f975cc8..3cadd40 100644 (file)
@@ -530,12 +530,11 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si
                          bool attach)
 {
        char buf2[256], *s, *os;
-       size_t len = max(sizeof(s) - 1, count);
        struct snd_ctl_elem_id id;
        int err;
 
-       strncpy(buf2, buf, len);
-       buf2[len] = '\0';
+       if (strscpy(buf2, buf, sizeof(buf2)) < 0)
+               return -E2BIG;
        memset(&id, 0, sizeof(id));
        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
        s = buf2;
index 81025f5..f901504 100644 (file)
@@ -541,16 +541,15 @@ static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
        struct sg_table *sgt;
        void *p;
 
+#ifdef CONFIG_SND_DMA_SGBUF
+       if (cpu_feature_enabled(X86_FEATURE_XENPV))
+               return snd_dma_sg_fallback_alloc(dmab, size);
+#endif
        sgt = dma_alloc_noncontiguous(dmab->dev.dev, size, dmab->dev.dir,
                                      DEFAULT_GFP, 0);
 #ifdef CONFIG_SND_DMA_SGBUF
-       if (!sgt && !get_dma_ops(dmab->dev.dev)) {
-               if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
-                       dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
-               else
-                       dmab->dev.type = SNDRV_DMA_TYPE_DEV_SG_FALLBACK;
+       if (!sgt && !get_dma_ops(dmab->dev.dev))
                return snd_dma_sg_fallback_alloc(dmab, size);
-       }
 #endif
        if (!sgt)
                return NULL;
@@ -717,19 +716,38 @@ static const struct snd_malloc_ops snd_dma_sg_wc_ops = {
 
 /* Fallback SG-buffer allocations for x86 */
 struct snd_dma_sg_fallback {
+       bool use_dma_alloc_coherent;
        size_t count;
        struct page **pages;
+       /* DMA address array; the first page contains #pages in ~PAGE_MASK */
+       dma_addr_t *addrs;
 };
 
 static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab,
                                       struct snd_dma_sg_fallback *sgbuf)
 {
-       bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
-       size_t i;
-
-       for (i = 0; i < sgbuf->count && sgbuf->pages[i]; i++)
-               do_free_pages(page_address(sgbuf->pages[i]), PAGE_SIZE, wc);
+       size_t i, size;
+
+       if (sgbuf->pages && sgbuf->addrs) {
+               i = 0;
+               while (i < sgbuf->count) {
+                       if (!sgbuf->pages[i] || !sgbuf->addrs[i])
+                               break;
+                       size = sgbuf->addrs[i] & ~PAGE_MASK;
+                       if (WARN_ON(!size))
+                               break;
+                       if (sgbuf->use_dma_alloc_coherent)
+                               dma_free_coherent(dmab->dev.dev, size << PAGE_SHIFT,
+                                                 page_address(sgbuf->pages[i]),
+                                                 sgbuf->addrs[i] & PAGE_MASK);
+                       else
+                               do_free_pages(page_address(sgbuf->pages[i]),
+                                             size << PAGE_SHIFT, false);
+                       i += size;
+               }
+       }
        kvfree(sgbuf->pages);
+       kvfree(sgbuf->addrs);
        kfree(sgbuf);
 }
 
@@ -738,24 +756,36 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
        struct snd_dma_sg_fallback *sgbuf;
        struct page **pagep, *curp;
        size_t chunk, npages;
+       dma_addr_t *addrp;
        dma_addr_t addr;
        void *p;
-       bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
+
+       /* correct the type */
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG)
+               dmab->dev.type = SNDRV_DMA_TYPE_DEV_SG_FALLBACK;
+       else if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
+               dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
 
        sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
        if (!sgbuf)
                return NULL;
+       sgbuf->use_dma_alloc_coherent = cpu_feature_enabled(X86_FEATURE_XENPV);
        size = PAGE_ALIGN(size);
        sgbuf->count = size >> PAGE_SHIFT;
        sgbuf->pages = kvcalloc(sgbuf->count, sizeof(*sgbuf->pages), GFP_KERNEL);
-       if (!sgbuf->pages)
+       sgbuf->addrs = kvcalloc(sgbuf->count, sizeof(*sgbuf->addrs), GFP_KERNEL);
+       if (!sgbuf->pages || !sgbuf->addrs)
                goto error;
 
        pagep = sgbuf->pages;
-       chunk = size;
+       addrp = sgbuf->addrs;
+       chunk = (PAGE_SIZE - 1) << PAGE_SHIFT; /* to fit in low bits in addrs */
        while (size > 0) {
                chunk = min(size, chunk);
-               p = do_alloc_pages(dmab->dev.dev, chunk, &addr, wc);
+               if (sgbuf->use_dma_alloc_coherent)
+                       p = dma_alloc_coherent(dmab->dev.dev, chunk, &addr, DEFAULT_GFP);
+               else
+                       p = do_alloc_pages(dmab->dev.dev, chunk, &addr, false);
                if (!p) {
                        if (chunk <= PAGE_SIZE)
                                goto error;
@@ -767,17 +797,25 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
                size -= chunk;
                /* fill pages */
                npages = chunk >> PAGE_SHIFT;
+               *addrp = npages; /* store in lower bits */
                curp = virt_to_page(p);
-               while (npages--)
+               while (npages--) {
                        *pagep++ = curp++;
+                       *addrp++ |= addr;
+                       addr += PAGE_SIZE;
+               }
        }
 
        p = vmap(sgbuf->pages, sgbuf->count, VM_MAP, PAGE_KERNEL);
        if (!p)
                goto error;
+
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
+               set_pages_array_wc(sgbuf->pages, sgbuf->count);
+
        dmab->private_data = sgbuf;
        /* store the first page address for convenience */
-       dmab->addr = snd_sgbuf_get_addr(dmab, 0);
+       dmab->addr = sgbuf->addrs[0] & PAGE_MASK;
        return p;
 
  error:
@@ -787,10 +825,23 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
 
 static void snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab)
 {
+       struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
+
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
+               set_pages_array_wb(sgbuf->pages, sgbuf->count);
        vunmap(dmab->area);
        __snd_dma_sg_fallback_free(dmab, dmab->private_data);
 }
 
+static dma_addr_t snd_dma_sg_fallback_get_addr(struct snd_dma_buffer *dmab,
+                                              size_t offset)
+{
+       struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
+       size_t index = offset >> PAGE_SHIFT;
+
+       return (sgbuf->addrs[index] & PAGE_MASK) | (offset & ~PAGE_MASK);
+}
+
 static int snd_dma_sg_fallback_mmap(struct snd_dma_buffer *dmab,
                                    struct vm_area_struct *area)
 {
@@ -805,8 +856,8 @@ static const struct snd_malloc_ops snd_dma_sg_fallback_ops = {
        .alloc = snd_dma_sg_fallback_alloc,
        .free = snd_dma_sg_fallback_free,
        .mmap = snd_dma_sg_fallback_mmap,
+       .get_addr = snd_dma_sg_fallback_get_addr,
        /* reuse vmalloc helpers */
-       .get_addr = snd_dma_vmalloc_get_addr,
        .get_page = snd_dma_vmalloc_get_page,
        .get_chunk_size = snd_dma_vmalloc_get_chunk_size,
 };
index a900fc0..88d1f4b 100644 (file)
@@ -87,6 +87,10 @@ static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
                        return -EFAULT;
 
                count = consumed;
+       } else {
+               spin_unlock_irq(&motu->lock);
+
+               count = 0;
        }
 
        return count;
index 91842c0..f7815ee 100644 (file)
@@ -598,8 +598,8 @@ static int cs35l41_system_suspend(struct device *dev)
        dev_dbg(cs35l41->dev, "System Suspend\n");
 
        if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_err(cs35l41->dev, "System Suspend not supported\n");
-               return -EINVAL;
+               dev_err_once(cs35l41->dev, "System Suspend not supported\n");
+               return 0; /* don't block the whole system suspend */
        }
 
        ret = pm_runtime_force_suspend(dev);
@@ -624,8 +624,8 @@ static int cs35l41_system_resume(struct device *dev)
        dev_dbg(cs35l41->dev, "System Resume\n");
 
        if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_err(cs35l41->dev, "System Resume not supported\n");
-               return -EINVAL;
+               dev_err_once(cs35l41->dev, "System Resume not supported\n");
+               return 0; /* don't block the whole system resume */
        }
 
        if (cs35l41->reset_gpio) {
@@ -647,6 +647,15 @@ static int cs35l41_system_resume(struct device *dev)
        return ret;
 }
 
+static int cs35l41_runtime_idle(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
+               return -EBUSY; /* suspend not supported yet on this model */
+       return 0;
+}
+
 static int cs35l41_runtime_suspend(struct device *dev)
 {
        struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
@@ -1536,7 +1545,8 @@ void cs35l41_hda_remove(struct device *dev)
 EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
 
 const struct dev_pm_ops cs35l41_hda_pm_ops = {
-       RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
+       RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
+                      cs35l41_runtime_idle)
        SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
 };
 EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);
index 1a868dd..890c2f7 100644 (file)
@@ -144,6 +144,7 @@ static int hda_codec_driver_probe(struct device *dev)
 
  error:
        snd_hda_codec_cleanup_for_unbind(codec);
+       codec->preset = NULL;
        return err;
 }
 
@@ -166,6 +167,7 @@ static int hda_codec_driver_remove(struct device *dev)
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
        snd_hda_codec_cleanup_for_unbind(codec);
+       codec->preset = NULL;
        module_put(dev->driver->owner);
        return 0;
 }
index edd653e..ac1cc7c 100644 (file)
@@ -795,7 +795,6 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec)
        snd_array_free(&codec->cvt_setups);
        snd_array_free(&codec->spdif_out);
        snd_array_free(&codec->verbs);
-       codec->preset = NULL;
        codec->follower_dig_outs = NULL;
        codec->spdif_status_reset = 0;
        snd_array_free(&codec->mixers);
index 386dd9d..9ea633f 100644 (file)
@@ -1981,6 +1981,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
        SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
        SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
        SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
+       SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
        SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
        SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
        {}
index 3794b52..1134a49 100644 (file)
@@ -3564,6 +3564,15 @@ static void alc256_init(struct hda_codec *codec)
        hda_nid_t hp_pin = alc_get_hp_pin(spec);
        bool hp_pin_sense;
 
+       if (spec->ultra_low_power) {
+               alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
+               alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
+               alc_update_coef_idx(codec, 0x08, 7<<4, 0);
+               alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
+               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
+               msleep(30);
+       }
+
        if (!hp_pin)
                hp_pin = 0x21;
 
@@ -3575,14 +3584,6 @@ static void alc256_init(struct hda_codec *codec)
                msleep(2);
 
        alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-       if (spec->ultra_low_power) {
-               alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
-               alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
-               alc_update_coef_idx(codec, 0x08, 7<<4, 0);
-               alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
-               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
-               msleep(30);
-       }
 
        snd_hda_codec_write(codec, hp_pin, 0,
                            AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
@@ -3713,6 +3714,13 @@ static void alc225_init(struct hda_codec *codec)
        hda_nid_t hp_pin = alc_get_hp_pin(spec);
        bool hp1_pin_sense, hp2_pin_sense;
 
+       if (spec->ultra_low_power) {
+               alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
+               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
+               alc_update_coef_idx(codec, 0x33, 1<<11, 0);
+               msleep(30);
+       }
+
        if (spec->codec_variant != ALC269_TYPE_ALC287 &&
                spec->codec_variant != ALC269_TYPE_ALC245)
                /* required only at boot or S3 and S4 resume time */
@@ -3734,12 +3742,6 @@ static void alc225_init(struct hda_codec *codec)
                msleep(2);
 
        alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-       if (spec->ultra_low_power) {
-               alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
-               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
-               alc_update_coef_idx(codec, 0x33, 1<<11, 0);
-               msleep(30);
-       }
 
        if (hp1_pin_sense || spec->ultra_low_power)
                snd_hda_codec_write(codec, hp_pin, 0,
@@ -4644,6 +4646,16 @@ static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
        }
 }
 
+static void alc285_fixup_hp_gpio_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->micmute_led_polarity = 1;
+       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+}
+
 static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -4665,6 +4677,13 @@ static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
        alc285_fixup_hp_coef_micmute_led(codec, fix, action);
 }
 
+static void alc285_fixup_hp_spectre_x360_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc285_fixup_hp_gpio_micmute_led(codec, fix, action);
+}
+
 static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -7106,6 +7125,7 @@ enum {
        ALC285_FIXUP_ASUS_G533Z_PINS,
        ALC285_FIXUP_HP_GPIO_LED,
        ALC285_FIXUP_HP_MUTE_LED,
+       ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
        ALC236_FIXUP_HP_GPIO_LED,
        ALC236_FIXUP_HP_MUTE_LED,
        ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
@@ -8486,6 +8506,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_hp_mute_led,
        },
+       [ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_spectre_x360_mute_led,
+       },
        [ALC236_FIXUP_HP_GPIO_LED] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc236_fixup_hp_gpio_led,
@@ -9178,6 +9202,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
+       SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
@@ -9239,6 +9264,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
        SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+       SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
        SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
@@ -9327,6 +9353,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
        SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
        SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+       SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
@@ -9396,6 +9423,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c3, "Zbook Studio G9", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
@@ -9406,6 +9434,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b7a, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b7d, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8a, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8b, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8d, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -9451,6 +9486,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
        SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
+       SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
        SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
@@ -9494,6 +9530,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
        SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
        SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
        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),
@@ -9672,6 +9709,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
        SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
        SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
+       SND_PCI_QUIRK(0x1c6c, 0x1251, "Positivo N14KP6-TG", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
        SND_PCI_QUIRK(0x1d05, 0x1096, "TongFang GMxMRxx", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x1d05, 0x1100, "TongFang GKxNRxx", ALC269_FIXUP_NO_SHUTUP),
index aea7fae..2994f85 100644 (file)
@@ -819,6 +819,9 @@ static int add_secret_dac_path(struct hda_codec *codec)
                return 0;
        nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn,
                                       ARRAY_SIZE(conn) - 1);
+       if (nums < 0)
+               return nums;
+
        for (i = 0; i < nums; i++) {
                if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)
                        return 0;
index d3f58a3..b5b0d43 100644 (file)
@@ -493,12 +493,11 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture,
                dev_dbg(chip->card->dev,
                        "CMD_08_ASK_BUFFERS: needed %d, freed %d\n",
                            *r_needed, *r_freed);
-               for (i = 0; i < MAX_STREAM_BUFFER; ++i) {
-                       for (i = 0; i != chip->rmh.stat_len; ++i)
-                               dev_dbg(chip->card->dev,
-                                       "  stat[%d]: %x, %x\n", i,
-                                           chip->rmh.stat[i],
-                                           chip->rmh.stat[i] & MASK_DATA_SIZE);
+               for (i = 0; i < MAX_STREAM_BUFFER && i < chip->rmh.stat_len;
+                    ++i) {
+                       dev_dbg(chip->card->dev, "  stat[%d]: %x, %x\n", i,
+                               chip->rmh.stat[i],
+                               chip->rmh.stat[i] & MASK_DATA_SIZE);
                }
        }
 
index 2fe8df8..8949954 100644 (file)
@@ -198,9 +198,11 @@ static int st_es8336_late_probe(struct snd_soc_card *card)
        int ret;
 
        adev = acpi_dev_get_first_match_dev("ESSX8336", NULL, -1);
-       if (adev)
-               put_device(&adev->dev);
+       if (!adev)
+               return -ENODEV;
+
        codec_dev = acpi_get_first_physical_node(adev);
+       acpi_dev_put(adev);
        if (!codec_dev)
                dev_err(card->dev, "can not find codec dev\n");
 
index 1f0b552..3631475 100644 (file)
@@ -206,6 +206,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "M5402RA"),
+               }
+       },
        {
                .driver_data = &acp6x_card,
                .matches = {
@@ -220,6 +227,34 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 14 2022"),
                }
        },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "TIMI"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Redmi Book Pro 15 2022"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Razer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Blade 14 (2022) - RZ09-0427"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "RB"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Swift SFA16-41"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "IRBIS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "15NBC1011"),
+               }
+       },
        {}
 };
 
index 2606668..3b0e715 100644 (file)
@@ -1191,18 +1191,12 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client)
        if (pdata) {
                cs42l56->pdata = *pdata;
        } else {
-               pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
-                                    GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
-
                if (i2c_client->dev.of_node) {
                        ret = cs42l56_handle_of_data(i2c_client,
                                                     &cs42l56->pdata);
                        if (ret != 0)
                                return ret;
                }
-               cs42l56->pdata = *pdata;
        }
 
        if (cs42l56->pdata.gpio_nreset) {
old mode 100755 (executable)
new mode 100644 (file)
index 9ddf6a3..28a0565
@@ -729,14 +729,16 @@ static int es8326_probe(struct snd_soc_component *component)
        }
        dev_dbg(component->dev, "jack-pol %x", es8326->jack_pol);
 
-       ret = device_property_read_u8(component->dev, "everest,interrupt-src", &es8326->jack_pol);
+       ret = device_property_read_u8(component->dev, "everest,interrupt-src",
+                                     &es8326->interrupt_src);
        if (ret != 0) {
                dev_dbg(component->dev, "interrupt-src return %d", ret);
                es8326->interrupt_src = ES8326_HP_DET_SRC_PIN9;
        }
        dev_dbg(component->dev, "interrupt-src %x", es8326->interrupt_src);
 
-       ret = device_property_read_u8(component->dev, "everest,interrupt-clk", &es8326->jack_pol);
+       ret = device_property_read_u8(component->dev, "everest,interrupt-clk",
+                                     &es8326->interrupt_clk);
        if (ret != 0) {
                dev_dbg(component->dev, "interrupt-clk return %d", ret);
                es8326->interrupt_clk = 0x45;
old mode 100755 (executable)
new mode 100644 (file)
index 3f981a9..c54ecf3 100644 (file)
@@ -167,7 +167,7 @@ static int rt715_sdca_read_prop(struct sdw_slave *slave)
        }
 
        /* set the timeout values */
-       prop->clk_stop_timeout = 20;
+       prop->clk_stop_timeout = 200;
 
        return 0;
 }
index 644300e..fcf4fba 100644 (file)
@@ -177,8 +177,20 @@ static int rt9120_codec_probe(struct snd_soc_component *comp)
        return 0;
 }
 
+static int rt9120_codec_suspend(struct snd_soc_component *comp)
+{
+       return pm_runtime_force_suspend(comp->dev);
+}
+
+static int rt9120_codec_resume(struct snd_soc_component *comp)
+{
+       return pm_runtime_force_resume(comp->dev);
+}
+
 static const struct snd_soc_component_driver rt9120_component_driver = {
        .probe = rt9120_codec_probe,
+       .suspend = rt9120_codec_suspend,
+       .resume = rt9120_codec_resume,
        .controls = rt9120_snd_controls,
        .num_controls = ARRAY_SIZE(rt9120_snd_controls),
        .dapm_widgets = rt9120_dapm_widgets,
index beb4ec6..4e38eb7 100644 (file)
@@ -154,6 +154,7 @@ static const uint32_t tas5805m_volume[] = {
 #define TAS5805M_VOLUME_MIN    0
 
 struct tas5805m_priv {
+       struct i2c_client               *i2c;
        struct regulator                *pvdd;
        struct gpio_desc                *gpio_pdn_n;
 
@@ -165,6 +166,9 @@ struct tas5805m_priv {
        int                             vol[2];
        bool                            is_powered;
        bool                            is_muted;
+
+       struct work_struct              work;
+       struct mutex                    lock;
 };
 
 static void set_dsp_scale(struct regmap *rm, int offset, int vol)
@@ -181,13 +185,11 @@ static void set_dsp_scale(struct regmap *rm, int offset, int vol)
        regmap_bulk_write(rm, offset, v, ARRAY_SIZE(v));
 }
 
-static void tas5805m_refresh(struct snd_soc_component *component)
+static void tas5805m_refresh(struct tas5805m_priv *tas5805m)
 {
-       struct tas5805m_priv *tas5805m =
-               snd_soc_component_get_drvdata(component);
        struct regmap *rm = tas5805m->regmap;
 
-       dev_dbg(component->dev, "refresh: is_muted=%d, vol=%d/%d\n",
+       dev_dbg(&tas5805m->i2c->dev, "refresh: is_muted=%d, vol=%d/%d\n",
                tas5805m->is_muted, tas5805m->vol[0], tas5805m->vol[1]);
 
        regmap_write(rm, REG_PAGE, 0x00);
@@ -201,6 +203,9 @@ static void tas5805m_refresh(struct snd_soc_component *component)
        set_dsp_scale(rm, 0x24, tas5805m->vol[0]);
        set_dsp_scale(rm, 0x28, tas5805m->vol[1]);
 
+       regmap_write(rm, REG_PAGE, 0x00);
+       regmap_write(rm, REG_BOOK, 0x00);
+
        /* Set/clear digital soft-mute */
        regmap_write(rm, REG_DEVICE_CTRL_2,
                (tas5805m->is_muted ? DCTRL2_MUTE : 0) |
@@ -226,8 +231,11 @@ static int tas5805m_vol_get(struct snd_kcontrol *kcontrol,
        struct tas5805m_priv *tas5805m =
                snd_soc_component_get_drvdata(component);
 
+       mutex_lock(&tas5805m->lock);
        ucontrol->value.integer.value[0] = tas5805m->vol[0];
        ucontrol->value.integer.value[1] = tas5805m->vol[1];
+       mutex_unlock(&tas5805m->lock);
+
        return 0;
 }
 
@@ -243,11 +251,13 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
                snd_soc_kcontrol_component(kcontrol);
        struct tas5805m_priv *tas5805m =
                snd_soc_component_get_drvdata(component);
+       int ret = 0;
 
        if (!(volume_is_valid(ucontrol->value.integer.value[0]) &&
              volume_is_valid(ucontrol->value.integer.value[1])))
                return -EINVAL;
 
+       mutex_lock(&tas5805m->lock);
        if (tas5805m->vol[0] != ucontrol->value.integer.value[0] ||
            tas5805m->vol[1] != ucontrol->value.integer.value[1]) {
                tas5805m->vol[0] = ucontrol->value.integer.value[0];
@@ -256,11 +266,12 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
                        tas5805m->vol[0], tas5805m->vol[1],
                        tas5805m->is_powered);
                if (tas5805m->is_powered)
-                       tas5805m_refresh(component);
-               return 1;
+                       tas5805m_refresh(tas5805m);
+               ret = 1;
        }
+       mutex_unlock(&tas5805m->lock);
 
-       return 0;
+       return ret;
 }
 
 static const struct snd_kcontrol_new tas5805m_snd_controls[] = {
@@ -294,54 +305,83 @@ static int tas5805m_trigger(struct snd_pcm_substream *substream, int cmd,
        struct snd_soc_component *component = dai->component;
        struct tas5805m_priv *tas5805m =
                snd_soc_component_get_drvdata(component);
-       struct regmap *rm = tas5805m->regmap;
-       unsigned int chan, global1, global2;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               dev_dbg(component->dev, "DSP startup\n");
-
-               /* We mustn't issue any I2C transactions until the I2S
-                * clock is stable. Furthermore, we must allow a 5ms
-                * delay after the first set of register writes to
-                * allow the DSP to boot before configuring it.
-                */
-               usleep_range(5000, 10000);
-               send_cfg(rm, dsp_cfg_preboot,
-                       ARRAY_SIZE(dsp_cfg_preboot));
-               usleep_range(5000, 15000);
-               send_cfg(rm, tas5805m->dsp_cfg_data,
-                       tas5805m->dsp_cfg_len);
-
-               tas5805m->is_powered = true;
-               tas5805m_refresh(component);
+               dev_dbg(component->dev, "clock start\n");
+               schedule_work(&tas5805m->work);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               dev_dbg(component->dev, "DSP shutdown\n");
+               break;
 
-               tas5805m->is_powered = false;
+       default:
+               return -EINVAL;
+       }
 
-               regmap_write(rm, REG_PAGE, 0x00);
-               regmap_write(rm, REG_BOOK, 0x00);
+       return 0;
+}
 
-               regmap_read(rm, REG_CHAN_FAULT, &chan);
-               regmap_read(rm, REG_GLOBAL_FAULT1, &global1);
-               regmap_read(rm, REG_GLOBAL_FAULT2, &global2);
+static void do_work(struct work_struct *work)
+{
+       struct tas5805m_priv *tas5805m =
+              container_of(work, struct tas5805m_priv, work);
+       struct regmap *rm = tas5805m->regmap;
 
-               dev_dbg(component->dev,
-                       "fault regs: CHAN=%02x, GLOBAL1=%02x, GLOBAL2=%02x\n",
-                       chan, global1, global2);
+       dev_dbg(&tas5805m->i2c->dev, "DSP startup\n");
 
-               regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ);
-               break;
+       mutex_lock(&tas5805m->lock);
+       /* We mustn't issue any I2C transactions until the I2S
+        * clock is stable. Furthermore, we must allow a 5ms
+        * delay after the first set of register writes to
+        * allow the DSP to boot before configuring it.
+        */
+       usleep_range(5000, 10000);
+       send_cfg(rm, dsp_cfg_preboot, ARRAY_SIZE(dsp_cfg_preboot));
+       usleep_range(5000, 15000);
+       send_cfg(rm, tas5805m->dsp_cfg_data, tas5805m->dsp_cfg_len);
+
+       tas5805m->is_powered = true;
+       tas5805m_refresh(tas5805m);
+       mutex_unlock(&tas5805m->lock);
+}
 
-       default:
-               return -EINVAL;
+static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct tas5805m_priv *tas5805m =
+               snd_soc_component_get_drvdata(component);
+       struct regmap *rm = tas5805m->regmap;
+
+       if (event & SND_SOC_DAPM_PRE_PMD) {
+               unsigned int chan, global1, global2;
+
+               dev_dbg(component->dev, "DSP shutdown\n");
+               cancel_work_sync(&tas5805m->work);
+
+               mutex_lock(&tas5805m->lock);
+               if (tas5805m->is_powered) {
+                       tas5805m->is_powered = false;
+
+                       regmap_write(rm, REG_PAGE, 0x00);
+                       regmap_write(rm, REG_BOOK, 0x00);
+
+                       regmap_read(rm, REG_CHAN_FAULT, &chan);
+                       regmap_read(rm, REG_GLOBAL_FAULT1, &global1);
+                       regmap_read(rm, REG_GLOBAL_FAULT2, &global2);
+
+                       dev_dbg(component->dev, "fault regs: CHAN=%02x, "
+                               "GLOBAL1=%02x, GLOBAL2=%02x\n",
+                               chan, global1, global2);
+
+                       regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ);
+               }
+               mutex_unlock(&tas5805m->lock);
        }
 
        return 0;
@@ -354,7 +394,8 @@ static const struct snd_soc_dapm_route tas5805m_audio_map[] = {
 
 static const struct snd_soc_dapm_widget tas5805m_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0,
+               tas5805m_dac_event, SND_SOC_DAPM_PRE_PMD),
        SND_SOC_DAPM_OUTPUT("OUT")
 };
 
@@ -375,11 +416,14 @@ static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction)
        struct tas5805m_priv *tas5805m =
                snd_soc_component_get_drvdata(component);
 
+       mutex_lock(&tas5805m->lock);
        dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n",
                mute, tas5805m->is_powered);
+
        tas5805m->is_muted = mute;
        if (tas5805m->is_powered)
-               tas5805m_refresh(component);
+               tas5805m_refresh(tas5805m);
+       mutex_unlock(&tas5805m->lock);
 
        return 0;
 }
@@ -434,6 +478,7 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
        if (!tas5805m)
                return -ENOMEM;
 
+       tas5805m->i2c = i2c;
        tas5805m->pvdd = devm_regulator_get(dev, "pvdd");
        if (IS_ERR(tas5805m->pvdd)) {
                dev_err(dev, "failed to get pvdd supply: %ld\n",
@@ -507,6 +552,9 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
        gpiod_set_value(tas5805m->gpio_pdn_n, 1);
        usleep_range(10000, 15000);
 
+       INIT_WORK(&tas5805m->work, do_work);
+       mutex_init(&tas5805m->lock);
+
        /* Don't register through devm. We need to be able to unregister
         * the component prior to deasserting PDN#
         */
@@ -527,6 +575,7 @@ static void tas5805m_i2c_remove(struct i2c_client *i2c)
        struct device *dev = &i2c->dev;
        struct tas5805m_priv *tas5805m = dev_get_drvdata(dev);
 
+       cancel_work_sync(&tas5805m->work);
        snd_soc_unregister_component(dev);
        gpiod_set_value(tas5805m->gpio_pdn_n, 0);
        usleep_range(10000, 15000);
index ca6a01a..791d873 100644 (file)
@@ -697,6 +697,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
        int dcs_mask;
        int dcs_l, dcs_r;
        int dcs_l_reg, dcs_r_reg;
+       int an_out_reg;
        int timeout;
        int pwr_reg;
 
@@ -712,6 +713,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
                dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
                dcs_r_reg = WM8904_DC_SERVO_8;
                dcs_l_reg = WM8904_DC_SERVO_9;
+               an_out_reg = WM8904_ANALOGUE_OUT1_LEFT;
                dcs_l = 0;
                dcs_r = 1;
                break;
@@ -720,6 +722,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
                dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
                dcs_r_reg = WM8904_DC_SERVO_6;
                dcs_l_reg = WM8904_DC_SERVO_7;
+               an_out_reg = WM8904_ANALOGUE_OUT2_LEFT;
                dcs_l = 2;
                dcs_r = 3;
                break;
@@ -792,6 +795,10 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
                snd_soc_component_update_bits(component, reg,
                                    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
                                    WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
+
+               /* Update volume, requires PGA to be powered */
+               val = snd_soc_component_read(component, an_out_reg);
+               snd_soc_component_write(component, an_out_reg, val);
                break;
 
        case SND_SOC_DAPM_POST_PMU:
index 966ba49..58fdb4e 100644 (file)
@@ -1359,8 +1359,8 @@ static struct snd_soc_dai_driver wsa883x_dais[] = {
                        .stream_name = "SPKR Playback",
                        .rates = WSA883X_RATES | WSA883X_FRAC_RATES,
                        .formats = WSA883X_FORMATS,
-                       .rate_max = 8000,
-                       .rate_min = 352800,
+                       .rate_min = 8000,
+                       .rate_max = 352800,
                        .channels_min = 1,
                        .channels_max = 1,
                },
index c836848..8d14b55 100644 (file)
@@ -121,11 +121,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static const struct snd_soc_dapm_route audio_map_ac97[] = {
        /* 1st half -- Normal DAPM routes */
-       {"Playback",  NULL, "AC97 Playback"},
-       {"AC97 Capture",  NULL, "Capture"},
+       {"AC97 Playback",  NULL, "CPU AC97 Playback"},
+       {"CPU AC97 Capture",  NULL, "AC97 Capture"},
        /* 2nd half -- ASRC DAPM routes */
-       {"AC97 Playback",  NULL, "ASRC-Playback"},
-       {"ASRC-Capture",  NULL, "AC97 Capture"},
+       {"CPU AC97 Playback",  NULL, "ASRC-Playback"},
+       {"ASRC-Capture",  NULL, "CPU AC97 Capture"},
 };
 
 static const struct snd_soc_dapm_route audio_map_tx[] = {
index 7b17f15..94341e4 100644 (file)
@@ -315,21 +315,21 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
 
 static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
        SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(0), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(1), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(2), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(3), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(4), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(5), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(6), 0x8, 0xF, gain_tlv),
        SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
-                         MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv),
+                         MICFIL_OUTGAIN_CHX_SHIFT(7), 0x8, 0xF, gain_tlv),
        SOC_ENUM_EXT("MICFIL Quality Select",
                     fsl_micfil_quality_enum,
                     micfil_quality_get, micfil_quality_set),
index 1c9be8a..35a52c3 100644 (file)
@@ -1141,6 +1141,7 @@ static int fsl_sai_check_version(struct device *dev)
 
        sai->verid.version = val &
                (FSL_SAI_VERID_MAJOR_MASK | FSL_SAI_VERID_MINOR_MASK);
+       sai->verid.version >>= FSL_SAI_VERID_MINOR_SHIFT;
        sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK;
 
        ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
index c9e0e31..46a5355 100644 (file)
@@ -1189,14 +1189,14 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
        .symmetric_channels = 1,
        .probe = fsl_ssi_dai_probe,
        .playback = {
-               .stream_name = "AC97 Playback",
+               .stream_name = "CPU AC97 Playback",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S20,
        },
        .capture = {
-               .stream_name = "AC97 Capture",
+               .stream_name = "CPU AC97 Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_48000,
index 2ca2427..6375018 100644 (file)
@@ -481,6 +481,29 @@ err_remap_bar0:
        return ret;
 }
 
+static void avs_pci_shutdown(struct pci_dev *pci)
+{
+       struct hdac_bus *bus = pci_get_drvdata(pci);
+       struct avs_dev *adev = hdac_to_avs(bus);
+
+       cancel_work_sync(&adev->probe_work);
+       avs_ipc_block(adev->ipc);
+
+       snd_hdac_stop_streams(bus);
+       avs_dsp_op(adev, int_control, false);
+       snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+       snd_hdac_ext_bus_link_power_down_all(bus);
+
+       snd_hdac_bus_stop_chip(bus);
+       snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+
+       if (avs_platattr_test(adev, CLDMA))
+               pci_free_irq(pci, 0, &code_loader);
+       pci_free_irq(pci, 0, adev);
+       pci_free_irq(pci, 0, bus);
+       pci_free_irq_vectors(pci);
+}
+
 static void avs_pci_remove(struct pci_dev *pci)
 {
        struct hdac_device *hdev, *save;
@@ -739,6 +762,7 @@ static struct pci_driver avs_pci_driver = {
        .id_table = avs_ids,
        .probe = avs_pci_probe,
        .remove = avs_pci_remove,
+       .shutdown = avs_pci_shutdown,
        .driver = {
                .pm = &avs_dev_pm,
        },
index a472de1..99308ed 100644 (file)
@@ -554,10 +554,12 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH
        select SND_SOC_RT1015P
        select SND_SOC_MAX98373_I2C
        select SND_SOC_MAX98357A
+       select SND_SOC_NAU8315
        select SND_SOC_DMIC
        select SND_SOC_HDAC_HDMI
        select SND_SOC_INTEL_HDA_DSP_COMMON
        select SND_SOC_INTEL_SOF_MAXIM_COMMON
+       select SND_SOC_INTEL_SOF_REALTEK_COMMON
        help
           This adds support for ASoC machine driver for SOF platforms
           with nau8825 codec.
index 09d1f0f..df157b0 100644 (file)
@@ -497,21 +497,28 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
        if (adev) {
                snprintf(codec_name, sizeof(codec_name),
                         "i2c-%s", acpi_dev_name(adev));
-               put_device(&adev->dev);
                byt_cht_es8316_dais[dai_index].codecs->name = codec_name;
        } else {
                dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
                return -ENXIO;
        }
 
+       codec_dev = acpi_get_first_physical_node(adev);
+       acpi_dev_put(adev);
+       if (!codec_dev)
+               return -EPROBE_DEFER;
+       priv->codec_dev = get_device(codec_dev);
+
        /* override platform name, if required */
        byt_cht_es8316_card.dev = dev;
        platform_name = mach->mach_params.platform;
 
        ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card,
                                                    platform_name);
-       if (ret)
+       if (ret) {
+               put_device(codec_dev);
                return ret;
+       }
 
        /* Check for BYTCR or other platform and setup quirks */
        dmi_id = dmi_first_match(byt_cht_es8316_quirk_table);
@@ -539,13 +546,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev)
 
        /* get the clock */
        priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3");
-       if (IS_ERR(priv->mclk))
+       if (IS_ERR(priv->mclk)) {
+               put_device(codec_dev);
                return dev_err_probe(dev, PTR_ERR(priv->mclk), "clk_get pmc_plt_clk_3 failed\n");
-
-       codec_dev = acpi_get_first_physical_node(adev);
-       if (!codec_dev)
-               return -EPROBE_DEFER;
-       priv->codec_dev = get_device(codec_dev);
+       }
 
        if (quirk & BYT_CHT_ES8316_JD_INVERTED)
                props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted");
index 4699ca7..79e0039 100644 (file)
@@ -1636,13 +1636,18 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
        if (adev) {
                snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
                         "i2c-%s", acpi_dev_name(adev));
-               put_device(&adev->dev);
                byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name;
        } else {
                dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
                return -ENXIO;
        }
 
+       codec_dev = acpi_get_first_physical_node(adev);
+       acpi_dev_put(adev);
+       if (!codec_dev)
+               return -EPROBE_DEFER;
+       priv->codec_dev = get_device(codec_dev);
+
        /*
         * swap SSP0 if bytcr is detected
         * (will be overridden if DMI quirk is detected)
@@ -1717,11 +1722,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
                byt_rt5640_quirk = quirk_override;
        }
 
-       codec_dev = acpi_get_first_physical_node(adev);
-       if (!codec_dev)
-               return -EPROBE_DEFER;
-       priv->codec_dev = get_device(codec_dev);
-
        if (byt_rt5640_quirk & BYT_RT5640_JD_HP_ELITEP_1000G2) {
                acpi_dev_add_driver_gpios(ACPI_COMPANION(priv->codec_dev),
                                          byt_rt5640_hp_elitepad_1000g2_gpios);
index 81ac6ee..8fca9b8 100644 (file)
@@ -922,7 +922,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
        if (adev) {
                snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name),
                         "i2c-%s", acpi_dev_name(adev));
-               put_device(&adev->dev);
                byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name;
        } else {
                dev_err(dev, "Error cannot find '%s' dev\n", mach->id);
@@ -930,6 +929,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
        }
 
        codec_dev = acpi_get_first_physical_node(adev);
+       acpi_dev_put(adev);
        if (!codec_dev)
                return -EPROBE_DEFER;
        priv->codec_dev = get_device(codec_dev);
index 1669eb3..c070653 100644 (file)
@@ -411,9 +411,9 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
                return -ENOENT;
        }
        snprintf(codec_name, sizeof(codec_name), "spi-%s", acpi_dev_name(adev));
-       put_device(&adev->dev);
 
        codec_dev = bus_find_device_by_name(&spi_bus_type, NULL, codec_name);
+       acpi_dev_put(adev);
        if (!codec_dev)
                return -EPROBE_DEFER;
 
index e38bd28..e9d190c 100644 (file)
@@ -336,6 +336,9 @@ static int create_spk_amp_dai_links(struct device *dev,
        links[*id].platforms = platform_component;
        links[*id].num_platforms = ARRAY_SIZE(platform_component);
        links[*id].dpcm_playback = 1;
+       /* firmware-generated echo reference */
+       links[*id].dpcm_capture = 1;
+
        links[*id].no_pcm = 1;
        links[*id].cpus = &cpus[*id];
        links[*id].num_cpus = 1;
index 773e5d1..894b661 100644 (file)
@@ -681,7 +681,6 @@ static int sof_es8336_probe(struct platform_device *pdev)
        if (adev) {
                snprintf(codec_name, sizeof(codec_name),
                         "i2c-%s", acpi_dev_name(adev));
-               put_device(&adev->dev);
                dai_links[0].codecs->name = codec_name;
 
                /* also fixup codec dai name if relevant */
@@ -692,16 +691,19 @@ static int sof_es8336_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card,
-                                                   mach->mach_params.platform);
-       if (ret)
-               return ret;
-
        codec_dev = acpi_get_first_physical_node(adev);
+       acpi_dev_put(adev);
        if (!codec_dev)
                return -EPROBE_DEFER;
        priv->codec_dev = get_device(codec_dev);
 
+       ret = snd_soc_fixup_dai_links_platform_name(&sof_es8336_card,
+                                                   mach->mach_params.platform);
+       if (ret) {
+               put_device(codec_dev);
+               return ret;
+       }
+
        if (quirk & SOF_ES8336_JD_INVERTED)
                props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted");
 
index 2788022..6794a02 100644 (file)
@@ -48,6 +48,7 @@
 #define SOF_MAX98373_SPEAKER_AMP_PRESENT       BIT(15)
 #define SOF_MAX98360A_SPEAKER_AMP_PRESENT      BIT(16)
 #define SOF_RT1015P_SPEAKER_AMP_PRESENT        BIT(17)
+#define SOF_NAU8318_SPEAKER_AMP_PRESENT        BIT(18)
 
 static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0);
 
@@ -338,6 +339,13 @@ static struct snd_soc_dai_link_component rt1019p_component[] = {
        }
 };
 
+static struct snd_soc_dai_link_component nau8318_components[] = {
+       {
+               .name = "NVTN2012:00",
+               .dai_name = "nau8315-hifi",
+       }
+};
+
 static struct snd_soc_dai_link_component dummy_component[] = {
        {
                .name = "snd-soc-dummy",
@@ -479,13 +487,16 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                        links[id].num_codecs = ARRAY_SIZE(max_98373_components);
                        links[id].init = max_98373_spk_codec_init;
                        links[id].ops = &max_98373_ops;
-                       /* feedback stream */
-                       links[id].dpcm_capture = 1;
                } else if (sof_nau8825_quirk &
                                SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
                        max_98360a_dai_link(&links[id]);
                } else if (sof_nau8825_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) {
                        sof_rt1015p_dai_link(&links[id]);
+               } else if (sof_nau8825_quirk &
+                               SOF_NAU8318_SPEAKER_AMP_PRESENT) {
+                       links[id].codecs = nau8318_components;
+                       links[id].num_codecs = ARRAY_SIZE(nau8318_components);
+                       links[id].init = speaker_codec_init;
                } else {
                        goto devm_err;
                }
@@ -493,6 +504,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                links[id].platforms = platform_component;
                links[id].num_platforms = ARRAY_SIZE(platform_component);
                links[id].dpcm_playback = 1;
+               /* feedback stream or firmware-generated echo reference */
+               links[id].dpcm_capture = 1;
+
                links[id].no_pcm = 1;
                links[id].cpus = &cpus[id];
                links[id].num_cpus = 1;
@@ -618,7 +632,7 @@ static const struct platform_device_id board_ids[] = {
 
        },
        {
-               .name = "adl_rt1019p_nau8825",
+               .name = "adl_rt1019p_8825",
                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
                                        SOF_SPEAKER_AMP_PRESENT |
                                        SOF_RT1019P_SPEAKER_AMP_PRESENT |
@@ -626,7 +640,7 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_NAU8825_NUM_HDMIDEV(4)),
        },
        {
-               .name = "adl_max98373_nau8825",
+               .name = "adl_max98373_8825",
                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
                                        SOF_SPEAKER_AMP_PRESENT |
                                        SOF_MAX98373_SPEAKER_AMP_PRESENT |
@@ -637,7 +651,7 @@ static const struct platform_device_id board_ids[] = {
        },
        {
                /* The limitation of length of char array, shorten the name */
-               .name = "adl_mx98360a_nau8825",
+               .name = "adl_mx98360a_8825",
                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
                                        SOF_SPEAKER_AMP_PRESENT |
                                        SOF_MAX98360A_SPEAKER_AMP_PRESENT |
@@ -648,7 +662,7 @@ static const struct platform_device_id board_ids[] = {
 
        },
        {
-               .name = "adl_rt1015p_nau8825",
+               .name = "adl_rt1015p_8825",
                .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
                                        SOF_SPEAKER_AMP_PRESENT |
                                        SOF_RT1015P_SPEAKER_AMP_PRESENT |
@@ -657,6 +671,16 @@ static const struct platform_device_id board_ids[] = {
                                        SOF_BT_OFFLOAD_SSP(2) |
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
        },
+       {
+               .name = "adl_nau8318_8825",
+               .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) |
+                                       SOF_SPEAKER_AMP_PRESENT |
+                                       SOF_NAU8318_SPEAKER_AMP_PRESENT |
+                                       SOF_NAU8825_SSP_AMP(1) |
+                                       SOF_NAU8825_NUM_HDMIDEV(4) |
+                                       SOF_BT_OFFLOAD_SSP(2) |
+                                       SOF_SSP_BT_OFFLOAD_PRESENT),
+       },
        { }
 };
 MODULE_DEVICE_TABLE(platform, board_ids);
index 2eabc4b..71a11d7 100644 (file)
@@ -761,8 +761,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                        links[id].num_codecs = ARRAY_SIZE(max_98373_components);
                        links[id].init = max_98373_spk_codec_init;
                        links[id].ops = &max_98373_ops;
-                       /* feedback stream */
-                       links[id].dpcm_capture = 1;
                } else if (sof_rt5682_quirk &
                                SOF_MAX98360A_SPEAKER_AMP_PRESENT) {
                        max_98360a_dai_link(&links[id]);
@@ -789,6 +787,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                links[id].platforms = platform_component;
                links[id].num_platforms = ARRAY_SIZE(platform_component);
                links[id].dpcm_playback = 1;
+               /* feedback stream or firmware-generated echo reference */
+               links[id].dpcm_capture = 1;
+
                links[id].no_pcm = 1;
                links[id].cpus = &cpus[id];
                links[id].num_cpus = 1;
index 94d25ae..7b74f12 100644 (file)
@@ -258,13 +258,12 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
                sof_rt1308_dai_link(&links[id]);
        } else if (sof_ssp_amp_quirk & SOF_CS35L41_SPEAKER_AMP_PRESENT) {
                cs35l41_set_dai_link(&links[id]);
-
-               /* feedback from amplifier */
-               links[id].dpcm_capture = 1;
        }
        links[id].platforms = platform_component;
        links[id].num_platforms = ARRAY_SIZE(platform_component);
        links[id].dpcm_playback = 1;
+       /* feedback from amplifier or firmware-generated echo reference */
+       links[id].dpcm_capture = 1;
        links[id].no_pcm = 1;
        links[id].cpus = &cpus[id];
        links[id].num_cpus = 1;
index 60aee56..56ee5fe 100644 (file)
@@ -450,6 +450,11 @@ static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = {
        .codecs = {"INTC10B0"}
 };
 
+static const struct snd_soc_acpi_codecs adl_nau8318_amp = {
+       .num_codecs = 1,
+       .codecs = {"NVTN2012"}
+};
+
 struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
        {
                .comp_ids = &adl_rt5682_rt5682s_hp,
@@ -474,21 +479,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
        },
        {
                .id = "10508825",
-               .drv_name = "adl_rt1019p_nau8825",
+               .drv_name = "adl_rt1019p_8825",
                .machine_quirk = snd_soc_acpi_codec_list,
                .quirk_data = &adl_rt1019p_amp,
                .sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg",
        },
        {
                .id = "10508825",
-               .drv_name = "adl_max98373_nau8825",
+               .drv_name = "adl_max98373_8825",
                .machine_quirk = snd_soc_acpi_codec_list,
                .quirk_data = &adl_max98373_amp,
                .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg",
        },
        {
                .id = "10508825",
-               .drv_name = "adl_mx98360a_nau8825",
+               .drv_name = "adl_mx98360a_8825",
                .machine_quirk = snd_soc_acpi_codec_list,
                .quirk_data = &adl_max98360a_amp,
                .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg",
@@ -502,11 +507,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = {
        },
        {
                .id = "10508825",
-               .drv_name = "adl_rt1015p_nau8825",
+               .drv_name = "adl_rt1015p_8825",
                .machine_quirk = snd_soc_acpi_codec_list,
                .quirk_data = &adl_rt1015p_amp,
                .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg",
        },
+       {
+               .id = "10508825",
+               .drv_name = "adl_nau8318_8825",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &adl_nau8318_amp,
+               .sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg",
+       },
        {
                .id = "10508825",
                .drv_name = "sof_nau8825",
index 31b4311..07f96a1 100644 (file)
@@ -203,6 +203,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01_rt71
        {}
 };
 
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link2_rt1316_link01[] = {
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
+               .adr_d = rt711_sdca_2_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+               .adr_d = rt1316_0_group2_adr,
+       },
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+               .adr_d = rt1316_1_group2_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt714_link3[] = {
        {
                .mask = BIT(0),
@@ -227,6 +246,25 @@ static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12_rt71
        {}
 };
 
+static const struct snd_soc_acpi_link_adr rpl_sdw_rt711_link0_rt1318_link12[] = {
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt711_sdca_0_adr),
+               .adr_d = rt711_sdca_0_adr,
+       },
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1318_1_group1_adr),
+               .adr_d = rt1318_1_group1_adr,
+       },
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1318_2_group1_adr),
+               .adr_d = rt1318_2_group1_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_link_adr rpl_sdw_rt1316_link12_rt714_link0[] = {
        {
                .mask = BIT(1),
@@ -271,12 +309,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = {
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12-rt714-l3.tplg",
        },
+       {
+               .link_mask = 0x7, /* rt711 on link0 & two rt1318s on link1 and link2 */
+               .links = rpl_sdw_rt711_link0_rt1318_link12,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-rpl-rt711-l0-rt1318-l12.tplg",
+       },
        {
                .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
                .links = rpl_sdw_rt1316_link12_rt714_link0,
                .drv_name = "sof_sdw",
                .sof_tplg_filename = "sof-rpl-rt1316-l12-rt714-l0.tplg",
        },
+       {
+               .link_mask = 0x7, /* rt711 on link2 & two rt1316s on link0 and link1 */
+               .links = rpl_sdw_rt711_link2_rt1316_link01,
+               .drv_name = "sof_sdw",
+               .sof_tplg_filename = "sof-rpl-rt711-l2-rt1316-l01.tplg",
+       },
        {
                .link_mask = 0x1, /* link0 required */
                .links = rpl_rvp,
index 363fa4d..b027fba 100644 (file)
@@ -182,10 +182,12 @@ config SND_SOC_MT8186_MT6366_DA7219_MAX98357
          If unsure select "N".
 
 config SND_SOC_MT8186_MT6366_RT1019_RT5682S
-       tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S codec"
+       tristate "ASoC Audio driver for MT8186 with RT1019 RT5682S MAX98357A/MAX98360 codec"
        depends on I2C && GPIOLIB
        depends on SND_SOC_MT8186 && MTK_PMIC_WRAP
+       select SND_SOC_MAX98357A
        select SND_SOC_MT6358
+       select SND_SOC_MAX98357A
        select SND_SOC_RT1015P
        select SND_SOC_RT5682S
        select SND_SOC_BT_SCO
index 8f77a0b..af44e33 100644 (file)
@@ -1083,6 +1083,21 @@ static struct snd_soc_card mt8186_mt6366_rt1019_rt5682s_soc_card = {
        .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
 };
 
+static struct snd_soc_card mt8186_mt6366_rt5682s_max98360_soc_card = {
+       .name = "mt8186_rt5682s_max98360",
+       .owner = THIS_MODULE,
+       .dai_link = mt8186_mt6366_rt1019_rt5682s_dai_links,
+       .num_links = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_dai_links),
+       .controls = mt8186_mt6366_rt1019_rt5682s_controls,
+       .num_controls = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_controls),
+       .dapm_widgets = mt8186_mt6366_rt1019_rt5682s_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_widgets),
+       .dapm_routes = mt8186_mt6366_rt1019_rt5682s_routes,
+       .num_dapm_routes = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_routes),
+       .codec_conf = mt8186_mt6366_rt1019_rt5682s_codec_conf,
+       .num_configs = ARRAY_SIZE(mt8186_mt6366_rt1019_rt5682s_codec_conf),
+};
+
 static int mt8186_mt6366_rt1019_rt5682s_dev_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card;
@@ -1232,9 +1247,14 @@ err_adsp_node:
 
 #if IS_ENABLED(CONFIG_OF)
 static const struct of_device_id mt8186_mt6366_rt1019_rt5682s_dt_match[] = {
-       {       .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
+       {
+               .compatible = "mediatek,mt8186-mt6366-rt1019-rt5682s-sound",
                .data = &mt8186_mt6366_rt1019_rt5682s_soc_card,
        },
+       {
+               .compatible = "mediatek,mt8186-mt6366-rt5682s-max98360-sound",
+               .data = &mt8186_mt6366_rt5682s_max98360_soc_card,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, mt8186_mt6366_rt1019_rt5682s_dt_match);
index 96a6d47..e7b00d1 100644 (file)
@@ -2,7 +2,6 @@
 menuconfig SND_SOC_QCOM
        tristate "ASoC support for QCOM platforms"
        depends on ARCH_QCOM || COMPILE_TEST
-       imply SND_SOC_QCOM_COMMON
        help
          Say Y or M if you want to add support to use audio devices
          in Qualcomm Technologies SOC-based platforms.
@@ -60,14 +59,16 @@ config SND_SOC_STORM
 config SND_SOC_APQ8016_SBC
        tristate "SoC Audio support for APQ8016 SBC platforms"
        select SND_SOC_LPASS_APQ8016
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
        help
          Support for Qualcomm Technologies LPASS audio block in
          APQ8016 SOC-based systems.
          Say Y if you want to use audio devices on MI2S.
 
 config SND_SOC_QCOM_COMMON
-       depends on SOUNDWIRE
+       tristate
+
+config SND_SOC_QCOM_SDW
        tristate
 
 config SND_SOC_QDSP6_COMMON
@@ -144,7 +145,7 @@ config SND_SOC_MSM8996
        depends on QCOM_APR
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
        help
          Support for Qualcomm Technologies LPASS audio block in
          APQ8096 SoC-based systems.
@@ -155,7 +156,7 @@ config SND_SOC_SDM845
        depends on QCOM_APR && I2C && SOUNDWIRE
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
        select SND_SOC_RT5663
        select SND_SOC_MAX98927
        imply SND_SOC_CROS_EC_CODEC
@@ -169,7 +170,8 @@ config SND_SOC_SM8250
        depends on QCOM_APR && SOUNDWIRE
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_SDW
        help
          To add support for audio on Qualcomm Technologies Inc.
          SM8250 SoC-based systems.
@@ -180,7 +182,8 @@ config SND_SOC_SC8280XP
        depends on QCOM_APR && SOUNDWIRE
        depends on COMMON_CLK
        select SND_SOC_QDSP6
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_SDW
        help
          To add support for audio on Qualcomm Technologies Inc.
          SC8280XP SoC-based systems.
@@ -190,7 +193,7 @@ config SND_SOC_SC7180
        tristate "SoC Machine driver for SC7180 boards"
        depends on I2C && GPIOLIB
        depends on SOUNDWIRE || SOUNDWIRE=n
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
        select SND_SOC_LPASS_SC7180
        select SND_SOC_MAX98357A
        select SND_SOC_RT5682_I2C
@@ -204,7 +207,7 @@ config SND_SOC_SC7180
 config SND_SOC_SC7280
        tristate "SoC Machine driver for SC7280 boards"
        depends on I2C && SOUNDWIRE
-       depends on SND_SOC_QCOM_COMMON
+       select SND_SOC_QCOM_COMMON
        select SND_SOC_LPASS_SC7280
        select SND_SOC_MAX98357A
        select SND_SOC_WCD938X_SDW
index 8b97172..254350d 100644 (file)
@@ -28,6 +28,7 @@ snd-soc-sdm845-objs := sdm845.o
 snd-soc-sm8250-objs := sm8250.o
 snd-soc-sc8280xp-objs := sc8280xp.o
 snd-soc-qcom-common-objs := common.o
+snd-soc-qcom-sdw-objs := sdw.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
 obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o
 obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
 obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
 obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
+obj-$(CONFIG_SND_SOC_QCOM_SDW) += snd-soc-qcom-sdw.o
 
 #DSP lib
 obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
index 49c74c1..96fe802 100644 (file)
@@ -180,120 +180,6 @@ err_put_np:
 }
 EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
 
-int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
-                        struct sdw_stream_runtime *sruntime,
-                        bool *stream_prepared)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       int ret;
-
-       if (!sruntime)
-               return 0;
-
-       switch (cpu_dai->id) {
-       case WSA_CODEC_DMA_RX_0:
-       case WSA_CODEC_DMA_RX_1:
-       case RX_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_1:
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               break;
-       default:
-               return 0;
-       }
-
-       if (*stream_prepared) {
-               sdw_disable_stream(sruntime);
-               sdw_deprepare_stream(sruntime);
-               *stream_prepared = false;
-       }
-
-       ret = sdw_prepare_stream(sruntime);
-       if (ret)
-               return ret;
-
-       /**
-        * NOTE: there is a strict hw requirement about the ordering of port
-        * enables and actual WSA881x PA enable. PA enable should only happen
-        * after soundwire ports are enabled if not DC on the line is
-        * accumulated resulting in Click/Pop Noise
-        * PA enable/mute are handled as part of codec DAPM and digital mute.
-        */
-
-       ret = sdw_enable_stream(sruntime);
-       if (ret) {
-               sdw_deprepare_stream(sruntime);
-               return ret;
-       }
-       *stream_prepared  = true;
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
-
-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
-                          struct snd_pcm_hw_params *params,
-                          struct sdw_stream_runtime **psruntime)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai;
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       struct sdw_stream_runtime *sruntime;
-       int i;
-
-       switch (cpu_dai->id) {
-       case WSA_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_1:
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               for_each_rtd_codec_dais(rtd, i, codec_dai) {
-                       sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
-                       if (sruntime != ERR_PTR(-ENOTSUPP))
-                               *psruntime = sruntime;
-               }
-               break;
-       }
-
-       return 0;
-
-}
-EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
-
-int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
-                        struct sdw_stream_runtime *sruntime, bool *stream_prepared)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-
-       switch (cpu_dai->id) {
-       case WSA_CODEC_DMA_RX_0:
-       case WSA_CODEC_DMA_RX_1:
-       case RX_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_1:
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               if (sruntime && *stream_prepared) {
-                       sdw_disable_stream(sruntime);
-                       sdw_deprepare_stream(sruntime);
-                       *stream_prepared = false;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
-
 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
                            struct snd_soc_jack *jack, bool *jack_setup)
 {
index 3ef5bb6..d7f80ee 100644 (file)
@@ -5,19 +5,9 @@
 #define __QCOM_SND_COMMON_H__
 
 #include <sound/soc.h>
-#include <linux/soundwire/sdw.h>
 
 int qcom_snd_parse_of(struct snd_soc_card *card);
 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
                            struct snd_soc_jack *jack, bool *jack_setup);
 
-int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
-                        struct sdw_stream_runtime *runtime,
-                        bool *stream_prepared);
-int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
-                          struct snd_pcm_hw_params *params,
-                          struct sdw_stream_runtime **psruntime);
-int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
-                        struct sdw_stream_runtime *sruntime,
-                        bool *stream_prepared);
 #endif
index 5435384..dbdaaa8 100644 (file)
@@ -1037,10 +1037,11 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
                                        struct lpass_data *data)
 {
        struct device_node *node;
-       int ret, id;
+       int ret, i, id;
 
        /* Allow all channels by default for backwards compatibility */
-       for (id = 0; id < data->variant->num_dai; id++) {
+       for (i = 0; i < data->variant->num_dai; i++) {
+               id = data->variant->dai_driver[i].id;
                data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
                data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
        }
index ade44ad..14d9fea 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/input-event-codes.h>
 #include "qdsp6/q6afe.h"
 #include "common.h"
+#include "sdw.h"
 
 #define DRIVER_NAME            "sc8280xp"
 
diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c
new file mode 100644 (file)
index 0000000..1024951
--- /dev/null
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Linaro Limited.
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include "qdsp6/q6afe.h"
+#include "sdw.h"
+
+int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *sruntime,
+                        bool *stream_prepared)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       int ret;
+
+       if (!sruntime)
+               return 0;
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case WSA_CODEC_DMA_RX_1:
+       case RX_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_1:
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               break;
+       default:
+               return 0;
+       }
+
+       if (*stream_prepared) {
+               sdw_disable_stream(sruntime);
+               sdw_deprepare_stream(sruntime);
+               *stream_prepared = false;
+       }
+
+       ret = sdw_prepare_stream(sruntime);
+       if (ret)
+               return ret;
+
+       /**
+        * NOTE: there is a strict hw requirement about the ordering of port
+        * enables and actual WSA881x PA enable. PA enable should only happen
+        * after soundwire ports are enabled if not DC on the line is
+        * accumulated resulting in Click/Pop Noise
+        * PA enable/mute are handled as part of codec DAPM and digital mute.
+        */
+
+       ret = sdw_enable_stream(sruntime);
+       if (ret) {
+               sdw_deprepare_stream(sruntime);
+               return ret;
+       }
+       *stream_prepared  = true;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
+
+int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params,
+                          struct sdw_stream_runtime **psruntime)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sdw_stream_runtime *sruntime;
+       int i;
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_1:
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               for_each_rtd_codec_dais(rtd, i, codec_dai) {
+                       sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
+                       if (sruntime != ERR_PTR(-ENOTSUPP))
+                               *psruntime = sruntime;
+               }
+               break;
+       }
+
+       return 0;
+
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
+
+int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *sruntime, bool *stream_prepared)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case WSA_CODEC_DMA_RX_1:
+       case RX_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_1:
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               if (sruntime && *stream_prepared) {
+                       sdw_disable_stream(sruntime);
+                       sdw_deprepare_stream(sruntime);
+                       *stream_prepared = false;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/sdw.h b/sound/soc/qcom/sdw.h
new file mode 100644 (file)
index 0000000..d74cbb8
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#ifndef __QCOM_SND_SDW_H__
+#define __QCOM_SND_SDW_H__
+
+#include <linux/soundwire/sdw.h>
+
+int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *runtime,
+                        bool *stream_prepared);
+int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params,
+                          struct sdw_stream_runtime **psruntime);
+int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *sruntime,
+                        bool *stream_prepared);
+#endif
index 8dbe9ef..9626a9e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/input-event-codes.h>
 #include "qdsp6/q6afe.h"
 #include "common.h"
+#include "sdw.h"
 
 #define DRIVER_NAME            "sm8250"
 #define MI2S_BCLK_RATE         1536000
index c3be24b..a79a2fb 100644 (file)
@@ -1401,13 +1401,17 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
 
        template.num_kcontrols = le32_to_cpu(w->num_kcontrols);
        kc = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(*kc), GFP_KERNEL);
-       if (!kc)
+       if (!kc) {
+               ret = -ENOMEM;
                goto hdr_err;
+       }
 
        kcontrol_type = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(unsigned int),
                                     GFP_KERNEL);
-       if (!kcontrol_type)
+       if (!kcontrol_type) {
+               ret = -ENOMEM;
                goto hdr_err;
+       }
 
        for (i = 0; i < le32_to_cpu(w->num_kcontrols); i++) {
                control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
index 6bd2888..d5ccd4d 100644 (file)
@@ -318,7 +318,6 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
 {
        struct snd_sof_dev *sdev = context;
        const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
-       unsigned int base = desc->dsp_intr_base;
        unsigned int val, count = ACP_HW_SEM_RETRY_COUNT;
 
        val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
@@ -328,28 +327,20 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
                return IRQ_HANDLED;
        }
 
-       val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
-       if (val & ACP_DSP_TO_HOST_IRQ) {
-               while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
-                       /* Wait until acquired HW Semaphore lock or timeout */
-                       count--;
-                       if (!count) {
-                               dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
-                               return IRQ_NONE;
-                       }
+       while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
+               /* Wait until acquired HW Semaphore lock or timeout */
+               count--;
+               if (!count) {
+                       dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
+                       return IRQ_NONE;
                }
-
-               sof_ops(sdev)->irq_thread(irq, sdev);
-               val |= ACP_DSP_TO_HOST_IRQ;
-               snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val);
-
-               /* Unlock or Release HW Semaphore */
-               snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
-
-               return IRQ_HANDLED;
        }
 
-       return IRQ_NONE;
+       sof_ops(sdev)->irq_thread(irq, sdev);
+       /* Unlock or Release HW Semaphore */
+       snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
+
+       return IRQ_HANDLED;
 };
 
 static irqreturn_t acp_irq_handler(int irq, void *dev_id)
@@ -360,8 +351,11 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
        unsigned int val;
 
        val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
-       if (val)
+       if (val) {
+               val |= ACP_DSP_TO_HOST_IRQ;
+               snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val);
                return IRQ_WAKE_THREAD;
+       }
 
        return IRQ_NONE;
 }
index d9a3ce7..ade0507 100644 (file)
@@ -353,7 +353,9 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev)
                        return err;
        }
 
-       return 0;
+       return snd_sof_debugfs_buf_item(sdev, &sdev->fw_state,
+                                       sizeof(sdev->fw_state),
+                                       "fw_state", 0444);
 }
 EXPORT_SYMBOL_GPL(snd_sof_dbg_init);
 
index 70dea8a..0ec6ef6 100644 (file)
@@ -344,9 +344,10 @@ static ssize_t sof_ipc4_priority_mask_dfs_write(struct file *file,
                                                size_t count, loff_t *ppos)
 {
        struct sof_mtrace_priv *priv = file->private_data;
-       int id, ret;
+       unsigned int id;
        char *buf;
        u32 mask;
+       int ret;
 
        /*
         * To update Nth mask entry, write:
@@ -357,9 +358,9 @@ static ssize_t sof_ipc4_priority_mask_dfs_write(struct file *file,
        if (IS_ERR(buf))
                return PTR_ERR(buf);
 
-       ret = sscanf(buf, "%d,0x%x", &id, &mask);
+       ret = sscanf(buf, "%u,0x%x", &id, &mask);
        if (ret != 2) {
-               ret = sscanf(buf, "%d,%x", &id, &mask);
+               ret = sscanf(buf, "%u,%x", &id, &mask);
                if (ret != 2) {
                        ret = -EINVAL;
                        goto out;
index df740be..8722bbd 100644 (file)
@@ -182,7 +182,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
        const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
        const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
        pm_message_t pm_state;
-       u32 target_state = 0;
+       u32 target_state = snd_sof_dsp_power_target(sdev);
        int ret;
 
        /* do nothing if dsp suspend callback is not set */
@@ -192,6 +192,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
        if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
                return 0;
 
+       if (tplg_ops && tplg_ops->tear_down_all_pipelines)
+               tplg_ops->tear_down_all_pipelines(sdev, false);
+
        if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
                goto suspend;
 
@@ -206,7 +209,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
                }
        }
 
-       target_state = snd_sof_dsp_power_target(sdev);
        pm_state.event = target_state;
 
        /* Skip to platform-specific suspend if DSP is entering D0 */
@@ -217,9 +219,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
                goto suspend;
        }
 
-       if (tplg_ops->tear_down_all_pipelines)
-               tplg_ops->tear_down_all_pipelines(sdev, false);
-
        /* suspend DMA trace */
        sof_fw_trace_suspend(sdev, pm_state);
 
index 7306a26..865c367 100644 (file)
@@ -271,9 +271,9 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
        struct snd_sof_widget *swidget = widget->dobj.private;
        struct snd_soc_dapm_path *p;
 
-       /* return if the widget is in use or if it is already unprepared */
-       if (!swidget->prepared || swidget->use_count > 1)
-               return;
+       /* skip if the widget is in use or if it is already unprepared */
+       if (!swidget || !swidget->prepared || swidget->use_count > 0)
+               goto sink_unprepare;
 
        if (widget_ops[widget->id].ipc_unprepare)
                /* unprepare the source widget */
@@ -281,6 +281,7 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
 
        swidget->prepared = false;
 
+sink_unprepare:
        /* unprepare all widgets in the sink paths */
        snd_soc_dapm_widget_for_each_sink_path(widget, p) {
                if (!p->walking && p->sink->dobj.private) {
@@ -303,7 +304,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
        struct snd_soc_dapm_path *p;
        int ret;
 
-       if (!widget_ops[widget->id].ipc_prepare || swidget->prepared)
+       if (!swidget || !widget_ops[widget->id].ipc_prepare || swidget->prepared)
                goto sink_prepare;
 
        /* prepare the source widget */
@@ -326,7 +327,8 @@ sink_prepare:
                        p->walking = false;
                        if (ret < 0) {
                                /* unprepare the source widget */
-                               if (widget_ops[widget->id].ipc_unprepare && swidget->prepared) {
+                               if (widget_ops[widget->id].ipc_unprepare &&
+                                   swidget && swidget->prepared) {
                                        widget_ops[widget->id].ipc_unprepare(swidget);
                                        swidget->prepared = false;
                                }
@@ -429,11 +431,11 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_l
 
        for_each_dapm_widgets(list, i, widget) {
                /* starting widget for playback is AIF type */
-               if (dir == SNDRV_PCM_STREAM_PLAYBACK && !WIDGET_IS_AIF(widget->id))
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in)
                        continue;
 
                /* starting widget for capture is DAI type */
-               if (dir == SNDRV_PCM_STREAM_CAPTURE && !WIDGET_IS_DAI(widget->id))
+               if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out)
                        continue;
 
                switch (op) {
index 8056422..0d6b82a 100644 (file)
@@ -349,6 +349,9 @@ int
 snd_emux_xg_control(struct snd_emux_port *port, struct snd_midi_channel *chan,
                    int param)
 {
+       if (param >= ARRAY_SIZE(chan->control))
+               return -EINVAL;
+
        return send_converted_effect(xg_effects, ARRAY_SIZE(xg_effects),
                                     port, chan, param,
                                     chan->control[param],
index 41ac718..4727043 100644 (file)
@@ -471,7 +471,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
        subs = find_matching_substream(chip, stream, target->sync_ep,
                                       target->fmt_type);
        if (!subs)
-               return sync_fmt;
+               goto end;
 
        high_score = 0;
        list_for_each_entry(fp, &subs->fmt_list, list) {
@@ -485,6 +485,7 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
                }
        }
 
+ end:
        if (fixed_rate)
                *fixed_rate = snd_usb_pcm_has_fixed_rate(subs);
        return sync_fmt;
index 99a66d0..d959da7 100644 (file)
@@ -160,9 +160,12 @@ find_substream_format(struct snd_usb_substream *subs,
 bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs)
 {
        const struct audioformat *fp;
-       struct snd_usb_audio *chip = subs->stream->chip;
+       struct snd_usb_audio *chip;
        int rate = -1;
 
+       if (!subs)
+               return false;
+       chip = subs->stream->chip;
        if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE))
                return false;
        list_for_each_entry(fp, &subs->fmt_list, list) {
@@ -525,6 +528,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
                if (snd_usb_endpoint_compatible(chip, subs->data_endpoint,
                                                fmt, hw_params))
                        goto unlock;
+               if (stop_endpoints(subs, false))
+                       sync_pending_stops(subs);
                close_endpoints(chip, subs);
        }
 
@@ -787,11 +792,27 @@ static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin,
        return changed;
 }
 
+/* get the specified endpoint object that is being used by other streams
+ * (i.e. the parameter is locked)
+ */
+static const struct snd_usb_endpoint *
+get_endpoint_in_use(struct snd_usb_audio *chip, int endpoint,
+                   const struct snd_usb_endpoint *ref_ep)
+{
+       const struct snd_usb_endpoint *ep;
+
+       ep = snd_usb_get_endpoint(chip, endpoint);
+       if (ep && ep->cur_audiofmt && (ep != ref_ep || ep->opened > 1))
+               return ep;
+       return NULL;
+}
+
 static int hw_rule_rate(struct snd_pcm_hw_params *params,
                        struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
        struct snd_usb_audio *chip = subs->stream->chip;
+       const struct snd_usb_endpoint *ep;
        const struct audioformat *fp;
        struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        unsigned int rmin, rmax, r;
@@ -803,6 +824,29 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
        list_for_each_entry(fp, &subs->fmt_list, list) {
                if (!hw_check_valid_format(subs, params, fp))
                        continue;
+
+               ep = get_endpoint_in_use(chip, fp->endpoint,
+                                        subs->data_endpoint);
+               if (ep) {
+                       hwc_debug("rate limit %d for ep#%x\n",
+                                 ep->cur_rate, fp->endpoint);
+                       rmin = min(rmin, ep->cur_rate);
+                       rmax = max(rmax, ep->cur_rate);
+                       continue;
+               }
+
+               if (fp->implicit_fb) {
+                       ep = get_endpoint_in_use(chip, fp->sync_ep,
+                                                subs->sync_endpoint);
+                       if (ep) {
+                               hwc_debug("rate limit %d for sync_ep#%x\n",
+                                         ep->cur_rate, fp->sync_ep);
+                               rmin = min(rmin, ep->cur_rate);
+                               rmax = max(rmax, ep->cur_rate);
+                               continue;
+                       }
+               }
+
                r = snd_usb_endpoint_get_clock_rate(chip, fp->clock);
                if (r > 0) {
                        if (!snd_interval_test(it, r))
@@ -872,6 +916,8 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
                          struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
+       struct snd_usb_audio *chip = subs->stream->chip;
+       const struct snd_usb_endpoint *ep;
        const struct audioformat *fp;
        struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        u64 fbits;
@@ -881,6 +927,27 @@ static int hw_rule_format(struct snd_pcm_hw_params *params,
        list_for_each_entry(fp, &subs->fmt_list, list) {
                if (!hw_check_valid_format(subs, params, fp))
                        continue;
+
+               ep = get_endpoint_in_use(chip, fp->endpoint,
+                                        subs->data_endpoint);
+               if (ep) {
+                       hwc_debug("format limit %d for ep#%x\n",
+                                 ep->cur_format, fp->endpoint);
+                       fbits |= pcm_format_to_bits(ep->cur_format);
+                       continue;
+               }
+
+               if (fp->implicit_fb) {
+                       ep = get_endpoint_in_use(chip, fp->sync_ep,
+                                                subs->sync_endpoint);
+                       if (ep) {
+                               hwc_debug("format limit %d for sync_ep#%x\n",
+                                         ep->cur_format, fp->sync_ep);
+                               fbits |= pcm_format_to_bits(ep->cur_format);
+                               continue;
+                       }
+               }
+
                fbits |= fp->formats;
        }
        return apply_hw_params_format_bits(fmt, fbits);
@@ -913,98 +980,95 @@ static int hw_rule_period_time(struct snd_pcm_hw_params *params,
        return apply_hw_params_minmax(it, pmin, UINT_MAX);
 }
 
-/* get the EP or the sync EP for implicit fb when it's already set up */
-static const struct snd_usb_endpoint *
-get_sync_ep_from_substream(struct snd_usb_substream *subs)
-{
-       struct snd_usb_audio *chip = subs->stream->chip;
-       const struct audioformat *fp;
-       const struct snd_usb_endpoint *ep;
-
-       list_for_each_entry(fp, &subs->fmt_list, list) {
-               ep = snd_usb_get_endpoint(chip, fp->endpoint);
-               if (ep && ep->cur_audiofmt) {
-                       /* if EP is already opened solely for this substream,
-                        * we still allow us to change the parameter; otherwise
-                        * this substream has to follow the existing parameter
-                        */
-                       if (ep->cur_audiofmt != subs->cur_audiofmt || ep->opened > 1)
-                               return ep;
-               }
-               if (!fp->implicit_fb)
-                       continue;
-               /* for the implicit fb, check the sync ep as well */
-               ep = snd_usb_get_endpoint(chip, fp->sync_ep);
-               if (ep && ep->cur_audiofmt)
-                       return ep;
-       }
-       return NULL;
-}
-
 /* additional hw constraints for implicit feedback mode */
-static int hw_rule_format_implicit_fb(struct snd_pcm_hw_params *params,
-                                     struct snd_pcm_hw_rule *rule)
-{
-       struct snd_usb_substream *subs = rule->private;
-       const struct snd_usb_endpoint *ep;
-       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
-       ep = get_sync_ep_from_substream(subs);
-       if (!ep)
-               return 0;
-
-       hwc_debug("applying %s\n", __func__);
-       return apply_hw_params_format_bits(fmt, pcm_format_to_bits(ep->cur_format));
-}
-
-static int hw_rule_rate_implicit_fb(struct snd_pcm_hw_params *params,
-                                   struct snd_pcm_hw_rule *rule)
-{
-       struct snd_usb_substream *subs = rule->private;
-       const struct snd_usb_endpoint *ep;
-       struct snd_interval *it;
-
-       ep = get_sync_ep_from_substream(subs);
-       if (!ep)
-               return 0;
-
-       hwc_debug("applying %s\n", __func__);
-       it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-       return apply_hw_params_minmax(it, ep->cur_rate, ep->cur_rate);
-}
-
 static int hw_rule_period_size_implicit_fb(struct snd_pcm_hw_params *params,
                                           struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
+       struct snd_usb_audio *chip = subs->stream->chip;
+       const struct audioformat *fp;
        const struct snd_usb_endpoint *ep;
        struct snd_interval *it;
+       unsigned int rmin, rmax;
 
-       ep = get_sync_ep_from_substream(subs);
-       if (!ep)
-               return 0;
-
-       hwc_debug("applying %s\n", __func__);
        it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
-       return apply_hw_params_minmax(it, ep->cur_period_frames,
-                                     ep->cur_period_frames);
+       hwc_debug("hw_rule_period_size: (%u,%u)\n", it->min, it->max);
+       rmin = UINT_MAX;
+       rmax = 0;
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               if (!hw_check_valid_format(subs, params, fp))
+                       continue;
+               ep = get_endpoint_in_use(chip, fp->endpoint,
+                                        subs->data_endpoint);
+               if (ep) {
+                       hwc_debug("period size limit %d for ep#%x\n",
+                                 ep->cur_period_frames, fp->endpoint);
+                       rmin = min(rmin, ep->cur_period_frames);
+                       rmax = max(rmax, ep->cur_period_frames);
+                       continue;
+               }
+
+               if (fp->implicit_fb) {
+                       ep = get_endpoint_in_use(chip, fp->sync_ep,
+                                                subs->sync_endpoint);
+                       if (ep) {
+                               hwc_debug("period size limit %d for sync_ep#%x\n",
+                                         ep->cur_period_frames, fp->sync_ep);
+                               rmin = min(rmin, ep->cur_period_frames);
+                               rmax = max(rmax, ep->cur_period_frames);
+                               continue;
+                       }
+               }
+       }
+
+       if (!rmax)
+               return 0; /* no limit by implicit fb */
+       return apply_hw_params_minmax(it, rmin, rmax);
 }
 
 static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params,
                                       struct snd_pcm_hw_rule *rule)
 {
        struct snd_usb_substream *subs = rule->private;
+       struct snd_usb_audio *chip = subs->stream->chip;
+       const struct audioformat *fp;
        const struct snd_usb_endpoint *ep;
        struct snd_interval *it;
+       unsigned int rmin, rmax;
 
-       ep = get_sync_ep_from_substream(subs);
-       if (!ep)
-               return 0;
-
-       hwc_debug("applying %s\n", __func__);
        it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIODS);
-       return apply_hw_params_minmax(it, ep->cur_buffer_periods,
-                                     ep->cur_buffer_periods);
+       hwc_debug("hw_rule_periods: (%u,%u)\n", it->min, it->max);
+       rmin = UINT_MAX;
+       rmax = 0;
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               if (!hw_check_valid_format(subs, params, fp))
+                       continue;
+               ep = get_endpoint_in_use(chip, fp->endpoint,
+                                        subs->data_endpoint);
+               if (ep) {
+                       hwc_debug("periods limit %d for ep#%x\n",
+                                 ep->cur_buffer_periods, fp->endpoint);
+                       rmin = min(rmin, ep->cur_buffer_periods);
+                       rmax = max(rmax, ep->cur_buffer_periods);
+                       continue;
+               }
+
+               if (fp->implicit_fb) {
+                       ep = get_endpoint_in_use(chip, fp->sync_ep,
+                                                subs->sync_endpoint);
+                       if (ep) {
+                               hwc_debug("periods limit %d for sync_ep#%x\n",
+                                         ep->cur_buffer_periods, fp->sync_ep);
+                               rmin = min(rmin, ep->cur_buffer_periods);
+                               rmax = max(rmax, ep->cur_buffer_periods);
+                               continue;
+                       }
+               }
+       }
+
+       if (!rmax)
+               return 0; /* no limit by implicit fb */
+       return apply_hw_params_minmax(it, rmin, rmax);
 }
 
 /*
@@ -1113,16 +1177,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
                return err;
 
        /* additional hw constraints for implicit fb */
-       err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
-                                 hw_rule_format_implicit_fb, subs,
-                                 SNDRV_PCM_HW_PARAM_FORMAT, -1);
-       if (err < 0)
-               return err;
-       err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                 hw_rule_rate_implicit_fb, subs,
-                                 SNDRV_PCM_HW_PARAM_RATE, -1);
-       if (err < 0)
-               return err;
        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
                                  hw_rule_period_size_implicit_fb, subs,
                                  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
index 3d13fdf..3ecd1ba 100644 (file)
@@ -2152,6 +2152,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x0525, 0xa4ad, /* Hamedal C20 usb camero */
                   QUIRK_FLAG_IFACE_SKIP_CLOSE),
+       DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
+                  QUIRK_FLAG_FIXED_RATE),
        DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
                   QUIRK_FLAG_FIXED_RATE),
 
index f75601c..f10f4e6 100644 (file)
@@ -1222,6 +1222,12 @@ static int __snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
                        if (err < 0)
                                return err;
                }
+
+               /* try to set the interface... */
+               usb_set_interface(chip->dev, iface_no, 0);
+               snd_usb_init_pitch(chip, fp);
+               snd_usb_init_sample_rate(chip, fp, fp->rate_max);
+               usb_set_interface(chip->dev, iface_no, altno);
        }
        return 0;
 }
index 4041748..b66e037 100644 (file)
@@ -311,7 +311,7 @@ static int xen_drv_probe(struct xenbus_device *xb_dev,
        return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
 
-static int xen_drv_remove(struct xenbus_device *dev)
+static void xen_drv_remove(struct xenbus_device *dev)
 {
        struct xen_snd_front_info *front_info = dev_get_drvdata(&dev->dev);
        int to = 100;
@@ -345,7 +345,6 @@ static int xen_drv_remove(struct xenbus_device *dev)
 
        xen_snd_drv_fini(front_info);
        xenbus_frontend_closed(dev);
-       return 0;
 }
 
 static const struct xenbus_device_id xen_drv_ids[] = {
index abc4186..683ca3a 100644 (file)
@@ -41,7 +41,7 @@
        (((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
 
 #define MIDR_CPU_MODEL(imp, partnum) \
-       (((imp)                 << MIDR_IMPLEMENTOR_SHIFT) | \
+       ((_AT(u32, imp)         << MIDR_IMPLEMENTOR_SHIFT) | \
        (0xf                    << MIDR_ARCHITECTURE_SHIFT) | \
        ((partnum)              << MIDR_PARTNUM_SHIFT))
 
@@ -80,6 +80,7 @@
 #define ARM_CPU_PART_CORTEX_X1         0xD44
 #define ARM_CPU_PART_CORTEX_A510       0xD46
 #define ARM_CPU_PART_CORTEX_A710       0xD47
+#define ARM_CPU_PART_CORTEX_A715       0xD4D
 #define ARM_CPU_PART_CORTEX_X2         0xD48
 #define ARM_CPU_PART_NEOVERSE_N2       0xD49
 #define ARM_CPU_PART_CORTEX_A78C       0xD4B
 #define APPLE_CPU_PART_M1_FIRESTORM_PRO        0x025
 #define APPLE_CPU_PART_M1_ICESTORM_MAX 0x028
 #define APPLE_CPU_PART_M1_FIRESTORM_MAX        0x029
+#define APPLE_CPU_PART_M2_BLIZZARD     0x032
+#define APPLE_CPU_PART_M2_AVALANCHE    0x033
 
 #define AMPERE_CPU_PART_AMPERE1                0xAC3
 
 #define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
 #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
+#define MIDR_CORTEX_A715 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A715)
 #define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
 #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
 #define MIDR_CORTEX_A78C       MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
 #define MIDR_APPLE_M1_FIRESTORM_PRO MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO)
 #define MIDR_APPLE_M1_ICESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX)
 #define MIDR_APPLE_M1_FIRESTORM_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX)
+#define MIDR_APPLE_M2_BLIZZARD MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD)
+#define MIDR_APPLE_M2_AVALANCHE MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE)
 #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1)
 
 /* Fujitsu Erratum 010001 affects A64FX 1.0 and 1.1, (v0r0 and v1r0) */
index 316917b..a7a857f 100644 (file)
@@ -43,6 +43,7 @@
 #define __KVM_HAVE_VCPU_EVENTS
 
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+#define KVM_DIRTY_LOG_PAGE_OFFSET 64
 
 #define KVM_REG_SIZE(id)                                               \
        (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
index 649e50a..e48deab 100644 (file)
@@ -206,6 +206,8 @@ struct kvm_msr_list {
 struct kvm_msr_filter_range {
 #define KVM_MSR_FILTER_READ  (1 << 0)
 #define KVM_MSR_FILTER_WRITE (1 << 1)
+#define KVM_MSR_FILTER_RANGE_VALID_MASK (KVM_MSR_FILTER_READ | \
+                                        KVM_MSR_FILTER_WRITE)
        __u32 flags;
        __u32 nmsrs; /* number of msrs in bitmap */
        __u32 base;  /* MSR index the bitmap starts at */
@@ -214,8 +216,11 @@ struct kvm_msr_filter_range {
 
 #define KVM_MSR_FILTER_MAX_RANGES 16
 struct kvm_msr_filter {
+#ifndef __KERNEL__
 #define KVM_MSR_FILTER_DEFAULT_ALLOW (0 << 0)
+#endif
 #define KVM_MSR_FILTER_DEFAULT_DENY  (1 << 0)
+#define KVM_MSR_FILTER_VALID_MASK (KVM_MSR_FILTER_DEFAULT_DENY)
        __u32 flags;
        struct kvm_msr_filter_range ranges[KVM_MSR_FILTER_MAX_RANGES];
 };
index 6c12295..5dee2b9 100644 (file)
@@ -86,6 +86,7 @@ int monitor_device(const char *device_name,
                        gpiotools_test_bit(values.bits, i));
        }
 
+       i = 0;
        while (1) {
                struct gpio_v2_line_event event;
 
index cc7070c..b4898ff 100644 (file)
 #define __static_assert(expr, msg, ...) _Static_assert(expr, msg)
 #endif // static_assert
 
+
+/*
+ * Compile time check that field has an expected offset
+ */
+#define ASSERT_STRUCT_OFFSET(type, field, expected_offset)     \
+       BUILD_BUG_ON_MSG(offsetof(type, field) != (expected_offset),    \
+               "Offset of " #field " in " #type " has changed.")
+
+
 #endif /* _LINUX_BUILD_BUG_H */
index 5fc5b80..7380093 100644 (file)
@@ -192,6 +192,7 @@ struct sys_stat_struct {
 __asm__ (".section .text\n"
     ".weak __start\n"
     ".set nomips16\n"
+    ".set push\n"
     ".set    noreorder\n"
     ".option pic0\n"
     ".ent __start\n"
@@ -210,6 +211,7 @@ __asm__ (".section .text\n"
     "li $v0, 4001\n"              // NR_exit == 4001
     "syscall\n"
     ".end __start\n"
+    ".set pop\n"
     "");
 
 #endif // _NOLIBC_ARCH_MIPS_H
index ba04771..a3bdd98 100644 (file)
 #define O_RDONLY            0
 #define O_WRONLY            1
 #define O_RDWR              2
-#define O_CREAT         0x100
-#define O_EXCL          0x200
-#define O_NOCTTY        0x400
-#define O_TRUNC        0x1000
-#define O_APPEND       0x2000
-#define O_NONBLOCK     0x4000
-#define O_DIRECTORY  0x200000
+#define O_CREAT          0x40
+#define O_EXCL           0x80
+#define O_NOCTTY        0x100
+#define O_TRUNC         0x200
+#define O_APPEND        0x400
+#define O_NONBLOCK      0x800
+#define O_DIRECTORY   0x10000
 
 struct sys_stat_struct {
        unsigned long   st_dev;         /* Device.  */
index e3000b2..6f90706 100644 (file)
@@ -96,4 +96,7 @@ int ispunct(int c)
        return isgraph(c) && !isalnum(c);
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_CTYPE_H */
index 06893d6..9dc4919 100644 (file)
@@ -24,4 +24,7 @@ static int errno;
  */
 #define MAX_ERRNO 4095
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_ERRNO_H */
index ef47e71..1375522 100644 (file)
@@ -19,4 +19,7 @@ int raise(int signal)
        return sys_kill(sys_getpid(), signal);
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_SIGNAL_H */
index a3cebc4..96ac8af 100644 (file)
@@ -303,4 +303,7 @@ void perror(const char *msg)
        fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_STDIO_H */
index 92378c4..a24000d 100644 (file)
@@ -419,4 +419,7 @@ char *u64toa(uint64_t in)
        return itoa_buffer;
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_STDLIB_H */
index ad97c0d..fffdaf6 100644 (file)
@@ -88,8 +88,11 @@ void *memset(void *dst, int b, size_t len)
 {
        char *p = dst;
 
-       while (len--)
+       while (len--) {
+               /* prevent gcc from recognizing memset() here */
+               asm volatile("");
                *(p++) = b;
+       }
        return dst;
 }
 
@@ -285,4 +288,7 @@ char *strrchr(const char *s, int c)
        return (char *)ret;
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_STRING_H */
index ce3ee03..78473d3 100644 (file)
@@ -1243,5 +1243,7 @@ ssize_t write(int fd, const void *buf, size_t count)
        return ret;
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
 
 #endif /* _NOLIBC_SYS_H */
index d18b766..8465536 100644 (file)
@@ -25,4 +25,7 @@ time_t time(time_t *tptr)
        return tv.tv_sec;
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_TIME_H */
index 9599970..fbbc0e6 100644 (file)
 #define S_IFSOCK       0140000
 #define S_IFMT         0170000
 
-#define S_ISDIR(mode)  (((mode) & S_IFDIR)  == S_IFDIR)
-#define S_ISCHR(mode)  (((mode) & S_IFCHR)  == S_IFCHR)
-#define S_ISBLK(mode)  (((mode) & S_IFBLK)  == S_IFBLK)
-#define S_ISREG(mode)  (((mode) & S_IFREG)  == S_IFREG)
-#define S_ISFIFO(mode) (((mode) & S_IFIFO)  == S_IFIFO)
-#define S_ISLNK(mode)  (((mode) & S_IFLNK)  == S_IFLNK)
-#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK)
+#define S_ISDIR(mode)  (((mode) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(mode)  (((mode) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(mode)  (((mode) & S_IFMT) == S_IFBLK)
+#define S_ISREG(mode)  (((mode) & S_IFMT) == S_IFREG)
+#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#define S_ISLNK(mode)  (((mode) & S_IFMT) == S_IFLNK)
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
 
 /* dirent types */
 #define DT_UNKNOWN     0x0
 #define EXIT_SUCCESS 0
 #define EXIT_FAILURE 1
 
+#define FD_SETIDXMASK (8 * sizeof(unsigned long))
+#define FD_SETBITMASK (8 * sizeof(unsigned long)-1)
+
 /* for select() */
 typedef struct {
-       uint32_t fd32[(FD_SETSIZE + 31) / 32];
+       unsigned long fds[(FD_SETSIZE + FD_SETBITMASK) / FD_SETIDXMASK];
 } fd_set;
 
-#define FD_CLR(fd, set) do {                                            \
-               fd_set *__set = (set);                                  \
-               int __fd = (fd);                                        \
-               if (__fd >= 0)                                          \
-                       __set->fd32[__fd / 32] &= ~(1U << (__fd & 31)); \
+#define FD_CLR(fd, set) do {                                           \
+               fd_set *__set = (set);                                  \
+               int __fd = (fd);                                        \
+               if (__fd >= 0)                                          \
+                       __set->fds[__fd / FD_SETIDXMASK] &=             \
+                               ~(1U << (__fd & FX_SETBITMASK));        \
        } while (0)
 
-#define FD_SET(fd, set) do {                                            \
-               fd_set *__set = (set);                                  \
-               int __fd = (fd);                                        \
-               if (__fd >= 0)                                          \
-                       __set->fd32[__fd / 32] |= 1U << (__fd & 31);    \
+#define FD_SET(fd, set) do {                                           \
+               fd_set *__set = (set);                                  \
+               int __fd = (fd);                                        \
+               if (__fd >= 0)                                          \
+                       __set->fds[__fd / FD_SETIDXMASK] |=             \
+                               1 << (__fd & FD_SETBITMASK);            \
        } while (0)
 
-#define FD_ISSET(fd, set) ({                                                  \
-               fd_set *__set = (set);                                        \
-               int __fd = (fd);                                              \
-               int __r = 0;                                                  \
-               if (__fd >= 0)                                                \
-                       __r = !!(__set->fd32[__fd / 32] & 1U << (__fd & 31)); \
-               __r;                                                          \
+#define FD_ISSET(fd, set) ({                                           \
+                       fd_set *__set = (set);                          \
+                       int __fd = (fd);                                \
+               int __r = 0;                                            \
+               if (__fd >= 0)                                          \
+                       __r = !!(__set->fds[__fd / FD_SETIDXMASK] &     \
+1U << (__fd & FD_SET_BITMASK));                                                \
+               __r;                                                    \
        })
 
-#define FD_ZERO(set) do {                                               \
-               fd_set *__set = (set);                                  \
-               int __idx;                                              \
-               for (__idx = 0; __idx < (FD_SETSIZE+31) / 32; __idx ++) \
-                       __set->fd32[__idx] = 0;                         \
+#define FD_ZERO(set) do {                                              \
+               fd_set *__set = (set);                                  \
+               int __idx;                                              \
+               int __size = (FD_SETSIZE+FD_SETBITMASK) / FD_SETIDXMASK;\
+               for (__idx = 0; __idx < __size; __idx++)                \
+                       __set->fds[__idx] = 0;                          \
        } while (0)
 
 /* for poll() */
@@ -202,4 +209,7 @@ struct stat {
 })
 #endif
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_TYPES_H */
index 1c25e20..1cfcd52 100644 (file)
@@ -51,4 +51,7 @@ int tcsetpgrp(int fd, pid_t pid)
        return ioctl(fd, TIOCSPGRP, &pid);
 }
 
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
 #endif /* _NOLIBC_UNISTD_H */
index 20522d4..55155e2 100644 (file)
@@ -1767,6 +1767,7 @@ struct kvm_xen_hvm_attr {
                __u8 runstate_update_flag;
                struct {
                        __u64 gfn;
+#define KVM_XEN_INVALID_GFN ((__u64)-1)
                } shared_info;
                struct {
                        __u32 send_port;
@@ -1798,6 +1799,7 @@ struct kvm_xen_hvm_attr {
        } u;
 };
 
+
 /* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */
 #define KVM_XEN_ATTR_TYPE_LONG_MODE            0x0
 #define KVM_XEN_ATTR_TYPE_SHARED_INFO          0x1
@@ -1823,6 +1825,7 @@ struct kvm_xen_vcpu_attr {
        __u16 pad[3];
        union {
                __u64 gpa;
+#define KVM_XEN_INVALID_GPA ((__u64)-1)
                __u64 pad[8];
                struct {
                        __u64 state;
index 4350be7..4b7c8b3 100644 (file)
@@ -427,6 +427,15 @@ static int decode_instructions(struct objtool_file *file)
                        if (func->type != STT_NOTYPE && func->type != STT_FUNC)
                                continue;
 
+                       if (func->offset == sec->sh.sh_size) {
+                               /* Heuristic: likely an "end" symbol */
+                               if (func->type == STT_NOTYPE)
+                                       continue;
+                               WARN("%s(): STT_FUNC at end of section",
+                                    func->name);
+                               return -1;
+                       }
+
                        if (func->return_thunk || func->alias != func)
                                continue;
 
index c2504c3..5b87846 100644 (file)
@@ -589,6 +589,8 @@ ifndef NO_LIBELF
           $(call feature_check,libbpf-bpf_program__set_insns)
           ifeq ($(feature-libbpf-bpf_program__set_insns), 1)
             CFLAGS += -DHAVE_LIBBPF_BPF_PROGRAM__SET_INSNS
+          else
+            dummy := $(error Error: libbpf devel library needs to be >= 0.8.0 to build with LIBBPF_DYNAMIC, update or build statically with the version that comes with the kernel sources);
           endif
           $(call feature_check,libbpf-btf__raw_data)
           ifeq ($(feature-libbpf-btf__raw_data), 1)
@@ -602,6 +604,8 @@ ifndef NO_LIBELF
           dummy := $(error Error: No libbpf devel library found, please install libbpf-devel);
         endif
       else
+        # Libbpf will be built as a static library from tools/lib/bpf.
+       LIBBPF_STATIC := 1
        CFLAGS += -DHAVE_LIBBPF_BTF__LOAD_FROM_KERNEL_BY_ID
         CFLAGS += -DHAVE_LIBBPF_BPF_PROG_LOAD
         CFLAGS += -DHAVE_LIBBPF_BPF_OBJECT__NEXT_PROGRAM
@@ -1314,14 +1318,6 @@ tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
 
 export perfexec_instdir_SQ
 
-# If we install to $(HOME) we keep the traceevent default:
-# $(HOME)/.traceevent/plugins
-# Otherwise we install plugins into the global $(libdir).
-ifdef DESTDIR
-plugindir=$(libdir)/traceevent/plugins
-plugindir_SQ= $(subst ','\'',$(plugindir))
-endif
-
 print_var = $(eval $(print_var_code)) $(info $(MSG))
 define print_var_code
     MSG = $(shell printf '...%40s: %s' $(1) $($(1)))
index 1e32c93..b7d9c42 100644 (file)
@@ -303,10 +303,12 @@ ifneq ($(OUTPUT),)
 else
   LIBBPF_OUTPUT = $(CURDIR)/libbpf
 endif
-LIBBPF_DESTDIR = $(LIBBPF_OUTPUT)
-LIBBPF_INCLUDE = $(LIBBPF_DESTDIR)/include
-LIBBPF = $(LIBBPF_OUTPUT)/libbpf.a
-CFLAGS += -I$(LIBBPF_OUTPUT)/include
+ifdef LIBBPF_STATIC
+  LIBBPF_DESTDIR = $(LIBBPF_OUTPUT)
+  LIBBPF_INCLUDE = $(LIBBPF_DESTDIR)/include
+  LIBBPF = $(LIBBPF_OUTPUT)/libbpf.a
+  CFLAGS += -I$(LIBBPF_OUTPUT)/include
+endif
 
 ifneq ($(OUTPUT),)
   LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
@@ -393,10 +395,8 @@ endif
 export PERL_PATH
 
 PERFLIBS = $(LIBAPI) $(LIBPERF) $(LIBSUBCMD) $(LIBSYMBOL)
-ifndef NO_LIBBPF
-  ifndef LIBBPF_DYNAMIC
-    PERFLIBS += $(LIBBPF)
-  endif
+ifdef LIBBPF_STATIC
+  PERFLIBS += $(LIBBPF)
 endif
 
 # We choose to avoid "if .. else if .. else .. endif endif"
@@ -756,12 +756,15 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
        $(arch_errno_name_array) \
        $(sync_file_range_arrays) \
        $(LIBAPI) \
-       $(LIBBPF) \
        $(LIBPERF) \
        $(LIBSUBCMD) \
        $(LIBSYMBOL) \
        bpf-skel
 
+ifdef LIBBPF_STATIC
+prepare: $(LIBBPF)
+endif
+
 $(OUTPUT)%.o: %.c prepare FORCE
        $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
 
index e20656c..8ae0a15 100644 (file)
@@ -26,6 +26,7 @@
 #include "util/string2.h"
 
 #include <linux/kernel.h>
+#include <linux/numa.h>
 #include <linux/rbtree.h>
 #include <linux/string.h>
 #include <linux/zalloc.h>
@@ -185,22 +186,33 @@ static int evsel__process_alloc_event(struct evsel *evsel, struct perf_sample *s
        total_allocated += bytes_alloc;
 
        nr_allocs++;
-       return 0;
-}
 
-static int evsel__process_alloc_node_event(struct evsel *evsel, struct perf_sample *sample)
-{
-       int ret = evsel__process_alloc_event(evsel, sample);
+       /*
+        * Commit 11e9734bcb6a ("mm/slab_common: unify NUMA and UMA
+        * version of tracepoints") adds the field "node" into the
+        * tracepoints 'kmalloc' and 'kmem_cache_alloc'.
+        *
+        * The legacy tracepoints 'kmalloc_node' and 'kmem_cache_alloc_node'
+        * also contain the field "node".
+        *
+        * If the tracepoint contains the field "node" the tool stats the
+        * cross allocation.
+        */
+       if (evsel__field(evsel, "node")) {
+               int node1, node2;
 
-       if (!ret) {
-               int node1 = cpu__get_node((struct perf_cpu){.cpu = sample->cpu}),
-                   node2 = evsel__intval(evsel, sample, "node");
+               node1 = cpu__get_node((struct perf_cpu){.cpu = sample->cpu});
+               node2 = evsel__intval(evsel, sample, "node");
 
-               if (node1 != node2)
+               /*
+                * If the field "node" is NUMA_NO_NODE (-1), we don't take it
+                * as a cross allocation.
+                */
+               if ((node2 != NUMA_NO_NODE) && (node1 != node2))
                        nr_cross_allocs++;
        }
 
-       return ret;
+       return 0;
 }
 
 static int ptr_cmp(void *, void *);
@@ -1369,8 +1381,8 @@ static int __cmd_kmem(struct perf_session *session)
                /* slab allocator */
                { "kmem:kmalloc",               evsel__process_alloc_event, },
                { "kmem:kmem_cache_alloc",      evsel__process_alloc_event, },
-               { "kmem:kmalloc_node",          evsel__process_alloc_node_event, },
-               { "kmem:kmem_cache_alloc_node", evsel__process_alloc_node_event, },
+               { "kmem:kmalloc_node",          evsel__process_alloc_event, },
+               { "kmem:kmem_cache_alloc_node", evsel__process_alloc_event, },
                { "kmem:kfree",                 evsel__process_free_event, },
                { "kmem:kmem_cache_free",       evsel__process_free_event, },
                /* page allocator */
@@ -1824,6 +1836,19 @@ static int parse_line_opt(const struct option *opt __maybe_unused,
        return 0;
 }
 
+static bool slab_legacy_tp_is_exposed(void)
+{
+       /*
+        * The tracepoints "kmem:kmalloc_node" and
+        * "kmem:kmem_cache_alloc_node" have been removed on the latest
+        * kernel, if the tracepoint "kmem:kmalloc_node" is existed it
+        * means the tool is running on an old kernel, we need to
+        * rollback to support these legacy tracepoints.
+        */
+       return IS_ERR(trace_event__tp_format("kmem", "kmalloc_node")) ?
+               false : true;
+}
+
 static int __cmd_record(int argc, const char **argv)
 {
        const char * const record_args[] = {
@@ -1831,22 +1856,28 @@ static int __cmd_record(int argc, const char **argv)
        };
        const char * const slab_events[] = {
        "-e", "kmem:kmalloc",
-       "-e", "kmem:kmalloc_node",
        "-e", "kmem:kfree",
        "-e", "kmem:kmem_cache_alloc",
-       "-e", "kmem:kmem_cache_alloc_node",
        "-e", "kmem:kmem_cache_free",
        };
+       const char * const slab_legacy_events[] = {
+       "-e", "kmem:kmalloc_node",
+       "-e", "kmem:kmem_cache_alloc_node",
+       };
        const char * const page_events[] = {
        "-e", "kmem:mm_page_alloc",
        "-e", "kmem:mm_page_free",
        };
        unsigned int rec_argc, i, j;
        const char **rec_argv;
+       unsigned int slab_legacy_tp_exposed = slab_legacy_tp_is_exposed();
 
        rec_argc = ARRAY_SIZE(record_args) + argc - 1;
-       if (kmem_slab)
+       if (kmem_slab) {
                rec_argc += ARRAY_SIZE(slab_events);
+               if (slab_legacy_tp_exposed)
+                       rec_argc += ARRAY_SIZE(slab_legacy_events);
+       }
        if (kmem_page)
                rec_argc += ARRAY_SIZE(page_events) + 1; /* for -g */
 
@@ -1861,6 +1892,10 @@ static int __cmd_record(int argc, const char **argv)
        if (kmem_slab) {
                for (j = 0; j < ARRAY_SIZE(slab_events); j++, i++)
                        rec_argv[i] = strdup(slab_events[j]);
+               if (slab_legacy_tp_exposed) {
+                       for (j = 0; j < ARRAY_SIZE(slab_legacy_events); j++, i++)
+                               rec_argv[i] = strdup(slab_legacy_events[j]);
+               }
        }
        if (kmem_page) {
                rec_argv[i++] = strdup("-g");
index 86e06f1..d21fe0f 100644 (file)
@@ -16,7 +16,9 @@
 
 #include "util/record.h"
 #include <api/fs/tracing_path.h>
+#ifdef HAVE_LIBBPF_SUPPORT
 #include <bpf/bpf.h>
+#endif
 #include "util/bpf_map.h"
 #include "util/rlimit.h"
 #include "builtin.h"
index bd83d36..91778b5 100644 (file)
@@ -20,6 +20,8 @@
 # undef if
 #endif
 
+typedef unsigned int __bitwise fmode_t;
+
 #define FMODE_READ             0x1
 #define FMODE_WRITE            0x2
 
index 05e818a..009d6ef 100644 (file)
@@ -222,19 +222,7 @@ installed_files_bin := bin/perf
 installed_files_bin += etc/bash_completion.d/perf
 installed_files_bin += libexec/perf-core/perf-archive
 
-installed_files_plugins := $(lib)/traceevent/plugins/plugin_cfg80211.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_scsi.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_xen.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_function.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_sched_switch.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_mac80211.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_kvm.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_kmem.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_hrtimer.so
-installed_files_plugins += $(lib)/traceevent/plugins/plugin_jbd2.so
-
 installed_files_all := $(installed_files_bin)
-installed_files_all += $(installed_files_plugins)
 
 test_make_install       := $(call test_dest_files,$(installed_files_all))
 test_make_install_O     := $(call test_dest_files,$(installed_files_all))
index f05670d..aaf8511 100755 (executable)
@@ -77,7 +77,20 @@ check()
        file=${build_id_dir}/.build-id/${id:0:2}/`readlink ${link}`/elf
        echo "file: ${file}"
 
-       if [ ! -x $file ]; then
+       # Check for file permission of original file
+       # in case of pe-file.exe file
+       echo $1 | grep ".exe"
+       if [ $? -eq 0 ]; then
+               if [ -x $1  -a ! -x $file ]; then
+                       echo "failed: file ${file} executable does not exist"
+                       exit 1
+               fi
+
+               if [ ! -x $file -a ! -e $file ]; then
+                       echo "failed: file ${file} does not exist"
+                       exit 1
+               fi
+       elif [ ! -x $file ]; then
                echo "failed: file ${file} does not exist"
                exit 1
        fi
index de3701a..13c3a23 100644 (file)
@@ -33,7 +33,10 @@ typedef __kernel_sa_family_t sa_family_t;
 
 struct sockaddr {
        sa_family_t     sa_family;      /* address family, AF_xxx       */
-       char            sa_data[14];    /* 14 bytes of protocol address */
+       union {
+               char sa_data_min[14];           /* Minimum 14 bytes of protocol address */
+               DECLARE_FLEX_ARRAY(char, sa_data);
+       };
 };
 
 struct linger {
index 265d20c..c2e323c 100644 (file)
@@ -2611,7 +2611,7 @@ static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
                                *size = sym->start - *start;
                        if (idx > 0) {
                                if (*size)
-                                       return 1;
+                                       return 0;
                        } else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
                                print_duplicate_syms(dso, sym_name);
                                return -EINVAL;
index 4dbf264..c6d21c0 100644 (file)
@@ -4,9 +4,12 @@
 
 #include <linux/list.h>
 #include <sys/resource.h>
+
+#ifdef HAVE_LIBBPF_SUPPORT
 #include <bpf/bpf.h>
 #include <bpf/btf.h>
 #include <bpf/libbpf.h>
+#endif
 
 struct evsel;
 struct target;
@@ -87,6 +90,8 @@ static inline void set_max_rlimit(void)
        setrlimit(RLIMIT_MEMLOCK, &rinf);
 }
 
+#ifdef HAVE_BPF_SKEL
+
 static inline __u32 bpf_link_get_id(int fd)
 {
        struct bpf_link_info link_info = { .id = 0, };
@@ -127,5 +132,6 @@ static inline int bperf_trigger_reading(int prog_fd, int cpu)
 
        return bpf_prog_test_run_opts(prog_fd, &opts);
 }
+#endif /* HAVE_BPF_SKEL */
 
 #endif /* __PERF_BPF_COUNTER_H */
index a839b30..ea9c083 100644 (file)
@@ -715,9 +715,13 @@ build_id_cache__add(const char *sbuild_id, const char *name, const char *realnam
                } else if (nsi && nsinfo__need_setns(nsi)) {
                        if (copyfile_ns(name, filename, nsi))
                                goto out_free;
-               } else if (link(realname, filename) && errno != EEXIST &&
-                               copyfile(name, filename))
-                       goto out_free;
+               } else if (link(realname, filename) && errno != EEXIST) {
+                       struct stat f_stat;
+
+                       if (!(stat(name, &f_stat) < 0) &&
+                                       copyfile_mode(name, filename, f_stat.st_mode))
+                               goto out_free;
+               }
        }
 
        /* Some binaries are stripped, but have .debug files with their symbol
index 0168a96..d47de5f 100644 (file)
@@ -42,8 +42,11 @@ static char *normalize(char *str, int runtime)
        char *dst = str;
 
        while (*str) {
-               if (*str == '\\')
+               if (*str == '\\') {
                        *dst++ = *++str;
+                       if (!*str)
+                               break;
+               }
                else if (*str == '?') {
                        char *paramval;
                        int i = 0;
index 5f195ee..5fd1424 100644 (file)
@@ -7,11 +7,6 @@ all:
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
 
-ifeq (x86,$(ARCH))
-TEST_GEN_FILES += ../../../power/x86/amd_pstate_tracer/amd_pstate_trace.py
-TEST_GEN_FILES += ../../../power/x86/intel_pstate_tracer/intel_pstate_tracer.py
-endif
-
 TEST_PROGS := run.sh
 TEST_FILES := basic.sh tbench.sh gitsource.sh
 
index 2cf0c7a..567e07c 100644 (file)
@@ -30,6 +30,8 @@
 #define MAX_STRERR_LEN 256
 #define MAX_TEST_NAME 80
 
+#define __always_unused        __attribute__((__unused__))
+
 #define _FAIL(errnum, fmt...)                                                  \
        ({                                                                     \
                error_at_line(0, (errnum), __func__, __LINE__, fmt);           \
@@ -321,7 +323,8 @@ static int socket_loopback(int family, int sotype)
        return socket_loopback_reuseport(family, sotype, -1);
 }
 
-static void test_insert_invalid(int family, int sotype, int mapfd)
+static void test_insert_invalid(struct test_sockmap_listen *skel __always_unused,
+                               int family, int sotype, int mapfd)
 {
        u32 key = 0;
        u64 value;
@@ -338,7 +341,8 @@ static void test_insert_invalid(int family, int sotype, int mapfd)
                FAIL_ERRNO("map_update: expected EBADF");
 }
 
-static void test_insert_opened(int family, int sotype, int mapfd)
+static void test_insert_opened(struct test_sockmap_listen *skel __always_unused,
+                              int family, int sotype, int mapfd)
 {
        u32 key = 0;
        u64 value;
@@ -359,7 +363,8 @@ static void test_insert_opened(int family, int sotype, int mapfd)
        xclose(s);
 }
 
-static void test_insert_bound(int family, int sotype, int mapfd)
+static void test_insert_bound(struct test_sockmap_listen *skel __always_unused,
+                             int family, int sotype, int mapfd)
 {
        struct sockaddr_storage addr;
        socklen_t len;
@@ -386,7 +391,8 @@ close:
        xclose(s);
 }
 
-static void test_insert(int family, int sotype, int mapfd)
+static void test_insert(struct test_sockmap_listen *skel __always_unused,
+                       int family, int sotype, int mapfd)
 {
        u64 value;
        u32 key;
@@ -402,7 +408,8 @@ static void test_insert(int family, int sotype, int mapfd)
        xclose(s);
 }
 
-static void test_delete_after_insert(int family, int sotype, int mapfd)
+static void test_delete_after_insert(struct test_sockmap_listen *skel __always_unused,
+                                    int family, int sotype, int mapfd)
 {
        u64 value;
        u32 key;
@@ -419,7 +426,8 @@ static void test_delete_after_insert(int family, int sotype, int mapfd)
        xclose(s);
 }
 
-static void test_delete_after_close(int family, int sotype, int mapfd)
+static void test_delete_after_close(struct test_sockmap_listen *skel __always_unused,
+                                   int family, int sotype, int mapfd)
 {
        int err, s;
        u64 value;
@@ -442,7 +450,8 @@ static void test_delete_after_close(int family, int sotype, int mapfd)
                FAIL_ERRNO("map_delete: expected EINVAL/EINVAL");
 }
 
-static void test_lookup_after_insert(int family, int sotype, int mapfd)
+static void test_lookup_after_insert(struct test_sockmap_listen *skel __always_unused,
+                                    int family, int sotype, int mapfd)
 {
        u64 cookie, value;
        socklen_t len;
@@ -470,7 +479,8 @@ static void test_lookup_after_insert(int family, int sotype, int mapfd)
        xclose(s);
 }
 
-static void test_lookup_after_delete(int family, int sotype, int mapfd)
+static void test_lookup_after_delete(struct test_sockmap_listen *skel __always_unused,
+                                    int family, int sotype, int mapfd)
 {
        int err, s;
        u64 value;
@@ -493,7 +503,8 @@ static void test_lookup_after_delete(int family, int sotype, int mapfd)
        xclose(s);
 }
 
-static void test_lookup_32_bit_value(int family, int sotype, int mapfd)
+static void test_lookup_32_bit_value(struct test_sockmap_listen *skel __always_unused,
+                                    int family, int sotype, int mapfd)
 {
        u32 key, value32;
        int err, s;
@@ -523,7 +534,8 @@ close:
        xclose(s);
 }
 
-static void test_update_existing(int family, int sotype, int mapfd)
+static void test_update_existing(struct test_sockmap_listen *skel __always_unused,
+                                int family, int sotype, int mapfd)
 {
        int s1, s2;
        u64 value;
@@ -551,7 +563,7 @@ close_s1:
 /* Exercise the code path where we destroy child sockets that never
  * got accept()'ed, aka orphans, when parent socket gets closed.
  */
-static void test_destroy_orphan_child(int family, int sotype, int mapfd)
+static void do_destroy_orphan_child(int family, int sotype, int mapfd)
 {
        struct sockaddr_storage addr;
        socklen_t len;
@@ -582,10 +594,38 @@ close_srv:
        xclose(s);
 }
 
+static void test_destroy_orphan_child(struct test_sockmap_listen *skel,
+                                     int family, int sotype, int mapfd)
+{
+       int msg_verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
+       int skb_verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
+       const struct test {
+               int progfd;
+               enum bpf_attach_type atype;
+       } tests[] = {
+               { -1, -1 },
+               { msg_verdict, BPF_SK_MSG_VERDICT },
+               { skb_verdict, BPF_SK_SKB_VERDICT },
+       };
+       const struct test *t;
+
+       for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
+               if (t->progfd != -1 &&
+                   xbpf_prog_attach(t->progfd, mapfd, t->atype, 0) != 0)
+                       return;
+
+               do_destroy_orphan_child(family, sotype, mapfd);
+
+               if (t->progfd != -1)
+                       xbpf_prog_detach2(t->progfd, mapfd, t->atype);
+       }
+}
+
 /* Perform a passive open after removing listening socket from SOCKMAP
  * to ensure that callbacks get restored properly.
  */
-static void test_clone_after_delete(int family, int sotype, int mapfd)
+static void test_clone_after_delete(struct test_sockmap_listen *skel __always_unused,
+                                   int family, int sotype, int mapfd)
 {
        struct sockaddr_storage addr;
        socklen_t len;
@@ -621,7 +661,8 @@ close_srv:
  * SOCKMAP, but got accept()'ed only after the parent has been removed
  * from SOCKMAP, gets cloned without parent psock state or callbacks.
  */
-static void test_accept_after_delete(int family, int sotype, int mapfd)
+static void test_accept_after_delete(struct test_sockmap_listen *skel __always_unused,
+                                    int family, int sotype, int mapfd)
 {
        struct sockaddr_storage addr;
        const u32 zero = 0;
@@ -675,7 +716,8 @@ close_srv:
 /* Check that child socket that got created and accepted while parent
  * was in a SOCKMAP is cloned without parent psock state or callbacks.
  */
-static void test_accept_before_delete(int family, int sotype, int mapfd)
+static void test_accept_before_delete(struct test_sockmap_listen *skel __always_unused,
+                                     int family, int sotype, int mapfd)
 {
        struct sockaddr_storage addr;
        const u32 zero = 0, one = 1;
@@ -784,7 +826,8 @@ done:
        return NULL;
 }
 
-static void test_syn_recv_insert_delete(int family, int sotype, int mapfd)
+static void test_syn_recv_insert_delete(struct test_sockmap_listen *skel __always_unused,
+                                       int family, int sotype, int mapfd)
 {
        struct connect_accept_ctx ctx = { 0 };
        struct sockaddr_storage addr;
@@ -847,7 +890,8 @@ static void *listen_thread(void *arg)
        return NULL;
 }
 
-static void test_race_insert_listen(int family, int socktype, int mapfd)
+static void test_race_insert_listen(struct test_sockmap_listen *skel __always_unused,
+                                   int family, int socktype, int mapfd)
 {
        struct connect_accept_ctx ctx = { 0 };
        const u32 zero = 0;
@@ -1473,7 +1517,8 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
                     int family, int sotype)
 {
        const struct op_test {
-               void (*fn)(int family, int sotype, int mapfd);
+               void (*fn)(struct test_sockmap_listen *skel,
+                          int family, int sotype, int mapfd);
                const char *name;
                int sotype;
        } tests[] = {
@@ -1520,7 +1565,7 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
                if (!test__start_subtest(s))
                        continue;
 
-               t->fn(family, sotype, map_fd);
+               t->fn(skel, family, sotype, map_fd);
                test_ops_cleanup(map);
        }
 }
index 68b14fd..d63fd89 100644 (file)
        .result_unpriv = ACCEPT,
        .insn_processed = 15,
 },
+/* The test performs a conditional 64-bit write to a stack location
+ * fp[-8], this is followed by an unconditional 8-bit write to fp[-8],
+ * then data is read from fp[-8]. This sequence is unsafe.
+ *
+ * The test would be mistakenly marked as safe w/o dst register parent
+ * preservation in verifier.c:copy_register_state() function.
+ *
+ * Note the usage of BPF_F_TEST_STATE_FREQ to force creation of the
+ * checkpoint state after conditional 64-bit assignment.
+ */
+{
+       "write tracking and register parent chain bug",
+       .insns = {
+       /* r6 = ktime_get_ns() */
+       BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns),
+       BPF_MOV64_REG(BPF_REG_6, BPF_REG_0),
+       /* r0 = ktime_get_ns() */
+       BPF_EMIT_CALL(BPF_FUNC_ktime_get_ns),
+       /* if r0 > r6 goto +1 */
+       BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_6, 1),
+       /* *(u64 *)(r10 - 8) = 0xdeadbeef */
+       BPF_ST_MEM(BPF_DW, BPF_REG_FP, -8, 0xdeadbeef),
+       /* r1 = 42 */
+       BPF_MOV64_IMM(BPF_REG_1, 42),
+       /* *(u8 *)(r10 - 8) = r1 */
+       BPF_STX_MEM(BPF_B, BPF_REG_FP, BPF_REG_1, -8),
+       /* r2 = *(u64 *)(r10 - 8) */
+       BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_FP, -8),
+       /* exit(0) */
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_EXIT_INSN(),
+       },
+       .flags = BPF_F_TEST_STATE_FREQ,
+       .errstr = "invalid read from stack off -8+1 size 8",
+       .result = REJECT,
+},
index 186e1c2..75c100d 100755 (executable)
@@ -268,6 +268,7 @@ TEST_MATRIX=(
        # Taking away all CPUs from parent or itself if there are tasks
        # will make the partition invalid.
        "  S+ C2-3:P1:S+  C3:P1  .      .      T     C2-3    .      .     0 A1:2-3,A2:2-3 A1:P1,A2:P-1"
+       "  S+  C3:P1:S+    C3    .      .      T      P1     .      .     0 A1:3,A2:3 A1:P1,A2:P-1"
        "  S+ $SETUP_A123_PARTITIONS    .    T:C2-3   .      .      .     0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
        "  S+ $SETUP_A123_PARTITIONS    . T:C2-3:C1-3 .      .      .     0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
 
index 9c79bbc..aff0a59 100755 (executable)
@@ -246,7 +246,7 @@ test_vlan_ingress_modify()
        bridge vlan add dev $swp2 vid 300
 
        tc filter add dev $swp1 ingress chain $(IS1 2) pref 3 \
-               protocol 802.1Q flower skip_sw vlan_id 200 \
+               protocol 802.1Q flower skip_sw vlan_id 200 src_mac $h1_mac \
                action vlan modify id 300 \
                action goto chain $(IS2 0 0)
 
index beb944f..54680dc 100644 (file)
@@ -237,6 +237,11 @@ static void guest_check_s1ptw_wr_in_dirty_log(void)
        GUEST_SYNC(CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG);
 }
 
+static void guest_check_no_s1ptw_wr_in_dirty_log(void)
+{
+       GUEST_SYNC(CMD_CHECK_NO_S1PTW_WR_IN_DIRTY_LOG);
+}
+
 static void guest_exec(void)
 {
        int (*code)(void) = (int (*)(void))TEST_EXEC_GVA;
@@ -304,7 +309,7 @@ static struct uffd_args {
 
 /* Returns true to continue the test, and false if it should be skipped. */
 static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,
-                               struct uffd_args *args, bool expect_write)
+                               struct uffd_args *args)
 {
        uint64_t addr = msg->arg.pagefault.address;
        uint64_t flags = msg->arg.pagefault.flags;
@@ -313,7 +318,6 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,
 
        TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING,
                    "The only expected UFFD mode is MISSING");
-       ASSERT_EQ(!!(flags & UFFD_PAGEFAULT_FLAG_WRITE), expect_write);
        ASSERT_EQ(addr, (uint64_t)args->hva);
 
        pr_debug("uffd fault: addr=%p write=%d\n",
@@ -337,19 +341,14 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,
        return 0;
 }
 
-static int uffd_pt_write_handler(int mode, int uffd, struct uffd_msg *msg)
-{
-       return uffd_generic_handler(mode, uffd, msg, &pt_args, true);
-}
-
-static int uffd_data_write_handler(int mode, int uffd, struct uffd_msg *msg)
+static int uffd_pt_handler(int mode, int uffd, struct uffd_msg *msg)
 {
-       return uffd_generic_handler(mode, uffd, msg, &data_args, true);
+       return uffd_generic_handler(mode, uffd, msg, &pt_args);
 }
 
-static int uffd_data_read_handler(int mode, int uffd, struct uffd_msg *msg)
+static int uffd_data_handler(int mode, int uffd, struct uffd_msg *msg)
 {
-       return uffd_generic_handler(mode, uffd, msg, &data_args, false);
+       return uffd_generic_handler(mode, uffd, msg, &data_args);
 }
 
 static void setup_uffd_args(struct userspace_mem_region *region,
@@ -471,9 +470,12 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd)
 {
        struct userspace_mem_region *data_region, *pt_region;
        bool continue_test = true;
+       uint64_t pte_gpa, pte_pg;
 
        data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA);
        pt_region = vm_get_mem_region(vm, MEM_REGION_PT);
+       pte_gpa = addr_hva2gpa(vm, virt_get_pte_hva(vm, TEST_GVA));
+       pte_pg = (pte_gpa - pt_region->region.guest_phys_addr) / getpagesize();
 
        if (cmd == CMD_SKIP_TEST)
                continue_test = false;
@@ -486,13 +488,13 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd)
                TEST_ASSERT(check_write_in_dirty_log(vm, data_region, 0),
                            "Missing write in dirty log");
        if (cmd & CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG)
-               TEST_ASSERT(check_write_in_dirty_log(vm, pt_region, 0),
+               TEST_ASSERT(check_write_in_dirty_log(vm, pt_region, pte_pg),
                            "Missing s1ptw write in dirty log");
        if (cmd & CMD_CHECK_NO_WRITE_IN_DIRTY_LOG)
                TEST_ASSERT(!check_write_in_dirty_log(vm, data_region, 0),
                            "Unexpected write in dirty log");
        if (cmd & CMD_CHECK_NO_S1PTW_WR_IN_DIRTY_LOG)
-               TEST_ASSERT(!check_write_in_dirty_log(vm, pt_region, 0),
+               TEST_ASSERT(!check_write_in_dirty_log(vm, pt_region, pte_pg),
                            "Unexpected s1ptw write in dirty log");
 
        return continue_test;
@@ -797,7 +799,7 @@ static void help(char *name)
        .expected_events        = { .uffd_faults = _uffd_faults, },             \
 }
 
-#define TEST_DIRTY_LOG(_access, _with_af, _test_check)                         \
+#define TEST_DIRTY_LOG(_access, _with_af, _test_check, _pt_check)              \
 {                                                                              \
        .name                   = SCAT3(dirty_log, _access, _with_af),          \
        .data_memslot_flags     = KVM_MEM_LOG_DIRTY_PAGES,                      \
@@ -805,13 +807,12 @@ static void help(char *name)
        .guest_prepare          = { _PREPARE(_with_af),                         \
                                    _PREPARE(_access) },                        \
        .guest_test             = _access,                                      \
-       .guest_test_check       = { _CHECK(_with_af), _test_check,              \
-                                   guest_check_s1ptw_wr_in_dirty_log},         \
+       .guest_test_check       = { _CHECK(_with_af), _test_check, _pt_check }, \
        .expected_events        = { 0 },                                        \
 }
 
 #define TEST_UFFD_AND_DIRTY_LOG(_access, _with_af, _uffd_data_handler,         \
-                               _uffd_faults, _test_check)                      \
+                               _uffd_faults, _test_check, _pt_check)           \
 {                                                                              \
        .name                   = SCAT3(uffd_and_dirty_log, _access, _with_af), \
        .data_memslot_flags     = KVM_MEM_LOG_DIRTY_PAGES,                      \
@@ -820,16 +821,17 @@ static void help(char *name)
                                    _PREPARE(_access) },                        \
        .guest_test             = _access,                                      \
        .mem_mark_cmd           = CMD_HOLE_DATA | CMD_HOLE_PT,                  \
-       .guest_test_check       = { _CHECK(_with_af), _test_check },            \
+       .guest_test_check       = { _CHECK(_with_af), _test_check, _pt_check }, \
        .uffd_data_handler      = _uffd_data_handler,                           \
-       .uffd_pt_handler        = uffd_pt_write_handler,                        \
+       .uffd_pt_handler        = uffd_pt_handler,                              \
        .expected_events        = { .uffd_faults = _uffd_faults, },             \
 }
 
 #define TEST_RO_MEMSLOT(_access, _mmio_handler, _mmio_exits)                   \
 {                                                                              \
-       .name                   = SCAT3(ro_memslot, _access, _with_af),         \
+       .name                   = SCAT2(ro_memslot, _access),                   \
        .data_memslot_flags     = KVM_MEM_READONLY,                             \
+       .pt_memslot_flags       = KVM_MEM_READONLY,                             \
        .guest_prepare          = { _PREPARE(_access) },                        \
        .guest_test             = _access,                                      \
        .mmio_handler           = _mmio_handler,                                \
@@ -840,6 +842,7 @@ static void help(char *name)
 {                                                                              \
        .name                   = SCAT2(ro_memslot_no_syndrome, _access),       \
        .data_memslot_flags     = KVM_MEM_READONLY,                             \
+       .pt_memslot_flags       = KVM_MEM_READONLY,                             \
        .guest_test             = _access,                                      \
        .fail_vcpu_run_handler  = fail_vcpu_run_mmio_no_syndrome_handler,       \
        .expected_events        = { .fail_vcpu_runs = 1 },                      \
@@ -848,9 +851,9 @@ static void help(char *name)
 #define TEST_RO_MEMSLOT_AND_DIRTY_LOG(_access, _mmio_handler, _mmio_exits,     \
                                      _test_check)                              \
 {                                                                              \
-       .name                   = SCAT3(ro_memslot, _access, _with_af),         \
+       .name                   = SCAT2(ro_memslot, _access),                   \
        .data_memslot_flags     = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,   \
-       .pt_memslot_flags       = KVM_MEM_LOG_DIRTY_PAGES,                      \
+       .pt_memslot_flags       = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,   \
        .guest_prepare          = { _PREPARE(_access) },                        \
        .guest_test             = _access,                                      \
        .guest_test_check       = { _test_check },                              \
@@ -862,7 +865,7 @@ static void help(char *name)
 {                                                                              \
        .name                   = SCAT2(ro_memslot_no_syn_and_dlog, _access),   \
        .data_memslot_flags     = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,   \
-       .pt_memslot_flags       = KVM_MEM_LOG_DIRTY_PAGES,                      \
+       .pt_memslot_flags       = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,   \
        .guest_test             = _access,                                      \
        .guest_test_check       = { _test_check },                              \
        .fail_vcpu_run_handler  = fail_vcpu_run_mmio_no_syndrome_handler,       \
@@ -874,11 +877,12 @@ static void help(char *name)
 {                                                                              \
        .name                   = SCAT2(ro_memslot_uffd, _access),              \
        .data_memslot_flags     = KVM_MEM_READONLY,                             \
+       .pt_memslot_flags       = KVM_MEM_READONLY,                             \
        .mem_mark_cmd           = CMD_HOLE_DATA | CMD_HOLE_PT,                  \
        .guest_prepare          = { _PREPARE(_access) },                        \
        .guest_test             = _access,                                      \
        .uffd_data_handler      = _uffd_data_handler,                           \
-       .uffd_pt_handler        = uffd_pt_write_handler,                        \
+       .uffd_pt_handler        = uffd_pt_handler,                              \
        .mmio_handler           = _mmio_handler,                                \
        .expected_events        = { .mmio_exits = _mmio_exits,                  \
                                    .uffd_faults = _uffd_faults },              \
@@ -889,10 +893,11 @@ static void help(char *name)
 {                                                                              \
        .name                   = SCAT2(ro_memslot_no_syndrome, _access),       \
        .data_memslot_flags     = KVM_MEM_READONLY,                             \
+       .pt_memslot_flags       = KVM_MEM_READONLY,                             \
        .mem_mark_cmd           = CMD_HOLE_DATA | CMD_HOLE_PT,                  \
        .guest_test             = _access,                                      \
        .uffd_data_handler      = _uffd_data_handler,                           \
-       .uffd_pt_handler        = uffd_pt_write_handler,                        \
+       .uffd_pt_handler        = uffd_pt_handler,                      \
        .fail_vcpu_run_handler  = fail_vcpu_run_mmio_no_syndrome_handler,       \
        .expected_events        = { .fail_vcpu_runs = 1,                        \
                                    .uffd_faults = _uffd_faults },              \
@@ -933,44 +938,51 @@ static struct test_desc tests[] = {
         * (S1PTW).
         */
        TEST_UFFD(guest_read64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_read_handler, uffd_pt_write_handler, 2),
-       /* no_af should also lead to a PT write. */
+                 uffd_data_handler, uffd_pt_handler, 2),
        TEST_UFFD(guest_read64, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_read_handler, uffd_pt_write_handler, 2),
-       /* Note how that cas invokes the read handler. */
+                 uffd_data_handler, uffd_pt_handler, 2),
        TEST_UFFD(guest_cas, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_read_handler, uffd_pt_write_handler, 2),
+                 uffd_data_handler, uffd_pt_handler, 2),
        /*
         * Can't test guest_at with_af as it's IMPDEF whether the AF is set.
         * The S1PTW fault should still be marked as a write.
         */
        TEST_UFFD(guest_at, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_read_handler, uffd_pt_write_handler, 1),
+                 uffd_no_handler, uffd_pt_handler, 1),
        TEST_UFFD(guest_ld_preidx, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_read_handler, uffd_pt_write_handler, 2),
+                 uffd_data_handler, uffd_pt_handler, 2),
        TEST_UFFD(guest_write64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_write_handler, uffd_pt_write_handler, 2),
+                 uffd_data_handler, uffd_pt_handler, 2),
        TEST_UFFD(guest_dc_zva, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_write_handler, uffd_pt_write_handler, 2),
+                 uffd_data_handler, uffd_pt_handler, 2),
        TEST_UFFD(guest_st_preidx, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_write_handler, uffd_pt_write_handler, 2),
+                 uffd_data_handler, uffd_pt_handler, 2),
        TEST_UFFD(guest_exec, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
-                 uffd_data_read_handler, uffd_pt_write_handler, 2),
+                 uffd_data_handler, uffd_pt_handler, 2),
 
        /*
         * Try accesses when the data and PT memory regions are both
         * tracked for dirty logging.
         */
-       TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log),
-       /* no_af should also lead to a PT write. */
-       TEST_DIRTY_LOG(guest_read64, no_af, guest_check_no_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_ld_preidx, with_af, guest_check_no_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_exec, with_af, guest_check_no_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_write64, with_af, guest_check_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_cas, with_af, guest_check_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log),
-       TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log),
+       TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_read64, no_af, guest_check_no_write_in_dirty_log,
+                      guest_check_no_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_ld_preidx, with_af,
+                      guest_check_no_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log,
+                      guest_check_no_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_exec, with_af, guest_check_no_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_write64, with_af, guest_check_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_cas, with_af, guest_check_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
+       TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log,
+                      guest_check_s1ptw_wr_in_dirty_log),
 
        /*
         * Access when the data and PT memory regions are both marked for
@@ -980,29 +992,43 @@ static struct test_desc tests[] = {
         * fault, and nothing in the dirty log.  Any S1PTW should result in
         * a write in the dirty log and a userfaultfd write.
         */
-       TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, uffd_data_read_handler, 2,
-                               guest_check_no_write_in_dirty_log),
-       /* no_af should also lead to a PT write. */
-       TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, uffd_data_read_handler, 2,
-                               guest_check_no_write_in_dirty_log),
-       TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, uffd_data_read_handler,
-                               2, guest_check_no_write_in_dirty_log),
-       TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, 0, 1,
-                               guest_check_no_write_in_dirty_log),
-       TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, uffd_data_read_handler, 2,
-                               guest_check_no_write_in_dirty_log),
-       TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, uffd_data_write_handler,
-                               2, guest_check_write_in_dirty_log),
-       TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, uffd_data_read_handler, 2,
-                               guest_check_write_in_dirty_log),
-       TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af, uffd_data_write_handler,
-                               2, guest_check_write_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af,
+                               uffd_data_handler, 2,
+                               guest_check_no_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af,
+                               uffd_data_handler, 2,
+                               guest_check_no_write_in_dirty_log,
+                               guest_check_no_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af,
+                               uffd_data_handler,
+                               2, guest_check_no_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, uffd_no_handler, 1,
+                               guest_check_no_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af,
+                               uffd_data_handler, 2,
+                               guest_check_no_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af,
+                               uffd_data_handler,
+                               2, guest_check_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af,
+                               uffd_data_handler, 2,
+                               guest_check_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
+       TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af,
+                               uffd_data_handler,
+                               2, guest_check_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
        TEST_UFFD_AND_DIRTY_LOG(guest_st_preidx, with_af,
-                               uffd_data_write_handler, 2,
-                               guest_check_write_in_dirty_log),
-
+                               uffd_data_handler, 2,
+                               guest_check_write_in_dirty_log,
+                               guest_check_s1ptw_wr_in_dirty_log),
        /*
-        * Try accesses when the data memory region is marked read-only
+        * Access when both the PT and data regions are marked read-only
         * (with KVM_MEM_READONLY). Writes with a syndrome result in an
         * MMIO exit, writes with no syndrome (e.g., CAS) result in a
         * failed vcpu run, and reads/execs with and without syndroms do
@@ -1018,7 +1044,7 @@ static struct test_desc tests[] = {
        TEST_RO_MEMSLOT_NO_SYNDROME(guest_st_preidx),
 
        /*
-        * Access when both the data region is both read-only and marked
+        * The PT and data regions are both read-only and marked
         * for dirty logging at the same time. The expected result is that
         * for writes there should be no write in the dirty log. The
         * readonly handling is the same as if the memslot was not marked
@@ -1043,7 +1069,7 @@ static struct test_desc tests[] = {
                                                  guest_check_no_write_in_dirty_log),
 
        /*
-        * Access when the data region is both read-only and punched with
+        * The PT and data regions are both read-only and punched with
         * holes tracked with userfaultfd.  The expected result is the
         * union of both userfaultfd and read-only behaviors. For example,
         * write accesses result in a userfaultfd write fault and an MMIO
@@ -1051,22 +1077,15 @@ static struct test_desc tests[] = {
         * no userfaultfd write fault. Reads result in userfaultfd getting
         * triggered.
         */
-       TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0,
-                                uffd_data_read_handler, 2),
-       TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0,
-                                uffd_data_read_handler, 2),
-       TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0,
-                                uffd_no_handler, 1),
-       TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0,
-                                uffd_data_read_handler, 2),
+       TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0, uffd_data_handler, 2),
+       TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0, uffd_data_handler, 2),
+       TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0, uffd_no_handler, 1),
+       TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0, uffd_data_handler, 2),
        TEST_RO_MEMSLOT_AND_UFFD(guest_write64, mmio_on_test_gpa_handler, 1,
-                                uffd_data_write_handler, 2),
-       TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas,
-                                            uffd_data_read_handler, 2),
-       TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva,
-                                            uffd_no_handler, 1),
-       TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx,
-                                            uffd_no_handler, 1),
+                                uffd_data_handler, 2),
+       TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas, uffd_data_handler, 2),
+       TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva, uffd_no_handler, 1),
+       TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx, uffd_no_handler, 1),
 
        { 0 }
 };
index ea0978f..251794f 100644 (file)
@@ -241,7 +241,7 @@ int main(int argc, char **argv)
        while ((opt = getopt(argc, argv, "hp:t:r")) != -1) {
                switch (opt) {
                case 'p':
-                       reclaim_period_ms = atoi_non_negative("Reclaim period", optarg);
+                       reclaim_period_ms = atoi_positive("Reclaim period", optarg);
                        break;
                case 't':
                        token = atoi_paranoid(optarg);
index dae510c..13c75dc 100644 (file)
@@ -434,6 +434,7 @@ static void *juggle_shinfo_state(void *arg)
 int main(int argc, char *argv[])
 {
        struct timespec min_ts, max_ts, vm_ts;
+       struct kvm_xen_hvm_attr evt_reset;
        struct kvm_vm *vm;
        pthread_t thread;
        bool verbose;
@@ -962,10 +963,8 @@ int main(int argc, char *argv[])
        }
 
  done:
-       struct kvm_xen_hvm_attr evt_reset = {
-               .type = KVM_XEN_ATTR_TYPE_EVTCHN,
-               .u.evtchn.flags = KVM_XEN_EVTCHN_RESET,
-       };
+       evt_reset.type = KVM_XEN_ATTR_TYPE_EVTCHN;
+       evt_reset.u.evtchn.flags = KVM_XEN_EVTCHN_RESET;
        vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &evt_reset);
 
        alarm(0);
index 291144c..f7900e7 100644 (file)
@@ -20,7 +20,7 @@ CLANG_TARGET_FLAGS              := $(CLANG_TARGET_FLAGS_$(ARCH))
 
 ifeq ($(CROSS_COMPILE),)
 ifeq ($(CLANG_TARGET_FLAGS),)
-$(error Specify CROSS_COMPILE or add '--target=' option to lib.mk
+$(error Specify CROSS_COMPILE or add '--target=' option to lib.mk)
 else
 CLANG_FLAGS     += --target=$(CLANG_TARGET_FLAGS)
 endif # CLANG_TARGET_FLAGS
index b57e91e..532459a 100644 (file)
@@ -124,7 +124,7 @@ void producer(struct sockaddr_un *consumer_addr)
 
        wait_for_signal(pipefd[0]);
        if (connect(cfd, (struct sockaddr *)consumer_addr,
-                    sizeof(struct sockaddr)) != 0) {
+                    sizeof(*consumer_addr)) != 0) {
                perror("Connect failed");
                kill(0, SIGTERM);
                exit(1);
index 2d89cb0..330d0b1 100755 (executable)
@@ -6,7 +6,7 @@ ksft_skip=4
 NS=ns
 IP6=2001:db8:1::1/64
 TGT6=2001:db8:1::2
-TMPF=`mktemp`
+TMPF=$(mktemp --suffix ".pcap")
 
 cleanup()
 {
index 1c4f866..3d8e4eb 100755 (executable)
@@ -914,14 +914,14 @@ sysctl_set()
        local value=$1; shift
 
        SYSCTL_ORIG[$key]=$(sysctl -n $key)
-       sysctl -qw $key=$value
+       sysctl -qw $key="$value"
 }
 
 sysctl_restore()
 {
        local key=$1; shift
 
-       sysctl -qw $key=${SYSCTL_ORIG["$key"]}
+       sysctl -qw $key="${SYSCTL_ORIG[$key]}"
 }
 
 forwarding_enable()
index dca1e6f..f11756e 100755 (executable)
 # In addition this script also checks if forcing a specific field in the
 # outer header is working.
 
+# Return 4 by default (Kselftest SKIP code)
+ERR=4
+
 if [ "$(id -u)" != "0" ]; then
        echo "Please run as root."
-       exit 0
+       exit $ERR
 fi
 if ! which tcpdump > /dev/null 2>&1; then
        echo "No tcpdump found. Required for this test."
-       exit 0
+       exit $ERR
 fi
 
 expected_tos="0x00"
 expected_ttl="0"
 failed=false
 
+readonly NS0=$(mktemp -u ns0-XXXXXXXX)
+readonly NS1=$(mktemp -u ns1-XXXXXXXX)
+
+RUN_NS0="ip netns exec ${NS0}"
+
 get_random_tos() {
        # Get a random hex tos value between 0x00 and 0xfc, a multiple of 4
        echo "0x$(tr -dc '0-9a-f' < /dev/urandom | head -c 1)\
@@ -61,7 +69,6 @@ setup() {
        local vlan="$5"
        local test_tos="0x00"
        local test_ttl="0"
-       local ns="ip netns exec testing"
 
        # We don't want a test-tos of 0x00,
        # because this is the value that we get when no tos is set.
@@ -94,14 +101,15 @@ setup() {
        printf "│%7s │%6s │%6s │%13s │%13s │%6s │" \
        "$type" "$outer" "$inner" "$tos" "$ttl" "$vlan"
 
-       # Create 'testing' netns, veth pair and connect main ns with testing ns
-       ip netns add testing
-       ip link add type veth
-       ip link set veth1 netns testing
-       ip link set veth0 up
-       $ns ip link set veth1 up
-       ip addr flush dev veth0
-       $ns ip addr flush dev veth1
+       # Create netns NS0 and NS1 and connect them with a veth pair
+       ip netns add "${NS0}"
+       ip netns add "${NS1}"
+       ip link add name veth0 netns "${NS0}" type veth \
+               peer name veth1 netns "${NS1}"
+       ip -netns "${NS0}" link set dev veth0 up
+       ip -netns "${NS1}" link set dev veth1 up
+       ip -netns "${NS0}" address flush dev veth0
+       ip -netns "${NS1}" address flush dev veth1
 
        local local_addr1=""
        local local_addr2=""
@@ -127,51 +135,59 @@ setup() {
                if [ "$type" = "gre" ]; then
                        type="gretap"
                fi
-               ip addr add 198.18.0.1/24 dev veth0
-               $ns ip addr add 198.18.0.2/24 dev veth1
-               ip link add name tep0 type $type $local_addr1 remote \
-               198.18.0.2 tos $test_tos ttl $test_ttl $vxlan $geneve
-               $ns ip link add name tep1 type $type $local_addr2 remote \
-               198.18.0.1 tos $test_tos ttl $test_ttl $vxlan $geneve
+               ip -netns "${NS0}" address add 198.18.0.1/24 dev veth0
+               ip -netns "${NS1}" address add 198.18.0.2/24 dev veth1
+               ip -netns "${NS0}" link add name tep0 type $type $local_addr1 \
+                       remote 198.18.0.2 tos $test_tos ttl $test_ttl         \
+                       $vxlan $geneve
+               ip -netns "${NS1}" link add name tep1 type $type $local_addr2 \
+                       remote 198.18.0.1 tos $test_tos ttl $test_ttl         \
+                       $vxlan $geneve
        elif [ "$outer" = "6" ]; then
                if [ "$type" = "gre" ]; then
                        type="ip6gretap"
                fi
-               ip addr add fdd1:ced0:5d88:3fce::1/64 dev veth0
-               $ns ip addr add fdd1:ced0:5d88:3fce::2/64 dev veth1
-               ip link add name tep0 type $type $local_addr1 \
-               remote fdd1:ced0:5d88:3fce::2 tos $test_tos ttl $test_ttl \
-               $vxlan $geneve
-               $ns ip link add name tep1 type $type $local_addr2 \
-               remote fdd1:ced0:5d88:3fce::1 tos $test_tos ttl $test_ttl \
-               $vxlan $geneve
+               ip -netns "${NS0}" address add fdd1:ced0:5d88:3fce::1/64 \
+                       dev veth0 nodad
+               ip -netns "${NS1}" address add fdd1:ced0:5d88:3fce::2/64 \
+                       dev veth1 nodad
+               ip -netns "${NS0}" link add name tep0 type $type $local_addr1 \
+                       remote fdd1:ced0:5d88:3fce::2 tos $test_tos           \
+                       ttl $test_ttl $vxlan $geneve
+               ip -netns "${NS1}" link add name tep1 type $type $local_addr2 \
+                       remote fdd1:ced0:5d88:3fce::1 tos $test_tos           \
+                       ttl $test_ttl $vxlan $geneve
        fi
 
        # Bring L2-tunnel link up and create VLAN on top
-       ip link set tep0 up
-       $ns ip link set tep1 up
-       ip addr flush dev tep0
-       $ns ip addr flush dev tep1
+       ip -netns "${NS0}" link set tep0 up
+       ip -netns "${NS1}" link set tep1 up
+       ip -netns "${NS0}" address flush dev tep0
+       ip -netns "${NS1}" address flush dev tep1
        local parent
        if $vlan; then
                parent="vlan99-"
-               ip link add link tep0 name ${parent}0 type vlan id 99
-               $ns ip link add link tep1 name ${parent}1 type vlan id 99
-               ip link set ${parent}0 up
-               $ns ip link set ${parent}1 up
-               ip addr flush dev ${parent}0
-               $ns ip addr flush dev ${parent}1
+               ip -netns "${NS0}" link add link tep0 name ${parent}0 \
+                       type vlan id 99
+               ip -netns "${NS1}" link add link tep1 name ${parent}1 \
+                       type vlan id 99
+               ip -netns "${NS0}" link set dev ${parent}0 up
+               ip -netns "${NS1}" link set dev ${parent}1 up
+               ip -netns "${NS0}" address flush dev ${parent}0
+               ip -netns "${NS1}" address flush dev ${parent}1
        else
                parent="tep"
        fi
 
        # Assign inner IPv4/IPv6 addresses
        if [ "$inner" = "4" ] || [ "$inner" = "other" ]; then
-               ip addr add 198.19.0.1/24 brd + dev ${parent}0
-               $ns ip addr add 198.19.0.2/24 brd + dev ${parent}1
+               ip -netns "${NS0}" address add 198.19.0.1/24 brd + dev ${parent}0
+               ip -netns "${NS1}" address add 198.19.0.2/24 brd + dev ${parent}1
        elif [ "$inner" = "6" ]; then
-               ip addr add fdd4:96cf:4eae:443b::1/64 dev ${parent}0
-               $ns ip addr add fdd4:96cf:4eae:443b::2/64 dev ${parent}1
+               ip -netns "${NS0}" address add fdd4:96cf:4eae:443b::1/64 \
+                       dev ${parent}0 nodad
+               ip -netns "${NS1}" address add fdd4:96cf:4eae:443b::2/64 \
+                       dev ${parent}1 nodad
        fi
 }
 
@@ -192,10 +208,10 @@ verify() {
                ping_dst="198.19.0.3" # Generates ARPs which are not IPv4/IPv6
        fi
        if [ "$tos_ttl" = "inherit" ]; then
-               ping -i 0.1 $ping_dst -Q "$expected_tos" -t "$expected_ttl" \
-               2>/dev/null 1>&2 & ping_pid="$!"
+               ${RUN_NS0} ping -i 0.1 $ping_dst -Q "$expected_tos"          \
+                        -t "$expected_ttl" 2>/dev/null 1>&2 & ping_pid="$!"
        else
-               ping -i 0.1 $ping_dst 2>/dev/null 1>&2 & ping_pid="$!"
+               ${RUN_NS0} ping -i 0.1 $ping_dst 2>/dev/null 1>&2 & ping_pid="$!"
        fi
        local tunnel_type_offset tunnel_type_proto req_proto_offset req_offset
        if [ "$type" = "gre" ]; then
@@ -216,10 +232,12 @@ verify() {
                                req_proto_offset="$((req_proto_offset + 4))"
                                req_offset="$((req_offset + 4))"
                        fi
-                       out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
-                       ip[$tunnel_type_offset] = $tunnel_type_proto and \
-                       ip[$req_proto_offset] = 0x01 and \
-                       ip[$req_offset] = 0x08 2>/dev/null | head -n 1)"
+                       out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
+                               -i veth0 -n                                   \
+                               ip[$tunnel_type_offset] = $tunnel_type_proto and \
+                               ip[$req_proto_offset] = 0x01 and              \
+                               ip[$req_offset] = 0x08 2>/dev/null            \
+                               | head -n 1)"
                elif [ "$inner" = "6" ]; then
                        req_proto_offset="44"
                        req_offset="78"
@@ -231,10 +249,12 @@ verify() {
                                req_proto_offset="$((req_proto_offset + 4))"
                                req_offset="$((req_offset + 4))"
                        fi
-                       out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
-                       ip[$tunnel_type_offset] = $tunnel_type_proto and \
-                       ip[$req_proto_offset] = 0x3a and \
-                       ip[$req_offset] = 0x80 2>/dev/null | head -n 1)"
+                       out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
+                               -i veth0 -n                                   \
+                               ip[$tunnel_type_offset] = $tunnel_type_proto and \
+                               ip[$req_proto_offset] = 0x3a and              \
+                               ip[$req_offset] = 0x80 2>/dev/null            \
+                               | head -n 1)"
                elif [ "$inner" = "other" ]; then
                        req_proto_offset="36"
                        req_offset="45"
@@ -250,11 +270,13 @@ verify() {
                                expected_tos="0x00"
                                expected_ttl="64"
                        fi
-                       out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
-                       ip[$tunnel_type_offset] = $tunnel_type_proto and \
-                       ip[$req_proto_offset] = 0x08 and \
-                       ip[$((req_proto_offset + 1))] = 0x06 and \
-                       ip[$req_offset] = 0x01 2>/dev/null | head -n 1)"
+                       out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
+                               -i veth0 -n                                   \
+                               ip[$tunnel_type_offset] = $tunnel_type_proto and \
+                               ip[$req_proto_offset] = 0x08 and              \
+                               ip[$((req_proto_offset + 1))] = 0x06 and      \
+                               ip[$req_offset] = 0x01 2>/dev/null            \
+                               | head -n 1)"
                fi
        elif [ "$outer" = "6" ]; then
                if [ "$type" = "gre" ]; then
@@ -273,10 +295,12 @@ verify() {
                                req_proto_offset="$((req_proto_offset + 4))"
                                req_offset="$((req_offset + 4))"
                        fi
-                       out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
-                       ip6[$tunnel_type_offset] = $tunnel_type_proto and \
-                       ip6[$req_proto_offset] = 0x01 and \
-                       ip6[$req_offset] = 0x08 2>/dev/null | head -n 1)"
+                       out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
+                               -i veth0 -n                                   \
+                               ip6[$tunnel_type_offset] = $tunnel_type_proto and \
+                               ip6[$req_proto_offset] = 0x01 and             \
+                               ip6[$req_offset] = 0x08 2>/dev/null           \
+                               | head -n 1)"
                elif [ "$inner" = "6" ]; then
                        local req_proto_offset="72"
                        local req_offset="106"
@@ -288,10 +312,12 @@ verify() {
                                req_proto_offset="$((req_proto_offset + 4))"
                                req_offset="$((req_offset + 4))"
                        fi
-                       out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
-                       ip6[$tunnel_type_offset] = $tunnel_type_proto and \
-                       ip6[$req_proto_offset] = 0x3a and \
-                       ip6[$req_offset] = 0x80 2>/dev/null | head -n 1)"
+                       out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
+                               -i veth0 -n                                   \
+                               ip6[$tunnel_type_offset] = $tunnel_type_proto and \
+                               ip6[$req_proto_offset] = 0x3a and             \
+                               ip6[$req_offset] = 0x80 2>/dev/null           \
+                               | head -n 1)"
                elif [ "$inner" = "other" ]; then
                        local req_proto_offset="64"
                        local req_offset="73"
@@ -307,15 +333,17 @@ verify() {
                                expected_tos="0x00"
                                expected_ttl="64"
                        fi
-                       out="$(tcpdump --immediate-mode -p -c 1 -v -i veth0 -n \
-                       ip6[$tunnel_type_offset] = $tunnel_type_proto and \
-                       ip6[$req_proto_offset] = 0x08 and \
-                       ip6[$((req_proto_offset + 1))] = 0x06 and \
-                       ip6[$req_offset] = 0x01 2>/dev/null | head -n 1)"
+                       out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \
+                               -i veth0 -n                                   \
+                               ip6[$tunnel_type_offset] = $tunnel_type_proto and \
+                               ip6[$req_proto_offset] = 0x08 and             \
+                               ip6[$((req_proto_offset + 1))] = 0x06 and     \
+                               ip6[$req_offset] = 0x01 2>/dev/null           \
+                               | head -n 1)"
                fi
        fi
        kill -9 $ping_pid
-       wait $ping_pid 2>/dev/null
+       wait $ping_pid 2>/dev/null || true
        result="FAIL"
        if [ "$outer" = "4" ]; then
                captured_ttl="$(get_field "ttl" "$out")"
@@ -351,11 +379,35 @@ verify() {
 }
 
 cleanup() {
-       ip link del veth0 2>/dev/null
-       ip netns del testing 2>/dev/null
-       ip link del tep0 2>/dev/null
+       ip netns del "${NS0}" 2>/dev/null
+       ip netns del "${NS1}" 2>/dev/null
 }
 
+exit_handler() {
+       # Don't exit immediately if one of the intermediate commands fails.
+       # We might be called at the end of the script, when the network
+       # namespaces have already been deleted. So cleanup() may fail, but we
+       # still need to run until 'exit $ERR' or the script won't return the
+       # correct error code.
+       set +e
+
+       cleanup
+
+       exit $ERR
+}
+
+# Restore the default SIGINT handler (just in case) and exit.
+# The exit handler will take care of cleaning everything up.
+interrupted() {
+       trap - INT
+
+       exit $ERR
+}
+
+set -e
+trap exit_handler EXIT
+trap interrupted INT
+
 printf "┌────────┬───────┬───────┬──────────────┬"
 printf "──────────────┬───────┬────────┐\n"
 for type in gre vxlan geneve; do
@@ -385,6 +437,10 @@ done
 printf "└────────┴───────┴───────┴──────────────┴"
 printf "──────────────┴───────┴────────┘\n"
 
+# All tests done.
+# Set ERR appropriately: it will be returned by the exit handler.
 if $failed; then
-       exit 1
+       ERR=1
+else
+       ERR=0
 fi
index d11d3d5..079f8f4 100755 (executable)
@@ -498,6 +498,12 @@ kill_events_pids()
        kill_wait $evts_ns2_pid
 }
 
+kill_tests_wait()
+{
+       kill -SIGUSR1 $(ip netns pids $ns2) $(ip netns pids $ns1)
+       wait
+}
+
 pm_nl_set_limits()
 {
        local ns=$1
@@ -1694,6 +1700,7 @@ chk_subflow_nr()
        local subflow_nr=$3
        local cnt1
        local cnt2
+       local dump_stats
 
        if [ -n "${need_title}" ]; then
                printf "%03u %-36s %s" "${TEST_COUNT}" "${TEST_NAME}" "${msg}"
@@ -1711,7 +1718,12 @@ chk_subflow_nr()
                echo "[ ok ]"
        fi
 
-       [ "${dump_stats}" = 1 ] && ( ss -N $ns1 -tOni ; ss -N $ns1 -tOni | grep token; ip -n $ns1 mptcp endpoint )
+       if [ "${dump_stats}" = 1 ]; then
+               ss -N $ns1 -tOni
+               ss -N $ns1 -tOni | grep token
+               ip -n $ns1 mptcp endpoint
+               dump_stats
+       fi
 }
 
 chk_link_usage()
@@ -3049,7 +3061,7 @@ endpoint_tests()
                pm_nl_set_limits $ns1 2 2
                pm_nl_set_limits $ns2 2 2
                pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
-               run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow &
+               run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow 2>/dev/null &
 
                wait_mpj $ns1
                pm_nl_check_endpoint 1 "creation" \
@@ -3062,14 +3074,14 @@ endpoint_tests()
                pm_nl_add_endpoint $ns2 10.0.2.2 flags signal
                pm_nl_check_endpoint 0 "modif is allowed" \
                        $ns2 10.0.2.2 id 1 flags signal
-               wait
+               kill_tests_wait
        fi
 
        if reset "delete and re-add"; then
                pm_nl_set_limits $ns1 1 1
                pm_nl_set_limits $ns2 1 1
                pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow
-               run_tests $ns1 $ns2 10.0.1.1 4 0 0 slow &
+               run_tests $ns1 $ns2 10.0.1.1 4 0 0 speed_20 2>/dev/null &
 
                wait_mpj $ns2
                pm_nl_del_endpoint $ns2 2 10.0.2.2
@@ -3079,7 +3091,7 @@ endpoint_tests()
                pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow
                wait_mpj $ns2
                chk_subflow_nr "" "after re-add" 2
-               wait
+               kill_tests_wait
        fi
 }
 
index a29deb9..ab2d581 100755 (executable)
@@ -752,6 +752,52 @@ test_subflows()
           "$server4_token" > /dev/null 2>&1
 }
 
+test_subflows_v4_v6_mix()
+{
+       # Attempt to add a listener at 10.0.2.1:<subflow-port>
+       ip netns exec "$ns1" ./pm_nl_ctl listen 10.0.2.1\
+          $app6_port > /dev/null 2>&1 &
+       local listener_pid=$!
+
+       # ADD_ADDR4 from server to client machine reusing the subflow port on
+       # the established v6 connection
+       :>"$client_evts"
+       ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server6_token" id\
+          $server_addr_id dev ns1eth2 > /dev/null 2>&1
+       stdbuf -o0 -e0 printf "ADD_ADDR4 id:%d 10.0.2.1 (ns1) => ns2, reuse port\t\t" $server_addr_id
+       sleep 0.5
+       verify_announce_event "$client_evts" "$ANNOUNCED" "$client6_token" "10.0.2.1"\
+                             "$server_addr_id" "$app6_port"
+
+       # CREATE_SUBFLOW from client to server machine
+       :>"$client_evts"
+       ip netns exec "$ns2" ./pm_nl_ctl csf lip 10.0.2.2 lid 23 rip 10.0.2.1 rport\
+          $app6_port token "$client6_token" > /dev/null 2>&1
+       sleep 0.5
+       verify_subflow_events "$client_evts" "$SUB_ESTABLISHED" "$client6_token"\
+                             "$AF_INET" "10.0.2.2" "10.0.2.1" "$app6_port" "23"\
+                             "$server_addr_id" "ns2" "ns1"
+
+       # Delete the listener from the server ns, if one was created
+       kill_wait $listener_pid
+
+       sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
+
+       # DESTROY_SUBFLOW from client to server machine
+       :>"$client_evts"
+       ip netns exec "$ns2" ./pm_nl_ctl dsf lip 10.0.2.2 lport "$sport" rip 10.0.2.1 rport\
+          $app6_port token "$client6_token" > /dev/null 2>&1
+       sleep 0.5
+       verify_subflow_events "$client_evts" "$SUB_CLOSED" "$client6_token" \
+                             "$AF_INET" "10.0.2.2" "10.0.2.1" "$app6_port" "23"\
+                             "$server_addr_id" "ns2" "ns1"
+
+       # RM_ADDR from server to client machine
+       ip netns exec "$ns1" ./pm_nl_ctl rem id $server_addr_id token\
+          "$server6_token" > /dev/null 2>&1
+       sleep 0.5
+}
+
 test_prio()
 {
        local count
@@ -861,6 +907,7 @@ make_connection "v6"
 test_announce
 test_remove
 test_subflows
+test_subflows_v4_v6_mix
 test_prio
 test_listener
 
index 704997f..8c3ac0a 100755 (executable)
@@ -293,19 +293,11 @@ setup-vm() {
        elif [[ -n $vtype && $vtype == "vnifilterg" ]]; then
           # Add per vni group config with 'bridge vni' api
           if [ -n "$group" ]; then
-             if [ "$family" == "v4" ]; then
-                if [ $mcast -eq 1 ]; then
-                   bridge -netns hv-$hvid vni add dev $vxlandev vni $tid group $group
-                else
-                   bridge -netns hv-$hvid vni add dev $vxlandev vni $tid remote $group
-                fi
-             else
-                if [ $mcast -eq 1 ]; then
-                   bridge -netns hv-$hvid vni add dev $vxlandev vni $tid group6 $group
-                else
-                   bridge -netns hv-$hvid vni add dev $vxlandev vni $tid remote6 $group
-                fi
-             fi
+               if [ $mcast -eq 1 ]; then
+                       bridge -netns hv-$hvid vni add dev $vxlandev vni $tid group $group
+               else
+                       bridge -netns hv-$hvid vni add dev $vxlandev vni $tid remote $group
+               fi
           fi
        fi
        done
index 90026a2..9ba0316 100644 (file)
@@ -215,7 +215,7 @@ static char *recv_frame(const struct ring_state *ring, char *frame)
 }
 
 /* A single TPACKET_V3 block can hold multiple frames */
-static void recv_block(struct ring_state *ring)
+static bool recv_block(struct ring_state *ring)
 {
        struct tpacket_block_desc *block;
        char *frame;
@@ -223,7 +223,7 @@ static void recv_block(struct ring_state *ring)
 
        block = (void *)(ring->mmap + ring->idx * ring_block_sz);
        if (!(block->hdr.bh1.block_status & TP_STATUS_USER))
-               return;
+               return false;
 
        frame = (char *)block;
        frame += block->hdr.bh1.offset_to_first_pkt;
@@ -235,6 +235,8 @@ static void recv_block(struct ring_state *ring)
 
        block->hdr.bh1.block_status = TP_STATUS_KERNEL;
        ring->idx = (ring->idx + 1) % ring_block_nr;
+
+       return true;
 }
 
 /* simple test: sleep once unconditionally and then process all rings */
@@ -245,7 +247,7 @@ static void process_rings(void)
        usleep(1000 * cfg_timeout_msec);
 
        for (i = 0; i < num_cpus; i++)
-               recv_block(&rings[i]);
+               do {} while (recv_block(&rings[i]));
 
        fprintf(stderr, "count: pass=%u nohash=%u fail=%u\n",
                frames_received - frames_nohash - frames_error,
@@ -257,12 +259,12 @@ static char *setup_ring(int fd)
        struct tpacket_req3 req3 = {0};
        void *ring;
 
-       req3.tp_retire_blk_tov = cfg_timeout_msec;
+       req3.tp_retire_blk_tov = cfg_timeout_msec / 8;
        req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
 
        req3.tp_frame_size = 2048;
        req3.tp_frame_nr = 1 << 10;
-       req3.tp_block_nr = 2;
+       req3.tp_block_nr = 16;
 
        req3.tp_block_size = req3.tp_frame_size * req3.tp_frame_nr;
        req3.tp_block_size /= req3.tp_block_nr;
index dc932fd..640bc43 100755 (executable)
@@ -7,6 +7,7 @@ readonly GREEN='\033[0;92m'
 readonly YELLOW='\033[0;33m'
 readonly RED='\033[0;31m'
 readonly NC='\033[0m' # No Color
+readonly TESTPORT=8000
 
 readonly KSFT_PASS=0
 readonly KSFT_FAIL=1
@@ -56,11 +57,26 @@ trap wake_children EXIT
 
 run_one() {
        local -r args=$@
+       local nr_socks=0
+       local i=0
+       local -r timeout=10
+
+       ./udpgso_bench_rx -p "$TESTPORT" &
+       ./udpgso_bench_rx -p "$TESTPORT" -t &
+
+       # Wait for the above test program to get ready to receive connections.
+       while [ "$i" -lt "$timeout" ]; do
+               nr_socks="$(ss -lnHi | grep -c "\*:${TESTPORT}")"
+               [ "$nr_socks" -eq 2 ] && break
+               i=$((i + 1))
+               sleep 1
+       done
+       if [ "$nr_socks" -ne 2 ]; then
+               echo "timed out while waiting for udpgso_bench_rx"
+               exit 1
+       fi
 
-       ./udpgso_bench_rx &
-       ./udpgso_bench_rx -t &
-
-       ./udpgso_bench_tx ${args}
+       ./udpgso_bench_tx -p "$TESTPORT" ${args}
 }
 
 run_in_netns() {
index 6a19342..4058c74 100644 (file)
@@ -250,7 +250,7 @@ static int recv_msg(int fd, char *buf, int len, int *gso_size)
 static void do_flush_udp(int fd)
 {
        static char rbuf[ETH_MAX_MTU];
-       int ret, len, gso_size, budget = 256;
+       int ret, len, gso_size = 0, budget = 256;
 
        len = cfg_read_all ? sizeof(rbuf) : 0;
        while (budget--) {
@@ -336,6 +336,8 @@ static void parse_opts(int argc, char **argv)
                        cfg_verify = true;
                        cfg_read_all = true;
                        break;
+               default:
+                       exit(1);
                }
        }
 
index f1fdaa2..4773927 100644 (file)
@@ -62,6 +62,7 @@ static int    cfg_payload_len = (1472 * 42);
 static int     cfg_port        = 8000;
 static int     cfg_runtime_ms  = -1;
 static bool    cfg_poll;
+static int     cfg_poll_loop_timeout_ms = 2000;
 static bool    cfg_segment;
 static bool    cfg_sendmmsg;
 static bool    cfg_tcp;
@@ -235,16 +236,17 @@ static void flush_errqueue_recv(int fd)
        }
 }
 
-static void flush_errqueue(int fd, const bool do_poll)
+static void flush_errqueue(int fd, const bool do_poll,
+                          unsigned long poll_timeout, const bool poll_err)
 {
        if (do_poll) {
                struct pollfd fds = {0};
                int ret;
 
                fds.fd = fd;
-               ret = poll(&fds, 1, 500);
+               ret = poll(&fds, 1, poll_timeout);
                if (ret == 0) {
-                       if (cfg_verbose)
+                       if ((cfg_verbose) && (poll_err))
                                fprintf(stderr, "poll timeout\n");
                } else if (ret < 0) {
                        error(1, errno, "poll");
@@ -254,6 +256,20 @@ static void flush_errqueue(int fd, const bool do_poll)
        flush_errqueue_recv(fd);
 }
 
+static void flush_errqueue_retry(int fd, unsigned long num_sends)
+{
+       unsigned long tnow, tstop;
+       bool first_try = true;
+
+       tnow = gettimeofday_ms();
+       tstop = tnow + cfg_poll_loop_timeout_ms;
+       do {
+               flush_errqueue(fd, true, tstop - tnow, first_try);
+               first_try = false;
+               tnow = gettimeofday_ms();
+       } while ((stat_zcopies != num_sends) && (tnow < tstop));
+}
+
 static int send_tcp(int fd, char *data)
 {
        int ret, done = 0, count = 0;
@@ -413,7 +429,8 @@ static int send_udp_segment(int fd, char *data)
 
 static void usage(const char *filepath)
 {
-       error(1, 0, "Usage: %s [-46acmHPtTuvz] [-C cpu] [-D dst ip] [-l secs] [-M messagenr] [-p port] [-s sendsize] [-S gsosize]",
+       error(1, 0, "Usage: %s [-46acmHPtTuvz] [-C cpu] [-D dst ip] [-l secs] "
+                   "[-L secs] [-M messagenr] [-p port] [-s sendsize] [-S gsosize]",
                    filepath);
 }
 
@@ -423,7 +440,7 @@ static void parse_opts(int argc, char **argv)
        int max_len, hdrlen;
        int c;
 
-       while ((c = getopt(argc, argv, "46acC:D:Hl:mM:p:s:PS:tTuvz")) != -1) {
+       while ((c = getopt(argc, argv, "46acC:D:Hl:L:mM:p:s:PS:tTuvz")) != -1) {
                switch (c) {
                case '4':
                        if (cfg_family != PF_UNSPEC)
@@ -452,6 +469,9 @@ static void parse_opts(int argc, char **argv)
                case 'l':
                        cfg_runtime_ms = strtoul(optarg, NULL, 10) * 1000;
                        break;
+               case 'L':
+                       cfg_poll_loop_timeout_ms = strtoul(optarg, NULL, 10) * 1000;
+                       break;
                case 'm':
                        cfg_sendmmsg = true;
                        break;
@@ -490,6 +510,8 @@ static void parse_opts(int argc, char **argv)
                case 'z':
                        cfg_zerocopy = true;
                        break;
+               default:
+                       exit(1);
                }
        }
 
@@ -677,7 +699,7 @@ int main(int argc, char **argv)
                        num_sends += send_udp(fd, buf[i]);
                num_msgs++;
                if ((cfg_zerocopy && ((num_msgs & 0xF) == 0)) || cfg_tx_tstamp)
-                       flush_errqueue(fd, cfg_poll);
+                       flush_errqueue(fd, cfg_poll, 500, true);
 
                if (cfg_msg_nr && num_msgs >= cfg_msg_nr)
                        break;
@@ -696,7 +718,7 @@ int main(int argc, char **argv)
        } while (!interrupted && (cfg_runtime_ms == -1 || tnow < tstop));
 
        if (cfg_zerocopy || cfg_tx_tstamp)
-               flush_errqueue(fd, true);
+               flush_errqueue_retry(fd, num_sends);
 
        if (close(fd))
                error(1, errno, "close");
index a7f62ad..2ffba45 100755 (executable)
 ksft_skip=4
 
 testns=testns-$(mktemp -u "XXXXXXXX")
+tmp=""
 
 tables="foo bar baz quux"
 global_ret=0
 eret=0
 lret=0
 
+cleanup() {
+       ip netns pids "$testns" | xargs kill 2>/dev/null
+       ip netns del "$testns"
+
+       rm -f "$tmp"
+}
+
 check_result()
 {
        local r=$1
@@ -43,6 +51,7 @@ if [ $? -ne 0 ];then
        exit $ksft_skip
 fi
 
+trap cleanup EXIT
 tmp=$(mktemp)
 
 for table in $tables; do
@@ -139,11 +148,4 @@ done
 
 check_result $lret "add/delete with nftrace enabled"
 
-pkill -9 ping
-
-wait
-
-rm -f "$tmp"
-ip netns del "$testns"
-
 exit $global_ret
diff --git a/tools/testing/selftests/netfilter/settings b/tools/testing/selftests/netfilter/settings
new file mode 100644 (file)
index 0000000..6091b45
--- /dev/null
@@ -0,0 +1 @@
+timeout=120
index d95b1cb..7588428 100644 (file)
@@ -25,6 +25,7 @@
 #undef NDEBUG
 #include <assert.h>
 #include <errno.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -41,7 +42,7 @@
  * 1: vsyscall VMA is --xp             vsyscall=xonly
  * 2: vsyscall VMA is r-xp             vsyscall=emulate
  */
-static int g_vsyscall;
+static volatile int g_vsyscall;
 static const char *g_proc_pid_maps_vsyscall;
 static const char *g_proc_pid_smaps_vsyscall;
 
@@ -147,11 +148,12 @@ static void vsyscall(void)
 
                g_vsyscall = 0;
                /* gettimeofday(NULL, NULL); */
+               uint64_t rax = 0xffffffffff600000;
                asm volatile (
-                       "call %P0"
-                       :
-                       : "i" (0xffffffffff600000), "D" (NULL), "S" (NULL)
-                       : "rax", "rcx", "r11"
+                       "call *%[rax]"
+                       : [rax] "+a" (rax)
+                       : "D" (NULL), "S" (NULL)
+                       : "rcx", "r11"
                );
 
                g_vsyscall = 1;
index 69551bf..cacbd2a 100644 (file)
@@ -257,11 +257,12 @@ static void vsyscall(void)
 
                g_vsyscall = 0;
                /* gettimeofday(NULL, NULL); */
+               uint64_t rax = 0xffffffffff600000;
                asm volatile (
-                       "call %P0"
-                       :
-                       : "i" (0xffffffffff600000), "D" (NULL), "S" (NULL)
-                       : "rax", "rcx", "r11"
+                       "call *%[rax]"
+                       : [rax] "+a" (rax)
+                       : "D" (NULL), "S" (NULL)
+                       : "rcx", "r11"
                );
 
                g_vsyscall = 1;
index a634f47..9a127a8 100644 (file)
@@ -17,7 +17,6 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/mman.h>
-#define __USE_GNU
 #include <fcntl.h>
 
 #define MIN_FREE_PAGES 20
index 813baf1..51a9190 100644 (file)
@@ -1,13 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef BUG_H
-#define BUG_H
+#ifndef _LINUX_BUG_H
+#define _LINUX_BUG_H
 
 #include <asm/bug.h>
 
 #define BUG_ON(__BUG_ON_cond) assert(!(__BUG_ON_cond))
 
-#define BUILD_BUG_ON(x)
-
 #define BUG() abort()
 
-#endif /* BUG_H */
+#endif /* _LINUX_BUG_H */
diff --git a/tools/virtio/linux/build_bug.h b/tools/virtio/linux/build_bug.h
new file mode 100644 (file)
index 0000000..cdbb75e
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_BUILD_BUG_H
+#define _LINUX_BUILD_BUG_H
+
+#define BUILD_BUG_ON(x)
+
+#endif /* _LINUX_BUILD_BUG_H */
diff --git a/tools/virtio/linux/cpumask.h b/tools/virtio/linux/cpumask.h
new file mode 100644 (file)
index 0000000..307da69
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_CPUMASK_H
+#define _LINUX_CPUMASK_H
+
+#include <linux/kernel.h>
+
+#endif /* _LINUX_CPUMASK_H */
diff --git a/tools/virtio/linux/gfp.h b/tools/virtio/linux/gfp.h
new file mode 100644 (file)
index 0000000..43d146f
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_GFP_H
+#define __LINUX_GFP_H
+
+#include <linux/topology.h>
+
+#endif
index 21593bf..8b87716 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdarg.h>
 
 #include <linux/compiler.h>
+#include <linux/log2.h>
 #include <linux/types.h>
 #include <linux/overflow.h>
 #include <linux/list.h>
diff --git a/tools/virtio/linux/kmsan.h b/tools/virtio/linux/kmsan.h
new file mode 100644 (file)
index 0000000..272b5aa
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_KMSAN_H
+#define _LINUX_KMSAN_H
+
+#include <linux/gfp.h>
+
+inline void kmsan_handle_dma(struct page *page, size_t offset, size_t size,
+                            enum dma_data_direction dir)
+{
+}
+
+#endif /* _LINUX_KMSAN_H */
index 369ee30..74d9e18 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef SCATTERLIST_H
 #define SCATTERLIST_H
 #include <linux/kernel.h>
+#include <linux/bug.h>
 
 struct scatterlist {
        unsigned long   page_link;
diff --git a/tools/virtio/linux/topology.h b/tools/virtio/linux/topology.h
new file mode 100644 (file)
index 0000000..910794a
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_TOPOLOGY_H
+#define _LINUX_TOPOLOGY_H
+
+#include <linux/cpumask.h>
+
+#endif /* _LINUX_TOPOLOGY_H */
index 13e8829..9c60384 100644 (file)
@@ -3954,6 +3954,13 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
        }
 
        mutex_lock(&kvm->lock);
+
+#ifdef CONFIG_LOCKDEP
+       /* Ensure that lockdep knows vcpu->mutex is taken *inside* kvm->lock */
+       mutex_lock(&vcpu->mutex);
+       mutex_unlock(&vcpu->mutex);
+#endif
+
        if (kvm_get_vcpu_by_id(kvm, id)) {
                r = -EEXIST;
                goto unlock_vcpu_destroy;
index 495ceab..9584eb5 100644 (file)
@@ -336,7 +336,7 @@ static int kvm_vfio_has_attr(struct kvm_device *dev,
        return -ENXIO;
 }
 
-static void kvm_vfio_destroy(struct kvm_device *dev)
+static void kvm_vfio_release(struct kvm_device *dev)
 {
        struct kvm_vfio *kv = dev->private;
        struct kvm_vfio_group *kvg, *tmp;
@@ -355,7 +355,7 @@ static void kvm_vfio_destroy(struct kvm_device *dev)
        kvm_vfio_update_coherency(dev);
 
        kfree(kv);
-       kfree(dev); /* alloc by kvm_ioctl_create_device, free by .destroy */
+       kfree(dev); /* alloc by kvm_ioctl_create_device, free by .release */
 }
 
 static int kvm_vfio_create(struct kvm_device *dev, u32 type);
@@ -363,7 +363,7 @@ static int kvm_vfio_create(struct kvm_device *dev, u32 type);
 static struct kvm_device_ops kvm_vfio_ops = {
        .name = "kvm-vfio",
        .create = kvm_vfio_create,
-       .destroy = kvm_vfio_destroy,
+       .release = kvm_vfio_release,
        .set_attr = kvm_vfio_set_attr,
        .has_attr = kvm_vfio_has_attr,
 };